ArrayMesh
Меш из массивов вершин и атрибутов с отдельными поверхностями.
ArrayMesh хранит геометрию, а MeshInstance3D размещает её в мире. Это ресурс, не Entity. Каждый AddSurfaceFromArrays добавляет поверхность; материал назначается отдельно через SurfaceSetMaterial. Индексы поверхностей начинаются с нуля и сдвигаются после SurfaceRemove. Для первого меша достаточно позиций и, при необходимости, индексов.
using var mesh = new ArrayMesh();
using var arrays = new Reckfell.Collections.Array();
arrays.Resize((int)Mesh.ArrayType.Max);
arrays[(int)Mesh.ArrayType.Vertex] = new Vector3[] {
new(0, 0, 0), new(1, 0, 0), new(1, 1, 0), new(0, 1, 0)
};
arrays[(int)Mesh.ArrayType.Index] = new int[] { 0, 1, 2, 0, 2, 3 };
mesh.AddSurfaceFromArrays(Mesh.PrimitiveType.Triangles, arrays);
int vertexCount = mesh.SurfaceGetArrayLen(0); // 4
int indexCount = mesh.SurfaceGetArrayIndexLen(0); // 6Пример проверяет данные, не создаёт видимый объект. Для вывода назначьте ресурс MeshInstance3D.Mesh и добавьте экземпляр в дерево; сохраняйте mesh живым на время использования, не завершайте его using раньше. Подготовьте материал, normals и UV под нужный результат. Для лицевой стороны треугольников используется обход по часовой стрелке.
Массив arrays должен иметь Mesh.ArrayType.Max слотов. Неиспользуемые слоты остаются Nil. Vertex принимает Vector3[] или Vector2[]; Index — int[] с индексами в пределах числа вершин. Normal/UV/Color заполняются для всех вершин, Tangent — четыре float на вершину. Bones/Weights должны иметь согласованное число влияний и корректный формат. Число индексов — не число треугольников: для Triangles оно делится на три. Перед добавлением проверяйте длины, значения и выбранный primitive. SurfaceGetArrays возвращает снимок: правка полученных массивов не редактирует поверхность.
Имена blend shapes задаются до добавления поверхностей; на каждой поверхности нужен массив для каждой формы в том же порядке. Каналы Vertex/Normal/Tangent должны совпадать с основным форматом. Режим по умолчанию Relative. ClearSurfaces сохраняет определения и режим blend shapes; затем ClearBlendShapes может удалить имена. LOD передаются как Dictionary с положительными числовыми порогами и более короткими int[] индексов той же геометрии. Это готовые уровни, не автоматическое упрощение. В C# нет публичного SurfaceGetLods: не переносите это C++-имя в пример.
SurfaceUpdateVertexRegion/AttributeRegion/SkinRegion работают с байтами упакованных буферов, не с индексами Vector3. Формат, смещения и stride зависят от каналов и сжатия; используйте соответствующие MeshSurfaceGetFormat-методы RenderingServer. Нельзя менять длину или топологию такой записью. При деформации расширяйте CustomAabb для корректного отсечения; геометрический GetAabb от установки CustomAabb не меняется. Changed после записи не доказывает пересчёт CPU-кешей, границ или коллизии. Headless backend эти region-записи вообще не выполняет.
RegenNormalMaps пересоздаёт поверхности через SurfaceTool и генерирует тангенты при наличии normals и UV; он не создаёт normal-map изображение и не генерирует normals. Это не способ без потерь сохранить имена, blend shapes, LOD и custom-каналы. LightmapUnwrap создаёт UV2 и может изменить разбиение вершин; свет он не запекает. Нужны callback развёртки в сборке, Triangles с normals, положительный texelSize и отсутствие blend shapes.
ClearSurfaces не отправляет Changed; SurfaceRemove, добавление поверхности, смена имени и CustomAabb отправляют. Если ваш потребитель зависит от сигнала после очистки, вызовите EmitChanged явно. ShadowMesh — общая дополнительная геометрия для теней/depth prepass с теми же позициями, включая LOD, а не замена видимого меша. Инициализируйте основной mesh через добавление поверхности или GetRid до назначения ShadowMesh.
20 Windows headless-проверок подтвердили метаданные, CPU-снимки, имена, очистку, bounds, общие ссылки и простой blend/LOD пакет. GPU-обновления, видимая деформация, выбор LOD, запекание/качество UV2 и производительность не проверены.
Объявления сверены с C# SDK 1.0.0. Раскройте имя, чтобы увидеть сигнатуры и описание.
Конструкторы1
ArrayMeshКонструктор
public ArrayMesh();Создаёт пустой собственный Mesh без поверхностей и blend shapes. Режим Relative; ресурс освобождайте после прекращения использования всеми потребителями.
Свойства5
BlendShapeModeСвойство
public Mesh.BlendShapeMode BlendShapeMode { get; set; }Режим интерпретации blend-данных: Relative по умолчанию, Normalized — нормализованное смешивание. Это не автоматический пересчёт существующих массивов.
CustomAabbСвойство
public Aabb CustomAabb { get; set; }Пользовательская граница отсечения, полезная при shader-деформации. Нулевая Aabb отключает override. Не меняет вершины или результат GetAabb; setter отправляет Changed.
ShadowMeshСвойство
public ArrayMesh ShadowMesh { get; set; }Общий дополнительный mesh для теней/depth prepass. Позиции должны совпадать с основным mesh, включая LOD; можно объединить вершины на швах и убрать ненужные атрибуты. Видимый материал/геометрия не заменяются.
_BlendShapeNamesСвойство
public string[] _BlendShapeNames { get; set; }Скрытое SDK-свойство сериализации списка имён. Для обычной работы используйте AddBlendShape/SetBlendShapeName/ClearBlendShapes; это не массив весов анимации.
_SurfacesСвойство
public Reckfell.Collections.Array _Surfaces { get; set; }Скрытое SDK-свойство сериализации упакованных поверхностей. Это Array словарей с format, vertex_data, counts и необязательными блоками, не массивы AddSurfaceFromArrays. Не редактируйте бинарные словари вручную. Getter отдаёт контейнер, которым владеет вызывающий.
Методы29
AddBlendShapevoid
public void AddBlendShape(StringName name);Добавляет имя до создания поверхностей. Совпадение получает суффикс « 2», « 3» и далее. После добавления поверхностей изменение количества отклоняется.
| Имя | Тип | По умолчанию |
|---|---|---|
name | StringName | — |
nameИмя формы; совпадение автоматически получает свободный числовой суффикс.
AddSurfaceFromArraysvoid
public void AddSurfaceFromArrays(Mesh.PrimitiveType primitive, Reckfell.Collections.Array arrays, Reckfell.Collections.Array<Reckfell.Collections.Array> blendShapes = null, Reckfell.Collections.Dictionary lods = null, Mesh.ArrayFormat flags = (Mesh.ArrayFormat)0);Добавляет поверхность, не заменяет существующую. Требует Max слотов, согласованных каналов и одного массива на каждую объявленную blend shape. Формат определяется данными и flags; на успехе отправляет Changed. Метод void: проверяйте число поверхностей и журнал.
| Имя | Тип | По умолчанию |
|---|---|---|
primitive | Mesh.PrimitiveType | — |
arrays | Reckfell.Collections.Array | — |
blendShapes | Reckfell.Collections.Array<Reckfell.Collections.Array> | null |
lods | Reckfell.Collections.Dictionary | null |
flags | Mesh.ArrayFormat | (Mesh.ArrayFormat)0 |
primitiveСпособ сборки примитивов; для Triangles передайте число углов/индексов, кратное трём.
arraysКонтейнер ровно Mesh.ArrayType.Max слотов: packed-массивы нужных типов и длин; неиспользуемые слоты Nil.
blendShapesПо одному Max-слотовому массиву на каждую объявленную форму в том же порядке; согласованные Vertex/Normal/Tangent. null только при отсутствии форм.
lodsНеобязательный Dictionary: положительный порог → более короткий int[] индексов основной геометрии. Индексы проверяйте сами; не новая сетка вершин.
flagsMesh.ArrayFormat флаги упаковки/обновления и форматов custom-каналов. По умолчанию 0; базовые channel bits определяются массивами.
ClearBlendShapesvoid
public void ClearBlendShapes();Удаляет определения blend shapes только при отсутствии поверхностей. Сначала ClearSurfaces. Сам не отправляет Changed.
ClearSurfacesvoid
public void ClearSurfaces();Удаляет все поверхности и сбрасывает геометрический Aabb. Сохраняет имена/режим blend shapes, CustomAabb и ShadowMesh. Не отправляет Changed и не заменяет полный reset ресурса.
GetBlendShapeCountint
public int GetBlendShapeCount();Возвращает число объявленных форм, не число поверхностей и не число активных весов MeshInstance3D.
intЧисло объявленных форм, включая определения после ClearSurfaces.
GetBlendShapeModeMesh.BlendShapeMode
public Mesh.BlendShapeMode GetBlendShapeMode();Читает текущий режим, также доступный через BlendShapeMode. Начальное значение Relative.
Mesh.BlendShapeModeТекущий Mesh.BlendShapeMode; Relative у нового mesh.
GetBlendShapeNameStringName
public StringName GetBlendShapeName(int index);Читает имя формы по порядку объявления. Пустой fallback при неверном индексе не подтверждает наличие формы.
| Имя | Тип | По умолчанию |
|---|---|---|
index | int | — |
indexИндекс формы от 0 до GetBlendShapeCount()-1, не индекс поверхности.
StringNameStringName текущей формы; пустой fallback при неверном индексе.
GetCustomAabbAabb
public Aabb GetCustomAabb();Читает culling override из CustomAabb, не объединённые геометрические bounds поверхностей.
AabbСохранённый пользовательский override, нулевая Aabb по умолчанию.
GetShadowMeshArrayMesh
public ArrayMesh GetShadowMesh();Возвращает общую ссылку ShadowMesh либо null. Не копирует ресурс; не освобождайте полученный alias раньше владельца.
ArrayMeshОбщая ссылка ArrayMesh либо null. Не копия и не отдельный объект для раннего Dispose.
LightmapUnwrapError
public Error LightmapUnwrap(Transform3D transform, float texelSize);Строит UV2 для lightmap, не запекает свет. Требует callback развёртки, Triangles с normals, texelSize > 0 и отсутствия blend shapes. Использует масштаб transform; может пересоздать вершины/индексы. Работайте с копией и проверяйте результат отдельно.
| Имя | Тип | По умолчанию |
|---|---|---|
transform | Transform3D | — |
texelSize | float | — |
transformМасштаб размещения для плотности UV2. Текущая реализация извлекает длины столбцов basis; перенос/поворот не запекаются в вершины.
texelSizeПоложительный конечный размер texel в единицах масштабированной геометрии; меньшее значение повышает требуемое разрешение.
ErrorError.Ok при завершении развёртки; Unconfigured без callback, Unavailable для blend shapes/неподходящей геометрии, ParameterRangeError при texelSize ≤ 0. Проверяйте и остальные ошибки, новые UV2 и журнал.
RegenNormalMapsvoid
public void RegenNormalMaps();Пересоздаёт поверхности через SurfaceTool.GenerateTangents. Нужны normals и UV; normals и normal-map изображения не генерируются. Не гарантирует сохранение имён, blend shapes, LOD и custom-каналов.
SetBlendShapeModevoid
public void SetBlendShapeMode(Mesh.BlendShapeMode mode);Задаёт режим, также доступный через BlendShapeMode. Не преобразует данные форм и не отправляет Changed.
| Имя | Тип | По умолчанию |
|---|---|---|
mode | Mesh.BlendShapeMode | — |
modeRelative или Normalized согласно данным форм. Это режим смешивания, не команда конвертации.
SetBlendShapeNamevoid
public void SetBlendShapeName(int index, StringName name);Переименовывает форму без изменения её индекса или данных. Конфликт с другим именем получает следующий свободный числовой суффикс; Changed не отправляется.
| Имя | Тип | По умолчанию |
|---|---|---|
index | int | — |
name | StringName | — |
indexИндекс формы от 0 до GetBlendShapeCount()-1, не индекс поверхности.
nameИмя формы; совпадение автоматически получает свободный числовой суффикс.
SetCustomAabbvoid
public void SetCustomAabb(Aabb aabb);Устанавливает CustomAabb для отсечения и отправляет Changed. Геометрический GetAabb и коллизии не изменяются.
| Имя | Тип | По умолчанию |
|---|---|---|
aabb | Aabb | — |
aabbКонечная граница, охватывающая деформацию; нулевая Aabb отключает override. Не новая геометрия.
SetShadowMeshvoid
public void SetShadowMesh(ArrayMesh mesh);Назначает общий дополнительный mesh либо null. Ссылка на себя отклоняется. Сначала инициализируйте RID основного меша; метод сам не вызывает GetRid и не отправляет Changed.
| Имя | Тип | По умолчанию |
|---|---|---|
mesh | ArrayMesh | — |
meshОбщий ArrayMesh с совпадающими позициями либо null для отключения. Не this; основной RID должен быть инициализирован.
SurfaceFindByNameint
public int SurfaceFindByName(string name);Возвращает первый индекс с точным совпадением имени или -1. Имена не обязаны быть уникальными; пустое имя также участвует в поиске.
| Имя | Тип | По умолчанию |
|---|---|---|
name | string | — |
nameТочная строка имени поверхности; уникальность не требуется.
intПервый совпавший индекс или -1 при отсутствии имени.
SurfaceGetArrayIndexLenint
public int SurfaceGetArrayIndexLen(int surfIdx);Число элементов Index у поверхности; 0 для неиндексированной геометрии. Это не число треугольников.
| Имя | Тип | По умолчанию |
|---|---|---|
surfIdx | int | — |
surfIdxТекущий индекс поверхности от 0 до GetSurfaceCount()-1; после удаления индексы могут сдвинуться.
intЧисло индексов; 0 без Index, -1 при неверном surface index.
SurfaceGetArrayLenint
public int SurfaceGetArrayLen(int surfIdx);Число вершин поверхности, не число индексов, байтов или треугольников.
| Имя | Тип | По умолчанию |
|---|---|---|
surfIdx | int | — |
surfIdxТекущий индекс поверхности от 0 до GetSurfaceCount()-1; после удаления индексы могут сдвинуться.
intЧисло вершин; -1 при неверном surface index.
SurfaceGetFormatMesh.ArrayFormat
public Mesh.ArrayFormat SurfaceGetFormat(int surfIdx);Битовая маска реально сохранённого формата: каналы, упаковка и флаги. Используйте её для расчёта layout; не считайте все каналы обычными float-массивами.
| Имя | Тип | По умолчанию |
|---|---|---|
surfIdx | int | — |
surfIdxТекущий индекс поверхности от 0 до GetSurfaceCount()-1; после удаления индексы могут сдвинуться.
Mesh.ArrayFormatСохранённая маска Mesh.ArrayFormat; 0 при диагностике неверного surface index.
SurfaceGetNamestring
public string SurfaceGetName(int surfIdx);Возвращает имя поверхности; оно может быть пустым или повторяться. Имя не является постоянным уникальным ID.
| Имя | Тип | По умолчанию |
|---|---|---|
surfIdx | int | — |
surfIdxТекущий индекс поверхности от 0 до GetSurfaceCount()-1; после удаления индексы могут сдвинуться.
stringИмя, возможно пустое; пустой fallback также используется при неверном surface index.
SurfaceGetPrimitiveTypeMesh.PrimitiveType
public Mesh.PrimitiveType SurfaceGetPrimitiveType(int surfIdx);Возвращает способ сборки примитивов поверхности. Диагностический Lines при неверном индексе не подтверждает валидность поверхности.
| Имя | Тип | По умолчанию |
|---|---|---|
surfIdx | int | — |
surfIdxТекущий индекс поверхности от 0 до GetSurfaceCount()-1; после удаления индексы могут сдвинуться.
Mesh.PrimitiveTypeСохранённый primitive; Lines при диагностике неверного surface index.
SurfaceRemovevoid
public void SurfaceRemove(int surfIdx);Удаляет одну поверхность, сдвигает следующие индексы, очищает кеш Mesh, пересчитывает геометрический Aabb и отправляет Changed. Сохранённые внешние surface IDs обновите самостоятельно.
| Имя | Тип | По умолчанию |
|---|---|---|
surfIdx | int | — |
surfIdxТекущий индекс поверхности от 0 до GetSurfaceCount()-1; после удаления индексы могут сдвинуться.
SurfaceSetNamevoid
public void SurfaceSetName(int surfIdx, string name);Назначает имя поверхности без проверки уникальности; отправляет Changed даже при повторной записи того же имени.
| Имя | Тип | По умолчанию |
|---|---|---|
surfIdx | int | — |
name | string | — |
surfIdxТекущий индекс поверхности от 0 до GetSurfaceCount()-1; после удаления индексы могут сдвинуться.
nameТочная строка имени поверхности; уникальность не требуется.
SurfaceUpdateAttributeRegion2 перегрузки
public void SurfaceUpdateAttributeRegion(int surfIdx, int offset, byte[] data);Записывает непустой блок байтов в существующий буфер атрибутов (цвет, UV, custom). offset измеряется в байтах. Требует точного layout и диапазона; не меняет topology/count и не пересчитывает Aabb/коллизию. Array/span имеют одну семантику. Отправляет Changed; dummy backend запись не выполняет.
| Имя | Тип | По умолчанию |
|---|---|---|
surfIdx | int | — |
offset | int | — |
data | byte[] | — |
surfIdxТекущий индекс поверхности от 0 до GetSurfaceCount()-1; после удаления индексы могут сдвинуться.
offsetБайтовое смещение внутри соответствующего packed-буфера; вместе с длиной data должно помещаться в выделенный диапазон.
dataНепустые байты в layout текущего SurfaceGetFormat. Не сериализованный Vector3[] и не значения Variant; вызов не увеличивает буфер.
public void SurfaceUpdateAttributeRegion(int surfIdx, int offset, ReadOnlySpan<byte> data);Записывает непустой блок байтов в существующий буфер атрибутов (цвет, UV, custom). offset измеряется в байтах. Требует точного layout и диапазона; не меняет topology/count и не пересчитывает Aabb/коллизию. Array/span имеют одну семантику. Отправляет Changed; dummy backend запись не выполняет.
| Имя | Тип | По умолчанию |
|---|---|---|
surfIdx | int | — |
offset | int | — |
data | ReadOnlySpan<byte> | — |
surfIdxТекущий индекс поверхности от 0 до GetSurfaceCount()-1; после удаления индексы могут сдвинуться.
offsetБайтовое смещение внутри соответствующего packed-буфера; вместе с длиной data должно помещаться в выделенный диапазон.
dataНепустые байты в layout текущего SurfaceGetFormat. Не сериализованный Vector3[] и не значения Variant; вызов не увеличивает буфер.
SurfaceUpdateSkinRegion2 перегрузки
public void SurfaceUpdateSkinRegion(int surfIdx, int offset, byte[] data);Записывает непустой блок байтов в существующий буфер костей и весов. offset измеряется в байтах. Требует точного layout и диапазона; не меняет topology/count и не пересчитывает Aabb/коллизию. Array/span имеют одну семантику. Отправляет Changed; dummy backend запись не выполняет.
| Имя | Тип | По умолчанию |
|---|---|---|
surfIdx | int | — |
offset | int | — |
data | byte[] | — |
surfIdxТекущий индекс поверхности от 0 до GetSurfaceCount()-1; после удаления индексы могут сдвинуться.
offsetБайтовое смещение внутри соответствующего packed-буфера; вместе с длиной data должно помещаться в выделенный диапазон.
dataНепустые байты в layout текущего SurfaceGetFormat. Не сериализованный Vector3[] и не значения Variant; вызов не увеличивает буфер.
public void SurfaceUpdateSkinRegion(int surfIdx, int offset, ReadOnlySpan<byte> data);Записывает непустой блок байтов в существующий буфер костей и весов. offset измеряется в байтах. Требует точного layout и диапазона; не меняет topology/count и не пересчитывает Aabb/коллизию. Array/span имеют одну семантику. Отправляет Changed; dummy backend запись не выполняет.
| Имя | Тип | По умолчанию |
|---|---|---|
surfIdx | int | — |
offset | int | — |
data | ReadOnlySpan<byte> | — |
surfIdxТекущий индекс поверхности от 0 до GetSurfaceCount()-1; после удаления индексы могут сдвинуться.
offsetБайтовое смещение внутри соответствующего packed-буфера; вместе с длиной data должно помещаться в выделенный диапазон.
dataНепустые байты в layout текущего SurfaceGetFormat. Не сериализованный Vector3[] и не значения Variant; вызов не увеличивает буфер.
SurfaceUpdateVertexRegion2 перегрузки
public void SurfaceUpdateVertexRegion(int surfIdx, int offset, byte[] data);Записывает непустой блок байтов в существующий буфер вершин и упакованных normals/tangents. offset измеряется в байтах. Требует точного layout и диапазона; не меняет topology/count и не пересчитывает Aabb/коллизию. Array/span имеют одну семантику. Отправляет Changed; dummy backend запись не выполняет.
| Имя | Тип | По умолчанию |
|---|---|---|
surfIdx | int | — |
offset | int | — |
data | byte[] | — |
surfIdxТекущий индекс поверхности от 0 до GetSurfaceCount()-1; после удаления индексы могут сдвинуться.
offsetБайтовое смещение внутри соответствующего packed-буфера; вместе с длиной data должно помещаться в выделенный диапазон.
dataНепустые байты в layout текущего SurfaceGetFormat. Не сериализованный Vector3[] и не значения Variant; вызов не увеличивает буфер.
public void SurfaceUpdateVertexRegion(int surfIdx, int offset, ReadOnlySpan<byte> data);Записывает непустой блок байтов в существующий буфер вершин и упакованных normals/tangents. offset измеряется в байтах. Требует точного layout и диапазона; не меняет topology/count и не пересчитывает Aabb/коллизию. Array/span имеют одну семантику. Отправляет Changed; dummy backend запись не выполняет.
| Имя | Тип | По умолчанию |
|---|---|---|
surfIdx | int | — |
offset | int | — |
data | ReadOnlySpan<byte> | — |
surfIdxТекущий индекс поверхности от 0 до GetSurfaceCount()-1; после удаления индексы могут сдвинуться.
offsetБайтовое смещение внутри соответствующего packed-буфера; вместе с длиной data должно помещаться в выделенный диапазон.
dataНепустые байты в layout текущего SurfaceGetFormat. Не сериализованный Vector3[] и не значения Variant; вызов не увеличивает буфер.