首页 > 解决方案 > 渲染警告:没有纹理绑定到单元 0

问题描述

我正在尝试使用 Three.js r71 重现three.js panaorama dualfisheye 示例

我需要坚持使用 r71,因为最终我将在基于 Three.js r71 的 autodesk forge 查看器上使用此代码。

我取得了一些进展,但我在浏览器 javascript 控制台中遇到错误消息:RENDER WARNING: there is no texture bound to the unit 0

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.applyMatrix(new THREE.Matrix4().makeRotationZ(-Math.PI / 2))
  // geometry.rotateZ( - Math.PI / 2 );

  //

  // var texture = new THREE.TextureLoader().load( 'ricoh_theta_s.jpg' );
  var texture = new THREE.TextureLoader('https://preview.ibb.co/hZXYmz/ricoh_theta_s.jpg');
  this.texture = texture;
  texture.format = THREE.RGBFormat;

  var material = new THREE.MeshBasicMaterial({ map: texture });
  material.map.repeat = { x: 0, y: 0 }
  material.map.offset = { x: 0, y: 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>

感谢您的时间。

标签: javascriptthree.js

解决方案


代码有很多问题

  1. r71 的加载代码错误。它应该是这样的

    THREE.ImageUtils.crossOrigin = '';
    var texture = THREE.ImageUtils.loadTexture('https://preview.ibb.co/hZXYmz/ricoh_theta_s.jpg');
    
  2. IIRC 三 r71 没有使用可渲染的东西预先初始化纹理,因此您需要等待纹理加载

    var texture = THREE.ImageUtils.loadTexture(
       'https://preview.ibb.co/hZXYmz/ricoh_theta_s.jpg', 
        undefined,
        animate);  // call animate after texture has loaded
    

    animate并删除了顶部的调用

这将摆脱警告,但继续

  1. 代码将重复设置为 0

    material.map.repeat = { x: 0, y: 0 };
    material.map.offset = { x: 0, y: 0 };
    

    将重复设置为 0 意味着您只会看到纹理的第一个像素,因为所有 UV 都将乘以 0

  2. 它的代码错误地设置了重复和偏移量。

    设置重复和偏移的正确方法是使用 set

    material.map.repeat.set(1, 1);
    material.map.offset.set(0, 0);
    

    它以另一种方式工作,但只能靠运气。2个设置是THREE.Vector2 对象。使用 repeat 和 offset 的代码可以随时更改以使用方法THREE.Vector2或将 repeat 和 offset 传递给期望 a 的函数,THREE.Vector2因此最好不要替换它们

    请注意,没有理由设置它们。1 1 表示重复,0 0 表示偏移量是默认值。

  3. 代码只渲染一次

    requestAnimationFrame被注释掉了。纹理是异步加载的,因此您将看不到几帧的纹理。您要么需要在渲染之前等待纹理加载,完成加载后再次渲染,要么连续渲染,以便在加载时使用它

  4. 该代码正在使用跨域图像

    这实际上不是一个错误,只是一个警告。WebGL 不能使用跨域图像,除非服务器本身给予许可。代码链接的那个确实授予了该权限,但我不确定您是否知道这一点,或者只是幸运。来自非您自己的服务器的大多数图像不太可能正常工作。

  5. 代码的 uv 数学是错误的

    你应该为此问另一个问题。评论出来我可以看到纹理

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();

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.applyMatrix(new THREE.Matrix4().makeRotationZ(-Math.PI / 2))
  // geometry.rotateZ( - Math.PI / 2 );

  //

  THREE.ImageUtils.crossOrigin = '';
  var texture = THREE.ImageUtils.loadTexture('https://preview.ibb.co/hZXYmz/ricoh_theta_s.jpg', undefined, animate);

  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>


推荐阅读