このコードの多くは、以下の編集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;
、適切なテクスチャ、適切なスポットが得られ、正しくフィットすることに注意してください。しかし、マップ全体が逆さまになっています!とても近い...