体绘制从一个方向比另一个方向更透明
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
并且这似乎可以解决问题
感谢所有看过的人
我正在尝试使用 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
并且这似乎可以解决问题
感谢所有看过的人