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

一曲冷凌霜 提交于 2019-12-24 19:08:05

问题


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.


回答1:


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



来源:https://stackoverflow.com/questions/52626174/how-do-i-figure-out-the-uv-mapping-from-ricoh-theta-s-dual-fish-eye-to-a-three-j

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!