如上所述,我想使用光线追踪将3D场景渲染到2D平面上。最终我想将它用于体积渲染,但我在这里努力学习基础知识。我有一个three.js场景,观察平面连接到摄像机(当然在它前面)。
设置:
然后(在着色器中)我从相机通过飞机中的每个点(250x250)拍摄一条光线。飞机后面是41x41x41音量(基本上是一个立方体)。如果光线穿过立方体,则光线穿过的观察平面中的点将呈现红色,否则该点将为黑色。不幸的是,只有从前面看立方体才有效。以下是示例:http://ec2-54-244-155-66.us-west-2.compute.amazonaws.com/example.html
如果你试图从不同的角度观察立方体(你可以用鼠标移动相机),那么我们不会像我们想要的那样将立方体渲染到观察平面上,而是在正方形上有一些奇怪的像素侧..
这是光线追踪的代码:
顶点着色器:
bool inside(vec3 posVec){
bool value = false;
if(posVec.x <0.0 ||posVec.x > 41.0 ){
value = false;
}
else if(posVec.y <0.0 ||posVec.y > 41.0 ){
value = false;
}
else if(posVec.z <0.0 ||posVec.z > 41.0 ){
value = false;
}
else{
value = true;
}
return value;
}
float getDensity(vec3 PointPos){
float stepsize = 1.0;
float emptyStep = 15.0;
vec3 leap;
bool hit = false;
float density = 0.000;
// Ray direction from the camera through the current point in the Plane
vec3 dir = PointPos- camera;
vec3 RayDirection = normalize(dir);
vec3 start = PointPos;
for(int i = 0; i<STEPS; i++){
vec3 alteredPosition = start;
alteredPosition.x += 20.5;
alteredPosition.y += 20.5;
alteredPosition.z += 20.5;
bool insideTest = inside(alteredPosition);
if(insideTest){
// advance from the start position
start = start + RayDirection * stepsize;
hit = true;
}else{
leap = start + RayDirection * emptyStep;
bool tooFar = inside(leap);
if(tooFar){
start = start + RayDirection * stepsize;
}else{
start = leap;
}
}
}
if(hit){
density = 1.000;
}
return density;
}
void main() {
PointIntensity = getDensity(position);
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_Position = projectionMatrix * mvPosition;
}
Fragment Shader:
varying float PointIntensity;
void main() {
//Rays that have traversed the volume (cube) should leave a red point on the viewplane, Rays that just went through empty space a black point
gl_FragColor= vec4(PointIntensity, 0.0, 0.0, 1.0);
}
完整代码: http://pastebin.com/4YmWL0u1
相同代码但正在运行 http://ec2-54-244-155-66.us-west-2.compute.amazonaws.com/example.html
如果有人对我在这里做错了什么提示,我会很高兴
修改
我使用Mark Lundin提出的更改更新了示例,但不幸的是,移动相机时我仍然只得到一个红色正方形(尽管侧面没有奇怪的像素):
mat4 uInvMVProjMatrix = modelViewMatrix *inverseProjectionMatrix;
inverseProjectionMatrix是Three.js相机属性projectionMatrixInverse作为制服传递给着色器。然后使用uv坐标为视图平面中的每个点调用unproject函数。
新代码在这里:
并在这里运行:
http://ec2-54-244-155-66.us-west-2.compute.amazonaws.com/example.html
要查看相机实际移动,您可以按x,y,z来获取当前相机的x,y,z坐标。
答案 0 :(得分:4)
您看到正方形而不是3D体积的原因是因为您的光线追踪方法没有考虑相机方向或投影。当您使用轨迹球移动摄像机时,它的方向会发生变化,因此这应该包含在您的计算中。其次,摄像机的投影矩阵也应该用于将平面的坐标投影到3D空间中。您可以通过以下方式实现此目的:
vec3 unproject( vec2 coord ){
vec4 screen = vec4( coord, 0, 1.0 );
vec4 homogenous = uInvMVProjMatrix * 2.0 * ( screen - vec4( 0.5 ) );
return homogenous.xyz / homogenous.w;
}
其中coord
是平面的2d坐标,uInvMVProjMatrix
是模型视图投影矩阵的倒数。这将返回vec3
,您可以使用它来测试交叉点。