Render TMX Map no plano Threejs

Pergunta atualizada com novo código

Eu estou tentando escrever um shader WebGL que vai desenhar umCamada TMX (exportado do editor Tiled). Eu estou usando THREE.js para criar umPlane malha e ter o material ser umShaderMaterial que desenhará o mapa nele.

Para quem não conhece um tilemap exportado peloEditor lado a lado como json vai dar umadata atributo para cada camada; Ele contém uma matriz de valores numéricos, cada um deles é o índice de blocos no tileset como:

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

Como o meu mapa é de 256 por 256 blocos, o array tem 65536 elementos de comprimento. O valor de cada elemento refere-se a um bloco no mapa, onde os índices são definidos como:

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

Então, o índice 0 do mapa de azulejos refere-se ao bloco 5438, onde eles são contados como acima. Os índices representam qual tile no tilemap tem aquele tile do tileset, onde eles são contados da mesma maneira.

Aqui está como eu estou criando o material, plano e malha:

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);

E finalmente os uniformes e shaders. Basicamente eu preciso mapear o elemento de dados para um bloco real no tileset e desenhá-lo. A fim de obter odata matriz para o shader estou carregando-o como umTHREE.DataTexture e tratá-lo como uma textura.

Aqui está a minha segunda tentativa:

//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');

E os uniformes e a textura dos dados:

//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 }
};

Então, quando isso renderiza, eu apenas obtenho o primeiro bloco do tileset repetido várias vezes:

Não tenho certeza do que está causando isso, mas já que está na posição0, 0 Eu acho que tenho um zero mexendo comigo em algum lugar.

questionAnswers(1)

yourAnswerToTheQuestion