Manual/ Referencia de la API

Mallas por código

Crea y modifica mallas con varios materiales desde Lua.

Crea o cambia geometría mientras se juega (terrenos procedurales, cuerdas, trazos, agua con olas, objetos generados…). Se asigna con entity.mesh = malla y el MeshRenderer la dibuja en lugar de su modelo, con sombras, luces y postproceso como cualquier objeto. Si la entidad tiene un MeshCollider, choca con ella (y se rehace al cambiarla).

Crear

Mesh.new(nombre)Malla vacía.
Mesh.cube(tamaño)Cubo (tamaño número o Vec3, 1 por defecto) con aristas duras.
Mesh.quad(ancho, alto)Cuadrado en XY mirando a +Z.
Mesh.plane(ancho, fondo, segX, segZ)Plano horizontal subdividido (10 × 10 m y 10 × 10 por defecto).
Mesh.sphere(radio, segmentos, anillos)Esfera UV.
Mesh.cylinder(radio, alto, segmentos)Cilindro con tapas.
Mesh.capsule(radio, alto, segmentos)Cápsula (alto total, con las semiesferas).
Mesh.wireCube(tamaño, grosor)Las 12 aristas de una caja como barras (contornos de selección).
malla:clone()Copia independiente.

Datos

verticesLista de Vec3 (posiciones locales).
normalsLista de Vec3. Si falta, se calcula sola al dibujarla.
uvCoordenadas de textura en Vec3 (se usan x e y).
tangentsLista de Vec3 (para normal maps). Mejor recalculateTangents().
trianglesÍndices de la submalla 0, tres por triángulo, en sentido antihorario visto desde fuera. Empiezan en 0: el vértice 0 es vertices[1].
:setTriangles(lista, submalla), :getTriangles(submalla)Triángulos de cada submalla. Cada submalla es un hueco de material.
subMeshCountNúmero de submallas (lectura y escritura).
:setVertex(i, p), :getVertex(i)Un vértice suelto (índice desde 0). Después llama a :apply().
vertexCount, triangleCountCuántos hay.
boundsMin, boundsMaxCaja envolvente.
nameNombre (para los mensajes).

Métodos

:recalculateNormals()Normales suaves por vértice (media de sus caras, por área). Para aristas duras, usa vértices separados en cada cara.
:recalculateTangents()Tangentes a partir de las UV (para que se vean los normal maps).
:recalculateBounds()Recalcula la caja envolvente.
:setMaterial(submalla, t)Material de una submalla. Campos: color (Vec3), alpha, metallic, roughness, emission (Vec3), emissionIntensity, y las texturas texture, normalMap, emissionMap (rutas en Assets; false la quita), normalStrength, tiling y offset (Vec3 x, y). El alfa de texture recorta (hojas, rejas, grietas). Solo se cambian los campos que pases. Un .crmat puesto con entity:setMaterial manda sobre él.
:getMaterial(submalla)Tabla con esos mismos campos.
:apply()Sube los cambios a la GPU en el siguiente frame. Asignar una lista entera (malla.vertices = {...}) ya lo hace.
:validate()"" si se puede dibujar; si no, qué falla (índice fuera de rango, listas de distinto tamaño…). Una malla no válida no se dibuja y se avisa en la consola.
:clear()La vacía.
Cambiar una malla sube solo esa malla (no se para la GPU ni se vuelve a subir la escena), así que se puede cambiar cada frame. Cambiar solo el color, el metal, la rugosidad o la emisión de un material ni siquiera la vuelve a subir: se actualiza al momento (efectos por frame). Cambiar texturas o repetición sí la vuelve a subir. Varias entidades pueden compartir la misma malla. Las mallas por código no se guardan en la escena: se crean al empezar el juego. No tienen color por vértice; usa submallas con materiales distintos.
-- Un triángulo a mano
local m = Mesh.new("Triángulo")
m.vertices = { Vec3(0, 0, 0), Vec3(1, 0, 0), Vec3(0, 1, 0) }
m.uv = { Vec3(0, 1, 0), Vec3(1, 1, 0), Vec3(0, 0, 0) }
m.triangles = { 0, 1, 2 }
m:recalculateNormals()
m:setMaterial(0, { color = Vec3(1, 0.5, 0.1), roughness = 0.4 })
self.entity.mesh = m

Objetos Static y static batching

La casilla Static del Inspector (junto al nombre) dice que el objeto no se mueve en el juego. Al exportar con Combinar mallas estáticas activado, las mallas de todos los objetos Static de cada escena se combinan en un lote: los materiales iguales (mismos valores y mismas texturas, aunque vengan de modelos distintos) se dibujan en una sola llamada. El lote se sigue partiendo por zonas, así que la GPU descarta lo que queda fuera de cámara o tapado. Solo cambia la copia de la escena que va al juego; el proyecto no se toca.

No marques Static lo que un script vaya a mover, ocultar o cambiar de malla o material: su malla va dentro del lote y esos cambios no se verían. Las colisiones y los scripts siguen encontrando el objeto. No se combinan los objetos con Animator, Script o un Rigidbody que no sea estático (en él o en un padre), las mallas creadas por código, ni las mallas repetidas más de 32 veces (esas ya se dibujan instanciadas, una llamada por material, sin gastar memoria de más).

¿Algo no queda claro o falta algo? Pregunta en el Discord.