谈到3D动画时,我不熟悉一些 很多 的术语和概念(可能是附加到此的第二个问题)一:熟悉这些概念有哪些好书?)。我不知道" UV"是(在3D渲染的背景下),我不熟悉将图像上的像素映射到网格上的点的工具。
我有一个360度相机生成以下图像(它实际上是HTML video
元素的输出):
我希望这张图片的中心位于"顶部"球体的角度,以及该图像中圆圈的任何半径都是从上到下沿球体的弧线。
这是我的起点(直接从Three.JS文档中复制代码行):
var video = document.getElementById( "texture-video" );
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var texture = new THREE.VideoTexture( video );
texture.minFilter = THREE.LinearFilter;
texture.magFilter = THREE.LinearFilter;
texture.format = THREE.RGBFormat;
var material = new THREE.MeshBasicMaterial( { map: texture } );
var geometry = new THREE.SphereGeometry(0.5, 100, 100);
var mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
camera.position.z = 1
function animate()
{
mesh.rotation.y += 0.01;
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
animate();
这会产生以下结果:
有一些问题:
目前,如果我将相机放在球体内,我会变成黑色。我不认为它是一个照明问题,因为Three.JS文档说MeshBasicMaterial
不需要照明。我认为问题可能是所有球体面的法线指向外部,我需要反转它们。我不确定如何做到这一点 - 但我很确定它是可能的,因为我认为这就是天空盒的工作方式。
做一些研究我很确定我需要修改" UV"来解决这个问题,我只是不知道这甚至意味着什么? / p>
答案 0 :(得分:2)
我分叉了@ manthrax的CodeSandbox.io解决方案,并用自己的解决方案进行了更新:
https://codesandbox.io/s/4w1njkrv9
因此,在花了一天时间研究紫外线贴图以了解其意义及其工作原理后,我能够坐下来划出一些触发来将球体上的点映射到我的立体图像上。它基本上归结为以下几点:
x = Rcos(theta), y = Rcos(theta)
计算立体图像上的直角坐标如果时间允许,我可以在Illustrator中绘制快速图像或者用来解释数学的东西,但它是标准的三角法
在此之后我更进了一步,因为我使用的相机只有240度的垂直视角 - 这导致图像稍微扭曲(特别是靠近地面)。通过从360减去垂直视角并除以2,您可以从垂直方向获得一个角度,在该角度内不应进行任何映射。因为球体是沿着Y轴定向的,所以这个角度映射到一个特定的Y坐标 - 在该坐标之上有数据,低于该坐标不存在。
出于某种原因,我写的代码将图像翻转过来。我不知道我是否搞砸了我的三角学,或者我是否搞砸了我对UV贴图的理解。无论如何,通过在映射
之后将球体翻转180度来简单地修复这个问题同样,我也不知道如何"什么也不返回"在UV地图中,所以我将最小Y值以下的所有点映射到图像的角落(黑色)
在240度视角下,球体底部没有图像数据的空间足够大(在我的显示器上),我可以看到直视前方的黑色圆圈。我不喜欢它的视觉外观,所以我插入270用于垂直FOV。这导致了地面的轻微扭曲,但没有使用360时那么糟糕。
这是我为更新UV地图而编写的代码:
// Enter the vertical FOV for the camera here
var vFov = 270; // = 240;
var material = new THREE.MeshBasicMaterial( { map: texture, side: THREE.BackSide } );
var geometry = new THREE.SphereGeometry(0.5, 200, 200);
function updateUVs()
{
var maxY = Math.cos(Math.PI * (360 - vFov) / 180 / 2);
var faceVertexUvs = geometry.faceVertexUvs[0];
// The sphere consists of many FACES
for ( var i = 0; i < faceVertexUvs.length; i++ )
{
// For each face...
var uvs = faceVertexUvs[i];
var face = geometry.faces[i];
// A face is a triangle (three vertices)
for ( var j = 0; j < 3; j ++ )
{
// For each vertex...
// x, y, and z refer to the point on the sphere in 3d space where this vertex resides
var x = face.vertexNormals[j].x;
var y = face.vertexNormals[j].y;
var z = face.vertexNormals[j].z;
// Because our stereograph goes from 0 to 1 but our vertical field of view cuts off our Y early
var scaledY = (((y + 1) / (maxY + 1)) * 2) - 1;
// uvs[j].x, uvs[j].y refer to a point on the 2d texture
if (y < maxY)
{
var radius = Math.acos(1 - ((scaledY / 2) + 0.5)) / Math.PI;
var angle = Math.atan2(x, z);
uvs[j].x = (radius * Math.cos(angle)) + 0.5;
uvs[j].y = (radius * Math.sin(angle)) + 0.5;
} else {
uvs[j].x = 0;
uvs[j].y = 0;
}
}
}
// For whatever reason my UV mapping turned everything upside down
// Rather than fix my math, I just replaced "minY" with "maxY" and
// rotated the sphere 180 degrees
geometry.rotateZ(Math.PI);
geometry.uvsNeedUpdate = true;
}
updateUVs();
var mesh = new THREE.Mesh( geometry, material );
现在,如果将此网格添加到场景中,一切看起来都很完美:
在&#34;洞周围&#34;在球体底部有一个多色环。它几乎看起来像天空的镜子。我不知道为什么会存在或者它是如何存在的。任何人都可以在评论中阐明这一点吗?
答案 1 :(得分:1)
在接近极端展开紫外线的大约10分钟内,我就可以得到它。
您可以修改polarUnwrap函数以尝试获得更好的映射....
https://codesandbox.io/s/8nx75lkn28
您可以使用
替换TextureLoader()。loadTexture()//assuming you have created a HTML video element with id="video"
var video = document.getElementById( 'video' );
var texture = new THREE.VideoTexture( video );
texture.minFilter = THREE.LinearFilter;
texture.magFilter = THREE.LinearFilter;
texture.format = THREE.RGBFormat;
将您的视频投放到那里......
更多信息:
https://threejs.org/docs/#api/textures/VideoTexture
这也可能对您有用:
https://community.theta360.guide/t/displaying-thetas-dual-fisheye-video-with-three-js/1160
答案 2 :(得分:0)
我认为,修改UV会非常困难,因此立体投影图像会很合适。球体的UV设置为适合具有等长矩形投影的纹理。
要将图像从立体图转换为equirectangular,您可能需要使用全景工具,例如PTGui或Hugin。或者您可以使用Photoshop(应用滤镜&gt;扭曲&gt;极坐标&gt;极坐标到矩形)。
图像的Equirectangular投影(使用Photoshop),调整为2:1宽高比(纹理不需要)
如果您希望纹理位于球体内(或法线翻转),则可以将材质设置为git diff <commit-hash1> <commit-hash2> <commit-hash3> | grep <my-search-text>
。
THREE.BackSide
也许,你必须水平翻转纹理:How to flip a Three.js texture horizontally