Renderizar el mapa TMX en el plano Threejs

Pregunta actualizada con nuevo código

Estoy tratando de escribir un sombreador WebGL que dibujará unCapa TMX (exportado desde el editor Tiled). Estoy usando THREE.js para crear unPlane malla y que el material sea unShaderMaterial Eso dibujará el mapa en él.

Para aquellos que no conocen un tilemap exportado por elEditor de azulejos como json dará undata atributo para cada capa; contiene una matriz de valores numéricos, cada uno de los cuales es el índice de mosaico en el conjunto de mosaicos como:

"data": [5438, 5436, 5437, 5438, 5436, 5437, 5438, 5436, 5437, 5438, 845, ...]

Dado que mi tilemap es de 256 por 256 mosaicos, la matriz tiene 65536 elementos de longitud. El valor de cada elemento se refiere a un mosaico en el tilemap, donde los índices se definen como:

conjunto de baldosas http://www.melonjs.org/docs/symbols/spritesheet_grid.png

Así que el índice 0 del tilemap se refiere al mosaico 5438 donde se cuentan como arriba. Los índices representan qué mosaico en el tilemap tiene ese mosaico del conjunto de fichas, donde se cuentan de la misma manera.

Así es como estoy creando el material, el plano y la malla:

this.size = new THREE.Vector2(256, 256);
this.tileSize = new THREE.Vector2(16, 16);

this._material = new THREE.ShaderMaterial({
    uniforms: this._uniforms,
    vertexShader: this.vShader,
    fragmentShader: this.fShader,
    transparent: (this.opacity === 0)
});

this._plane = new THREE.PlaneGeometry(
    this.size.x * this.tileSize.x,
    this.size.y * this.tileSize.y
);

this._mesh = new THREE.Mesh(this._plane, this._material);

Y finalmente los uniformes, y los shaders. Básicamente, necesito asignar el elemento de datos a un mosaico real en el conjunto de mosaicos y dibujarlo. Para obtener eldata matriz en el shader lo estoy cargando como unaTHREE.DataTexture y tratándolo como una textura.

Aquí está mi segundo intento:

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

    'uniform vec2 layerSize;',
    'uniform vec2 tilesetSize;',
    'uniform vec2 inverseTilesetSize;',

    'uniform vec2 tileSize;',
    'uniform vec2 inverseTileSize;',
    'uniform float scale;',

    'void main(void) {',
    '   pixelCoord = (uv * layerSize) * tileSize * scale;', //pixel we are at
    '   texCoord = pixelCoord * inverseTilesetSize * inverseTileSize;', //calculate the coord on this map
    '   gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);',
    '}'
].join('\n');

var fShader = [
    //"precision highp float;",

    'varying vec2 pixelCoord;',         
    'varying vec2 texCoord;',

    'uniform vec2 tilesetSize;',
    'uniform vec2 inverseTilesetSize;',

    'uniform vec2 tileSize;',
    'uniform vec2 inverseTileSize;',
    'uniform vec2 numTiles;',
    'uniform float scale;',

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

    //I store the tile IDs as a texture (1 float value = rgba)
    //this will decode the rgba values back into a float ID
    'highp float decode32(highp vec4 rgba) {',
    '   const vec4 bit_shift = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0);',
    '   float depth = dot(rgba, bit_shift);',
    '   return depth;',
    '}',

    'void main(void) {',
    '   vec4 tileId = texture2D(tileIds, texCoord);', //grab this tileId from the layer data
    '   tileId.rgba = tileId.abgr;', //flip flop due to endianess
    //I find that this value is always `0 < tileValue < 1`, I think my `decode32` sucks...
    '   float tileValue = decode32(tileId);', //decode the vec4 into the float ID
    '   vec2 tileLoc = vec2(mod(tileValue, numTiles.y), floor(tileValue / numTiles.y));', //convert the ID into x, y coords
    '   vec2 coord = floor(tileLoc * 256.0) * tileSize;', //coord in the tileset
    '   vec2 offset = mod(pixelCoord, tileSize);', //how much to draw
    '   gl_FragColor = texture2D(tileset, (coord + offset) * inverseTilesetSize);', //grab tile from tilset
    '}'
].join('\n');

Y los uniformes, y la textura de los datos.

//tried making this 256 x 256 like it is conceptually,
//and also tried 65536 x 1 like the data structure
this.dataTex = new THREE.DataTexture(
                this.data,
                this.data.length, //width (65536)
                1, //height (1)
                THREE.RGBAFormat, //format
                THREE.UnsignedByteType, //type
                THREE.UVMapping, //mapping
                THREE.ClampToEdgeWrapping, //wrapS
                THREE.ClampToEdgeWrapping, //wrapT
                THREE.NearestFilter, //magFilter
                THREE.NearestMipMapNearestFilter //minFilter
            );
this.dataTex.needsUpdate = true;


this._uniforms = window._uniforms = {
    layerSize:          { type: 'v2', value: this.size },
    tilesetSize:        { type: 'v2', value: new THREE.Vector2(this.tileset.image.width, this.tileset.image.height) },
    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) },
    scale:              { type: 'f', value: 1 / this.scale },

    tileset:            { type: 't', value: this.tileset },
    tileIds:            { type: 't', value: this.dataTex },
    repeatTiles:        { type: 'i', value: this.repeat ? 1 : 0 }
};

Entonces, cuando esto se traduce, solo hago que se repita una y otra vez la primera pieza del conjunto de fichas:

No estoy seguro de qué lo está causando, pero ya que está en posición0, 0 Creo que tengo un cero jugando conmigo en alguna parte.

Respuestas a la pregunta(1)

Su respuesta a la pregunta