How do I get the position of each instance in MultiMeshInstance at fragment()?
Asked Answered
T

6

0

Hello everyone!

I don't think this is a bug with godot, So I post it here for help!

In my project, I need to get the position of each instance in shader to do some computation.

I have tried NODE_POSITION_WORLD and VERTEX.
The NODE_POSITION_WORLD can get the position of the MultiMeshInstance node. All the instances have the same value!

shader_type spatial;
//render_mode world_vertex_coords;

void fragment() {
    ALBEDO = NODE_POSITION_WORLD.xyz;
}

Image:

And VERTEX looks like it would return the position of each pixel in view space.

shader_type spatial;
//render_mode world_vertex_coords;

void fragment() {
    ALBEDO = VERTEX.xyz;
}

Image:

Is there a way to get the position of each instance in MultiMeshInstance at fragment()?

Timmie answered 20/4, 2023 at 7:49 Comment(0)
S
0

Looks like MODEL_MATRIX in fragment() is node's matrix. However in vertex() it is indeed per instance matrix. Hopefully that's intentional 🙂. Didn't find anything about this in docs. You can simply send it from vertex to fragment via varying.

varying vec3 instance_pos;

void vertex() {
	instance_pos = WORLD_MATRIX[3].xyz;
}

void fragment() {
	ALBEDO = instance_pos;
}
Shaving answered 20/4, 2023 at 14:58 Comment(0)
S
0

Timmie NODE_POSITION_WORLD will always give you the same result because it's the position of the whole MultiMeshInstance node.
You can extract instance's position from model-to-world transformation matrix:

vec3 instance_pos = WORLD_MATRIX[3].xyz

I think they changed the name of this built-in in v4:

vec3 instance_pos = MODEL_MATRIX[3].xyz
Shaving answered 20/4, 2023 at 10:41 Comment(0)
T
0

Shaving
Thanks for your reply!
I tried MODEL_MATRIX[3].xyz in my project a few minutes ago. It returned the same value as well.

And I found some code below from Godot sources.

In scene_shader_forward_clustered.cpp Line 558:
actions.renames["MODEL_MATRIX"] = "read_model_matrix";
Line 631
actions.renames["NODE_POSITION_WORLD"] = "read_model_matrix[3].xyz";

So does it mean NODE_POSITION_WORLD = MODEL_MATRIX[3].xyz?

Timmie answered 20/4, 2023 at 11:41 Comment(0)
S
0

Looks like MODEL_MATRIX in fragment() is node's matrix. However in vertex() it is indeed per instance matrix. Hopefully that's intentional 🙂. Didn't find anything about this in docs. You can simply send it from vertex to fragment via varying.

varying vec3 instance_pos;

void vertex() {
	instance_pos = WORLD_MATRIX[3].xyz;
}

void fragment() {
	ALBEDO = instance_pos;
}
Shaving answered 20/4, 2023 at 14:58 Comment(0)
T
0

Shaving
It works! 

shader_type spatial;

varying vec3 instance_pos;

void vertex() {
	instance_pos = MODEL_MATRIX[3].xyz;
}

void fragment() {
	ALBEDO = instance_pos.rgb;
}

Thanks for your support and patience.

But this workaround looks a bit odd.

I created an issue about this on Github, but I haven't received any response yet.

See:
https://github.com/godotengine/godot/issues/76292

Timmie answered 20/4, 2023 at 15:57 Comment(0)
S
0

Timmie I wouldn't exactly call it a workaround. Passing per object stuff from vertex to fragment shader actually happens quite often as an optimization technique to avoid unnecessary per pixel calculations. I think this difference is by design. It's similar with VERTEX built in for example; it's in object space in vertex function, while in camera space in fragment function.
The only problem is that documentation is currently not clear about the distinction for MODEL_MATRIX when used with multi-instanced meshes.

Shaving answered 20/4, 2023 at 16:7 Comment(0)
T
0

Shaving It makes sense! Thanks a lot! :

Timmie answered 20/4, 2023 at 16:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.