【问题标题】:How to load Texturepacker spritesheets in ThreeJS?如何在 ThreeJS 中加载 Texturepacker 精灵表?
【发布时间】:2019-12-17 00:08:37
【问题描述】:

我正在尝试从 ThreeJS 中的 Texturepacker 加载 spritesheets,其中包含图像和 json。图像有一堆小精灵打包在一起,json 定义了图像中小精灵的位置和大小。

我尝试了 3 种加载方法。

  • 对 json 和图像使用 ThreeJS 加载器,并分配具有不同重复和偏移值的新纹理。
  • 使用 WebGLRenderTarget 缓冲区将源图像裁剪为
  • 使用 Canvas 缓冲区将源图像裁剪为

使用具有不同偏移量的多个纹理实例的方法应该可以正常工作,因为我没有复制源图像,但是当我通过切换材质的纹理来运行动画时,它使用了大量的 RAM,就好像它正在复制整个源图像一样spritesheet 到内存中的每一个。如果我更改动画的纹理偏移而不是使用纹理副本,它可以正常工作,但偏移更改将应用​​到使用相同源 spritesheet 的每个对象。

WebGLRenderTarget 方法需要用于裁剪纹理的相机和场景以及添加到场景中的精灵。此输出无法使用,因为它不会生成原始纹理的 1:1 裁剪,而且加载速度非常慢。有没有办法在 ThreeJS 中将纹理 1:1 渲染到更小的缓冲区?

Canvas 方法在我为每个精灵创建一个画布元素并将 spritesheet 裁剪到每个元素时效果最佳。这是 1:1 并且质量很好,但使用 spritesheet 的要点是 GPU 只需要处理一个图像,这需要一个 HTML 加载器进程。理想情况下,我不想将 spritesheet 裁剪为更小的纹理缓冲区。

为什么使用具有多个 THREE.Texture 对象的同一个大型源图像会占用这么多内存?我预计它只需要在内存中保留一个纹理,Texture 对象只会显示具有不同偏移量的相同纹理。

【问题讨论】:

标签: three.js texturepacker


【解决方案1】:

我找到了一种可行的方法。

首先,我从通过 ThreeJS ImageLoader 加载的 spritesheet 图像生成 WebGLTexture 来加载纹理,该图像存储在 _spritesheets[textureID].texture 中。

let texture = this._spritesheets[textureID].texture;
let gl = this._renderer.getContext();
let webGLTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, webGLTexture);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

然后我将纹理对象的 webGL 纹理参数设置为 this 并将其 webglInit 值设置为 true,因此它不会创建新缓冲区。

let frames = textureJSON.frames;
for (let frameID of Object.keys(frames)) {
    let frame = frames[frameID];
    let t = new THREE.Texture(texture);

    let data = frame.frame;
    t.repeat.set(data.w / texture.width, data.h / texture.height);
    t.offset.x = data.x / texture.width;
    t.offset.y = 1 - data.h / texture.height - data.y / texture.height;

    let textureProperties = this._renderer.properties.get(t);
    textureProperties.__webglTexture = webGLTexture;
    textureProperties.__webglInit = true;

    this._textures[frameID] = {};
    this._textures[frameID].texture = t;
    this._textures[frameID].settings = { wrapS: 1, wrapT: 1, magFilter: THREE.LinearFilter, minFilter: THREE.NearestFilter };
}

spritesheet JSON 是通过 ThreeJS FileLoader 加载的。然后我按帧 id 将精灵存储在 _textures 对象中,并可以将它们分配给材质的贴图属性。

【讨论】:

  • 这太棒了!谢谢你。当我尝试为多个对象上绘制的纹理添加随机偏移时,我遇到了加载大量纹理的问题。我不希望每个纹理都从同一个位置开始,这非常适合消除这个问题。
  • 我最终使用了另一种方法,我发现它更易于使用。这是函数 Object3D.onBeforeRender 调用。如果您在绘制的每个具有不同纹理偏移的对象上运行此函数,则可以在每个对象渲染之前设置纹理偏移。您可以设置一个辅助函数,以便更轻松地分配偏移量并将偏移量存储在纹理 id 上。
猜你喜欢
  • 1970-01-01
  • 2012-08-16
  • 2012-06-06
  • 2016-02-03
  • 1970-01-01
  • 2016-11-25
  • 2013-10-18
  • 1970-01-01
  • 2023-03-21
相关资源
最近更新 更多