Blenderでモデリングしている合間に、three.jsのShader MaterialとPoint Spriteを使って、2Dスプライト・エンジンを作ってみた。 動機としては、以前作った2Dスプライト・エンジンは、処理的に無駄が多いので。
ちょっとポイントスプライト+GLSLで2Dスプライト・エンジンを作ったみたりもしたけど、これはお蔵入りかも。 pic.twitter.com/Rv1tzIelUg
— S.F. (@SFPGMR) 2017年11月11日
ポイントスプライトというのは、「1点で正方形を描くGPUの機能」と言える。1つの点の位置とサイズを指定すると、正方形が描画できるのである。 ただWebGLでは、描ける点のサイズに制限がある(大体は64px * 64pxくらいまで)。
今までは四角形1つ描くのに4つの頂点を使っていたから、2Dスプライトエンジンの効率化にはうってつけではないか。しかも私の場合、低解像度志向なので64pxもあれば十分な大きさである。それよりも大きいものは今まで通り4つの頂点を使えばいい。
ただし、ポイントスプライトを使うと正方形しか描けず、また1点なので回転などの表現ができない。これを実現するには角度というAttributeを用意して、シェーダーでテクスチャ・サンプルするときに読み出し位置を回転させればよい。
ということで書いたシェーダーは以下のとおり。Three.jsのシェーダー・マテリアルで使うことを前提としている。 コードではさらにスプライトNOを指定すれば、指定した番号のビットマップ・セルを表示するようにしてみている。
const vertexShader = `
attribute vec3 pointColor;
attribute float size;
attribute float visible;
attribute float spriteNo;
attribute float rotate;
varying vec3 vColor;
varying float vVisible;
varying float vSpriteNo;
varying float vRotate;
void main() {
vColor = pointColor;
vVisible = visible;
vSpriteNo = spriteNo;
vRotate = rotate;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_PointSize = size;
gl_Position = projectionMatrix * mvPosition;
}
`;
const fragmentShader = `
uniform vec3 color;
uniform float spriteSize;
uniform sampler2D texture;
varying vec3 vColor;
varying float vVisible;
varying float vSpriteNo;
varying float vRotate;
void main() {
if(vVisible == 0.0) discard;
//gl_FragColor = vec4( color * vColor, 1.0 );
//gl_FragColor = /*gl_FragColor */ texture2D( texture, gl_PointCoord / 4.0 );
vec2 coord = gl_PointCoord - 0.5;
vec2 coord2;
float s = sin(vRotate);
float c = cos(vRotate);
coord2.x = coord.x * c - coord.y * s;
coord2.y = coord.x * s + coord.y * c;
coord = coord2 + 0.5;
if(coord.x < 0.0 || coord.x > 1.0 || coord.y < 0.0 || coord.y > 1.0 ) discard;
coord.x = coord.x / 16.0 + vSpriteNo / 16.0;
coord.y = coord.y / 16.0 + 14.0 / 16.0;
gl_FragColor = texture2D( texture, coord);//vec4(1.0,1.0,1.0,1.0);
}
`;
動作サンプル
ソースコード・リソース
/dev/shooting3/devver/20171116/css/style.css
/dev/shooting3/devver/20171116/index.html