Rendern Sie die TMX-Karte in der Threejs-Ebene

Frage mit neuem Code aktualisiert

Ich versuche, einen WebGL-Shader zu schreiben, der a zeichnetTMX-Schicht (Aus dem Kacheleditor exportiert). Ich benutze THREE.js, um einePlane mesh und habe das material aShaderMaterial Das wird die Karte darauf zeichnen.

Für diejenigen, die eine vom exportierte Tilemap nicht kennenGekachelte Editor als json gibts einedata Attribut für jede Schicht; Es enthält ein Array von numerischen Werten, von denen jeder der Kachelindex im Kachelsatz ist, wie folgt:

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

Da meine Kachelkarte 256 mal 256 Kacheln groß ist, hat das Array eine Länge von 65536 Elementen. Der Wert jedes Elements bezieht sich auf eine Kachel in der Kachelkarte, in der die Indizes wie folgt definiert sind:

Kachelsatz http://www.melonjs.org/docs/symbols/spritesheet_grid.png

Der Index 0 der Kachelkarte bezieht sich also auf die Kachel 5438, in der sie wie oben gezählt werden. Die Indizes geben an, welche Kachel in der Kachelkarte über diese Kachel aus dem Kachelsatz verfügt. Dort werden sie auf die gleiche Weise gezählt.

So erstelle ich das Material, die Ebene und das Netz:

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

Und schließlich die Uniformen und Shader. Grundsätzlich muss ich das Datenelement einer tatsächlichen Kachel im Kachelsatz zuordnen und zeichnen. Um das zu bekommendata Array in den Shader Ich lade es alsTHREE.DataTexture und es als Textur behandeln.

Hier ist mein zweiter Versuch:

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

Und die Uniformen und die Datenstruktur:

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

Wenn dies gerendert wird, wird nur die erste Kachel des Kachelsatzes wiederholt:

Nicht sicher, was es verursacht, aber da es an der Position ist0, 0 Ich glaube, ich habe irgendwo eine Null mit mir zu tun.

Antworten auf die Frage(1)

Ihre Antwort auf die Frage