体绘制从一个方向比另一个方向更透明

Volume rendering is more transparent from one direction that another

我正在尝试使用 three.js 和光线行进 GLSL 来了解体积渲染。我有一些从 numpy 数组合成的数据。

正在呈现的数据立方体在一侧更不透明,逐渐在另一侧变得透明 - 就像这样(忽略线框,这只是为了一点方向)

然而,当您从更透明的一端看立方体时,透明度似乎 "block out" 不太透明的一端(希望这是有道理的)。像这样:

我不知道这是否相关,但我也有一个问题,当相机稍微进入立方体内部时,它会停止正确渲染。它会切断离相机最近的位,如下所示: 这是一个相关问题,还是只是方法的局限性。

代码在这里 https://github.com/niallrobinson/test-volume-rendering/blob/master/viewer.htmlhttps://github.com/niallrobinson/test-volume-rendering/blob/master/viewer.js https://github.com/niallrobinson/test-volume-rendering/blob/master/viewer.html

第二遍着色器如下所示:

<script id="vertexShaderFirstPass" type="x-shader/x-vertex">
    varying vec3 worldSpaceCoords;
    void main(){
        //Set the world space coordinates of the back faces vertices as output.
        worldSpaceCoords = position + vec3(0.5, 0.5, 0.5); //move it from [-0.5;0.5] to [0,1]
        gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
    }
</script>

<script id="fragmentShaderFirstPass" type="x-shader/x-fragment">
    varying vec3 worldSpaceCoords;
    void main(){
        //The fragment's world space coordinates as fragment output.
        gl_FragColor = vec4( worldSpaceCoords.x , worldSpaceCoords.y, worldSpaceCoords.z, 1 );
    }
</script>


<!-- second pass shaders -->
<script id="vertexShaderSecondPass" type="x-shader/x-vertex">
    varying vec3 worldSpaceCoords;
    varying vec4 projectedCoords;

    void main()
    {
        worldSpaceCoords = (modelMatrix * vec4(position + vec3(0.5, 0.5, 0.5), 1.0 )).xyz;
        gl_Position = projectionMatrix *  modelViewMatrix * vec4( position, 1.0 );
        projectedCoords =  projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
    }
</script>

<script id="fragmentShaderSecondPass" type="x-shader/x-fragment">
    varying vec3 worldSpaceCoords;
    varying vec4 projectedCoords;

    uniform sampler2D firstPassTexture, dataTexture; //i.e. tex and cubeTex
    uniform float steps;
    uniform float alphaCorrection;
    const int MAX_STEPS = 512;

    vec3 dataDims = vec3(4, 4, 4);

    vec4 sampleAs3DTexture(sampler2D tex, vec3 pos) {
        // pos is in UV coords i.e. 0->1. We also want to interrogate out texture in the range 0->1
        // however, our 3D dimensions are conceptually 4,4,4
        float nTiles = dataDims.z;
        float tileWidth = 1.0 / nTiles;
        float p = pos.y * tileWidth + pos.x / nTiles;
        float q = pos.z;

        lowp vec4 sample = texture2D(tex, vec2(p, q)); //I think this fn might convert from 255 range to 0->1 range
        vec4 returnSample = vec4(0.7, 0., 0., sample.x * alphaCorrection); // alpha is 255 in png so overwrite
        return returnSample;
    }

    // max 2d size is 4096 x 4096

    void main( void ) {
        //Transform the coordinates it from [-1;1] to [0;1]
        vec2 firstPassTexCoord = vec2(((projectedCoords.x / projectedCoords.w) + 1.0 ) / 2.0,
                        ((projectedCoords.y / projectedCoords.w) + 1.0 ) / 2.0 );

        //The back position is the world space position stored in the texture.
        vec3 backPos = texture2D(firstPassTexture, firstPassTexCoord).xyz;

        //The front position is the world space position of the second render pass.
        vec3 frontPos = worldSpaceCoords;

        //The direction from the front position to back position.
        vec3 dir = backPos - frontPos;

        float rayLength = length(dir);

        //Calculate how long to increment in each step.
        float delta = 1.0 / steps;

        //The increment in each direction for each step.
        vec3 deltaDirection = normalize(dir) * delta;
        float deltaDirectionLength = length(deltaDirection);

        //Start the ray casting from the front position.
        vec3 currentPosition = frontPos;

        //The color accumulator.
        vec4 accumulatedColor = vec4(0.0);

        //The alpha value accumulated so far.
        float accumulatedAlpha = 0.0;

        //How long has the ray travelled so far.
        float accumulatedLength = 0.0;

        //vec4 dataSample;
        vec4 dataSample;

        float alphaSample;

        //Perform the ray marching iterations
        for(int i = 0; i < MAX_STEPS; i++){
            //Get the voxel intensity value from the 3D texture.    
            dataSample = sampleAs3DTexture(dataTexture, currentPosition);

            //Allow the alpha correction customization
            alphaSample = dataSample.a;

            //Perform the composition.
            accumulatedColor += (1.0 - accumulatedAlpha) * dataSample * alphaSample;
            //accumulatedColor += dataSample;

            //Store the alpha accumulated so far.
            accumulatedAlpha += alphaSample;

            //Advance the ray.
            currentPosition += deltaDirection;
            accumulatedLength += deltaDirectionLength;

            //If the length traversed is more than the ray length, or if the alpha accumulated reaches 1.0 then exit.
            if(accumulatedLength >= rayLength || accumulatedAlpha >= 1.0 )
                break;
        }
        gl_FragColor = accumulatedColor;
    }

</script>

提前谢谢大家

编辑: 经过一些实验,问题似乎是只渲染了立方体的外部。如果我把一团数据放在立方体的中间,你什么也看不到。

编辑: 事实上,它只在正面渲染数据。如果我反转光线行进方向(即改变它朝向相机),你只能在背面看到它

认为它已排序!从 tex 查找返回的数据是一个 vec4。然后它被用来增加 accumulatedColor。我将 accumulatedColor 更改为 vec3 并且仅将其递增 .xyz 并且这似乎可以解决问题

感谢所有看过的人