Визуализация карты TMX на плоскости Threejs

Вопрос обновлен новым кодом

Я пытаюсь написать шейдер WebGL, который будет рисоватьTMX Layer (экспортировано из Tiled-редактора). Я использую THREE.js для созданияPlane сетка и материал должен бытьShaderMaterial это нарисует карту на нем.

Для тех, кто не знает карту тайла, экспортируемуюПлиточный редактор как JSON дастdata атрибут для каждого слоя; он содержит массив числовых значений, каждое из которых является индексом плитки в наборе плиток, например:

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

Поскольку моя мозаичная карта имеет размер 256 на 256 плиток, длина массива составляет 65536 элементов. Значение каждого элемента относится к листу в карте листов, где индексы определены следующим образом:

набор плиток http://www.melonjs.org/docs/symbols/spritesheet_grid.png

Таким образом, индекс 0 карты тайлов относится к тайлу 5438, где они подсчитываются, как указано выше. Индексы представляют, какая плитка в карте тайлов имеет эту плитку из набора тайлов, где они подсчитываются одинаковым образом.

Вот как я создаю материал, плоскость и сетку:

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

И, наконец, униформа и шейдеры. По сути, мне нужно отобразить элемент данных на фактическую плитку в наборе плиток и нарисовать его. Для того, чтобы получитьdata массив в шейдер я загружаю его какTHREE.DataTexture и рассматривая это как текстуру.

Вот моя вторая попытка:

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

И униформа, и текстура данных:

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

Поэтому, когда это рендерится, я просто получаю первый тайл набора тайлов снова и снова:

Не уверен, что это вызывает, но так как он находится в положении0, 0 Я думаю, что у меня где-то есть ноль.

Ответы на вопрос(1)

Ваш ответ на вопрос