Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MeshPhysicalMaterial: Volume attenuation in world or local units? #22343

Closed
donmccurdy opened this issue Aug 17, 2021 · 4 comments
Closed

MeshPhysicalMaterial: Volume attenuation in world or local units? #22343

donmccurdy opened this issue Aug 17, 2021 · 4 comments

Comments

@donmccurdy
Copy link
Collaborator

I've constructed two versions of the Khronos AttenuationTest sample model. Both have the same world scale (viewable in the "Inspect" tab of https://gltf.report/), but one uses float32 vertex attributes with world units, and the other uses normalized int16 vertex attributes with scale on the parent object used to achieve the same world scale. Rendered results are quite different:

Screen Shot 2021-08-16 at 5 45 50 PM

Left: world units in vertex attributes. Right: scale on parent object.

Archive.zip

According to the glTF specification, these two glTF models should look the same. They don't here, but I'm not sure if that's the responsibility of MeshPhysicalMaterial or GLTFLoader to solve. Do we expect that the MeshPhysicalMaterial shader should understand the world transform of the object? Or that GLTFLoader should output different versions of the same material, with different attenuation distance and/or thickness or each? I think it's the former — the node's transform appears to affect a normal map, for instance — but would like to confirm this is correct.

/cc @takahirox

@WestLangley
Copy link
Collaborator

FWIW

vec3 getVolumeTransmissionRay( vec3 n, vec3 v, float thickness, float ior, mat4 modelMatrix ) {
// Direction of refracted light.
vec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior );
// Compute rotation-independant scaling of the model matrix.
vec3 modelScale;
modelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) );
modelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) );
modelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) );
// The thickness is specified in local space.
return normalize( refractionVector ) * thickness * modelScale;
}

@takahirox
Copy link
Collaborator

takahirox commented Aug 17, 2021

To be honest I just copied that function from the shader in glTF Sample Viewer without deeply thinking. Probably we should revisit the implementation of the function.

@donmccurdy
Copy link
Collaborator Author

donmccurdy commented Aug 17, 2021

Looks like my quantized sample looks wrong in babylon.js as well (same issue), and just doesn't render at all in the khronos sample renderer (probably a viewport bounding box issue?). Reported at KhronosGroup/glTF-Sample-Viewer#345.

/cc @emackey, @bghgary – Does it seem correct that these two models should appear the same, given the same world scale?

@donmccurdy
Copy link
Collaborator Author

Hm, that second model appears the same in three.js, babylon.js, and gestaltor. Thinking about it more, that's expected — thickness is given "in the coordinate space of the mesh". If we quantize and normalize vertex attributes to a [-1,1] bounding box, and rescale the parent node to cancel it out, that scale on the parent is also affecting the material whereas vertex scaling is not.

Practically, this means that any vertex quantization method needs to also adjust the thickness property. Attenuation distance can be left alone, it is given in world units by glTF.

I'll consider this a bug in glTF-Transform's quantization implementation, then, at donmccurdy/glTF-Transform#330.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants