In this second example we'll show how to create your own geometry from the Octane Lua Api. We'll create a simple cube and assign a material to each face of the cube. We do this by creating a mesh node and directly manipulating it's attributes. Be aware that if you set up a mesh node incorrectly you could potentially crash Octane!
All it boils down to is setting up the attributes of the mesh node correctly. Let's see what the API browser has to say about mesh nodes (type NT_GEO_MESH):
Code: Select all
A_VERTICES_PER_POLY
• Description : An array of the number of vertices for each polygon in the polygon sequence. Must not be empty.
• Type : AT_INT
• Array : true
A_VERTICES
• Description : An array of vertex positions. Must not be empty.
• Type : AT_FLOAT3
• Array : true
A_POLY_VERTEX_INDICES
• Description : An array that stores the indices into A_VERTICES for each vertex of each polygon. Its size must be equal to the sum of all vertex counts in A_VERTICES_PER_POLY.
• Type : AT_INT
• Array : true
A_NORMALS
• Description : An array of vertex normals. If not empty, but A_POLY_NORMAL_INDICES is empty this array must directly store the normals for each vertex of each polygon. If left empty, the vertex normals will be calculated on-the-fly. To calculate the vertex normals the geometry import preferences as well as the smooth groups (if specified) will be used.
• Type : AT_FLOAT3
• Array : true
A_POLY_NORMAL_INDICES
• Description : An array that stores the indices into A_NORMALS for each vertex of each polygon. Must be either empty or its size must be equal to the sum of all vertex counts in A_VERTICES_PER_POLY.
• Type : AT_INT
• Array : true
A_SMOOTH_GROUPS
• Description : If A_NORMALS is empty and the vertex normals will be calculated on-the-fly, you can specify a smooth group for each polygon. The edges between different smooth groups will not be smoothed. Also all polygons with a negative smooth group will not be smoothed at all. If not empty, the size of this array must be equal to the size of A_VERTICES_PER_POLY.
• Type : AT_INT
• Array : true
A_UVWS
• Description : An array of UVW coordinates. If empty, every vertex will have a UVW coordinate of (0,0,0). If not empty, but A_POLY_UVW_INDICES is empty this array mst directly store the UVW coordinates for each vertex of each polygon, i.e. its size must be the sum of all elements of A_VERTICES_PER_POLY.
• Type : AT_FLOAT3
• Array : true
A_POLY_UVW_INDICES
• Description : An array that stores the indices into A_UVWS for each vertex of each polygon.Must be either empty or its size must be equal to the sum of all vertex counts in A_VERTICES_PER_POLY.
• Type : AT_INT
• Array : true
A_MATERIAL_NAMES
• Description : An array of material names. Must not be empty.
• Type : AT_STRING
• Array : true
A_POLY_MATERIAL_INDICES
• Description : An array that stores the indices into A_MATERIAL_NAMES for each polygon, i.e. the size must be equal to the size of A_VERTICES_PER_POLY.
• Type : AT_INT
• Array : true
First we make sure we start with a clean slate:
Code: Select all
-- start with a clean slate
octane.project.reset()
Code: Select all
-- vertices for the cube
vertices =
{
{ -1. , -1. , 1.} ,
{ -1. , 1. , 1.} ,
{ 1. , 1. , 1.} ,
{ 1. , -1. , 1.} ,
{ -1. , -1. , -1.} ,
{ -1. , 1. , -1.} ,
{ 1. , 1. , -1.} ,
{ 1. , -1. , -1.} ,
}
-- 4 vertices per poly (each face is a quad)
verticesPerPoly =
{
4, -- face1
4, -- face2
4, -- face3
4, -- face4
4, -- face5
4, -- face6
}
-- tells which vertices are used for each face of the cube
-- each number is an index in vertices
-- NOTE: indices are 0-based!
polyVertexIndices =
{
3 , 2 , 1 , 0 , -- face1
0 , 1 , 5 , 4 , -- face2
6 , 5 , 1 , 2 , -- face3
3 , 7 , 6 , 2 , -- face4
4 , 7 , 3 , 0 , -- face5
4 , 5 , 6 , 7 -- face6
}
and an array that assigns each face a material name:
Code: Select all
-- material names (we use 1 material per face)
materialNames = { "f1", "f2", "f3", "f4", "f5", "f6" }
-- material indices (we assign 1 material per face)
-- NOTE: indices are 0-based!
polyMaterialIndices = { 0, 1, 2, 3, 4, 5 }
Code: Select all
-- create the actual mesh node, at this point the mesh node isn't usable yet!
meshNode = octane.node.create{ type=octane.NT_GEO_MESH , name="MyCube", position={ 500, 500 } }
Code: Select all
-- set up the geometry attributes. we shouldn't evaluate them immediately!
meshNode:setAttribute(octane.A_VERTICES , vertices , false)
meshNode:setAttribute(octane.A_VERTICES_PER_POLY , verticesPerPoly , false)
meshNode:setAttribute(octane.A_POLY_VERTEX_INDICES , polyVertexIndices , false)
meshNode:setAttribute(octane.A_MATERIAL_NAMES , materialNames , false)
meshNode:setAttribute(octane.A_POLY_MATERIAL_INDICES , polyMaterialIndices , false)
-- all is set up correctly, now we can evaluate the geometry
meshNode:evaluate()
Code: Select all
-- colours for each face
faceColours =
{
f1 = { 255, 0, 0 },
f2 = { 0, 255, 0 },
f3 = { 0, 0, 255 },
f4 = { 255, 255, 0 },
f5 = { 255, 0, 255 },
f6 = { 0, 255, 255 },
}
-- create a diffuse material in each input pin, the input pins will have the same
-- names as the material names defined above
for _, matName in ipairs(materialNames) do
-- create each diffuse material internal to the pin
matNode = octane.node.create
{
type = octane.NT_MAT_DIFFUSE,
name = "Diffuse_"..matName,
pinOwnerNode = meshNode,
pinOwnerName = matName
}
-- set the diffuse colour of the material via the pin
matNode:setPinValue(octane.P_DIFFUSE, faceColours[matName])
end
Code: Select all
-- let's export our cube to an obj file. The file name will be the node's name in the
-- geometry directory (e.g. /tmp/LuaCube/geometry/MyCube.obj)
directory = "/tmp/LuaCube"
meshNode:exportToFile(directory)
Code: Select all
-- let's load the obj file again.
loadedMesh = octane.node.create{ type=octane.NT_GEO_MESH , name="Loaded Cube", position={ 550, 550 } }
loadedMesh:setAttribute(octane.A_FILENAME, "/tmp/LuaCube/geometry/MyCube.obj", true)
Code: Select all
--
-- create a textured cube from Lua.
--
-- start with a clean slate
octane.project.reset()
-- vertices for the cube
vertices =
{
{ -1. , -1. , 1.} ,
{ -1. , 1. , 1.} ,
{ 1. , 1. , 1.} ,
{ 1. , -1. , 1.} ,
{ -1. , -1. , -1.} ,
{ -1. , 1. , -1.} ,
{ 1. , 1. , -1.} ,
{ 1. , -1. , -1.} ,
}
-- 4 vertices per poly (each face is a quad)
verticesPerPoly =
{
4, -- face1
4, -- face2
4, -- face3
4, -- face4
4, -- face5
4, -- face6
}
-- tells which vertices are used for each face of the cube
-- each number is an index in vertices
-- NOTE: indices are 0-based!
polyVertexIndices =
{
3 , 2 , 1 , 0 , -- face1
0 , 1 , 5 , 4 , -- face2
6 , 5 , 1 , 2 , -- face3
3 , 7 , 6 , 2 , -- face4
4 , 7 , 3 , 0 , -- face5
4 , 5 , 6 , 7 -- face6
}
-- material names (we use 1 material per face)
materialNames = { "f1", "f2", "f3", "f4", "f5", "f6" }
-- material indices (we assign 1 material per face)
-- NOTE: indices are 0-based!
polyMaterialIndices = { 0, 1, 2, 3, 4, 5 }
-- create the actual mesh node, at this point the mesh node isn't usable yet!
meshNode = octane.node.create{ type=octane.NT_GEO_MESH , name="MyCube", position={ 500, 500 } }
-- set up the geometry attributes. we shouldn't evaluate them immediately!
meshNode:setAttribute(octane.A_VERTICES , vertices , false)
meshNode:setAttribute(octane.A_VERTICES_PER_POLY , verticesPerPoly , false)
meshNode:setAttribute(octane.A_POLY_VERTEX_INDICES , polyVertexIndices , false)
meshNode:setAttribute(octane.A_MATERIAL_NAMES , materialNames , false)
meshNode:setAttribute(octane.A_POLY_MATERIAL_INDICES , polyMaterialIndices , false)
-- all is set up correctly, now we can evaluate the geometry
meshNode:evaluate()
-- colours for each face
faceColours =
{
f1 = { 255, 0, 0 },
f2 = { 0, 255, 0 },
f3 = { 0, 0, 255 },
f4 = { 255, 255, 0 },
f5 = { 255, 0, 255 },
f6 = { 0, 255, 255 },
}
-- create a diffuse material in each input pin, the input pins will have the same
-- names as the material names defined above
for _, matName in ipairs(materialNames) do
-- create each diffuse material internal to the pin
matNode = octane.node.create
{
type = octane.NT_MAT_DIFFUSE,
name = "Diffuse_"..matName,
pinOwnerNode = meshNode,
pinOwnerName = matName
}
-- set the diffuse colour of the material via the pin
matNode:setPinValue(octane.P_DIFFUSE, faceColours[matName])
end
-- let's export our cube to an obj file. The file name will be the node's name in the
-- geometry directory (e.g. /tmp/LuaCube/geometry/MyCube.obj)
directory = "/tmp/LuaCube"
meshNode:exportToFile(directory)
-- let's load the obj file again.
loadedMesh = octane.node.create{ type=octane.NT_GEO_MESH , name="Loaded Cube", position={ 550, 550 } }
loadedMesh:setAttribute(octane.A_FILENAME, "/tmp/LuaCube/geometry/MyCube.obj", true)
have fun,
Thomas