使用外部链接将纹理应用于 WebGL 中的 3D 模型

Applying texture to 3D-models in WebGL, using external links

我刚刚学习了如何使用 .mtl 文件(和 .obj 文件)在 WebGL 中将纹理应用到我的 3D 模型。当图像保存在我的电脑上时,应用纹理效果很好。这是我的 .mtl 文件的示例:

newmtl Earth_MATERIAL
Ns 96.078431
Ka 1.000000 1.000000 1.000000
Kd 0.640000 0.640000 0.640000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 1

map_Kd Earth.png

这个效果很好。但是我想发布我的模拟,因此我必须以某种方式引用图像。我的第一个想法是将图像上传到 DropBox 并使用它 link,但这没有用:

...
map_Kd https://dl.dropbox.com/s/t4cm3vzsbx21crc/Earth.png?dl=0

我在 运行 这段代码中得到的错误是:

Error: WebGL warning: texImage2D: Element is write-only, thus cannot be uploaded.

为了加载纹理和模型,我使用了 MTLloader 和 OBJloader。这是我正在使用的装载机:

MTLloader:link

OBJloader:link

我也用 ThreeJS 库:

三杰:link

编辑: 感谢 Jave 解决了问题!对于那些想看的人,这是结果:https://code.sololearn.com/WWY9cXN6OVBX/

MTLLoader 有一个名为 setTexturePath 的方法,您可以使用它来设置加载纹理的基本路径。由于您使用的是文件的外部来源 (保管箱),您可能还必须调用 setCrossOrigin(true)。我附上了一个使用这些方法加载纹理的注释示例。

您可能需要考虑的一些事项:

  • 通常你会把你的纹理放在与 mtl 文件或子目录,以便您可以直接引用它们(如 只是 Earth.pngtextures/Earth.png).
  • 如果您使用 mipmaps,则纹理尺寸必须为 例如,二的幂 (2048 x 1024)。你的形象不是,现在是 加载时自动调整大小。这样做会更有效率 事先手动调整大小。
  • 您的纹理是 5689 x 2844 像素。这对于纹理来说非常大 你应该减少它。一些移动设备甚至可能不 能够使用大于 2048 x 2048 的纹理。

const canvas = document.getElementById("canvas");
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(45, 1, 1, 10);
const renderer = new THREE.WebGLRenderer({ canvas });
const light = new THREE.AmbientLight();
scene.add(light);
camera.position.set(0, 0, 6);

const mesh = new THREE.Mesh(new THREE.SphereBufferGeometry( 1, 32, 32 ));
scene.add(mesh);


function update(){
  scene.rotation.y = 0.001 * performance.now();
  renderer.render(scene, camera);

  requestAnimationFrame(update);
}

update();

//This is just creating a data-url from the div containing the mtl-data, it is not really neccessary, but it will make the example more similiar to loading a file.
const data = document.getElementById("mtlplaceholder").textContent;
const dataurl = "data:text/plain;base64," + btoa(data);

const loader = new THREE.MTLLoader();

//To load texture files not in the same folder as the mtl-file, we need to call setTexurePath with the proper base path. Note that every texture will have to be available at this same base url, which might not be the case when shared from dropbox.
//The complete URL is  https://dl.dropbox.com/s/t4cm3vzsbx21crc/Earth.png
loader.setTexturePath("https://dl.dropbox.com/s/t4cm3vzsbx21crc/");
//To use cross-origin loading of textures, call setCrossOrigin(true):
loader.setCrossOrigin(true);
//Finally. load the mtl file (in this case the "file" is the dataurl created above):
loader.load(dataurl, res => {
  //MTLLoader.load creates a MTLLoader.MaterialCreator, to get the actual material we have to call create with the name of the material we want.
  //If you are using the OBJLoader, use preload instead and then objloader.setMaterials.
  const loadedMat = res.create("Earth_MATERIAL");
  //Finally, we set the material on the mesh.
  mesh.material = loadedMat;
}, e => console.log("error", e));
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/92/three.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/53838a2/examples/js/loaders/MTLLoader.js"></script>

<canvas id="canvas" width="400" height="400"></canvas>

<div id="mtlplaceholder" style:"white-space:pre">
newmtl Earth_MATERIAL
Ns 96.078431
Ka 1.000000 1.000000 1.000000
Kd 0.640000 0.640000 0.640000
Ks 0.000000 0.000000 0.000000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 1

map_Kd Earth.png
</div>