Three.js и загрузка междоменного изображения
Я знаю, что это было задано раньше, и я прочитал все вопросы и ответы, которые мне удалось найти, но ничего не работает.
Я запускаю это на локальном сервере (IIS). Я пытаюсь загрузить изображение из imgur, а затем использовать его как текстуру для объекта с помощью кода:
var savedImage = /[^?]*$/.exec(location.search)[0];
if (savedImage != "") { savedImageLoad("http://i.imgur.com/" + savedImage + ".jpg"); };
function savedImageLoad(image) {
var mapOverlay = new THREE.ImageUtils.loadTexture(image);
sphere.material = new THREE.MeshBasicMaterial({map: mapOverlay, needsUpdate: true});;
sphere.geometry.buffersNeedUpdate = true;
sphere.geometry.uvsNeedUpdate = true;
}
Но это дает ошибку:
Uncaught SecurityError: Failed to execute 'texImage2D' on 'WebGLRenderingContext': The cross-origin image at http://i.imgur.com/uBD0g95.jpg may not be loaded.
Я попытался разместить THREE.ImageUtils.crossOrigin = "anonymous";
или некоторые изменения в начале моего кода в конце и в других разных точках. Я добавил web.config с
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="GET,PUT,POST,DELETE,OPTIONS" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
но это не сработало. Это также не работает на сайте, размещенном на bitbucket.org, который мне говорит, что в моем коде отсутствует что-то.
Кажется, что он не работает в строке sphere.material = new THREE.MeshBasicMaterial({map: mapOverlay, needsUpdate: true});;
, как если бы я прокомментировал это, тогда нет ошибки (но тогда сетка не обновляется).
Я действительно в недоумении, что еще попробовать здесь, и любая помощь будет оценена.
Ответы
Ответ 1
Обновить
В более новых версиях THREE.js изображения перекрестного происхождения обрабатываются по умолчанию. THREE.ImageUtils.loadTexture
устарела. Обычно используется TextureLoader
const loader = new THREE.TextureLoader();
const mapOverlay = loader.load('http://i.imgur.com/3tU4Vig.jpg');
Оригинальный ответ
Это работает
THREE.ImageUtils.crossOrigin = '';
var mapOverlay = THREE.ImageUtils.loadTexture('http://i.imgur.com/3tU4Vig.jpg');
Вот образец
var canvas = document.getElementById("c");
var renderer = new THREE.WebGLRenderer({canvas: canvas});
var camera = new THREE.PerspectiveCamera( 20, 1, 1, 10000 );
var scene = new THREE.Scene();
var sphereGeo = new THREE.SphereGeometry(40, 16, 8);
var light = new THREE.DirectionalLight(0xE0E0FF, 1);
light.position.set(200, 500, 200);
scene.add(light);
var light = new THREE.DirectionalLight(0xFFE0E0, 0.5);
light.position.set(-200, -500, -200);
scene.add(light);
camera.position.z = 300;
THREE.ImageUtils.crossOrigin = '';
var texture = THREE.ImageUtils.loadTexture('http://i.imgur.com/3tU4Vig.jpg');
var material = new THREE.MeshPhongMaterial({
map: texture,
specular: 0xFFFFFF,
shininess: 30,
shading: THREE.FlatShading,
});
var mesh = new THREE.Mesh(sphereGeo, material);
scene.add(mesh);
function resize() {
var width = canvas.clientWidth;
var height = canvas.clientHeight;
if (canvas.width != width ||
canvas.height != height) {
renderer.setSize(canvas.clientWidth, canvas.clientHeight, false); // don't update the style. Why does three.js fight CSS? It should respect CSS :(
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
}
function render(time) {
time *= 0.001; // seconds
resize();
mesh.rotation.y = time;
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
body {
margin: 0;
}
#c {
width: 100vw;
height: 100vh;
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/84/three.min.js"></script>
<canvas id="c"></canvas>
Ответ 2
UPDATE: устаревший метод
Я столкнулся с этой проблемой и применил решение из ответа, чтобы найти его не работающим из-за устаревшего метода в более новых версиях THREE.js. Я отправляю этот ответ, если у кого-то возникнет такая же проблема. Несмотря на устаревание, информация, предоставленная gman в оригинальном ответе, наиболее полезна, и я рекомендую прочитать ее.
THREE.ImageUtils.loadTexture()
метод стал устаревшим с оригинального вопроса и ответа.
Текущий способ загрузки текстуры:
// instantiate a loader
var loader = new THREE.TextureLoader();
//allow cross origin loading
loader.crossOrigin = '';
// load a resource
loader.load('textures/land_ocean_ice_cloud_2048.jpg',
// Function when resource is loaded
function ( texture ) {},
// Function called when download progresses
function ( xhr ) {},
// Function called when download errors
function ( xhr ) {}
);
Ответ 3
Я нашел решение для изображений и моделей JSON в соответствии с проблемой междоменного доступа.
Это всегда работает, также на Localhost.
В моем случае, я загружаю игру из NodeJS на порт 3001, чтобы работать с Socket.io.
Я хочу, чтобы 3d модели с порта 80.
Предположим, что все модели находятся в каталоге: game/dist/models/**/*
Я создал файловую игру PHP/dist/models/json.php:
<?php
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Allow-Methods: GET');
header('Access-Control-Allow-Origin: http://localhost:3001');
if (isset($_GET['file']))
{
switch($_GET['file'])
{
case 'house1':
header('Content-Type: application/json');
$file = 'houses/house1.json';
$json = json_decode(file_get_contents($file),TRUE);
echo json_encode($json, TRUE);
die();
break;
}
}
?>
ThreeJS:
var loader = new THREE.ObjectLoader();
loader.load(distPath+"models/json.php?file=house1",function ( obj ) {
scene.add( obj );
});
Удачи!
Ответ 4
Снимок экрана с ошибкой
VM266 three.min.js:127 THREE.WebGLState: DOMException: Failed to execute 'texImage2D' on 'WebGLRenderingContext': The image element contains cross-origin data, and may not be loaded.
at Object.texImage2D (https://unpkg.com/[email protected]/build/three.min.js:127:99)
at dg.r [as setTexture2D] (https://unpkg.com/[email protected]/build/three.min.js:103:189)
Просто столкнулся с той же проблемой во время работы над моей демонстрацией codepen: https://codepen.io/fritx/project/editor/AoLRoy
Решено путем обновления three.js с 0,86 до> = 0,87
- <script src="https://unpkg.com/[email protected]/build/three.min.js"></script>
+ <script src="https://unpkg.com/[email protected]/build/three.min.js"></script><!-- >=0.87 (img.crossorigin) -->
Ответ 5
Вы можете использовать переменную изображения там?
что-то вроде
var myImage = new Image();
myImage.src = "//i.imgur.com/ADBTaLw.jpg";
var mapOverlay = new THREE.ImageUtils.loadTexture(myImage.src);