【问题标题】:Three.js and loading a cross-domain image三.js并加载跨域图片
【发布时间】:2014-07-28 01:46:09
【问题描述】:

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

我在本地服务器 (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});; 行似乎失败了,好像我将其注释掉然后没有错误(但随后网格未更新)。

我真的不知道还能在这里尝试什么,如果能提供任何帮助,我们将不胜感激。

【问题讨论】:

    标签: javascript three.js cross-domain


    【解决方案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>

    注意:不要将newTHREE.ImageUtils.loadTexture 一起使用

    为了将图像跨域加载到 WebGL 中,发送图像的服务器必须使用正确的标头进行响应。你说要使用镜像跨域是不够的。所做的只是告诉服务器您正在请求使用图像的权限。

    您可以将img.crossOrigin 或在三种情况下为THREE.ImageUtils.crossOrigin 设置为'''anonymous',这与'' 相同,或者您可以将其设置为'use-credentials',以发送更多信息到服务器。浏览器看到您设置了crossOrigin 并将某些标头发送到服务器。服务器读取这些标头,确定您的域是否有权使用图像,如果您有权限,它会将某些标头发送回浏览器。浏览器,如果它看到这些标题,就会让你使用图像。

    从上述内容中最大的一点是 服务器 必须发送标头。大多数服务器不发送这些标头。 imgur.com 显然做到了。我怀疑bitlocker没有,虽然我没有测试过。

    您还必须设置crossOrigin。如果您不这样做,浏览器将不允许您以您不应该能够使用的方式使用 img,即使服务器发送了正确的标头。

    【讨论】:

    • 看来我的问题是双重的。我在 loadTexture() 方法中使用了不正确的变量,但我也在上述方法中使用了new。删除 new 似乎已经完成了这项工作。谢谢!
    • 不错!正在做与@Braffin 相同的事情。谢谢:)
    • 请注意,如果您无法控制的人(例如第三方库)正在创建new THREE.TextureLoader(),您仍然可以使用THREE.TextureLoader.prototype.crossOrigin = ''; 设置他们的跨源策略
    • 这个答案对我们不起作用,下面的一个是使用 loader.crossOrigin = ''; 的较新实现并且有效。
    • @gman - 您能否详细说明您关于设置 crossOrigin 的最后一句话?我遇到了类似的错误,在按照您(和 Michal 的)修复后,我现在得到了标准 Origin is therefor not allowed access error。我应该如何正确设置标题?在js?谢谢
    【解决方案2】:

    更新:不推荐使用的方法

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

    【讨论】:

    • 谢谢!对其他人来说,这是截至 2016 年 6 月的正确答案
    • 太可惜了,旧的给了你一个纹理对象,所以你可以立即使用它。新的在完成之前不会给你一个纹理对象,这意味着它更难正确使用。
    • 谢谢!这同样适用于其他加载程序,例如本例中的MTLLoadergithub.com/mrdoob/three.js/blob/master/examples/…
    【解决方案3】:

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

    在我的例子中,我在端口 3001 从 NodeJS 加载游戏,以使用 Socket.io。 我想要 80 端口的 3d 模型。

    假设所有模型都在目录:game/dist/models/**/*

    我创建了一个 PHP 文件 game/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;
        }
    }
    ?>
    

    三个JS:

    var loader = new THREE.ObjectLoader();  
        loader.load(distPath+"models/json.php?file=house1",function ( obj ) {
             scene.add( obj );
        });
    

    玩得开心!

    【讨论】:

      【解决方案4】:

      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) -->
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-04-14
        • 1970-01-01
        • 2019-04-06
        • 2016-04-20
        • 2012-11-20
        • 1970-01-01
        • 1970-01-01
        • 2018-04-08
        相关资源
        最近更新 更多