如何使用threejs渲染360 x 235度FOV图像?

时间:2019-04-03 02:57:48

标签: javascript three.js texture-mapping

我有一台照相机拍摄的圆形图像声称代表着235度视野,例如:enter image description here

我对threejs有一定的经验,并已使用它来正确渲染以等边矩形投影形式存储的360x360图像-网络上有很多示例可以做到这一点。

但是我想使用threejs渲染我的圆形图像,可能作为球体内部的纹理。我看了一些示例(例如https://threejs.org/examples/#webgl_panorama_dualfisheyeMapping image onto a sphere in Three.js),这些示例似乎为我指明了正确的方向,但我想我只是对threejs如何工作分解的认识不足在一起。

第二个(眼球)似乎使我靠近,但是遵循眼球代码恰好意味着我的图像显示了两次(我想这是有道理的,因为我的图像是正方形的,纹理必须覆盖整个球体。

因此,我尝试使用SphereGeometry的长版本构造函数制作部分球体(360 * 235),但是更改phi会给我带来看起来像橙色缺失切片的东西。改变theta可以给我正确的形状,但是纹理不能正确放置在上面。

所以我的总体问题是如何进行这项工作,但我认为困扰我的主要因素是:

  1. 由什么控制如何将纹理绘制到网格上? (这样我就可以只一次绘制纹理,并且只能绘制到我需要的球体部分上)

  2. 我看到设置UV是必要的(geometry.faceVertexUvs?),我读了https://en.wikipedia.org/wiki/UV_mapping,所以我有点理解这是什么意思,但我不知道从哪里着手。纠正我的图像的紫外线(仍然像数字1一样,如何阻止它显示在球体的“背面”)

2 个答案:

答案 0 :(得分:0)

好的,所以我继续阅读了一些关于UV的知识,并做了很多实验。这是我主要理解的工作代码(仅是相关位):

var geometry = new THREE.SphereGeometry( 30, 256, 128, 0, Math.PI * 2, 0, Math.PI );
geometry.scale( - 1, 1, 1 );//inside out

var imgWidth = 0.8;//I thought this should be 235/360, but used trial and error for less fisheye distortion

var faceVertexUvs = geometry.faceVertexUvs[ 0 ];
for ( i = 0; i < faceVertexUvs.length; i ++ ) {

    var uvs = faceVertexUvs[ i ];
    var face = geometry.faces[ i ];
    //y is top to bottom
    //z is in-out?
    //x is side-side? positive x is front, negative is back

    for ( var j = 0; j < 3; j ++ ) {
        var fvNj = face.vertexNormals[j];
        var yaw = Math.atan2(fvNj.z, fvNj.x)/(Math.PI); //around, -1 to 1
        var pitch = Math.asin(fvNj.y)/Math.PI; //height, -0.5 to 0.5
        pitch = pitch * -1 + 0.5;//flip and make zero to one
        pitch *= imgWidth;

        if(pitch < 0.5){
            //how to do fisheye correction??
            //var correction = (fvNj.x == 0 && fvNj.z == 0) ? 1 : (Math.acos(fvNj.y) / Math.sqrt(fvNj.x * fvNj.x + fvNj.z * fvNj.z)) * (2 / Math.PI);
            var x = Math.cos(yaw * Math.PI);// -1 to 1
            var y = Math.sin(yaw * Math.PI);// -1 to 1
            var u = 0.5 + x*pitch;
            var v = 0.5 + y*pitch;  

            uvs[ j ].x = u;
            uvs[ j ].y = v;
        }else{
            uvs[j].x = 0;
            uvs[j].y = 0;
        }
    }
}

mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );

答案 1 :(得分:0)

如您所知,您的源图片不完整,因为它覆盖了 360x235。您必须“扩展”它以覆盖整个 360x360 球体。

我也有一台可以创建相同图像的相机;到目前为止,我无法找到一个完整的 javascript 源代码来获取这些原始图像、转换为正确的格式并在球体上变形,所以我不得不找到另一个解决方案:提前转换图像。

为此我使用 ffmpeg。

使用此命令行:

ffmpeg -i C:\Users\luca\Downloads\qNfrX.jpg -vf v360=fisheye:e:ih_fov=235:iv_fov=235 test.jpg 

你得到这张图片:

equirectangular 1

改用这个命令行:

ffmpeg -i C:\Users\luca\Downloads\qNfrX.jpg -vf v360=fisheye:e:ih_fov=235:iv_fov=235:pitch=-90 test2.jpg

使用不同的俯仰角,你会得到这个图像:

equirectangular 2

然后您可以使用一个这些等距柱状图来包裹一个球体,但在这方面我无法直接提供帮助;可能这个来源可以提供帮助,但我仍在研究它:

https://github.com/legokichi/three-fisheye