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 ://github.com/niallrobinson/test-volume-rendering/blob/master/viewer.html
2 番目のパス シェーダーは次のようになります。
<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>
よろしくお願いします
編集:少し実験した後、立方体の外側だけがレンダリングされていることが問題のようです。立方体の真ん中にデータの塊を置いても、何も見えません。
EDIT:実際には、前面の唯一のレンダリングデータです。レイ マーチングの方向を逆にすると (つまり、カメラに向かう方向に変更すると)、裏側の表面でしか見ることができません。