Three.js并加载跨域图像

时间:2014-06-06 17:44:00

标签: javascript three.js cross-domain

我知道以前曾经问过这个问题,而且我已经读过我能找到的问题和答案,但没有任何效果。

我在本地服务器(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});;行失败了,就好像我发表评论那样没有错误(但网格没有更新)。

我真的不知道在这里尝试什么,任何帮助都会受到赞赏。

4 个答案:

答案 0 :(得分:52)

更新

在较新版本的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');

这是一个样本

&#13;
&#13;
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);
&#13;
body {
    margin: 0;
}

#c {
    width: 100vw;
    height: 100vh;
    display: block;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/84/three.min.js"></script>
<canvas id="c"></canvas>
&#13;
&#13;
&#13;

注意:您不能将newTHREE.ImageUtils.loadTexture

一起使用

为了将图像跨源加载到WebGL中,发送图像的服务器必须使用正确的标头进行响应。仅仅说你想要使用图像交叉来源是不够的。所有这一切都告诉服务器您要求使用该图像的权限。

您可以将img.crossOrigin或三个案例THREE.ImageUtils.crossOrigin设置为与''相同的'anonymous''',或者您可以将其设置为'use-credentials',它会向服务器发送更多信息。浏览器会看到您设置crossOrigin并将某些标头发送到服务器。服务器读取这些标头,决定您的域是否有权使用该图像,如果您有权限,它会将某些标头发送回浏览器。如果浏览器看到这些标题,则可以使用该图像。

最重要的一点是服务器必须发送标题。大多数服务器都不会发送这些标头。 imgur.com显然。我怀疑bitlocker没有,但我没有测试它。

您还必须设置crossOrigin。如果您不是,浏览器不会允许您以您不应该使用的方式使用img,即使服务器发送了正确的标题。

答案 1 :(得分:25)

更新:不推荐的方法

我遇到了这个问题并从答案中应用了解决方案,因为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 ) {}
);

答案 2 :(得分:0)

我根据跨域问题找到了图像和JSON模型的解决方案。 这总是有效,也在Localhost上。

在我的情况下,我正在从端口3001的NodeJS加载游戏,以使用Socket.io。 我想要80端口的3D模型。

假设所有模型都在目录中: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 );
    });

玩得开心!

答案 3 :(得分:0)

A screencapture of the error

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/three@0.86.0/build/three.min.js:127:99)
    at dg.r [as setTexture2D] (https://unpkg.com/three@0.86.0/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/three@0.86.0/build/three.min.js"></script>
+ <script src="https://unpkg.com/three@0.87.0/build/three.min.js"></script><!-- >=0.87 (img.crossorigin) -->