Exciting features and exciting times!
Who will be the first to make a voxel like world?
Exciting features and exciting times!
Who will be the first to make a voxel like world?
Epic Component!
Finally some long awaited 3D features!
Awesome work guys! Defold is just getting better and better.
Should every mesh cause a drawcall? I tried to optimize it but it seems like they always do?
Edit: Nevermind, material had local instead of world.
What’s wrong with this? Trying to create a dynamic cube from a triangle strip primitive. Sometimes the cube shows up right, other times vertices seem like they are out into infinity.
/gen/custom.script
local function fill_positions_strip(self, verts)
for key, value in ipairs(verts) do
self.positions[key] = verts[key]
end
end
function init(self)
self.res = go.get("#mesh", "vertices")
print(self.res)
self.buffer = resource.get_buffer(self.res)
print(self.buffer)
self.positions = buffer.get_stream(self.buffer, "position")
print(self.positions)
-- if the buffer has some data you could change these values here
-- self.positions[1] = self.positions[1] + dt
-- create a new buffer, since the one in the resource doesn't have enough size
self.new_buffer = buffer.create(3 * 14, {
{ name = hash("position"),
type=buffer.VALUE_TYPE_FLOAT32,
count = 3 }
})
-- get the position stream
self.positions = buffer.get_stream(self.new_buffer, "position")
local verts2 = {
0, 0, 0,
0, 1, 0,
1, 0, 0,
1, 1, 0,
1, 1, 1,
0, 1, 0,
0, 1, 1,
0, 0, 1,
1, 1, 1,
1, 0, 1,
1, 0, 0,
0, 0, 1,
0, 0, 0,
0, 1, 0
}
fill_positions_strip(self, verts2)
resource.set_buffer(self.res, self.new_buffer)
end
function update(self, dt)
end
MeshTest.zip (241.6 KB)
Since each stream specifies its component count, we specify the buffer size in elements
.
The problem here is that you allocate a buffer with 3 * 14
elements.
And, if you don’t fill up the whole buffer, you’ll get garbage data, which may or may not show up in the renderer.
Here’s a fixed version.
local function fill_stream(stream, verts)
for key, value in ipairs(verts) do
stream[key] = verts[key]
end
end
function init(self)
self.res = go.get("#mesh", "vertices")
self.buffer = resource.get_buffer(self.res)
local verts2 = {
0, 0, 0,
0, 1, 0,
1, 0, 0,
1, 1, 0,
1, 1, 1,
0, 1, 0,
0, 1, 1,
0, 0, 1,
1, 1, 1,
1, 0, 1,
1, 0, 0,
0, 0, 1,
0, 0, 0,
0, 1, 0
}
-- create a new buffer, since the one in the resource doesn't have enough size
self.new_buffer = buffer.create(#verts2 / 3, {
{ name = hash("position"), type=buffer.VALUE_TYPE_FLOAT32, count = 3 }
})
-- get the position stream
self.positions = buffer.get_stream(self.new_buffer, "position")
fill_stream(self.positions, verts2)
resource.set_buffer(self.res, self.new_buffer)
end
Thank you!
How would the same example be extended to have the normals, uvs, and colors?
I mean the part with buffer.create and then resource.set_buffer ?
local function fill_buffers_strip(self, verts)
for key, value in ipairs(verts) do
self.positions[key] = verts[key]
self.normals[key] = verts[key]
end
end
function init(self)
self.res = go.get("#mesh", "vertices")
-- unit square
local verts2 = {
0, 0, 0,
0, 1, 0,
1, 0, 0,
1, 1, 0,
1, 1, 1,
0, 1, 0,
0, 1, 1,
0, 0, 1,
1, 1, 1,
1, 0, 1,
1, 0, 0,
0, 0, 1,
0, 0, 0,
0, 1, 0
}
self.buffer_position = buffer.create(#verts2 / 3, {
{ name = hash("position"),
type=buffer.VALUE_TYPE_FLOAT32,
count = 3 }
})
self.buffer_normal = buffer.create(#verts2 / 3, {
{ name = hash("normal"),
type=buffer.VALUE_TYPE_FLOAT32,
count = 3 }
})
self.buffer_texcoord0 = buffer.create(#verts2 / 3, {
{ name = hash("texcoord0"),
type=buffer.VALUE_TYPE_FLOAT32,
count = 2 }
})
self.buffer_color0 = buffer.create(#verts2 / 3, {
{ name = hash("color0"),
type=buffer.VALUE_TYPE_FLOAT32,
count = 4 }
})
-- get the position stream
self.positions = buffer.get_stream(self.buffer_position, "position")
self.normals = buffer.get_stream(self.buffer_normal, "normal")
fill_buffers_strip(self, verts2)
resource.set_buffer(self.res, self.buffer_position)
resource.set_buffer(self.res, self.buffer_normal)
end
function update(self, dt)
end
This is erroring with the below (referring to resource.set_buffer(self.res, self.buffer_normal)
), what am I doing wrong?
ERROR:SCRIPT: /gen/custom.script:62: Could not copy data from buffer (9).
stack traceback:
[C]: in function 'set_buffer'
/gen/custom.script:62: in function </gen/custom.script:10>
Beyond that then we need a way to generate normals for custom meshes… or multiple ways with the different primitive types? There are for sure existing solutions out there…
Each buffer can have multiple streams:
self.new_buffer = buffer.create(num_vertices, {
{ name = hash("position"), type=buffer.VALUE_TYPE_FLOAT32, count = 3 },
{ name = hash("normal"), type=buffer.VALUE_TYPE_FLOAT32, count = 3 },
{ name = hash("texcoord0"), type=buffer.VALUE_TYPE_FLOAT32, count = 2 },
{ name = hash("color0"), type=buffer.VALUE_TYPE_FLOAT32, count = 4 }
})
Remember to match this format with the format of the original (empty) buffer:
empty.buffer:
[
{
"name": "position",
"type": "float32",
"count": 3,
"data": []
},
{
"name": "normal",
"type": "float32",
"count": 3,
"data": []
},
{
"name": "texcoord0",
"type": "float32",
"count": 2,
"data": []
},
{
"name": "color0",
"type": "float32",
"count": 4,
"data": []
}
]
Here’s the patched code:
local function fill_stream(stream, verts)
for key, value in ipairs(verts) do
stream[key] = verts[key]
end
end
function init(self)
self.res = go.get("#mesh", "vertices")
self.buffer = resource.get_buffer(self.res)
local position = {
0, 0, 0,
0, 1, 0,
1, 0, 0,
1, 1, 0,
1, 1, 1,
0, 1, 0,
0, 1, 1,
0, 0, 1,
1, 1, 1,
1, 0, 1,
1, 0, 0,
0, 0, 1,
0, 0, 0,
0, 1, 0
}
local normal = {
0, 0, 0,
0, 1, 0,
1, 0, 0,
1, 1, 0,
1, 1, 1,
0, 1, 0,
0, 1, 1,
0, 0, 1,
1, 1, 1,
1, 0, 1,
1, 0, 0,
0, 0, 1,
0, 0, 0,
0, 1, 0
}
local texcoord0 = {
0, 0,
0, 1,
1, 0,
1, 1,
1, 1,
0, 1,
0, 1,
0, 0,
1, 1,
1, 0,
1, 0,
0, 0,
0, 0,
0, 1,
}
local color0 = {
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
1,1,1,1,
}
local num_vertices = #position / 3
-- create a new buffer, since the one in the resource doesn't have enough size
self.new_buffer = buffer.create(num_vertices, {
{ name = hash("position"), type=buffer.VALUE_TYPE_FLOAT32, count = 3 },
{ name = hash("normal"), type=buffer.VALUE_TYPE_FLOAT32, count = 3 },
{ name = hash("texcoord0"), type=buffer.VALUE_TYPE_FLOAT32, count = 2 },
{ name = hash("color0"), type=buffer.VALUE_TYPE_FLOAT32, count = 4 }
})
-- get the position stream
local stream_position = buffer.get_stream(self.new_buffer, "position")
local stream_normal = buffer.get_stream(self.new_buffer, "normal")
local stream_texcoord0 = buffer.get_stream(self.new_buffer, "texcoord0")
local stream_color0 = buffer.get_stream(self.new_buffer, "color0")
fill_stream(stream_position, position)
fill_stream(stream_normal, normal)
fill_stream(stream_texcoord0, texcoord0)
fill_stream(stream_color0, color0)
resource.set_buffer(self.res, self.new_buffer)
end
After playing with this for a bit, I have a bit of feedback:
For 3 to work, I think the material vertex space needs to be world instead of local. Then the vertex position needs to be setup differently. Would still be nice for us to be shown the ideal way of doing this.
Yes, but I couldn’t get Material World Space to work. I selected the right streams for position and normal in the mesh component in the editor, and switched the vertex space to World Space in the material. And it seems like it completely discards the world transform on anything that I render, as if it’s sending the data in the buffer without transforming it.
And anyway, even in this state, I still get one render call per mesh.
Re 2) When you use World Space, all vertices are transformed on the CPU, thus the world matrix for that mesh essentially becomes the identity matrix. It sounds like what you expected, but didn’t get, so I’ll take a look and try to create an example for you.
Re 3) The batching mechanism triggered only when using World Space. When using “Local Space”, each draw call uses a separate (unique) world transform, and thus cannot be batched. For that to happen, we’d have to implement instancing
, which we currently haven’t had in the road map.
I added #4818 for instancing, and #4819 for physics custom meshes using the buffer format.
Yay, and now the links actually make sense to the community as well!
I remember noting that at one point the Release Notes switched over to point towards a private github repo, which means that the older links that didn’t work previously will now work for everyone!
This means that people can even go back to older release notes if they are interesting in how something was fixed (Looked quickly and it seem to be anything after and including 1.2.163
I have an idea for a new Defold library: functions for transforming 2d primitives into each other. Like circle -> square, square -> triangle and so on
Just if somebody has time to play with math
Hi, awesome feature!
I’m trying to play with your example for studing purposes:
I’ve a bit modified a shader to render textures with alpha channel.
Now I try to fix a mistake with semi-transparent quad (dice shadow), when his Z-coord is behind Z of the ground this quad renders wrong. I get an advice to modify render script with new predicate for transparent materials.
Sources: mesh.zip (313.3 KB)
Questions:
Thanks!
An atlas actually becomes a single texture. The problem is then to figure out the uv coordinates of the original images inside this texture.
I haven’t seen that error output before. Thanks for reporting!
If we could generate or use our own atlases…
I guess we can but if we use raw images then we don’t get the benefits of texture profiles.
Updated sources: mesh2.zip (322.0 KB)
Now correct rendering of transparent textures, except a situation of cross of them