ste*_*esu 5 javascript 3d textures mesh three.js
当谈到 3D 动画时,有很多我不熟悉的术语和概念(也许附加到这个问题的第二个问题:有哪些好书可以熟悉这些概念?)。我不知道“UV”是什么(在 3D 渲染的上下文中),也不熟悉用于将图像上的像素映射到网格上的点的工具。
我有一个 360 度相机生成的以下图像(它实际上是 HTMLvideo
元素的输出):
我希望该图像的中心是球体的“顶部”,并且该图像中圆的任何半径都是沿着球体从上到下的弧。
这是我的起点(直接从 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();
Run Code Online (Sandbox Code Playgroud)
这会产生以下结果:
有几个问题:
目前,如果我将相机放置在球体内,我会得到纯黑色。我不认为这是照明问题,因为 Three.JS 文档说 aMeshBasicMaterial
不需要照明。我认为问题可能是所有球体面的法线都指向外,我需要反转它们。我不确定如何做到这一点 - 但我很确定这是可能的,因为我认为这就是天空盒的工作原理。
做了一些研究,我很确定我需要修改“UV”来解决这个问题,我只是不知道这意味着什么,或者到底意味着什么......
我分叉了 @manthrax 的 CodeSandbox.io 解决方案并用我自己的解决方案更新了它:
https://codesandbox.io/s/4w1njkrv9
因此,在花了一天时间研究 UV 映射以了解其含义及其工作原理之后,我能够坐下来并制定一些三角函数,将球体上的点映射到立体图像上的点。基本上可以归结为以下几点:
x = Rcos(theta), y = Rsin(theta)
计算立体图像上的直角坐标如果时间允许,我可能会在 Illustrator 中快速绘制一个图像或其他东西来解释数学,但它是标准三角学
在此之后我更进一步,因为我使用的相机只有 240 度垂直视角 - 这导致图像稍微扭曲(尤其是在地面附近)。通过从 360 度减去垂直视角并除以二,您可以得到一个与垂直方向的角度,在该角度内不应发生映射。由于球体沿 Y 轴定向,因此该角度映射到特定的 Y 坐标 - 在该坐标上方有数据,在该坐标下方没有数据。
由于某种原因,我编写的代码将图像颠倒了。我不知道是我搞砸了我的三角学还是我对 UV 贴图的理解搞砸了。不管怎样,这个问题可以通过在映射后将球体翻转 180 度来轻松解决
另外,我不知道如何在 UV 贴图中“不返回任何内容”,因此我将低于最小 Y 值的所有点映射到图像的角(黑色)
在 240 度视角下,球体底部没有图像数据的空间足够大(在我的显示器上),当我直视前方时,我可以看到黑色圆圈。我不喜欢它的视觉外观,所以我将垂直 FOV 设置为 270。这会导致地面周围出现轻微变形,但没有使用 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 );
Run Code Online (Sandbox Code Playgroud)
现在,如果您将此网格添加到场景中,一切看起来都很完美:
在球体底部的“洞”周围有一个彩色环。它看起来几乎就像天空的镜子。我不知道它为什么存在或它是如何到达那里的。有人可以在评论中阐明这一点吗?
归档时间: |
|
查看次数: |
3303 次 |
最近记录: |