jes notes Index Gallery . Signed Distance Functions Shaft passers Snap issues

2025-03-29

Last modified: 2025-03-29 16:06:59

< 2025-03-28 2025-03-30 >

Meshes

Current status is my mesh node can draw a mesh, but it is hollow.

So the plan is to have some function tell me the distance from p to a triangle, and whether the ray from p to (inf,0,0) crosses through the triangle or not.

Then we pick the smallest distance, and make it negative if we crossed an odd number of triangles.

So I need to know:

I have it almost working:

Just some spurious points outside the triangle have negative sign.

And some spurious points have incorrect distance.

I am wondering if this is a numerical problem?

Intersecting the tetrahedron with a gyroid, I can see that it is mostly correct.

Yes, it is numerical error! I increased an epsilon value from 1e-5 to 1e-3 and not it works! 1e-2 also seems to work. I'm not thrilled about needing magic constants that I don't understand though.

Cursor has given me a longer and more complicated version that works without a magic constant. I'll keep this for now.

So, good! I can now draw triangle meshes.

I think next up is importing STL files so that I can load meshes from external tools.

I predict that this will create shaders that are way too slow, and possibly too long to even be allowed. So then I'll want the voxel octree system.

OK, I refactored the "Mesher" a bit, to split out STL file export, Mesh handling, and the act of creating a mesh from an SDF.

And now MeshNode takes a Mesh, and the STL class can import STL files as well as export.

I tried to import a 22 megabyte STL file and it failed because of "too much recursion" in trying to simplify the Peptide tree, lol. So we don't even get as far as the shader.

The mesh had 34k triangles, so the min() chain that finds the closest triangle in MeshNode will go 34k levels deep. We could improve that by making it "balanced", so instead of min(a, min(b, min(c, min(d, ..., we would do min(min(min(a,b), min(c,d)), ....

So that would fix the deep recursion but may not fundamentally help.

Testing with a trivial STL file, STL import is definitely working.

So I just need a better way to support large meshes.

On a mesh with 2040 triangles:

So I guess I have to somehow simplify the mesh so that it can actually work.

Mesh simplification

I think the plan is to store signed distances in an octree and then somehow interpolate them in the shader.

So maybe Peptide wants to have a way for you to expose a "data array" or something?

But first, how would I actually do that in a shader? It can have a compile-time fixed size. And actually, just exposing a data array to Peptide wouldn't be enough to do sparse octrees because Peptide doesn't have conditional execution. Or, would that be enough? That would mean every operation takes the same amount of time as one that goes all the way to the deepest leaf nodes, but we still get to save on memory usage compared to just using voxels.

Another option would be for Peptide to have an "octree lookup" method, and then you expose your fixed octree data to it.

ChatGPT tells me that the normal thing to do is to sample the distance field into a 3d texture. And don't worry about compressing it with an octree.

And, agreed, octrees are obviously a premature optimisation.

So I need:

And it turns out that GLSL shaders will interpolate 3d textures for us for free, so that is good. But I will also want to duplicate that behaviour in JavaScript.

And if I'm going to the trouble of sampling 3d textures, why not also 2d? Could be handy for fonts, heightmaps, etc.

Stick to 3d for now, duplicate for 2d if wanted.

Peptide gets a texture3d and vtexture3d node type.

For evaluation in GLSL we'll have to work out how to pass in the 3d texture.

For evaluation in JavaScript we'll have to set a variable containing a Texture3D object that can be sampled.

OK, initial version working!

You can clearly see the voxels. Issues are:

  1. we are using "nearest" filtering instead of "linear"
  2. outside the AABB it should be telling us the distance to the edge of the bounding box, instead of the distance at the edge

OK, both of those solved now. To use "linear" filtering you have to use R16F textures instead of R32F. Don't know why.

Now the problem is that the mesh is very clearly truncated.

Also when I expand the AABB, there is random voxels being leaked, shown here with much higher resolution than before:

< 2025-03-28 2025-03-30 >