简体   繁体   中英

How do I figure out the UV Mapping from Ricoh Theta S Dual FIsh Eye to a Three.js r71 SphereGeometry

I am trying to reproduce the three.js panaorama dualfisheye example using Three.js r71.

I need to stick to r71 because eventually I will use this code on autodesk forge viewer which is based on Three.js r71.

I made some progress, but I need help in figuring out UV mapping.

If you compare the result from this link three.js panaorama dualfisheye example with the code snippet there is obiously an issue.

  var camera, scene, renderer; var isUserInteracting = false, onMouseDownMouseX = 0, onMouseDownMouseY = 0, lon = 0, onMouseDownLon = 0, lat = 0, onMouseDownLat = 0, phi = 0, theta = 0, distance = 500; init(); animate(); function init() { var container, mesh; container = document.getElementById('container'); camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 2000); scene = new THREE.Scene(); // var geometry = new THREE.SphereBufferGeometry( 500, 60, 40 ).toNonIndexed(); var geometry = new THREE.SphereGeometry(500, 60, 40); // invert the geometry on the x-axis so that all of the faces point inward // geometry.scale( - 1, 1, 1 ); geometry.applyMatrix(new THREE.Matrix4().makeScale(-1, 1, 1)); /* // Remap UVs // var normals = geometry.attributes.normal.array; var normals = []; geometry.faces.forEach(element => { normals.push(element.normal) }); var uvs = geometry.faceVertexUvs // var uvs = geometry.attributes.uv.array; for (var i = 0, l = normals.length / 3; i < l; i++) { var x = normals[i * 3 + 0]; var y = normals[i * 3 + 1]; var z = normals[i * 3 + 2]; if (i < l / 2) { var correction = (x == 0 && z == 0) ? 1 : (Math.acos(y) / Math.sqrt(x * x + z * z)) * (2 / Math.PI); uvs[i * 2 + 0] = x * (404 / 1920) * correction + (447 / 1920); uvs[i * 2 + 1] = z * (404 / 1080) * correction + (582 / 1080); } else { var correction = (x == 0 && z == 0) ? 1 : (Math.acos(- y) / Math.sqrt(x * x + z * z)) * (2 / Math.PI); uvs[i * 2 + 0] = - x * (404 / 1920) * correction + (1460 / 1920); uvs[i * 2 + 1] = z * (404 / 1080) * correction + (582 / 1080); } } */ // geometry.rotateZ( - Math.PI / 2 ); geometry.applyMatrix(new THREE.Matrix4().makeRotationZ(Math.PI / 2)) THREE.ImageUtils.crossOrigin = ''; var texture = THREE.ImageUtils.loadTexture('https://threejs.org/examples/textures/ricoh_theta_s.jpg'); this.texture = texture; texture.format = THREE.RGBFormat; var material = new THREE.MeshBasicMaterial({ map: texture }); material.map.repeat.set(1, 1); material.map.offset.set(0, 0); mesh = new THREE.Mesh(geometry, material); scene.add(mesh); renderer = new THREE.WebGLRenderer(); renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(window.innerWidth, window.innerHeight); container.appendChild(renderer.domElement); document.addEventListener('mousedown', onDocumentMouseDown, false); document.addEventListener('mousemove', onDocumentMouseMove, false); document.addEventListener('mouseup', onDocumentMouseUp, false); document.addEventListener('wheel', onDocumentMouseWheel, false); window.addEventListener('resize', onWindowResize, false); } function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); } function onDocumentMouseDown(event) { event.preventDefault(); isUserInteracting = true; onPointerDownPointerX = event.clientX; onPointerDownPointerY = event.clientY; onPointerDownLon = lon; onPointerDownLat = lat; } function onDocumentMouseMove(event) { if (isUserInteracting === true) { lon = (onPointerDownPointerX - event.clientX) * 0.1 + onPointerDownLon; lat = (onPointerDownPointerY - event.clientY) * 0.1 + onPointerDownLat; } } function onDocumentMouseUp(event) { isUserInteracting = false; } function onDocumentMouseWheel(event) { distance += event.deltaY * 0.05; distance = THREE.Math.clamp(distance, 400, 1000); } function animate() { requestAnimationFrame(animate); update(); } function update() { if (isUserInteracting === false) { lon += 0.1; } lat = Math.max(- 85, Math.min(85, lat)); phi = THREE.Math.degToRad(90 - lat); theta = THREE.Math.degToRad(lon - 180); camera.position.x = distance * Math.sin(phi) * Math.cos(theta); camera.position.y = distance * Math.cos(phi); camera.position.z = distance * Math.sin(phi) * Math.sin(theta); camera.lookAt(scene.position); renderer.render(scene, camera); } 
  body { background-color: #000000; margin: 0px; overflow: hidden; } 
  <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/71/three.js"></script> <div id="container"></div> 

Thank you for your time.

With a Geometry instead of a BufferGeometry normals are per face ( face.vertexNormals ) and are an array of Vector3 . The uvs are an array of arrays of arrays of Vector2s.

someVector2 = geometry.faceVertexUvs[setNdx][faceNdx][vertexNdx]

 var camera, scene, renderer; var isUserInteracting = false, onMouseDownMouseX = 0, onMouseDownMouseY = 0, lon = 0, onMouseDownLon = 0, lat = 0, onMouseDownLat = 0, phi = 0, theta = 0, distance = 500; init(); animate(); function init() { var container, mesh; container = document.getElementById('container'); camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 2000); scene = new THREE.Scene(); var geometry = new THREE.SphereGeometry(500, 60, 40); // invert the geometry on the x-axis so that all of the faces point inward geometry.applyMatrix(new THREE.Matrix4().makeScale(-1, 1, 1)); // Remap UVs var uvs = geometry.faceVertexUvs[0]; geometry.faces.forEach((face, ndx) => { const faceUVs = uvs[ndx]; for (var i = 0; i < 3; ++i) { const faceNormal = face.vertexNormals[i]; var x = faceNormal.x; var y = faceNormal.y; var z = faceNormal.z; if (ndx < geometry.faces.length / 2) { var correction = (x == 0 && z == 0) ? 1 : (Math.acos(y) / Math.sqrt(x * x + z * z)) * (2 / Math.PI); faceUVs[i].x = x * (404 / 1920) * correction + (447 / 1920); faceUVs[i].y = z * (404 / 1080) * correction + (582 / 1080); } else { var correction = (x == 0 && z == 0) ? 1 : (Math.acos(- y) / Math.sqrt(x * x + z * z)) * (2 / Math.PI); faceUVs[i].x = - x * (404 / 1920) * correction + (1460 / 1920); faceUVs[i].y = z * (404 / 1080) * correction + (582 / 1080); } } }); geometry.applyMatrix(new THREE.Matrix4().makeRotationZ(Math.PI / 2)) THREE.ImageUtils.crossOrigin = ''; var texture = THREE.ImageUtils.loadTexture('https://threejs.org/examples/textures/ricoh_theta_s.jpg'); this.texture = texture; texture.format = THREE.RGBFormat; var material = new THREE.MeshBasicMaterial({ map: texture }); material.map.repeat.set(1, 1); material.map.offset.set(0, 0); mesh = new THREE.Mesh(geometry, material); scene.add(mesh); renderer = new THREE.WebGLRenderer(); renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(window.innerWidth, window.innerHeight); container.appendChild(renderer.domElement); document.addEventListener('mousedown', onDocumentMouseDown, false); document.addEventListener('mousemove', onDocumentMouseMove, false); document.addEventListener('mouseup', onDocumentMouseUp, false); document.addEventListener('wheel', onDocumentMouseWheel, false); window.addEventListener('resize', onWindowResize, false); } function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); } function onDocumentMouseDown(event) { event.preventDefault(); isUserInteracting = true; onPointerDownPointerX = event.clientX; onPointerDownPointerY = event.clientY; onPointerDownLon = lon; onPointerDownLat = lat; } function onDocumentMouseMove(event) { if (isUserInteracting === true) { lon = (onPointerDownPointerX - event.clientX) * 0.1 + onPointerDownLon; lat = (onPointerDownPointerY - event.clientY) * 0.1 + onPointerDownLat; } } function onDocumentMouseUp(event) { isUserInteracting = false; } function onDocumentMouseWheel(event) { distance += event.deltaY * 0.05; distance = THREE.Math.clamp(distance, 400, 1000); } function animate() { requestAnimationFrame(animate); update(); } function update() { if (isUserInteracting === false) { lon += 0.1; } lat = Math.max(- 85, Math.min(85, lat)); phi = THREE.Math.degToRad(90 - lat); theta = THREE.Math.degToRad(lon - 180); camera.position.x = distance * Math.sin(phi) * Math.cos(theta); camera.position.y = distance * Math.cos(phi); camera.position.z = distance * Math.sin(phi) * Math.sin(theta); camera.lookAt(scene.position); renderer.render(scene, camera); } 
 body { background-color: #000000; margin: 0px; overflow: hidden; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/71/three.js"></script> <div id="container"></div> 

Let me point out I figured this out by running the sample, then opening the devtools in Chrome, putting a breakpoint, and inspecting the variables.

Here's the uvs

在此处输入图片说明

And here's the vertex normals

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM