【问题标题】:Converting a 3D-Scene to 2D-image using raytracing (webgl, three.js)使用光线追踪(webgl、three.js)将 3D 场景转换为 2D 图像
【发布时间】:2013-10-07 22:01:28
【问题描述】:

如上所述,我想通过光线追踪将 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;

}

片段着色器:

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://pastebin.com/Dxh5C9XX

在这里运行:

http://ec2-54-244-155-66.us-west-2.compute.amazonaws.com/example.html

要查看相机是否实际移动,您可以按 x、y、z 来获取当前相机的 x、y、z 坐标。

【问题讨论】:

  • 请问您到底想达到什么目标?您正在寻找的不是正交相机吗?或者可能是渲染目标?此外,控件在我的示例中似乎不起作用。

标签: javascript three.js webgl raytracing


【解决方案1】:

您看到的是正方形而不是 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 是平面的二维坐标,uInvMVProjMatrix 是模型视图投影矩阵的倒数。这将返回一个vec3,您可以使用它来测试交叉点。

【讨论】:

  • 感谢您抽出宝贵的时间回答,但它似乎不起作用
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-10
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
  • 2014-10-01
  • 1970-01-01
  • 2019-01-23
相关资源
最近更新 更多