reckfellENGINE

RenderingServer: создать экземпляр и освободить RID

Отображение без MeshInstance3D, сильные ссылки на ресурсы и очистка при выходе из дерева.

На этой странице

Когда нужен серверный API

Обычная MeshInstance3D уже управляет отображаемым экземпляром и интеграцией с деревом. RenderingServer позволяет вести такие экземпляры самостоятельно через RID. Это полезно при собственной системе отображения, но добавляет ответственность за ресурс, сценарий, преобразование, видимость и освобождение. Сам выбор низкоуровневого API не доказывает ускорение.

Запустить экземпляр без MeshInstance3D

Добавьте GeometryStage3D.cs и ServerBoxLab3D.cs. Прикрепите ServerBoxLab3D к Entity3D-корню отдельного C#-уровня 1.0.0, задайте viewport 640×420, соберите и нажмите F6. Появится синий куб. Пол стенда использует обычную MeshInstance3D, а сам синий куб создан через RenderingServer.InstanceCreate.

Синий куб RenderingServer с явным владением RID

GeometryStage3D.cs
C#
using Reckfell;

public static class GeometryStage3D
{
    public static StandardMaterial3D Material(bool vertexColors = false, bool unshaded = false)
    {
        return new StandardMaterial3D
        {
            AlbedoColor = vertexColors ? Colors.White : new Color(0.24f, 0.44f, 1),
            VertexColorUseAsAlbedo = vertexColors,
            ShadingMode = unshaded ? BaseMaterial3D.ShadingModeEnum.Unshaded : BaseMaterial3D.ShadingModeEnum.PerPixel,
            Roughness = 0.8f
        };
    }

    public static void Setup(Entity3D root, string ru, string en)
    {
        root.AddChild(new WorldEnvironment { Environment = new Reckfell.Environment
        {
            BackgroundMode = Reckfell.Environment.BGMode.Color,
            BackgroundColor = new Color(0.035f, 0.04f, 0.05f),
            AmbientLightSource = Reckfell.Environment.AmbientSource.Color,
            AmbientLightColor = Colors.White, AmbientLightEnergy = 0.5f
        }});
        root.AddChild(new DirectionalLight3D { RotationDegrees = new Vector3(-55, -25, 0), LightEnergy = 1.2f });
        root.AddChild(new MeshInstance3D
        {
            Mesh = new BoxMesh { Size = new Vector3(8, 0.05f, 6) }, Position = new Vector3(0, -0.12f, 0),
            MaterialOverride = new StandardMaterial3D { AlbedoColor = new Color(0.10f, 0.11f, 0.13f), Roughness = 1 }
        });
        var camera = new Camera3D { Position = new Vector3(4, 4.8f, 6), Current = true, Fov = 45 };
        root.AddChild(camera); camera.LookAt(new Vector3(0, 0.35f, 0), Vector3.Up);
        var canvas = new CanvasLayer(); root.AddChild(canvas);
        var label = new Label { Position = new Vector2(24, 20), Text = TranslationServer.GetLocale().StartsWith("ru") ? ru : en };
        label.AddThemeFontSizeOverride("font_size", 22); canvas.AddChild(label);
    }
}
ServerBoxLab3D.cs
C#
using Reckfell;

public partial class ServerBoxLab3D : Entity3D
{
    public bool Active => _instance.IsValid;
    public Rid Instance => _instance;
    private Rid _instance;
    private BoxMesh? _mesh;
    private StandardMaterial3D? _material;

    public Error Open()
    {
        if (!ReckfellThread.IsMainThread()) return Error.Unavailable;
        if (!IsInsideTree()) return Error.Unconfigured;
        if (Active) return Error.Busy;
        _material = GeometryStage3D.Material();
        _mesh = new BoxMesh { Size = new Vector3(1.5f, 1.5f, 1.5f), Material = _material };
        _instance = RenderingServer.InstanceCreate();
        RenderingServer.InstanceSetBase(_instance, _mesh.GetRid());
        RenderingServer.InstanceSetScenario(_instance, GetWorld3D().Scenario);
        UpdateTransform();
        SetProcess(true);
        return Error.Ok;
    }

    private void UpdateTransform()
    {
        RenderingServer.InstanceSetTransform(_instance, GlobalTransform.TranslatedLocal(new Vector3(0, 0.75f, 0)));
    }

    public void Close()
    {
        if (Active) RenderingServer.FreeRid(_instance);
        _instance = default;
        _mesh?.Dispose(); _mesh = null;
        _material?.Dispose(); _material = null;
        SetProcess(false);
    }

    public override void _Ready()
    {
        GeometryStage3D.Setup(this, "RenderingServer: экземпляр без MeshInstance3D", "RenderingServer: an instance without MeshInstance3D");
        Error error = Open();
        if (error != Error.Ok) ReckfellApi.PrintErr("ServerBox open: " + error);
    }

    public override void _Process(double delta)
    {
        if (Active) UpdateTransform();
    }

    public override void _ExitTree() => Close();
}

Цепочка владения

  1. Сохраните сильные C#-ссылки на Mesh и Material. Их RID не заменяют эти ссылки.
  2. InstanceCreate создаёт собственный экземпляр.
  3. InstanceSetBase указывает Mesh RID; InstanceSetScenario подключает экземпляр к сценарию GetWorld3D().Scenario.
  4. InstanceSetTransform передаёт мировое преобразование. Оно не синхронизируется с Entity автоматически — код обновляет его сам.
  5. При завершении FreeRid освобождает созданный экземпляр. Затем можно отпустить собственные ресурсы и обнулить сохранённый RID.

RID — значение-идентификатор, а не Resource с автоматическим временем жизни. Копия RID не владеет объектом. IsValid означает ненулевое значение; после FreeRid сохранённая отдельно копия всё ещё может иметь IsValid = true, хотя нативного экземпляра уже нет. Не используйте такую копию для последующих вызовов.

Нельзя FreeRid для заимствованного World3D.Scenario или вручную освобождать RID живого Mesh вместо его ресурсного владельца. В примере освобождается только собственный instance RID; Material и Mesh удерживаются до этого и освобождаются через свои C#-обёртки.

Отключение и повторный вход

Close идемпотентен, сбрасывает RID и ссылки. _ExitTree вызывает его. Повторный вход той же Entity сам по себе не повторяет _Ready; после добавления вызовите Open явно, если нужно открыть новый экземпляр. В стенде проверены повторное открытие и новый RID, выход из дерева и отсутствие двойного освобождения. В графическом тесте после Close куб действительно исчезает из viewport, а не только меняется флаг Active.

Open/Close и управление Entity выполняйте в главном потоке в этой архитектуре. Отдельные потоки server API не дают общего разрешения обращаться к дереву или общим ресурсам; см. потокобезопасность.

PhysicsServer2D/3D и другие серверы имеют собственные типы RID и контракты: тело, shape, space, callbacks и шаг симуляции не создаются этим рендер-примером. Он не реализует ECS, физику, игровые скрипты для каждого экземпляра, сетевую репликацию или стриминг. Для многих одинаковых мешей сначала оцените более простой MultiMesh.

Документация Reckfell EngineНаверх ↑
БЫСТРЫЙ ПЕРЕХОДНачало работыEntity и иерархияC# & .NET 10Сцены и префабы
Руководства и полный API Reckfell K
reckfellENGINE
RECKFELL ACCOUNT

Вход в аккаунт

Войдите в аккаунт Reckfell.

Один аккаунт для всей платформы Reckfell.