reckfellENGINE

ImmediateMesh: небольшая обновляемая геометрия

Каркас из 12 отрезков, SurfaceBegin/End и пересборка без накопления поверхностей.

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

Запустить каркас

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

Каркас ImmediateMesh с одной поверхностью Lines

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);
    }
}
ImmediateWireLab3D.cs
C#
using System;
using Reckfell;

public partial class ImmediateWireLab3D : Entity3D
{
    [Export] public bool Animate { get; set; } = true;
    public ImmediateMesh Generated { get; private set; } = null!;
    private StandardMaterial3D _material = null!;
    private double _time;

    public override void _Ready()
    {
        GeometryStage3D.Setup(this, "ImmediateMesh: 12 отрезков, 1 поверхность", "ImmediateMesh: 12 lines, 1 surface");
        _material = GeometryStage3D.Material(unshaded: true);
        Generated = new ImmediateMesh();
        AddChild(new MeshInstance3D { Mesh = Generated });
        Rebuild(1.4f);
    }

    public Error Rebuild(float height)
    {
        if (Generated is null) return Error.Unconfigured;
        if (!float.IsFinite(height) || height <= 0 || height > 3) return Error.InvalidParameter;
        Vector3[] points = [new(-1, 0, -1), new(1, 0, -1), new(1, 0, 1), new(-1, 0, 1),
            new(-1, height, -1), new(1, height, -1), new(1, height, 1), new(-1, height, 1)];
        int[] edges = [0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7];
        Generated.ClearSurfaces();
        Generated.SurfaceBegin(Mesh.PrimitiveType.Lines, _material);
        foreach (int index in edges) Generated.SurfaceAddVertex(points[index]);
        Generated.SurfaceEnd();
        return Error.Ok;
    }

    public override void _Process(double delta)
    {
        if (!Animate) return;
        _time += delta;
        Rebuild(1.4f + 0.3f * (float)Math.Sin(_time));
    }
}

Жизненный цикл построения

SurfaceBegin открывает одну поверхность указанного типа. Для Lines каждые две SurfaceAddVertex задают отрезок; 12 отрезков требуют 24 выдачи вершин. SurfaceEnd завершает поверхность. Не вызывайте выдачу вершины до SurfaceBegin и не оставляйте активное построение незавершённым.

SurfaceSetColor, SurfaceSetNormal и UV-методы относятся к следующим выдаваемым вершинам. В примере цвет задаёт материал целой поверхности. Unshaded выбран для диагностических линий: они не зависят от нормалей и освещения как обычная поверхность.

Перерисовать без накопления

Поверхность не исчезает автоматически в следующем кадре. Перед полным построением нового каркаса код делает ClearSurfaces. Повторить SurfaceBegin/End без очистки означает добавить ещё одну поверхность. В проверке после 20 пересборок остаётся ровно одна.

Rebuild сначала проверяет высоту и наличие созданного ресурса, затем очищает собственную геометрию. Копирование ссылки на ImmediateMesh не создаёт независимую копию: очистка общего ресурса затронет всех, кто его показывает. Для крупных статических моделей выберите ArrayMesh/SurfaceTool и не выдавайте каждый кадр тысячи неизменившихся треугольников.

Границы применения

Каркас показывает геометрию, а не физическую форму. Он не участвует в столкновениях и не является сеткой навигации. Толщина и сглаживание линий могут зависеть от renderer; проверена видимая отрисовка установленной Windows/OpenGL-сборки. API ImmediateMesh в C# не предоставляет все методы ArrayMesh: число выданных позиций в стенде читается через SurfaceGetArrays, а не выдуманный ImmediateMesh.SurfaceGetArrayLen.

Для выборочного обновления большого меша исследуйте формат буфера и нужный update API отдельно. Полная пересборка здесь выбрана для 24 позиций; это не обещание высокой производительности любого объёма.

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

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

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

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