2017-02-22 62 views
0

我正在做一個光貼圖的瓷磚地圖,我想知道我該如何聲明一個瓷磚貼圖(光柵化在兩個三角形中)作爲第1層,而其他瓷磚貼圖上面有透明的部分來看第一層?如何在WebGL上使用圖層?

回答

0

WebGL是一個光柵化API。它只是繪製。它沒有「層」的概念。

您可以在每個框架中實現圖層,繪製第一個地圖,然後在第一個地圖上繪製第二個地圖。這與畫布2D API沒有區別。

至於如何使只有2個三角形(或一個偶數)一tilemap的see this article

也有在使用相同的技術this project但它也支持翻轉和旋轉的磚(90度),並有代碼從Tiled加載地圖。對不起,沒有文檔。查看tilemap.js獲取繪製圖層的着色器和代碼,查看從Tiled加載地圖和圖塊的代碼tiledloader.js

讓我們從基礎開始。首先,如果我們只是抽2個矩形:第二個(藍色)是一個「層」在第一(紅色)

const ctx = document.querySelector("canvas").getContext("2d"); 
 
function render(time) { 
 
    time *= 0.001; // seconds 
 
    
 
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); 
 
    
 
    var t1 = time * -1.1; 
 
    ctx.fillStyle = "red"; 
 
    ctx.fillRect(50 + Math.sin(t1) * 20, 50 + Math.cos(t1) * 20, 128, 64); 
 
    
 
    var t2 = time * 1.3; 
 
    ctx.fillStyle = "blue"; 
 
    ctx.fillRect(75 + Math.sin(t2) * 20, 30 + Math.cos(t2) * 20, 64, 128); 
 

 
    requestAnimationFrame(render); 
 
} 
 
requestAnimationFrame(render);
canvas { border: 1px solid black; }
<canvas />

這將是WebGL的沒有什麼不同。

如果我們把靜態tilemap像圖像一樣,除了矩形的內容之外沒有任何變化。

這裏的第一個圖像

layer2

而這裏的第二

layer2

const ctx = document.querySelector("canvas").getContext("2d"); 
 
const layer1 = new Image(); 
 
layer1.src = "http://i.imgur.com/KTXDmsa.png"; 
 
const layer2 = new Image(); 
 
layer2.src = "http://i.imgur.com/3qVLkO5.png"; 
 

 

 
function render(time) { 
 
    time *= 0.001; // seconds 
 
    
 
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); 
 
    
 
    var t1 = time * -1.1; 
 
    ctx.drawImage(layer1, 50 + Math.sin(t1) * 20, 50 + Math.cos(t1) * 20); 
 
    
 
    var t2 = time * 1.3; 
 
    ctx.drawImage(layer2, 75 + Math.sin(t2) * 20, 30 + Math.cos(t2) * 20); 
 

 
    requestAnimationFrame(render); 
 
} 
 
requestAnimationFrame(render);
canvas { border: 1px solid black; }
<canvas />

再次,在WebGL中沒有什麼不同。

現在,您需要從tilemap生成這些圖像,而不是靜態加載它們,這是鏈接的代碼和下面的代碼的作用。基於this tileset

tileset

const m4 = twgl.m4; 
 
const gl = document.querySelector("canvas").getContext("webgl"); 
 

 
// compile & link shaders and lookup locations 
 
const progInfo = twgl.createProgramInfo(gl, ["vs", "fs"]); 
 

 
// make a unit quad 
 
const quadBufferInfo = twgl.primitives.createXYQuadBufferInfo(gl, 1, .5, .5); 
 

 
// load tiles into texture 
 
const tilesAcross = 16; 
 
const tilesDown = 16; 
 
const tileWidth = 32; 
 
const tileHeight = 32; 
 
const tiles = twgl.createTexture(gl, { 
 
    src: "http://i.imgur.com/sz79FPd.png", 
 
    crossOrigin: "", 
 
    minMag: gl.NEAREST, 
 
}); 
 

 
// layer 0 
 
const tilemap0 = createTilemap({ 
 
    width: 8, 
 
    height: 5, 
 
    map: new Uint32Array([ 
 
    t(1, 2), t(1, 2), t(1, 2), t(1, 2), t(1, 2), t(1, 2), t(1, 2), t(1, 2), 
 
    t(1, 2), t(9, 6), t(9, 6), t(9, 6), t(9, 6), t(9, 6), t(9, 6), t(1, 2),  
 
    t(1, 2), t(9, 6), t(9, 6), t(9, 6), t(9, 6), t(9, 6), t(9, 6), t(1, 2),  
 
    t(1, 2), t(9, 6), t(9, 6), t(9, 6), t(9, 6), t(9, 6), t(9, 6), t(1, 2),  
 
    t(1, 2), t(1, 2), t(1, 2), t(1, 2), t(1, 2), t(1, 2), t(1, 2), t(1, 2), 
 
    ]), 
 
}); 
 

 
// layer 1 
 
const tilemap1 = createTilemap({ 
 
    width: 8, 
 
    height: 5, 
 
    map: new Uint32Array([ 
 
    t(0, 0), t(0, 0), t(0, 0), t(0, 0), t(0, 0), t(0, 0), t(0, 0), t(0, 0), 
 
    t(0, 0), t(4, 5), t(5, 5), t(6, 5), t(0, 0), t(0, 0), t(0, 0), t(0, 0), 
 
    t(0, 0), t(0, 0), t(0, 0), t(0, 0), t(0, 0), t(4, 5), t(5, 5), t(6, 5), 
 
    t(4, 5), t(5, 5), t(6, 5), t(0, 0), t(0, 0), t(0, 0), t(0, 0), t(0, 0), 
 
    t(0, 0), t(0, 0), t(0, 0), t(0, 0), t(0, 0), t(0, 0), t(0, 0), t(0, 0), 
 
    ]), 
 
}); 
 

 
function t(x, y, xflip, yflip, xyswap) { 
 
    return x | (y << 8) | 
 
     (((xflip ? 0x80 : 0) | (yflip ? 0x40 : 0) | (xyswap ? 0x20 : 0)) << 24); 
 
} 
 

 
// copy the tilemap into a texture 
 
function createTilemap(tilemap) { 
 
    tilemap.texture = twgl.createTexture(gl, { 
 
    src: new Uint8Array(tilemap.map.buffer), 
 
    width: tilemap.width, 
 
    minMag: gl.NEAREST, 
 
    }); 
 
    return tilemap; 
 
}; 
 

 

 
function drawTilemap(options) { 
 
    const tilemap = options.tilemap; 
 
    
 
    const scaleX = options.scaleX || 1; 
 
    const scaleY = options.scaleY || 1; 
 

 
    const dispScaleX = options.width/gl.canvas.width; 
 
    const dispScaleY = options.height/gl.canvas.height; 
 

 
    let texMat = m4.translation([options.scrollX, options.scrollY, 0]); 
 
    texMat = m4.rotateZ(texMat, options.rotation); 
 
    texMat = m4.scale(texMat, [ 
 
    gl.canvas.width/tileWidth/scaleX * (dispScaleX), 
 
    gl.canvas.height/tileHeight/scaleY * (dispScaleY), 
 
    1, 
 
    ]); 
 
    texMat = m4.translate(texMat, [ 
 
    -options.originX/gl.canvas.width, 
 
    -options.originY/gl.canvas.height, 
 
    0, 
 
    ]); 
 

 
    const matrix = [ 
 
    2 * dispScaleX,0,0,0, 
 
    0,-2 * dispScaleY,0,0, 
 
    0,0,1,0, 
 
    -1 + 2 * (options.x | 0)/gl.canvas.width, 1 - 2 * (options.y | 0)/gl.canvas.height,0,1, 
 
    ]; 
 

 
    gl.useProgram(progInfo.program); 
 
    
 
    // calls gl.bindBuffer, gl.enableVertexAttribArray, gl.vertexAttribPointer 
 
    twgl.setBuffersAndAttributes(gl, progInfo, quadBufferInfo); 
 
    
 
    // calls gl.uniformXXX and gl.activeTexture, gl.bindTexture 
 
    twgl.setUniforms(progInfo, { 
 
    u_matrix: matrix, 
 
    u_texMatrix: texMat, 
 
    u_tilemap: tilemap.texture, 
 
    u_tiles: tiles, 
 
    u_tilemapSize: [tilemap.width, tilemap.height], 
 
    u_tilesetSize: [tilesAcross, tilesDown], 
 
    }); 
 
    
 
    // calls gl.drawElements 
 
    twgl.drawBufferInfo(gl, quadBufferInfo); 
 
} 
 

 
function render(time) { 
 
    time *= 0.001; 
 
    
 
    // draw layer 0 
 
    drawTilemap({ 
 
    tilemap: tilemap0, 
 
    tiles: tiles, 
 
    // position and width, height on canvas 
 
    x: Math.cos(time * .9) * 20, 
 
    y: Math.sin(time * .9) * 20, 
 
    width: 256, 
 
    height: 160, 
 
    // offset into tilemap (repeats at edges) 
 
    scrollX: 0, 
 
    scrollY: 0, 
 
    // rotation/scale point 
 
    originX: 0, 
 
    originY: 0, 
 
    // rotation in radians 
 
    rotation: 0, 
 
    // scale 
 
    scaleX: 1, 
 
    scaleY: 1, 
 
    }); 
 

 
    // draw layer 1 
 
    drawTilemap({ 
 
    tilemap: tilemap1, 
 
    tiles: tiles, 
 
    x: Math.sin(time) * 20, 
 
    y: Math.cos(time) * 20, 
 
    width: 256, 
 
    height: 160, 
 
    scrollX: 0, 
 
    scrollY: 0, 
 
    originX: 0, 
 
    originY: 0, 
 
    rotation: 0, 
 
    }); 
 

 

 
    requestAnimationFrame(render); 
 
} 
 
requestAnimationFrame(render);
canvas { border: 1px solid black; }
<canvas /> 
 
<script src="https://twgljs.org/dist/3.x/twgl-full.min.js"></script> 
 
<script id="vs" type="foo"> 
 
attribute vec4 position; 
 
attribute vec4 texcoord; 
 

 
uniform mat4 u_matrix; 
 
uniform mat4 u_texMatrix; 
 

 
varying vec2 v_texcoord; 
 

 
void main() { 
 
    gl_Position = u_matrix * position; 
 
    v_texcoord = (u_texMatrix * texcoord).xy; 
 
} 
 
</script> 
 
<script id="fs" type="foo"> 
 
precision mediump float; 
 

 
uniform sampler2D u_tilemap; 
 
uniform sampler2D u_tiles; 
 
uniform vec2 u_tilemapSize; // tiles across/down map 
 
uniform vec2 u_tilesetSize; // pixels across a single tile 
 

 
varying vec2 v_texcoord; 
 

 
void main() { 
 
    // v_texcoord is in tile units which is based on u_texMatrix from the 
 
    // vertex shader 
 
    
 
    // this is the tile to start at 
 
    vec2 tilemapCoord = floor(v_texcoord); 
 
    
 
    // this is a fractional amount into a tile 
 
    vec2 texcoord = fract(v_texcoord); 
 
    
 
    // computes the UV coord pull the correct value out of tilemap 
 
    vec2 tileFoo = fract((tilemapCoord + vec2(0.5, 0.5))/u_tilemapSize); 
 
    
 
    // get a single tile out of the tilemap and convert from 0 -> 1 to 0 -> 255 
 
    vec4 tile = floor(texture2D(u_tilemap, tileFoo) * 256.0); 
 

 
    // flags for the tile are in w (xflip, yflip, xyswap) 
 
    float flags = tile.w; 
 
    float xflip = step(128.0, flags); 
 
    flags = flags - xflip * 128.0; 
 
    float yflip = step(64.0, flags); 
 
    flags = flags - yflip * 64.0; 
 
    float xySwap = step(32.0, flags); 
 
    
 
    // based on the flags swap the texcoord inside the tile 
 
    if (xflip > 0.0) { 
 
    texcoord = vec2(1.0 - texcoord.x, texcoord.y); 
 
    } 
 
    if (yflip > 0.0) { 
 
    texcoord = vec2(texcoord.x, 1.0 - texcoord.y); 
 
    } 
 
    if (xySwap > 0.0) { 
 
    texcoord = texcoord.yx; 
 
    } 
 

 
    // scale the tex coords for a single tile 
 
    vec2 tileCoord = (tile.xy + texcoord)/u_tilesetSize; 
 
    
 
    // get the color from the tile 
 
    vec4 color = texture2D(u_tiles, tileCoord); 
 
    
 
    // if alpha is below some threshold don't draw at all 
 
    if (color.a <= 0.1) { 
 
    discard; 
 
    } 
 
    gl_FragColor = color; 
 
} 
 
</script>

+0

,我試圖瞭解東治的示例代碼是如何工作的,他畫的 「層」 的一個循環(在WebGL的-tilemap.js從第237行到第247行),但我不明白他是如何聲明瓷磚貼圖位於頂部,我認爲它是uniform2f,或者它只是聲明爲同一個頂點和柵格化的ab因爲有相同的座標。我不確定 – AngeLOL

+0

他沒有在頂部宣佈一個。第一個繪製在底部,下一個繪製在上面,下一個繪製在上面。沒有魔法。見答案 – gman

相關問題