Mesh Component

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!

3 Likes

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.

1 Like

Updated sources: mesh2.zip (322.0 KB)

Now correct rendering of transparent textures, except a situation of cross of them

3 Likes

Today’ results :slight_smile:

Question:
How to enable ADD blending for mesh or models?

17 Likes

Whoa!!! Truly amazing !!!

3 Likes

You’ll want to add an extra material and render predicate for that most likely. But I do not remember right now what requires to be set. Maybe @d954mas knows? I am not sure if we can set anything which modifies GL_FUNC_ADD currently? You can use a render target for the light step to draw additively more easily.

The godrays are missing some double sided meshes?

The problem you are seeing with your sprite shadows I believe is because of depth culling? So you need to draw those sprites last, disable drawing to depth, but still test depth? It’s been a while since I worked with that.

The shadows appear to have fighting happening in the video where the shadows share the same y position. A possible way to do this is always add a little extra small amount of position like 0.0001 depending on its id.

Some of this is covered here https://learnopengl.com/Advanced-OpenGL/Blending

5 Likes

They’re just sprite components with ADD blending for now, while I research how this effect meet to meshes.

Inside an editor it looks like that:

Thanks for some advice!

12 Likes

And finally, HTML5 demo:
https://dragosha.com/dice/

14 Likes

This looks super exciting! Great work!

4 Likes

@Dragosha it looks great!

Also I’m always amazed at how well Defold runs on html5, even on my super old iPhone6!

6 Likes

Added:

  • simple dice gameplay
  • click to quad detection (coloring)
  • mesh wave fx

15 Likes

:open_mouth: Well this is a pretty amazing feature, I didn’t get a chance to really try it out until now. My mind kind of boggles at all the possibilities this opens up.

A question: When does the “vertices” buffer get copied? I mean, when you do: ‘resource.get_buffer’, is that just a copy, or not? Or does it copy the buffer when you do ‘resource.set_buffer’?

I’ve noticed that:

local buf1 = resource.get_buffer(self.bufferResourceAddress)
local buf2 = resource.get_buffer(self.bufferResourceAddress)
print(buf1 == buf2)

…always gives false. Is that just because == doesn’t work for the buffer type, or are they actually different things?

This is my current experiment:
defold_mesh_line_drawing
So, on every click, I make a new buffer with space for 2 more points and copy the contents of the old one.

My function code
local function makeNewBuffer(self, vertCount)
	local newBuffer = buffer.create(
		vertCount,
		{
			{ name = POSITION, type = buffer.VALUE_TYPE_FLOAT32, count = 3 },
			{ name = COLOR, type = buffer.VALUE_TYPE_FLOAT32, count = 4 },
		}
	)
	buffer.copy_buffer(newBuffer, 0, self.buffer, 0, self.vertCt)
	resource.set_buffer(self.bufferResourceAddress, newBuffer)
	-- self.buffer = newBuffer -- This does NOT work.
	self.buffer = resource.get_buffer(self.bufferResourceAddress) -- Must do this.
	self.verts = buffer.get_stream(self.buffer, POSITION)
	self.colors = buffer.get_stream(self.buffer, COLOR)
	self.vertCt = vertCount
end

It took me a while to figure out that I needed to do ‘resource.get_buffer’ immediately after ‘resource.set_buffer’. I couldn’t just use the buffer that I created. :confused:


Question 2: Will it ever be possible to create and destroy elements from a buffer?

[Edit] Question 2.5: Would it be possible to make a native extension to do this? (as a complete NE noob)

2 Likes

Yes, there’s a matching dmBuffer API for extensions: https://defold.com/ref/stable/dmBuffer/

1 Like

@britzl Yeah, I took a look at that, but there’s nothing in there about modifying the length of a buffer (or about getting/setting values in a buffer’s stream), and I don’t know enough C++ to easily figure it out myself.


I was curious how the mesh component’s performance compared to using sprites, so I made a Bunnymark with it—using a single mesh component and modifying the vertex buffer.

Computer Specs: Intel i5-3570K and Intel HD Graphics 4000

Fullscreen at 1600 x 900, with 10,000 bunnies:
--------------------------------------------
                              go.animate       go update-single    mesh update-single
CPU Load                :          8%                  16%                 24%
Engine.Sim              :          12ms                22ms                37ms

Likewise, but drawing only: (static bunny positions spread over the screen):
---------------------------------------------------------------------------
                            go update-single    mesh update-single
CPU Load                :          8%                  8%
Engine.Sim              :          10.3ms              5.6ms
Profile.Draw            :          0.75ms              0.68ms
Renderscript.UpdateRSI  :          3.1ms               3.8ms
GameObject.Update       :          1.8ms               0.0ms
Sprite.UpdateTransforms :          2.5ms               0.0ms
Sprite.CreateVertexData :          1.4ms               0.0ms

To sum up:

  • Setting individual vertex positions from lua is very expensive.
    • Setting 6 vertex positions (two triangles) for each sprite…
  • Rendering static images with a single mesh instead of tons of game objects is a lot cheaper.
    • With the tradeoff that you need each vertex pos in world space.

The results are pretty much to be expected. It’s nice to know that the Mesh component is as efficient as anything else in the engine, but you won’t gain any performance by using it, except in very limited situations.

Note: These stats don’t include the cost of recreating the mesh buffer to add or remove tris. That takes more than a frame’s time to do, for larger buffers.

Correct, changing size requires that you create a new buffer and copy over existing values.

You get the buffer (dmBuffer::GetBytes()) or stream (dmBuffer::GetStream())as a C array and ready/write to it. Example:

1 Like

Modifying the length of the buffer hasn’t really been something we’ve thought of I must admit.
In general recreating the buffer is usually enough, but is generally not done every frame.

Alternative is ofc to create degenerate triangles at the end of the buffer, which allows the graphics driver to cull those triangles.

2 Likes

Ah! Sorry, I didn’t read enough! :man_facepalming: Perfect, thanks!


@Mathias_Westerdahl What do you mean by “degenerate triangles” exactly? That’s exactly what I was hoping for: some way to tell it to not use some part of the buffer. In practice it seems to cost the same no matter what is in the buffer. Using a buffer with only zeros costs the same as one full of real data.

Profiler with buffer with only zeros (60k verts)

Profiler with filled buffer (60k verts)

[Edit] OK, I tested it again at higher resolution and it did cost substantially less while empty. I guess that makes sense, it still has to go through all the vertices and cull them, and just saves time it would have spent in the fragment shader.

1 Like

A degenerate triangle is a triangle that covers no pixels, i.e. it is a segment (two equal vertices, a different vertex) or a point (three equal vertices).

3 Likes

Another approach would be not to increase the buffer size each line draw, but to double it when you run out of space. That way, you spread out the reallocations in increasingly rare steps.

2 Likes

Another question about mesh component.
May someone explain me how to get an independet instances of mesh buffer?
What I mean: if you create an object with mesh, then another object with the same mesh (same buffer), etc. Then if modify any stream in this buffer you modify all instances of mesh at once.
Example:

On this example, green meshes are simple GO on scene, but brown ones created by factory. The only one object has an update function with vertex position modificator.

I tried to create Go with meshes by factory, no result.
Tried to create a new buffer by buffer.create. The same result.

The only way to create fully unique mesh is copy file of original buffer and set it to other mesh component. But in this case you can’t create unique instances by factory (All objects will have the same buffer).

What I missed?
Simple project to reproduce: test.zip (8.8 KB)

@Mathias_Westerdahl ?

1 Like