Render TMX Map on Threejs Plane

六月ゝ 毕业季﹏ 提交于 2019-12-03 17:12:38

Finally have a working solution, my biggest problem was packing my array of floats into a texture then later decoding. I had forgotten that when the bytes are loaded from the data texture they are "normalized". This means each values is divided by 255 to clamp it to [0, 1]. After shifting the bits I needed to multiply by 255.0 to denormalize.

I also read somewhere that webgl floats are 24-bit not 32-bit, so I changed my encode and decode algorithms to only use the RGB channels.

Now it successfully packs an array of ints (or floats) into a Uint8Array, passes that to webgl as a texture and uses it properly:

Array packing:

var array = [5438, 5436, 5437, 5438, 5436, 5437, ...],
    arrayBuff = new ArrayBuffer(array.length * 3),
    array8 = new Uint8Array(arrayBuff);

for(var i = 0, y = 0, il = array.length; i < il; ++i, y += 3) {
    var value = array[i];

    array8[y + 0] = (value & 0x000000ff);
    array8[y + 1] = (value & 0x0000ff00) >> 8;
    array8[y + 2] = (value & 0x00ff0000) >> 16;
}


dataTex = new THREE.DataTexture(
                            array8,
                            this.size.x, //width
                            this.size.y, //height
                            THREE.RGBFormat, //format
                            THREE.UnsignedByteType, //type
                            THREE.UVMapping, //mapping
                            THREE.ClampToEdgeWrapping, //wrapS
                            THREE.ClampToEdgeWrapping, //wrapT
                            THREE.NearestFilter, //magFilter
                            THREE.NearestMipMapNearestFilter //minFilter
                        );
dataTex.needsUpdate = true;

Shaders:

var vShader = [
    'varying vec2 pixelCoord;',
    'varying vec2 texCoord;',

    'uniform vec2 mapSize;',
    'uniform vec2 inverseLayerSize;',

    'uniform vec2 inverseTileSize;',

    'void main(void) {',
    '   pixelCoord = (uv * mapSize);',
    '   texCoord = pixelCoord * inverseLayerSize * inverseTileSize;',
    '   gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);', //hand this position to WebGL
    '}'
].join('\n');

var fShader = [
    'varying vec2 pixelCoord;',         
    'varying vec2 texCoord;',

    'uniform vec2 inverseTilesetSize;',

    'uniform vec2 tileSize;',
    'uniform vec2 numTiles;',

    'uniform sampler2D tileset;',
    'uniform sampler2D tileIds;',

    'float decode24(const in vec3 rgb) {',
    '   const vec3 bit_shift = vec3((256.0*256.0), 256.0, 1.0);',
    '   float fl = dot(rgb, bit_shift);', //shift the values appropriately
    '   return fl * 255.0;', //denormalize the value
    '}',

    'void main(void) {',
    '   vec3 tileId = texture2D(tileIds, texCoord).rgb;', //grab this tileId from the layer data
    '   tileId.rgb = tileId.bgr;', //flip flop due to endianess
    '   float tileValue = decode24(tileId);', //decode the normalized vec3 into the float ID
    '   vec2 tileLoc = vec2(mod(tileValue, numTiles.x) - 1.0, floor(tileValue / numTiles.x));', //convert the ID into x, y coords;
    '   tileLoc.y = numTiles.y - 1.0 - tileLoc.y;', //convert the coord from bottomleft to topleft

    '   vec2 offset = floor(tileLoc) * tileSize;', //offset in the tileset
    '   vec2 coord = mod(pixelCoord, tileSize);', //coord of the tile.

    '   gl_FragColor = texture2D(tileset, (offset + coord) * inverseTilesetSize);', //grab tile from tileset
    '}'
].join('\n');

Uniforms:

this._uniforms = window._uniforms = {
    mapSize:            { type: 'v2', value: new THREE.Vector2(this.size.x * this.tileSize.x, this.size.y * this.tileSize.y) },
    inverseLayerSize:   { type: 'v2', value: new THREE.Vector2(1 / this.size.x, 1 / this.size.y) },
    inverseTilesetSize: { type: 'v2', value: new THREE.Vector2(1 / this.tileset.image.width, 1 / this.tileset.image.height) },

    tileSize:           { type: 'v2', value: this.tileSize },
    inverseTileSize:    { type: 'v2', value: new THREE.Vector2(1 / this.tileSize.x, 1 / this.tileSize.y) },
    numTiles:           { type: 'v2', value: new THREE.Vector2(this.tileset.image.width / this.tileSize.x, this.tileset.image.height / this.tileSize.y) },

    tileset:            { type: 't', value: this.tileset },
    tileIds:            { type: 't', value: this.dataTex }
};
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!