【问题标题】:Load Collada/image data stored in a multipart file into three.js将存储在多部分文件中的 Collada/图像数据加载到 three.js 中
【发布时间】:2021-01-21 09:47:40
【问题描述】:

我将 Collada 和相关图像数据存储在从应用程序输出的多部分文件中。我需要能够通过 three.js 加载 Collada 对象和图像以在 Web 中显示。 three.js 可以解释多部分文件或文件中的数据,还是需要将其解析为实际文件,因为 Collada 加载程序示例显示它链接到 .dae 文件(例如 loader.load('models/ monster.dae') 而不是实际数据。

无论如何,我将如何实现这一目标?最终目标是加载并查看文件中多部分数据所代表的“盒子”。

这是我从应用程序收到的多部分文件的示例结构:

MIME-Version:1.0
Content-Type:multipart/mixed; 
boundary="----=_Part_4_153315749.1440434094461"

------=_Part_4_153315749.1440434094461
Content-Type: application/octet-stream; name=Texture_1.png
Content-ID: response-1
Content-Disposition: attachment; filename=Texture_1.png

‰PNG
"blob data here"

------=_Part_4_153315749.1440434094461
Content-Type: application/octet-stream; name=manifest.xml
Content-ID: response-2
Content-Disposition: attachment; filename=manifest.xml

<?xml version="1.0"?>
<dae_root>blank_3D.dae</dae_root>

------=_Part_4_153315749.1440434094461
Content-Type: application/octet-stream; name=texture_3D.dae
Content-ID: response-3
Content-Disposition: attachment; filename=texture_3D.dae

<xml data here... lots of xml data>

------=_Part_4_153315749.1440434094461
Content-Type: application/octet-stream; name=Texture_0.png
Content-ID: response-4
Content-Disposition: attachment; filename=Texture_0.png

‰PNG
"blob image data"

更新:

通过让供应商拆分文件,我可以将 collada 文件直接加载到查看器中......但我不知道如何将图像连同它一起加载到内存中或以其他方式加载。关于如何包含属于 collada 文件的图像/纹理的任何想法?这是我当前的加载代码:

    // instantiate a loader
    var loader = new THREE.ColladaLoader();
    loader.options.convertUpAxis = true;
    loader.load('http://applicationvendorapi.com/dae', function (collada) {

        box = collada.scene;

        box.traverse(function (child) {

            if (child instanceof THREE.SkinnedMesh) {

                var animation = new THREE.Animation(child, child.geometry.animation);
                animation.play();

            }
        });

        box.scale.x = box.scale.y = box.scale.z = .2;
        box.updateMatrix();

        init();
        animate();
    });

纹理的位置往往与 Collada 文件位于同一目录中。这是 Collada 的 XML。问题是我可以通过 Web 服务(例如 /endpoint/texture_0 和 /endpoint/texture_1 )拉入其他图像来引用这些图像

<library_images>
<image id="Texture_0_png">
  <init_from>./Texture_0.png</init_from>
</image>
<image id="Texture_1_png">
  <init_from>./Texture_1.png</init_from>
</image>

更新 2:

使用@gaitat 的建议,我尝试首先通过 ImageUtils 加载纹理。但是,它永远不会调用纹理的 URL/加载纹理。但是,它仍然会调用对象。这是包装在纹理调用中的当前对象:

// Load texture before loading and initializing 3D object
    var texture0 = THREE.ImageUtils.loadTexture('http://vendorwebservice/texture_0', {}, function loaded() {
        // Instantiate a Collada loader
        var loader = new THREE.ColladaLoader();
        loader.options.convertUpAxis = true;
        loader.load('http://vendorwebservice/dae', function (collada) {

            box = collada.scene;

            box.traverse(function (child) {

                if (child instanceof THREE.SkinnedMesh) {

                    var animation = new THREE.Animation(child, child.geometry.animation);
                    animation.play();

                }
            });

            box.scale.x = box.scale.y = box.scale.z = .2;
            box.updateMatrix();

            init();
            animate();
        });

    });

这就是有趣的地方。由于我拉入的 DAE 文件具有对其纹理的以下 xml 引用,它实际上也尝试“获取”这些,但不存在具有 .png 扩展名的端点,因此它失败(例如http://vendorwebservice/texture_0.png):

<library_images>
<image id="Texture_0_png">
  <init_from>./Texture_0.png</init_from>
</image>
<image id="Texture_1_png">
  <init_from>./Texture_1.png</init_from>
</image>

【问题讨论】:

标签: javascript three.js


【解决方案1】:

由于您的应用程序是一个网络服务,其中数据没有静态 URI,您需要下载服务在本地返回的数据。只要 Collada 文件引用的纹理文件位于相对路径(到 .dae)中,THREE.ColladaLoader() 就能够找到它们、加载它们并显示它们。

【讨论】:

    【解决方案2】:

    我知道为时已晚,但我希望我的回答对未来的读者有所帮助。

    我遇到了类似的情况,静态 URI 没有引用文件。我不想下载这些文件,因为我担心通过网络传输的数据效率低下并占用服务器资源。所以我决定通过这个过程在浏览器上手动处理它:

    1. 读取 collada 的纹理所引用的图像文件的名称
    2. 使用您在步骤 1 中找到的名称查找图像文件
    3. 使用您在第 2 步中找到的文件生成 Threejs 纹理
    4. 将您在第 3 步中制作的纹理连接到 collada 材质中的纹理槽

    这是一个示例代码。就我而言,代码中的 URL 是数据 URL

    const loadCollada = async (dae, img) => {
      const collada = new ColladaLoader().load(dae.url);
    
      // Get all materials in the loaded collada
      const materials = new Set();
      collada.traverse((object) => {
        const mat = object.material
        if (mat) {
          if (mat.constructor.name === "Array") {
            mat.forEach((e) => {
              materials.add(e);  
            })
          } else {
            materials.add(mat);
          }
        }
      });
    
      // Parse collada file
      const daeText = await fetch(dae.url).then((r) => r.text())
      const daeXml = new DOMParser().parseFromString(daeText,"text/xml")
      const materialLibrary = daeXml.getElementsByTagName("material")
    
      // Get material name and texture name(image file name)
      Array.from(materialLibrary).forEach((e) => {
        const materialName = e.getAttribute("name")
        const effect = e.getElementsByTagName("instance_effect")[0]
        const textureUrl = effect.attributes.url.value.slice(1)
        const textureTag = daeXml.getElementById(textureUrl)
        const textureName = textureTag.getElementsByTagName("init_from")[0]?.innerHTML
    
        // Find the material that matches name
        if (textureName) {
          Array.from(materials).forEach((mat) => {
            if (mat.name === materialName) {
              // Generate a texture and override it to the material we found
              const texture = new THREE.TextureLoader().load(img[textureName].url)
              texture.wrapS = THREE.RepeatWrapping
              texture.wrapT = THREE.RepeatWrapping
              mat.map = texture
            }
          });
        }
      })
    }
    

    【讨论】:

      猜你喜欢
      • 2013-05-08
      • 2016-03-26
      • 2013-02-04
      • 2015-11-13
      • 1970-01-01
      • 2015-11-06
      • 2017-02-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多