沿z平面观察时,体绘制会产生伪影

时间:2015-02-19 10:42:03

标签: glsl webgl shader data-visualization volume-rendering

我一直试图让一些WebGL卷呈现并运行。我设法将3D数据平铺到2D纹理(横向和沿RGB通道平铺)。它现在显示一些合成数据(球体)。

沿着x,y平面(即在瓷砖上看脸)观察时,一切似乎都可以。 OK on x,y plane

但是一旦你开始观察从另一侧进入立方体的光线,就会产生一种奇怪的雾霾效果,阻挡正在渲染的体积,就像这样 starting to get a bit funky

当你直接沿着z平面观察(即边缘到瓷砖上)时,事情变得非常混乱 wtf

有没有人见过这个?完整的代码可用here

以下是我的着色器的业务端 - 看起来对平铺数组进行采样并执行光线行进的部分。

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;

const vec3 dataShape = vec3(99, 93, 330); // really this should be passed not hard coded
const vec2 textureShape = vec2(1024, 1024);

vec3 getDatumColor(float datum) {
    vec3 color = vec3(255, 255, 255);
    if (datum == 9999.9999){
        color = vec3(255, 0, 0);
    }
    return color;
}

float getDatumAlpha(float datum) {
    return datum * alphaCorrection;
}

float getDatum(sampler2D tex, vec3 pos, vec3 dataShape, vec2 nTiles, float tilesPerLayer, vec2 tileDim, float thisTileN){
    float zTile = floor(thisTileN/tilesPerLayer);
    float yTile = floor((thisTileN - (zTile * tilesPerLayer)) / nTiles.x);
    float xTile = mod((thisTileN - (zTile * tilesPerLayer)), nTiles.x);

    vec2 thisPoint = vec2(xTile+pos.x, yTile+pos.y) * tileDim;

    float datum;
    if (zTile == 0.0){
        datum = texture2D(tex, thisPoint).r;
    }else if (zTile == 1.0){
        datum = texture2D(tex, thisPoint).g;
    }else if (zTile == 2.0){
        datum = texture2D(tex, thisPoint).b;
    }

    return datum;
}

float sampleAs3DTexture(sampler2D tex, vec3 pos, vec3 dataShape, vec2 texShape) {
    /* 
    A function to reference a 2D RGBA texture which contains tiles 3D array data.

    Tiling goes column, row, channel

    Args:
        * tex: texture of tiled data
        * pos: position of the datum
        * dataShape: the x,y,z shape of the data which has been tiled
        * texShape: the x,y dims of the tiles texture
    */

    vec2 fracNTiles = texShape.xy / dataShape.xy;
    vec2 nTiles = vec2(floor(fracNTiles.x), floor(fracNTiles.y));
    float tilesPerLayer = nTiles.x * nTiles.y;
    vec2 tileDim = vec2(1.0, 1.0) / fracNTiles;
    float thisTileN = floor((dataShape.z-1.0) * pos.z);
    float thisTileNp1 = min(thisTileN+1.0, dataShape.z);

    float datumN = getDatum(tex, pos, dataShape, nTiles, tilesPerLayer, tileDim, thisTileN);
    float datumNp1 = getDatum(tex, pos, dataShape, nTiles, tilesPerLayer, tileDim, thisTileNp1);

    float zDiff = mod((dataShape.z-1.0) * pos.z, 1.0);

    return ((1.0 - zDiff) * datumN) + (zDiff * datumNp1);
}

vec4 getRGBAfromDataTex(sampler2D tex, vec3 pos, vec3 dataShape, vec2 texShape){
    float datum = sampleAs3DTexture(tex, pos, dataShape, texShape);
    vec3 color = getDatumColor(datum);
    float alpha = getDatumAlpha(datum);

    return vec4(color.xyz, alpha);
}

// 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.
    vec3 accumulatedColor = vec3(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 = getRGBAfromDataTex(dataTexture, currentPosition, dataShape, textureShape);

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

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

        //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;
    }
    vec4 fragColor = vec4(accumulatedColor.x, accumulatedColor.y, accumulatedColor.z, accumulatedAlpha);
    gl_FragColor = fragColor;
}

感谢大家的帮助!

0 个答案:

没有答案