Объемный рендеринг более прозрачен с одного направления, чем с другого

Я пытаюсь разобраться с объемным рендерингом с помощью three.js и лучевого марширования GLSL. У меня есть некоторые данные, которые я синтезировал из массива NumPy.

Куб визуализируемых данных с одной стороны более непрозрачен, а с другой стороны становится прозрачным - вот так (не обращайте внимания на каркас, это просто для ориентации)

однако, когда вы смотрите на куб с более прозрачного конца, прозрачность, кажется, "блокирует" менее прозрачный конец (надеюсь, что это имеет смысл). Как это:

Я не знаю, связано ли это, но у меня также есть проблема, что, когда камера находится немного внутри куба, она перестает правильно рендериться. Отсекает бит, ближайший к камере, вот так:Это связанная проблема, или это просто ограничение метода.

Код здесь 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>

Заранее всем спасибо

РЕДАКТИРОВАТЬ: После небольшого количества экспериментов, кажется, что проблема в том, что визуализируется только внешняя часть куба. Если я помещу большой объем данных в середину куба, вы ничего не увидите.

РЕДАКТИРОВАТЬ: Infact, это только данные рендеринга на передней поверхности. Если я переверну направление движения луча (т.е. поменяю его на камеру), вы сможете увидеть его только на задней поверхности

1 ответ

Решение

Думаю, что это отсортировано! Данные, возвращенные из поиска tex, были vec4. Это было тогда использовано для увеличения accumulatedColor, Я изменился accumulatedColor к vec3 и только увеличил его на .xyz и это, казалось, добилось цели

Спасибо всем, кто посмотрел

Другие вопросы по тегам