Three.js和加载跨域图片

IT技术 javascript three.js cross-domain
2021-03-11 23:26:48

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

我在本地服务器 (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个回答

更新

在 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');

这是一个示例

注意:你不使用newwithTHREE.ImageUtils.loadTexture

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

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

从上面带走的最重要的一点是服务器必须发送标头。大多数服务器不发送这些标头。imgur.com 显然确实如此。我怀疑 bitlocker 没有,尽管我没有测试过它。

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

好的!和@Braffin 做同样的事情。谢谢 :)
2021-04-24 23:26:48
似乎我的问题有两个方面。我在 loadTexture() 方法中使用了不正确的变量,但我也在使用new上述方法。删除new似乎已经完成了这项工作。谢谢!
2021-04-26 23:26:48
这个答案对我们不起作用,下面是使用loader.crossOrigin = '';和工作的较新实现
2021-05-05 23:26:48
请注意,如果您无法控制的人(例如第三方库)正在制作new THREE.TextureLoader(),您仍然可以使用THREE.TextureLoader.prototype.crossOrigin = '';
2021-05-15 23:26:48
@gman - 你能详细说明你关于设置 crossOrigin 的最后一句话吗?我遇到了类似的错误,在按照您(和 Michal 的)修复之后,我现在得到了标准的Origin is therefor not allowed access error. 我应该如何正确设置标题?js谢谢
2021-05-19 23:26:48

更新:不推荐使用的方法

我遇到了这个问题,并从答案中应用了解决方案,发现由于 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 ) {}
);
谢谢!这同样适用于其他加载器,例如MTLLoader在此示例中:github.com/mrdoob/three.js/blob/master/examples/...
2021-04-26 23:26:48
太可悲了,旧的给了你一个纹理对象,这样你就可以立即使用它。新的在完成之前不会为您提供纹理对象,这意味着正确使用要困难得多。
2021-05-03 23:26:48
谢谢!对其他人来说,这是截至 2016 年 6 月的正确答案
2021-05-07 23:26:48

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

就我而言,我从 NodeJS 的 3001 端口加载游戏,以使用 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 );
    });

玩得开心!

错误的屏幕截图

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