Skip to content

Conversation

HenryWConklin
Copy link
Contributor

@HenryWConklin HenryWConklin commented May 7, 2025

For #5

Adds a renderer that slices a 4D tetrahedron mesh on the GPU in the vertex shader. Works by packing data wherever it fits on Godot's rendering server and reinterpreting it in the shader.

In a decent state but there are a couple issues I'm aware of:

  • 3D editor preview is broken, the preview camera's transform isn't passed to the shader so 4D meshes stay fixed in place and don't move with the camera view, probably means adding support for 3D cameras
  • UVWs look off, can't tell if they're wrong on the 4D mesh or getting mangled on the way to the shader. Haven't had the brainpower to delve into the fourth dimension and debug that.
  • Missing some kind of support for wireframe meshes, should be possible but not quite sure what that looks like. Should be able to re-use the same shader with a mesh using line primitives.
  • Missing the "shadow" effect to give some indication of the rest of the mesh, should be doable with another shader on next_pass for the first shader, may need another surface on the mesh as well

@HenryWConklin HenryWConklin force-pushed the crossection branch 3 times, most recently from 1fd7321 to a54c515 Compare May 12, 2025 12:09
@HenryWConklin HenryWConklin changed the title WIP: Cross-section rendering Cross-section rendering May 12, 2025
@HenryWConklin
Copy link
Contributor Author

movie_render.mp4

@HenryWConklin HenryWConklin force-pushed the crossection branch 3 times, most recently from d2f25dc to 61c687a Compare May 13, 2025 00:59
@HenryWConklin
Copy link
Contributor Author

Man first this formatter says too few newlines at end of file, then it says too many. Needs to make up its mind 😞

@aaronfranke
Copy link
Member

UVWs look off, can't tell if they're wrong on the 4D mesh or getting mangled on the way to the shader.

The current UVW maps for the box and orthoplex were tediously hand-unwrapped by me, because I wanted to have some kind of test mesh but didn't have a general algorithm for unwrapping them. It's very possible I made a mistake. But I would be surprised if the whole thing is wrong.

@HenryWConklin
Copy link
Contributor Author

Ok, I'll take a closer look some time soon. Normals were also messed up in a similar way when I tried passing them in, so could be one of the fields I'm stashing data in is getting messed with and breaking things.

@HenryWConklin
Copy link
Contributor Author

Did some more digging and found out that the normal is getting normalized somewhere in the pipeline but I couldn't figure out where. Also found some weird processing happening where data is getting clamped into [0,1]: https://github.com/godotengine/godot/blob/45fc515ae3574e9c1f9deacaa6960dec68a7d38b/servers/rendering_server.cpp#L712C1-L717C8

Looks a bit better with a fix for the normalization but there are still some seams in the middle of faces which seems off. They're at least continuous now.

Before:

4d_pre_normalization_fix.mp4

After:

4d_normalization_fix.mp4

Thinking I need to take a different approach. This is definitely hacky and there isn't really enough space to fit all the data I need. What do you think about switching to using ImmediateMesh and doing the cross-section on the CPU? Could maybe do a compute/geometry shader which would only work on the Forward+ renderer as far as I know, but I can't find any examples.

@aaronfranke
Copy link
Member

@HenryWConklin I think it's most performant to do it on the GPU, but any approach you can get working is better than wireframe-only, so a CPU-based solution would be welcome.

Also, about the visual of the box, did you test with both 40-cell and 48-cell BoxTetraDecomp settings?

@HenryWConklin
Copy link
Contributor Author

Figured it out, I was using the wrong UVW coords. Turns out they're not indexed like the positions so I was reading the wrong UVW coords out of the array. The other samples were all 40-cell, 40 and 48 cell cubes look identical now.

4d_fix_40cell.mp4
4d_orthoplex.mp4

Still no smooth normals support, but I added support for Texture3D:

4d_orthoplex_textured.mp4

@aaronfranke
Copy link
Member

@HenryWConklin Ah, that makes sense. And yes, they are duplicated to allow for different tets on the same vertices to have different teture coordinates at those vertices. This is vital even for simple shapes.

@aaronfranke aaronfranke force-pushed the master branch 2 times, most recently from d94a2a2 to 6e47fd8 Compare June 10, 2025 18:52
Copy link
Member

@aaronfranke aaronfranke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your patience with this! It's a super cool feature for sure.

One important aspect of this module is that I am keeping it able to be compiled as both a module and a GDExtension. As usual when any work happens on this module, this PR has revealed problems with a mismatched API between the engine and GDExtension, so I did a few detours to fix a few of those problems: godotengine/godot#107139, godotengine/godot#107141, godotengine/godot-cpp#1789.

The new render/cross_section/ folder isn't referenced in the GDExtension SConstruct, so it's currently not compiled at all for GDExtension. It needs to be added:

Screenshot 2025-06-16 at 4 26 48 AM

I also added the header builders script from godotengine/godot-cpp#1789 in commit 6e5ae5d (be sure to rebase your PR!) which should allow for env.GLSL_HEADER("../../render/cross_section/cross_section_shader.glsl") in the GDExtension SConstruct. However, I'm getting an error TypeError: 'tuple' object is not callable:, which is strange because I swear the same build system code was working earlier when I was testing on top of your PR before I pushed that commit. I don't know what's different between then and now. Maybe some fresh eyes will help. Either way, ideally, we want this header to be able to generate with the GDExtension build.

@HenryWConklin
Copy link
Contributor Author

HenryWConklin commented Jun 23, 2025

I also added the header builders script from godotengine/godot-cpp#1789 in commit 6e5ae5d (be sure to rebase your PR!) which should allow for env.GLSL_HEADER("../../render/cross_section/cross_section_shader.glsl") in the GDExtension SConstruct. However, I'm getting an error TypeError: 'tuple' object is not callable:, which is strange because I swear the same build system code was working earlier when I was testing on top of your PR before I pushed that commit. I don't know what's different between then and now. Maybe some fresh eyes will help. Either way, ideally, we want this header to be able to generate with the GDExtension build.

Got the GLSL header working, seems like it was just a stray comma in the definition for GLSL_HEADER making a 1-element tuple.

GDExtension complies now with all the source files included. I haven't been able to get it to run to test it out though. I run into some odd errors from the method registration that cause crashes on loading the project. The full editor/module build still works though.

This bit in G4MFItem4D seems like it's shadowing a property from Resource which causes some errors saying the set_name and get_name methods aren't defined, then throwing errors if you do re-bind them:

ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "name"), "set_name", "get_name");

And I get some kind of segfault from a class in physics, seems like it's interpreting something as a pointer that is not a pointer but I didn't dig too far.

@HenryWConklin
Copy link
Contributor Author

Moved everything to a separate world3d which fixes the weird rendering in the 3D preview, should be more robust overall.

I am getting an error message now on the first frame when running a scene, seems like the 4D rendering server gets called in pre_render_frame and some things are still null in the rendering server. Doesn't seem to cause any problems. Maybe the render_frame method could be moved to _process? Would need to make sure it runs after everything else but might be a better place for it.

@aaronfranke
Copy link
Member

@HenryWConklin That might cause things to be a frame late in some cases. I think it's better to check for null things in RenderingServer and silently skip rendering that frame if null.

@HenryWConklin
Copy link
Contributor Author

Yeah, makes sense. I think there's also a DRAW notification on some types of nodes but seems like that would be a lot of refactoring.

Tried some things and found a work around doing some manual RID stuff.

Actual error happens here: https://github.com/godotengine/godot/blob/e1b4101e3460dd9c6ba0b7f8d88e9751b8383f5b/servers/rendering/renderer_scene_cull.cpp#L488

Coming from here: https://github.com/godotengine/godot/blob/e1b4101e3460dd9c6ba0b7f8d88e9751b8383f5b/servers/rendering/renderer_viewport.cpp#L1236

It's trying to clean up the old world on the viewport but it's somewhere in the middle of being created where the RID is valid but hasn't been initialized or something.

Copy link
Member

@aaronfranke aaronfranke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for being a bit slow to review this. I've made some changes on master which will help with this.

In general I'm happy to merge this sooner rather than later, to get something in which we can build on top of further, even if it's missing features like 4D shadows, lighting, editor gizmos, etc, those could always be added later.

Please run doctool: ./bin/godot.something.exe --doctool . (replace godot.something.exe with your executable) and fill out the descriptions in the generated documentation XML.

@HenryWConklin HenryWConklin force-pushed the crossection branch 2 times, most recently from 543624d to ee9d3b7 Compare July 2, 2025 02:05
@HenryWConklin
Copy link
Contributor Author

No worries on being slow, I've been meaning to add more to this and haven't been. Have most of the change to add support for wireframes to the cross-section renderer, but I can send that as another PR. Need to do some research for the shadow effect so might be a while but I'm interested in working on it.

Should be in a good state to merge, let me know if you want any other changes!

The albedo source of the material, an enum specific to tetrahedral meshes. Can be a single color, per-vertex, per-cell, per-cell UVW coordinates, 4D texture, or a combination of single color and the other color sources.
</member>
<member name="texture" type="Texture3D" setter="set_texture" getter="get_texture">
The albedo texture of the material as a Texture3D. Used by the cross-section renderer. Used when albedo_source is [constant TETRA_COLOR_SOURCE_TEXTURE4D_ONLY] or [constant TETRA_COLOR_SOURCE_TEXTURE4D_AND_SINGLE].
Copy link
Member

@aaronfranke aaronfranke Jul 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's actually not what the Texture4D color source is meant to be used for. Texture4D is when you have a 4D texture which directly maps 4D coordinates to a 4D texture without using the cell UVW map. The TETRA_COLOR_SOURCE_CELL_UVW_ONLY and TETRA_COLOR_SOURCE_CELL_UVW_AND_SINGLE options are for using a cell UVW map to map cells onto a 3D texture. Maybe it could be renamed for clarity.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok, fixed. Is texture 4D a thing? Not sure I've seen that as a supported type anywhere. Might need to be a shader or a sprite sheet type thing with some manual sampling.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not a thing in Godot yet, but can be done with shaders. See https://www.youtube.com/watch?v=Ir8oft_qAMQ&t=3m35s

@HenryWConklin HenryWConklin force-pushed the crossection branch 2 times, most recently from 207f1a7 to a05d063 Compare July 3, 2025 12:16
Pipes all the right data to the GPU, still need to implement the actual
cross-section logic.

- Added a new rendering engine, CrossSectionRenderingEngine4D
- Added method to Mesh4D to compute a special cross-section mesh that
  can be cross-sectioned in a vertex shader.
- Added a method to Material4D to get a ShaderMaterial used for
  cross-section rendering
Supports UVW texture coords but not pre-computed normals due to limits
on mesh data.

Also supports sampling from Texture3Ds.
Fixes the floating meshes in the 3D preview, transforms aren't set correctly using the 3D preview camera.

Also makes sure 4d objects are visible across all 4d viewports.
Copy link
Member

@aaronfranke aaronfranke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work, thank you!

@aaronfranke aaronfranke merged commit 5a34a61 into godot-dimensions:master Jul 3, 2025
1 check passed
Comment on lines +149 to +169
Color albedo;
Variant texture;
switch (_albedo_source) {
case TETRA_COLOR_SOURCE_SINGLE_COLOR:
albedo = _albedo_color;
// Setting to a Nil variant resets to the default texture, which is white.
texture = Variant();
break;
case TETRA_COLOR_SOURCE_CELL_UVW_ONLY:
albedo = Color(1.0, 1.0, 1.0);
texture = _texture;
break;
case TETRA_COLOR_SOURCE_CELL_UVW_AND_SINGLE:
albedo = _albedo_color;
texture = _texture;
break;
default:
albedo = Color(1.0, 1.0, 1.0);
texture = Variant();
break;
}
Copy link
Member

@aaronfranke aaronfranke Jul 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The TetraColorSource enum is intended for safe user-friendly setting, but when reading, there are bitwise flags available to simplify this. That code can be replaced with this:

	const ColorSourceFlags flags = get_albedo_source_flags();
	const Color albedo = (flags & Material4D::COLOR_SOURCE_FLAG_SINGLE_COLOR) ? _albedo_color : Color(1.0, 1.0, 1.0);
	// Setting to a Nil variant resets to the default texture, which is white.
	const Variant texture = (flags & Material4D::COLOR_SOURCE_FLAG_CELL_UVW) ? Variant(_texture) : Variant();

I've pushed this in commit f2b29bd

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants