如何在 ThreeJS 中加载Texturepacker spritesheets?

ade*_*art 5 three.js texturepacker

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

我尝试了3种加载方法。

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

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

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

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

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

ade*_*art 4

我找到了一种有效的方法。

首先,我通过从通过 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);
Run Code Online (Sandbox Code Playgroud)

然后我将纹理对象的 webGL 纹理参数设置为此,并将其 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 };
}
Run Code Online (Sandbox Code Playgroud)

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