ПРЕДУПРЕЖДЕНИЕ РЕНДЕРА: нет текстуры, привязанной к юниту 0

Я пытаюсь воспроизвести Пример использования three.js panaorama dualfisheye с помощью Three.js r71.

Мне нужно придерживаться r71, потому что в конечном итоге я буду использовать этот код в программе просмотра Autodesk Forge Viewer, основанной на Three.js r71.

Я добился некоторого прогресса, но в консоли 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>

Спасибо за уделенное время.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
0
1 922
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Есть множество проблем с кодом

  1. Код загрузки неправильный для r71. Должно получиться что-то вроде этого

    THREE.ImageUtils.crossOrigin = '';
    var texture = THREE.ImageUtils.loadTexture('https://preview.ibb.co/hZXYmz/ricoh_theta_s.jpg');
    
  2. IIRC THREE 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);
    

    Это работает наоборот, но только по счастливой случайности. Две настройки: THREE.Vector2. объекты. Код, использующий повторение и смещение, может в любой момент измениться на используйте методы на THREE.Vector2 или передайте повторение и смещение функциям которые ожидают THREE.Vector2, поэтому лучше не заменять их

    обратите внимание, что нет никаких причин для их установки. 1 1 для повтора и 0 0 для смещения являются значениями по умолчанию.

  3. Код отображается только один раз

    requestAnimationFrame был закомментирован. Текстуры загружаются асинхронно так что вы не увидите текстуры для нескольких кадров. Вам либо нужно подождать чтобы текстура загружалась перед рендерингом, выполните рендеринг снова, как только он будет закончен загрузка или рендеринг непрерывно, чтобы при загрузке он использовался

  4. В коде используется кросс-доменное изображение

    На самом деле это не ошибка, а просто предупреждение. WebGL не может использовать кросс-домен изображения, если сам сервер не дает разрешения. Тот, который ссылается на код чтобы дать это разрешение, но я не был уверен, знаете ли вы об этом или просто повезло. Большинство изображений с серверов чужие вряд ли сработают.

  5. Математика кода неверна

    Для этого вам следует задать другой вопрос. Комментируя это, я вижу текстуру

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>

Спасибо за помощь, я оценил и решение, и объяснения, которые вы дали по ходу дела. Я опубликую новый вопрос, чтобы попросить помощи с частью UV-мэппинга.

AlexisV 03.10.2018 12:52

Вот ссылка на следующий вопрос по UV-картированию: stackoverflow.com/questions/52626174/…

AlexisV 03.10.2018 13:36

одно небольшое изменение для исправления предупреждения: P

gman 03.10.2018 15:05

Для тех, кто просто ищет ответ на предупреждение RENDER WARNING: there is no texture bound to the unit 0

Он выдается Chrome, когда:

  1. Программа связанного шейдера ожидает текстуры.
  2. Никакая текстура не привязана.

Источник и дальнейшие ссылки: https://github.com/NASAWorldWind/WebWorldWind/issues/302#issuecomment-346188472

Тогда исправление состоит в том, чтобы всегда связывать текстуру с семплерами шейдера, даже если шейдер не будет ее использовать.

Как предложил gman в своем более длинном ответе, привязка белой текстуры размером 1 пиксель, когда "текстуры нет", является хорошей практикой., потому что он не будет занимать много места или полосы пропускания, и код шейдера может использовать его для умножения на другой цвет, не изменяя его.

Другие вопросы по теме