Я пытаюсь воспроизвести Пример использования 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>Спасибо за уделенное время.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Есть множество проблем с кодом
Код загрузки неправильный для r71. Должно получиться что-то вроде этого
THREE.ImageUtils.crossOrigin = '';
var texture = THREE.ImageUtils.loadTexture('https://preview.ibb.co/hZXYmz/ricoh_theta_s.jpg');
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 вверху
Это избавит от предупреждения, но продолжит
Код устанавливает повторение на 0
material.map.repeat = { x: 0, y: 0 };
material.map.offset = { x: 0, y: 0 };
Установка повтора на 0 означает, что вы увидите только первый пиксель текстуры, так как все UV будут умножены на 0.
Этот код неправильно устанавливает повтор и смещение.
Правильный способ установить повтор и смещение - с помощью set
material.map.repeat.set(1, 1);
material.map.offset.set(0, 0);
Это работает наоборот, но только по счастливой случайности. Две настройки: THREE.Vector2.
объекты. Код, использующий повторение и смещение, может в любой момент измениться на
используйте методы на THREE.Vector2 или передайте повторение и смещение функциям
которые ожидают THREE.Vector2, поэтому лучше не заменять их
обратите внимание, что нет никаких причин для их установки. 1 1 для повтора и 0 0 для смещения являются значениями по умолчанию.
Код отображается только один раз
requestAnimationFrame был закомментирован. Текстуры загружаются асинхронно
так что вы не увидите текстуры для нескольких кадров. Вам либо нужно подождать
чтобы текстура загружалась перед рендерингом, выполните рендеринг снова, как только он будет закончен
загрузка или рендеринг непрерывно, чтобы при загрузке он использовался
В коде используется кросс-доменное изображение
На самом деле это не ошибка, а просто предупреждение. WebGL не может использовать кросс-домен изображения, если сам сервер не дает разрешения. Тот, который ссылается на код чтобы дать это разрешение, но я не был уверен, знаете ли вы об этом или просто повезло. Большинство изображений с серверов чужие вряд ли сработают.
Математика кода неверна
Для этого вам следует задать другой вопрос. Комментируя это, я вижу текстуру
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-картированию: stackoverflow.com/questions/52626174/…
одно небольшое изменение для исправления предупреждения: P
Для тех, кто просто ищет ответ на предупреждение
RENDER WARNING: there is no texture bound to the unit 0
Он выдается Chrome, когда:
Источник и дальнейшие ссылки: https://github.com/NASAWorldWind/WebWorldWind/issues/302#issuecomment-346188472
Тогда исправление состоит в том, чтобы всегда связывать текстуру с семплерами шейдера, даже если шейдер не будет ее использовать.
Как предложил gman в своем более длинном ответе, привязка белой текстуры размером 1 пиксель, когда "текстуры нет", является хорошей практикой., потому что он не будет занимать много места или полосы пропускания, и код шейдера может использовать его для умножения на другой цвет, не изменяя его.
Спасибо за помощь, я оценил и решение, и объяснения, которые вы дали по ходу дела. Я опубликую новый вопрос, чтобы попросить помощи с частью UV-мэппинга.