3

このコードの多くは、以下の編集3の時点で変更されていることに注意してください。

だから私はブランドンジョーンズ(ここにあります)によるブログ投稿が本当に好きです。彼のコードをThree.jsに変換したかったのですが、いくつか問題があります。彼の完全なコードはここにあります。これが私のこれまでの試みであり、私が持っている質問に対するいくつかのコメントがあります。

// Shader
var tilemapVS = [
    "attribute vec2 pos;",
    "attribute vec2 texture;",

    "varying vec2 pixelCoord;",
    "varying vec2 texCoord;",

    "uniform vec2 viewOffset;",
    "uniform vec2 viewportSize;",
    "uniform vec2 inverseTileTextureSize;",
    "uniform float inverseTileSize;",

    "void main(void) {",
    "   pixelCoord = (texture * viewportSize) + viewOffset;",
    "   texCoord = pixelCoord * inverseTileTextureSize * inverseTileSize;",
    "   gl_Position = vec4(pos, 0.0, 1.0);",
    "}"
].join("\n");

var tilemapFS = [
    "precision highp float;",

    "varying vec2 pixelCoord;",
    "varying vec2 texCoord;",

    "uniform sampler2D tiles;",
    "uniform sampler2D sprites;",

    "uniform vec2 inverseTileTextureSize;",
    "uniform vec2 inverseSpriteTextureSize;",
    "uniform float tileSize;",
    "uniform int repeatTiles;",

    "void main(void) {",
    "   if(repeatTiles == 0 && (texCoord.x < 0.0 || texCoord.x > 1.0 || texCoord.y < 0.0 || texCoord.y > 1.0)) { discard; }",
    "   vec4 tile = texture2D(tiles, texCoord);",
    "   if(tile.x == 1.0 && tile.y == 1.0) { discard; }",
    "   vec2 spriteOffset = floor(tile.xy * 256.0) * tileSize;",
    "   vec2 spriteCoord = mod(pixelCoord, tileSize);",
    "   gl_FragColor = texture2D(sprites, (spriteOffset + spriteCoord) * inverseSpriteTextureSize);",
    //"   gl_FragColor = tile;",
    "}"
].join("\n");

this.material = new THREE.ShaderMaterial({
    attributes: {
        //not really sure what to use here, he uses some quadVertBuffer
        //for these values, but not sure how to translate.
        pos: { type: 'v2', value: new THREE.Vector2(0, 0) },
        texture: { type: 'v2', value: new THREE.Vector2(0, 0) }
    },
    uniforms: {
        viewportSize: { type: 'v2', value: new THREE.Vector2(viewport.width() / this.tileScale, viewport.height() / this.tileScale) },
        inverseSpriteTextureSize: { type: 'v2', value: new THREE.Vector2(1/tileset.image.width, 1/tileset.image.height) },
        tileSize: { type: 'f', value: this.tileSize },
        inverseTileSize: { type: 'f', value: 1/this.tileSize },

        tiles: { type: 't', value: tilemap },
        sprites: { type: 't', value: tileset },

        viewOffset: { type: 'v2', value: new THREE.Vector2(Math.floor(0), Math.floor(0)) },
        inverseTileTextureSize: { type: 'v2', value: new THREE.Vector2(1/tilemap.image.width, 1/tilemap.image.height) },
        //is 'i' the correct type for an int?
        repeatTiles: { type: 'i', value: 1 }
    },
    vertexShader: tilemapVS,
    fragmentShader: tilemapFS,
    transparent: false
});

/*this.material = new THREE.MeshBasicMaterial({
    color: 0xCC0000
})*/

this.plane = new THREE.PlaneGeometry(
    tilemap.image.width * this.tileSize * this.tileScale, //width
    tilemap.image.height * this.tileSize * this.tileScale//, //height
    //tilemap.image.width * this.tileScale, //width-segments
    //tilemap.image.height * this.tileScale //height-segments
);

this.plane.dynamic = true;

this.mesh = new THREE.Mesh(this.plane, this.material);

ページをロードすると、次のエラーが発生します。

TypeError: v1 is undefined
    customAttribute.array[ offset_custom ] = v1.x;

これは私が属性を設定する方法と関係があると確信していますが、それらがどうあるべきかわかりません。Three.jsのカスタムシェーダーに関するドキュメントはほとんどまたはまったくないため、助けていただければ幸いです。

編集:これは、頂点シェーダーの2つの属性(、、posおよびtexture)を埋めるためにブログ投稿で使用されるコードです。

//in ctor
var quadVerts = [
    //x  y  u  v
    -1, -1, 0, 1,
     1, -1, 1, 1,
     1,  1, 1, 0,

    -1, -1, 0, 1,
     1,  1, 1, 0,
    -1,  1, 0, 0
];

this.quadVertBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, this.quadVertBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(quadVerts), gl.STATIC_DRAW);

this.tilemapShader = GLUtil.createProgram(gl, tilemapVS, tilemapFS);

//...

//then on the draw method
gl.bindBuffer(gl.ARRAY_BUFFER, this.quadVertBuffer);

gl.enableVertexAttribArray(shader.attribute.position);
gl.enableVertexAttribArray(shader.attribute.texture);
gl.vertexAttribPointer(shader.attribute.position, 2, gl.FLOAT, false, 16, 0);
gl.vertexAttribPointer(shader.attribute.texture, 2, gl.FLOAT, false, 16, 8);

ここで何が起こっているのかを完全には理解していませんが、正しければ、それぞれFloat32Arrayのデータの半分で2秒を埋めていると思いますquadVertBuffer。理由がわからないだけでなく、自分が正しいかどうかもわかりません。また、これをThree.jsメソッドに変換する方法もわかりません。


EDIT2:現在、平面を使用して(2D)背景を表示していますが、代わりにスプライトを使用する必要がありますか?


EDIT3

そのため、Three.jsが位置とuvベクトルを設定することに気付いたとき、私は少し遠くに行きました(これは、上記の例の位置/テクスチャと同じではないにしても類似しているようです)。'v2'また、私が持っていたタイプの多く(を呼び出すuniform2f)が実際にを介してロードされていたため、いくつかのタイプが間違っている可能性があることに気付きました。uniform2fvそこで、それらをに変更し'v2v'て値を更新しました。今、私はエラーを受け取りません、そしてそれは何かをペイントします、ただタイルマップではありません。

更新されたVertexShaderは次のとおりです。

var tilemapVS = [
    "varying vec2 pixelCoord;",
    "varying vec2 texCoord;",

    "uniform vec2 viewOffset;",
    "uniform vec2 viewportSize;",
    "uniform vec2 inverseTileTextureSize;",
    "uniform float inverseTileSize;",

    "void main(void) {",
    "   pixelCoord = (uv * viewportSize) + viewOffset;",
    "   texCoord = pixelCoord * inverseTileTextureSize * inverseTileSize;",
    "   gl_Position = vec4(position.x, position.y, 0.0, 1.0);",
    "}"
].join("\n");

および更新されたシェーダーマテリアル:

this._material = new THREE.ShaderMaterial({
    uniforms: {
        viewportSize: { type: 'v2v', value: [new THREE.Vector2(viewport.width() / this.tileScale, viewport.height() / this.tileScale)] },
        inverseSpriteTextureSize: { type: 'v2v', value: [new THREE.Vector2(1/tileset.image.width, 1/tileset.image.height)] },
        tileSize: { type: 'f', value: this.tileSize },
        inverseTileSize: { type: 'f', value: 1/this.tileSize },

        tiles: { type: 't', value: tilemap },
        sprites: { type: 't', value: tileset },

        viewOffset: { type: 'v2', value: new THREE.Vector2(0, 0) },
        inverseTileTextureSize: { type: 'v2v', value: [new THREE.Vector2(1/tilemap.image.width, 1/tilemap.image.height)] },
        repeatTiles: { type: 'i', value: 1 }
    },
    vertexShader: tilemapVS,
    fragmentShader: tilemapFS,
    transparent: false
});

そして、これが私が得た結果です:

ここに画像の説明を入力してください

どんなアイデアでも大歓迎です!


編集4

設定の「Three.jsメソッド」であることがわかったものを使用するようにVertexシェーダーを変更すると、gl_Positionさらに近づくことができますが、スプライトシートのオフセットが間違っています。pixelCoord変化は間違って設定されていると思います(私が思うuvよりもわずかに異なる値を持っているためtexture)。

VertexShaderのメイン関数を次のように変更しました。

void main(void) {
   pixelCoord = (uv * viewportSize) + viewOffset;
   texCoord = pixelCoord * inverseTileTextureSize * inverseTileSize;
   gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}

そして今、私は実際のタイルをテクスチャシートから取得しますが、それが選択する実際のタイルは間違っています:

ここに画像の説明を入力してください

近づいても、どんな助けでもありがたいです。


編集5

答えが近づいているので、これが私の最後の更新になると思います。設定後tileset.flipY = false;、tilesetは実際のテクスチャタイルであり、赤いマップではありません。私はすべての適切なタイルを適切な場所に着陸させます。それらがすべて逆さまであることを除いて!

この変更後の外観は次のとおりです。

ここに画像の説明を入力してください

(タイルセット画像を編集せずに)個々のテクスチャをY軸上で反転させる方法はありますか?シェーダーに追加して、描画する各テクスチャを反転し、これを完成させることができる簡単なベクトル計算があるように感じます。

tilemap.flipY = false;(と)の両方を反転しないとtileset.flipY = false;、適切なテクスチャ、適切なスポットが得られ、正しくフィットすることに注意してください。しかし、マップ全体が逆さまになっています!とても近い...

ここに画像の説明を入力してください

4

1 に答える 1

1

私はそれを「修正された」とは考えていませんが、なんとかこの「動作」を得ることができました。

tilemap.flipY = trueタイルマップ( )を反転し、タイルセット( )を反転してから、スプライトシート(タイルセット)に各タイルを上下逆に描画するように(Tojiが書いたこれらのタイルマップを作成する)をtileset.flipY = false変更しました。mapmaker.html

私は、このように問題を回避するのではなく、実際に問題を修正する別の答えを好むでしょうが、今のところこれが私の解決策です。

以下は完全な関連コードです。

シェーダー:

var tilemapVS = [
    "varying vec2 pixelCoord;",
    "varying vec2 texCoord;",

    "uniform vec2 viewOffset;",
    "uniform vec2 viewportSize;",
    "uniform vec2 inverseTileTextureSize;",
    "uniform float inverseTileSize;",

    "void main(void) {",
    "    pixelCoord = (uv * viewportSize) + viewOffset;",
    "    texCoord = pixelCoord * inverseTileTextureSize * inverseTileSize;",
    "    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);",
    "}"
].join("\n");

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

    "varying vec2 pixelCoord;",
    "varying vec2 texCoord;",

    "uniform sampler2D tiles;",
    "uniform sampler2D sprites;",

    "uniform vec2 inverseTileTextureSize;",
    "uniform vec2 inverseSpriteTextureSize;",
    "uniform float tileSize;",
    "uniform int repeatTiles;",

    "void main(void) {",
    "    vec4 tile = texture2D(tiles, texCoord);", //load this pixel of the tilemap
    "    if(tile.x == 1.0 && tile.y == 1.0) { discard; }", //discard if R is 255 and G is 255
    "    vec2 spriteOffset = floor(tile.xy * 256.0) * tileSize;", //generate the offset in the tileset this pixel represents
    "    vec2 spriteCoord = mod(pixelCoord, tileSize);",
    "    vec4 texture = texture2D(sprites, (spriteOffset + spriteCoord) * inverseSpriteTextureSize);",
    "    gl_FragColor = texture;",
    "}"
].join("\n");

シェーダーマテリアル(tilemapおよびtilesetTHREE.Textures):

//Setup Tilemap
tilemap.magFilter = THREE.NearestFilter;
tilemap.minFilter = THREE.NearestMipMapNearestFilter;
if(this.repeat) {
    tilemap.wrapS = tilemap.wrapT = THREE.RepeatWrapping;
} else {
    tilemap.wrapS = tilemap.wrapT = THREE.ClampToEdgeWrapping;
}

//Setup Tileset
tileset.wrapS = tileset.wrapT = THREE.ClampToEdgeWrapping;
tileset.flipY = false;
if(this.filtered) {
    tileset.magFilter = THREE.LinearFilter;
    tileset.minFilter = THREE.LinearMipMapLinearFilter;
} else {
    tileset.magFilter = THREE.NearestFilter;
    tileset.minFilter = THREE.NearestMipMapNearestFilter;
}

//setup shader uniforms
this.offset = new THREE.Vector2(0, 0);
this._uniforms = {
    viewportSize: { type: 'v2', value: new THREE.Vector2(viewport.width / this.tileScale, viewport.height / this.tileScale) },
    inverseSpriteTextureSize: { type: 'v2', value: new THREE.Vector2(1/tileset.image.width, 1/tileset.image.height) },
    tileSize: { type: 'f', value: this.tileSize },
    inverseTileSize: { type: 'f', value: 1/this.tileSize },

    tiles: { type: 't', value: tilemap },
    sprites: { type: 't', value: tileset },

    viewOffset: { type: 'v2', value: this.offset },
    inverseTileTextureSize: { type: 'v2', value: new THREE.Vector2(1/tilemap.image.width, 1/tilemap.image.height) },
    repeatTiles: { type: 'i', value: this.repeat ? 1 : 0 }
};

//create the shader material
this._material = new THREE.ShaderMaterial({
    uniforms: this._uniforms,
    vertexShader: tilemapVS,
    fragmentShader: tilemapFS,
    transparent: false
});

this._plane = new THREE.PlaneGeometry(viewport.width, viewport.height, this.tileSize, this.tileSize);

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

変更されたマップメーカー部分:

MapMaker.prototype.processTile = function(x, y) {
    //rotate upside down, and draw
    this.tileCtx.save();
    this.tileCtx.translate(0, this.tileSize);
    this.tileCtx.scale(1, -1);
    this.tileCtx.drawImage(this.srcImage, 
        x * this.tileSize, y * this.tileSize, this.tileSize, this.tileSize, 
        0, 0, this.tileSize, this.tileSize);

    var sprite = this.cacheSprite();

    this.tileCtx.restore();

    this.mapCtx.fillStyle="rgb(" + sprite.x + "," + sprite.y + ", 0)";
    this.mapCtx.fillRect(x,y,1,1);

    /* Why was this thing drawing 2 times?
    this.tileCtx.drawImage(this.srcImage, 
        x * this.tileSize, y * this.tileSize, this.tileSize, this.tileSize, 
        0, 0, this.tileSize, this.tileSize);*/
};

誰かが別の答えを持っている場合は、それを投稿することを躊躇しないでください。

于 2012-10-26T13:00:30.777 に答える