Clipping a volume in Three.Js giving Black area instead of Inner Material

Description of the problem

I am trying to clip a volume from all three planes in ThreeJS to look into the inner structure.

Clipping is done inspired and implemented in fragment shader by discarding the drawing of the pixel if it is beyond your clipping limit:

gl_FragColor  = accumulatedColor;
				
if(worldSpaceCoords.x < xClippingPlaneMin) discard;
if(worldSpaceCoords.x < xClippingPlaneMin) discard;
if(worldSpaceCoords.z < zClippingPlaneMin) discard;
if(worldSpaceCoords.z > zClippingPlaneMax) discard;
if(worldSpaceCoords.y < yClippingPlaneMin) discard;
if(worldSpaceCoords.y > yClippingPlaneMax) discard;

And have circulated the above information by passing through the shader material (Two pass Volume Rendering) as shown in below code.

var materialFirstPass = new THREE.ShaderMaterial( {
				vertexShader: document.getElementById( 'vertexShaderFirstPass' ).textContent,
				fragmentShader: document.getElementById( 'fragmentShaderFirstPass' ).textContent,
				side: THREE.BackSide,
			
			} );
materialSecondPass = new THREE.ShaderMaterial( {
				vertexShader: document.getElementById( 'vertexShaderSecondPass' ).textContent,
				fragmentShader: document.getElementById( 'fragmentShaderSecondPass' ).textContent,
				side: THREE.FrontSide,
				depthWrite: false,



uniforms: {	tex:  { type: "t", value: rtTexture },
							cubeTex:  { type: "t", value: cubeTextures['bonsai'] },
							transferTex:  { type: "t", value: transferTexture },
							steps : {type: "1f" , value: guiControls.steps },
							alphaCorrection : {type: "1f" , value: guiControls.alphaCorrection },
							xClippingPlaneMin : {type: "1f" , value: guiControls.xClippingPlaneMin },
							xClippingPlaneMax : {type: "1f" , value: guiControls.xClippingPlaneMax },
							yClippingPlaneMin : {type: "1f" , value: guiControls.yClippingPlaneMin },
							yClippingPlaneMax : {type: "1f" , value: guiControls.yClippingPlaneMax },
							zClippingPlaneMin : {type: "1f" , value: guiControls.zClippingPlaneMin },
							zClippingPlaneMax : {type: "1f" , value: guiControls.zClippingPlaneMax }
						},
			 });

sceneFirstPass = new THREE.Scene();
sceneSecondPass = new THREE.Scene();

var boxGeometry = new THREE.BoxGeometry(1.0, 1.0, 1.0);
boxGeometry.doubleSided = true;

var meshFirstPass = new THREE.Mesh( boxGeometry, materialFirstPass );
var meshSecondPass = new THREE.Mesh( boxGeometry, materialSecondPass );

sceneFirstPass.add( meshFirstPass );
sceneSecondPass.add( meshSecondPass );

It looks something of this sort black boundary which I want to be the rendered surface.
1

2

This code is an extension of lebarba’s code

I am new to THREE.jS and WebGL. Any help would be appreciated. My motive is to look inside the Volume clipping from all 3 direction plane X, Y and Z respectively. You can think of slicing too like I want to look into the volume at some slice.

I looked into these examples Clipping, Advance Clipping and Intersection Clipping , but these were not of much use so used the coordinate based discarding and clipping way to achieve my goal.

Three.js version
  • [ ] Dev
  • [ ] r104
  • [x] r68
Browser
  • [x] All of them
  • [ ] Chrome
  • [ ] Firefox
  • [ ] Internet Explorer
OS
  • [x] All of them
  • [ ] Windows
  • [ ] macOS
  • [ ] Linux
  • [ ] Android
  • [ ] iOS
Hardware Requirements (graphics card, VR Device, …)

This is happening because you are preventing the pixel from rendering, by discarding it in the fragment shader.

What you should do, instead, is to only allow the ray march to accumulate color and alpha if it’s within the clip boundaries, like this:

//Perform the ray marching iterations
for( int i = 0; i < MAX_STEPS; i++) {
    // ...
    if ( withinBoundaries( currentPosition ) ) {
	    //Perform the composition.
	    accumulatedColor += colorSample * alphaSample;
	    //Store the alpha accumulated so far.
	    accumulatedAlpha += alphaSample;
    }
    // ...
}

Then you can create withinBoundaries() outside your main function:

bool withinBoundaries( vec3 pos ) {
	if (
		pos.x < xClippingPlaneMin ||
		pos.y < yClippingPlaneMin ||
		pos.z < zClippingPlaneMin ||
		pos.x > xClippingPlaneMax ||
		pos.y > yClippingPlaneMax ||
		pos.z > zClippingPlaneMax
	) return false;
	return true;
}

With these changes, you should see the results you expect. It’s important to note that the clipping coordinates must be within [0,1], otherwise you won’t see any changes.

front persp

2 Likes

Thanks, yes my slider to fix the x,y and z are within the 0-1 range. It saved don’t know how many days. I tried changing the worldSpace coordinate too, where rendering was starting(changing start point basically), but that was hack. But this completed it.