我一直试图让一些WebGL卷呈现并运行。我设法将3D数据平铺到2D纹理(横向和沿RGB通道平铺)。它现在显示一些合成数据(球体)。
沿着x,y平面(即在瓷砖上看脸)观察时,一切似乎都可以。
但是一旦你开始观察从另一侧进入立方体的光线,就会产生一种奇怪的雾霾效果,阻挡正在渲染的体积,就像这样
当你直接沿着z平面观察(即边缘到瓷砖上)时,事情变得非常混乱
有没有人见过这个?完整的代码可用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;
}
感谢大家的帮助!