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
vertices | Lista de Vec3 (posiciones locales). |
normals | Lista de Vec3. Si falta, se calcula sola al dibujarla. |
uv | Coordenadas de textura en Vec3 (se usan x e y). |
tangents | Lista 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. |
subMeshCount | Número de submallas (lectura y escritura). |
:setVertex(i, p), :getVertex(i) | Un vértice suelto (índice desde 0). Después llama a :apply(). |
vertexCount, triangleCount | Cuántos hay. |
boundsMin, boundsMax | Caja envolvente. |
name | Nombre (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. |
-- 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.
¿Algo no queda claro o falta algo? Pregunta en el Discord.