RenderingServer.viewport_create
最后同步日期:2026-04-15 | Godot 官方原文 — RenderingServer.viewport_create
RenderingServer.viewport_create
定义
RenderingServer.viewport_create() 是底层渲染服务器提供的方法,用于创建一个新的视口(Viewport)资源,并返回一个视口 RID。
视口可以理解为"一块虚拟的画布"——引擎把 3D 场景和 2D 内容渲染到这块画布上,然后再把画布的内容显示到屏幕上,或者作为纹理贴到其他物体表面。比如游戏中的小地图、监控摄像头画面、后视镜等,都是不同视口的渲染结果。
普通开发中我们用的是 SubViewport 节点,而 RenderingServer.viewport_create() 则绕过节点系统,直接在渲染服务器层面创建视口,适合需要精细控制渲染管线的场景。
函数签名
public static Rid ViewportCreate()func viewport_create() -> RID参数说明
| 参数 | 类型 | 必需 | 说明 |
|---|---|---|---|
| — | — | — | 此函数不接受任何参数 |
返回值
类型: Rid(资源 ID)
返回新创建的视口的 RID。后续所有对该视口的操作(设置大小、挂载场景、绑定摄像机等)都需要用到这个 RID。
代码示例
基础用法:创建视口并设置基本属性
using Godot;
public partial class BasicViewportDemo : Node
{
private Rid _viewportRid;
public override void _Ready()
{
// 1. 创建视口
_viewportRid = RenderingServer.ViewportCreate();
// 2. 设置视口大小(512x512 像素)
RenderingServer.ViewportSetSize(_viewportRid, 512, 512);
// 3. 启用更新(默认是禁用的)
RenderingServer.ViewportSetActive(_viewportRid, true);
// 4. 设置渲染场景为当前场景
var sceneRid = GetTree().Root.GetViewportRid();
// 注意:这里仅为演示,实际需要通过 scenario 关联
var scenarioRid = RenderingServer.ViewportGetScenario(
GetViewport().GetViewportRid()
);
RenderingServer.ViewportSetScenario(_viewportRid, scenarioRid);
GD.Print("视口创建完成,RID: ", _viewportRid);
GD.Print("视口大小: 512x512");
// 运行结果: 视口创建完成,RID: RID(0, 2)
// 运行结果: 视口大小: 512x512
}
public override void _ExitTree()
{
RenderingServer.FreeRid(_viewportRid);
}
}extends Node
var _viewport_rid: RID
func _ready():
# 1. 创建视口
_viewport_rid = RenderingServer.viewport_create()
# 2. 设置视口大小(512x512 像素)
RenderingServer.viewport_set_size(_viewport_rid, 512, 512)
# 3. 启用更新(默认是禁用的)
RenderingServer.viewport_set_active(_viewport_rid, true)
# 4. 设置渲染场景为当前场景
var scenario_rid = RenderingServer.viewport_get_scenario(
get_viewport().get_viewport_rid()
)
RenderingServer.viewport_set_scenario(_viewport_rid, scenario_rid)
print("视口创建完成,RID: ", _viewport_rid)
print("视口大小: 512x512")
# 运行结果: 视口创建完成,RID: RID(0, 2)
# 运行结果: 视口大小: 512x512
func _exit_tree():
RenderingServer.free_rid(_viewport_rid)实际场景:创建渲染纹理用于监控画面
using Godot;
/// <summary>
/// 创建一个独立的视口,把它的渲染结果作为纹理
/// 显示在 UI 上的 TextureRect 中,模拟监控摄像头效果。
/// </summary>
public partial class SurveillanceCamera : Node3D
{
private Rid _cameraRid;
private Rid _viewportRid;
[Export] public TextureRect DisplayRect { get; set; }
[Export] public int ExViewportWidth = 256;
[Export] public int ExViewportHeight = 256;
public override void _Ready()
{
// 1. 创建视口
_viewportRid = RenderingServer.ViewportCreate();
RenderingServer.ViewportSetSize(_viewportRid, ExViewportWidth, ExViewportHeight);
RenderingServer.ViewportSetActive(_viewportRid, true);
// 关联到当前场景的渲染环境
var scenarioRid = RenderingServer.ViewportGetScenario(
GetViewport().GetViewportRid()
);
RenderingServer.ViewportSetScenario(_viewportRid, scenarioRid);
// 设置视口更新模式为每帧更新
RenderingServer.ViewportSetUpdateMode(
_viewportRid,
RenderingServer.ViewportUpdateMode.Always
);
// 设置视口输出为纹理
RenderingServer.ViewportSetRenderTargetVFlip(_viewportRid, true);
// 2. 创建摄像机并挂载到视口
_cameraRid = RenderingServer.CameraCreate();
RenderingServer.CameraSetPerspective(_cameraRid, fov: 60f, znear: 0.05f, zfar: 100f);
var camTransform = GlobalTransform;
RenderingServer.CameraSetTransform(_cameraRid, camTransform);
RenderingServer.ViewportAttachCamera(_viewportRid, _cameraRid);
// 3. 将视口纹理显示到 UI 上
if (DisplayRect != null)
{
var viewportTexture = RenderingServer.ViewportGetTexture(_viewportRid);
DisplayRect.Texture = viewportTexture;
GD.Print("监控画面已连接到显示区域");
}
// 运行结果: 监控画面已连接到显示区域
}
public override void _ExitTree()
{
RenderingServer.FreeRid(_cameraRid);
RenderingServer.FreeRid(_viewportRid);
}
}extends Node3D
## 创建一个独立的视口,把它的渲染结果作为纹理
## 显示在 UI 上的 TextureRect 中,模拟监控摄像头效果。
@export var display_rect: TextureRect
@export var viewport_width: int = 256
@export var viewport_height: int = 256
var _camera_rid: RID
var _viewport_rid: RID
func _ready():
# 1. 创建视口
_viewport_rid = RenderingServer.viewport_create()
RenderingServer.viewport_set_size(_viewport_rid, viewport_width, viewport_height)
RenderingServer.viewport_set_active(_viewport_rid, true)
# 关联到当前场景的渲染环境
var scenario_rid = RenderingServer.viewport_get_scenario(
get_viewport().get_viewport_rid()
)
RenderingServer.viewport_set_scenario(_viewport_rid, scenario_rid)
# 设置视口更新模式为每帧更新
RenderingServer.viewport_set_update_mode(
_viewport_rid,
RenderingServer.ViewportUpdateMode.VIEWPORT_UPDATE_ALWAYS
)
# 设置视口输出为纹理
RenderingServer.viewport_set_render_target_vflip(_viewport_rid, true)
# 2. 创建摄像机并挂载到视口
_camera_rid = RenderingServer.camera_create()
RenderingServer.camera_set_perspective(_camera_rid, 60.0, 0.05, 100.0)
var cam_transform = global_transform
RenderingServer.camera_set_transform(_camera_rid, cam_transform)
RenderingServer.viewport_attach_camera(_viewport_rid, _camera_rid)
# 3. 将视口纹理显示到 UI 上
if display_rect:
var viewport_texture = RenderingServer.viewport_get_texture(_viewport_rid)
display_rect.texture = viewport_texture
print("监控画面已连接到显示区域")
# 运行结果: 监控画面已连接到显示区域
func _exit_tree():
RenderingServer.free_rid(_camera_rid)
RenderingServer.free_rid(_viewport_rid)进阶用法:分屏多人游戏视口
using Godot;
/// <summary>
/// 分屏多人游戏示例:为每个玩家创建独立的视口和摄像机,
/// 实现上下分屏效果(适合双人本地对战)。
/// </summary>
public partial class SplitScreenManager : Node
{
private Rid _viewport1;
private Rid _viewport2;
private Rid _camera1;
private Rid _camera2;
[Export] public Node3D Player1 { get; set; }
[Export] public Node3D Player2 { get; set; }
public override void _Ready()
{
var mainViewportRid = GetViewport().GetViewportRid();
var screenWidth = (int)GetViewport().GetVisibleRect().Size.X;
var screenHeight = (int)GetViewport().GetVisibleRect().Size.Y;
var halfHeight = screenHeight / 2;
// 获取场景环境
var scenarioRid = RenderingServer.ViewportGetScenario(mainViewportRid);
// ---- 玩家 1 的视口(上半屏)----
_viewport1 = RenderingServer.ViewportCreate();
RenderingServer.ViewportSetSize(_viewport1, screenWidth, halfHeight);
RenderingServer.ViewportSetActive(_viewport1, true);
RenderingServer.ViewportSetScenario(_viewport1, scenarioRid);
RenderingServer.ViewportSetUpdateMode(
_viewport1, RenderingServer.ViewportUpdateMode.Always
);
_camera1 = RenderingServer.CameraCreate();
RenderingServer.CameraSetPerspective(_camera1, fov: 65f, znear: 0.1f, zfar: 200f);
RenderingServer.ViewportAttachCamera(_viewport1, _camera1);
// ---- 玩家 2 的视口(下半屏)----
_viewport2 = RenderingServer.ViewportCreate();
RenderingServer.ViewportSetSize(_viewport2, screenWidth, halfHeight);
RenderingServer.ViewportSetActive(_viewport2, true);
RenderingServer.ViewportSetScenario(_viewport2, scenarioRid);
RenderingServer.ViewportSetUpdateMode(
_viewport2, RenderingServer.ViewportUpdateMode.Always
);
_camera2 = RenderingServer.CameraCreate();
RenderingServer.CameraSetPerspective(_camera2, fov: 65f, znear: 0.1f, zfar: 200f);
RenderingServer.ViewportAttachCamera(_viewport2, _camera2);
GD.Print($"分屏设置完成: {screenWidth}x{halfHeight} x 2");
// 运行结果: 分屏设置完成: 1920x540 x 2
}
public override void _Process(double delta)
{
// 每帧更新摄像机位置跟随各自玩家
if (Player1 != null)
{
var t1 = Player1.GlobalTransform;
var offset1 = new Transform3D(Basis.Identity, t1.Origin + new Vector3(0, 5, 8));
offset1 = offset1.LookingAt(t1.Origin, Vector3.Up);
RenderingServer.CameraSetTransform(_camera1, offset1);
}
if (Player2 != null)
{
var t2 = Player2.GlobalTransform;
var offset2 = new Transform3D(Basis.Identity, t2.Origin + new Vector3(0, 5, 8));
offset2 = offset2.LookingAt(t2.Origin, Vector3.Up);
RenderingServer.CameraSetTransform(_camera2, offset2);
}
}
public override void _ExitTree()
{
RenderingServer.FreeRid(_camera1);
RenderingServer.FreeRid(_camera2);
RenderingServer.FreeRid(_viewport1);
RenderingServer.FreeRid(_viewport2);
}
}extends Node
## 分屏多人游戏示例:为每个玩家创建独立的视口和摄像机,
## 实现上下分屏效果(适合双人本地对战)。
@export var player1: Node3D
@export var player2: Node3D
var _viewport1: RID
var _viewport2: RID
var _camera1: RID
var _camera2: RID
func _ready():
var main_viewport_rid = get_viewport().get_viewport_rid()
var screen_size = get_viewport().get_visible_rect().size
var screen_width = int(screen_size.x)
var screen_height = int(screen_size.y)
var half_height = screen_height / 2
# 获取场景环境
var scenario_rid = RenderingServer.viewport_get_scenario(main_viewport_rid)
# ---- 玩家 1 的视口(上半屏)----
_viewport1 = RenderingServer.viewport_create()
RenderingServer.viewport_set_size(_viewport1, screen_width, half_height)
RenderingServer.viewport_set_active(_viewport1, true)
RenderingServer.viewport_set_scenario(_viewport1, scenario_rid)
RenderingServer.viewport_set_update_mode(
_viewport1, RenderingServer.ViewportUpdateMode.VIEWPORT_UPDATE_ALWAYS
)
_camera1 = RenderingServer.camera_create()
RenderingServer.camera_set_perspective(_camera1, 65.0, 0.1, 200.0)
RenderingServer.viewport_attach_camera(_viewport1, _camera1)
# ---- 玩家 2 的视口(下半屏)----
_viewport2 = RenderingServer.viewport_create()
RenderingServer.viewport_set_size(_viewport2, screen_width, half_height)
RenderingServer.viewport_set_active(_viewport2, true)
RenderingServer.viewport_set_scenario(_viewport2, scenario_rid)
RenderingServer.viewport_set_update_mode(
_viewport2, RenderingServer.ViewportUpdateMode.VIEWPORT_UPDATE_ALWAYS
)
_camera2 = RenderingServer.camera_create()
RenderingServer.camera_set_perspective(_camera2, 65.0, 0.1, 200.0)
RenderingServer.viewport_attach_camera(_viewport2, _camera2)
print("分屏设置完成: %dx%d x 2" % [screen_width, half_height])
# 运行结果: 分屏设置完成: 1920x540 x 2
func _process(_delta: float) -> void:
# 每帧更新摄像机位置跟随各自玩家
if player1:
var origin = player1.global_transform.origin
var offset = Transform3D(Basis.IDENTITY, origin + Vector3(0, 5, 8))
offset = offset.looking_at(origin, Vector3.UP)
RenderingServer.camera_set_transform(_camera1, offset)
if player2:
var origin = player2.global_transform.origin
var offset = Transform3D(Basis.IDENTITY, origin + Vector3(0, 5, 8))
offset = offset.looking_at(origin, Vector3.UP)
RenderingServer.camera_set_transform(_camera2, offset)
func _exit_tree():
RenderingServer.free_rid(_camera1)
RenderingServer.free_rid(_camera2)
RenderingServer.free_rid(_viewport1)
RenderingServer.free_rid(_viewport2)注意事项
必须手动释放资源:通过
RenderingServer.viewport_create()创建的视口不会随节点树自动销毁,务必在_ExitTree()中调用RenderingServer.FreeRid()释放。新视口默认不活跃:创建后需要调用
ViewportSetActive(viewportRid, true)才能启用渲染。必须设置大小:新创建的视口大小默认为 0x0,必须通过
ViewportSetSize()设置具体的像素尺寸。需要关联场景环境:视口需要通过
ViewportSetScenario()关联到某个渲染场景(scenario),否则无法看到任何 3D 内容。优先使用 SubViewport 节点:绝大多数情况下使用场景树中的
SubViewport节点就足够了,更简单且不易出错。底层 API 适合需要同时管理大量视口、或需要极致性能优化的场景。视口纹理获取:可以通过
RenderingServer.ViewportGetTexture(viewportRid)获取视口的渲染结果纹理,用于贴图到 UI 或 3D 物体表面。
