在 Three.Js 中剪裁一个体积,给出黑色区域而不是内部材质

Posted

技术标签:

【中文标题】在 Three.Js 中剪裁一个体积,给出黑色区域而不是内部材质【英文标题】:Clipping a volume in Three.Js giving Black area instead of Inner Material 【发布时间】:2019-09-27 15:14:30 【问题描述】:

我正在尝试从 ThreeJS 中的所有三个平面剪辑一个卷以查看内部结构。

如果像素的绘图超出了您的剪辑限制,则剪辑是在片段着色器中进行启发和实现的:

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;

并通过shader材质(Two pass Volume Rendering)传递了上述信息,如下代码所示。

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 );

它看起来有点像黑色边界,我想成为渲染表面。

更新:我的动机是分别从所有 3 个方向平面 X、Y 和 Z 看内部裁剪。您也可以考虑切片,就像我想查看某个切片的体积一样。

我查看了这些示例 Clipping、Advance Clipping 和 Intersection Clipping ,但这些示例并没有多大用处,因此使用基于坐标的丢弃和裁剪方式来实现我的目标。

【问题讨论】:

【参考方案1】:

正如Three.js Discourse 所讨论的那样,您的方法的问题在于,通过在片段着色器上丢弃像素,您根本无法对其进行渲染。

如果光线位置在您的剪切框之外,正确的方法是防止光线行进累积颜色和 alpha。剪切框坐标必须在 [0,1] 空间内。

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;


// ...

//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;
    
    // ...

【讨论】:

以上是关于在 Three.Js 中剪裁一个体积,给出黑色区域而不是内部材质的主要内容,如果未能解决你的问题,请参考以下文章

Three.js - 立方体和球体与平面奇怪地剪裁

Three.js 为啥带有视口和剪刀的渲染器和我有一个完整的黑色画布

three.js 纹理未显示且为黑色

three.js obj 和 mtl 文件用阴影呈现黑色

WebGL 多画布three.js 示例

使用vue学习three.js之渲染后期处理-使用VignetteShader定制效果添加晕映效果,在图片周围显示黑色边框