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

Examples: Add webgpu_refraction. #28761

Merged
merged 4 commits into from
Jun 30, 2024
Merged

Examples: Add webgpu_refraction. #28761

merged 4 commits into from
Jun 30, 2024

Conversation

Mugen87
Copy link
Collaborator

@Mugen87 Mugen87 commented Jun 29, 2024

Related issue: -

Description

Next to ReflectorNode, there is now RefractorNode. They are the counterparts of Reflector and Refractor.

This PR shows how to implement a planar refraction effect like in webgl_refraction with WebGPURenderer.

@Mugen87 Mugen87 added this to the r167 milestone Jun 29, 2024
@Mugen87
Copy link
Collaborator Author

Mugen87 commented Jun 29, 2024

Sidenote: This is how a render target of the reflector/refractor looks like when you render it as a texture with plane uv coordinates (uv()).

image

The black color is part of the texture. It is in fact the scene's background, in this case a black color.

Normally, you use special texture coordinates for sampling this type of texture. Previously, texture2DProj() was used along with a special texture matrix for transforming the default uvs, now ViewportNode is in place.

In any event, when transforming/offsetting uv coordinates in the shader, the coordinates might exceed the "valid" range of texture coordinates meaning you end up sampling the scene's background (e.g. a black color). The sampled background color appears at top-left or bottom-right side of the reflector/refractor, depending on whether you add or subtract the offset to the uv node.

This color issue was already present in Reflector and Refractor and not reported as a bug so far. Granted it's a subtle issue and most noticeable if you look from a steep angle on the reflector's/refractor's surface. I could not come up with a fix so far but maybe others have an idea.

@sunag
Copy link
Collaborator

sunag commented Jun 29, 2024

I think most most part of cases we could use viewportSharedTexture() and calculate the distance between the depths to fix any offset issues. It would still be simpler and more optimized since we won't need to re-draw the entire scene again. This is also fix the sort() on transparent materials, I think refractor() would have to handle this manually.

const verticalRefractor = viewportSharedTexture();

const verticalNormalScale = 0.1;
const verticalUVOffset = texture( floorNormal, uv().mul( 5 ) ).xy.mul( 2 ).sub( 1 ).mul( verticalNormalScale );
verticalRefractor.uvNode = verticalRefractor.uvNode.add( verticalUVOffset );

const refractorGeometry = new THREE.PlaneGeometry( 90, 90 );

const planeRefractor = new THREE.Mesh( refractorGeometry, new MeshBasicNodeMaterial( {
	colorNode: verticalRefractor
} ) );
planeRefractor.material.transparent = true;
planeRefractor.position.y = 50;
scene.add( planeRefractor );
@Mugen87
Copy link
Collaborator Author

Mugen87 commented Jun 29, 2024

Awesome! I've seen the usage of ViewportNode in other examples and already thought Refractor might not be required.

I'll revert parts of the change and only add a refraction example so we can easier guide users who want to migrate to the new approach.

@Mugen87 Mugen87 changed the title Node: Add RefractorNode. Jun 29, 2024
@sunag sunag merged commit 6e66343 into mrdoob:dev Jun 30, 2024
11 checks passed
@Mugen87
Copy link
Collaborator Author

Mugen87 commented Jul 30, 2024

While porting Water2 I have realized a side effect when using (shared) viewport node for refraction. Check out:

image

With Refractor it was possible to cull all objects above the refraction plane which is not possible with a (shared) viewport node. The torus which is above the water appears refracted.

A similar side effect is also visible in webgpu_refraction. Can we fix this somehow with a depth compare?

@sunag
Copy link
Collaborator

sunag commented Jul 30, 2024

Can we fix this somehow with a depth compare?

Yes, I did this webgpu_backdrop_water, the node depthTestForRefraction is for this purpose

@sunag
Copy link
Collaborator

sunag commented Jul 30, 2024

With
image

and without
image

@sunag
Copy link
Collaborator

sunag commented Jul 30, 2024

In many situations this is unnecessary, only in cases where we need to have offset in the UV. #28761 (comment)

@sunag
Copy link
Collaborator

sunag commented Jul 30, 2024

const refractionUV = ...;
const depth = linearDepth();
const depthTestForRefraction = linearDepth( viewportDepthTexture( refractionUV ) ).sub( depth );
const finalUV = depthTestForRefraction.lessThan( 0 ).cond( viewportTopLeft, refractionUV );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
2 participants