Three.js并加载跨域图像

Kur*_*urt 36 javascript cross-domain 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;
    }
Run Code Online (Sandbox Code Playgroud)

但它给出了错误:

Uncaught SecurityError: Failed to execute 'texImage2D' on 'WebGLRenderingContext': The cross-origin image at http://i.imgur.com/uBD0g95.jpg may not be loaded.
Run Code Online (Sandbox Code Playgroud)

我已尝试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>
Run Code Online (Sandbox Code Playgroud)

但那没用.这也不适用于bitbucket.org上托管的网站,我说我在代码中遗漏了一些东西.

这似乎是失败的sphere.material = new THREE.MeshBasicMaterial({map: mapOverlay, needsUpdate: true});;,就好像我评论那样没有错误(但是网格没有更新).

我真的不知道在这里尝试什么,任何帮助将不胜感激.

gma*_*man 53

更新

在较新版本的THREE.js中,默认处理交叉原始图像.THREE.ImageUtils.loadTexture已弃用.它很常见TextureLoader

const loader = new THREE.TextureLoader();
const mapOverlay = loader.load('http://i.imgur.com/3tU4Vig.jpg');
Run Code Online (Sandbox Code Playgroud)

原始答案

这有效

THREE.ImageUtils.crossOrigin = '';
var mapOverlay = THREE.ImageUtils.loadTexture('http://i.imgur.com/3tU4Vig.jpg');
Run Code Online (Sandbox Code Playgroud)

这是一个样本

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);
Run Code Online (Sandbox Code Playgroud)
body {
    margin: 0;
}

#c {
    width: 100vw;
    height: 100vh;
    display: block;
}
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/84/three.min.js"></script>
<canvas id="c"></canvas>
Run Code Online (Sandbox Code Playgroud)

注意:不要使用newTHREE.ImageUtils.loadTexture

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

您可以设置img.crossOrigin,或在三个的情况下THREE.ImageUtils.crossOrigin,要么'','anonymous'这是一样的'',也可以将其设置为'use-credentials'它发送到服务器甚至更多的信息.浏览器会看到您设置crossOrigin并向服务器发送某些标头.服务器读取这些标头,决定您的域是否有权使用该图像,如果您有权限,它会将某些标头发送回浏览器.浏览器,如果它看到这些标题将允许您使用该图像.

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

你也必须设置crossOrigin.如果你不这样做,浏览器将不允许你以你不应该的方式使用img,即使服务器发送了正确的标题.

  • 请注意,如果您控制之外的人(如第三方库)正在创建一个`new THREE.TextureLoader()`,您仍然可以使用`THREE.TextureLoader.prototype.crossOrigin =''设置其交叉原始策略; (6认同)
  • 这个答案对我们不起作用,下面的一个是使用`loader.crossOrigin ='';`的新实现. (3认同)

小智 25

更新:不推荐使用的方法

我遇到了这个问题并从答案中应用了解决方案,因为在THREE.js的新版本中已弃用的方法,因此找不到它.我发布这个答案,万一有人得到同样的问题.尽管弃用,gman在原始答案中提供的信息是最有帮助的,我建议阅读它.

THREE.ImageUtils.loadTexture()
Run Code Online (Sandbox Code Playgroud)

方法因原始问答而被弃用.

当前加载纹理的方法:

// 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 ) {}
);
Run Code Online (Sandbox Code Playgroud)

  • 谢谢!对于其他任何人来说,这是截至2016年6月的正确答案 (4认同)