簡體   English   中英

WebGL-動畫精靈+動畫坐標

[英]WebGL - animated sprites + animated coordinates

我需要同時運行精靈動畫和動畫坐標。

也就是說,為動畫中的某些特定精靈指定了[0,1]中的紋理坐標,然后將其轉換為另一個坐標。

平移可能會導致[0,1]以外的坐標,而重復則需要此坐標。

問題是-我將精靈作為紋理地圖集提供。 因此,選擇子畫面意味着在[0,1]中獲得一個子矩形。 由於此精靈位於其他精靈之間,因此無法重復-畢竟,如果紋理坐標移動到該精靈的矩形之外,則將對其他精靈進行采樣。

精靈必須在紋理圖集中給出-我正在使用實例渲染,每個實例都可以使用動畫中的任何精靈,據我所知,唯一的實現方法是使用紋理圖集(或OpenGL中的紋理數組等)。

tl; dr-是否可以在WebGL中同時實現紋理重復和精靈動畫?

如果您知道精靈在地圖集中的位置,那么您是否不能僅在片段着色器中以該范圍模來計算紋理坐標?

vec2 animatedUV;      // animation value
vec2 spriteStartUV;   // corner uv coord for sprite in atlas
vec2 spriteEndVU;     // opposite corner uv coord for sprite in atlas

vec2 spriteRange = (spriteEndUV - spriteStartUV);
vec2 uv = spriteStartUV + fract(texcoord + animatedUV) * spriteRange;

vec4 color = texture2D(someTexture, uv);

我不知道這是否適合您的特定情況,但也許可以給您一些想法。

工作示例:

 const vs = ` void main() { // using a point sprite because it's easy but the concept // is the same. gl_Position = vec4(0, 0, 0, 1); gl_PointSize = 40.0; } `; const fs = ` precision mediump float; // I'm passing these in as uniforms but you can pass them in as varyings // from buffers if that fits your needs better uniform vec2 animatedUV; // animation value uniform vec2 spriteStartUV; // corner uv coord for sprite in atlas uniform vec2 spriteEndUV; // opposite corner uv coord for sprite in atlas uniform sampler2D someTexture; void main() { // this would normally come from a varying but lazy so using point sprite vec2 texcoord = gl_PointCoord.xy; vec2 spriteRange = (spriteEndUV - spriteStartUV); vec2 uv = spriteStartUV + fract(texcoord + animatedUV) * spriteRange; vec4 color = texture2D(someTexture, uv); gl_FragColor = color; } `; // use the canvas to make a texture atlas with one sprite const ctx = document.querySelector("#atlas").getContext("2d"); const w = ctx.canvas.width; const h = ctx.canvas.height const sx = 30; const sy = 40; const sw = 50; const sh = 60; ctx.fillStyle = "red"; ctx.fillRect(0, 0, w, h); ctx.fillStyle = "blue"; ctx.fillRect(sx, sy, sw, sh); ctx.fillStyle = "yellow"; ctx.font = "45px sans-serif"; ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.fillText("G", sx + sw / 2, sy + sh / 2); // compute texcoods for sprite const spriteStartUV = [ sx / w, sy / h ]; const spriteEndUV = [ (sx + sw) / w, (sy + sh) / h ]; const gl = document.querySelector("#webgl").getContext("webgl"); const programInfo = twgl.createProgramInfo(gl, [vs, fs]); const tex = twgl.createTexture(gl, { src: ctx.canvas, }); function render(time) { time *= 0.001; // seconds gl.useProgram(programInfo.program); twgl.setUniforms(programInfo, { animatedUV: [time, time * 1.1], spriteStartUV: spriteStartUV, spriteEndUV: spriteEndUV, someTexture: tex, }); gl.drawArrays(gl.POINTS, 0, 1); // draw 1 point requestAnimationFrame(render); } requestAnimationFrame(render); 
 canvas { border: 1px solid black; margin: 2px; } 
 <script src="https://twgljs.org/dist/4.x/twgl.min.js"></script> <canvas id="atlas"></canvas> <canvas id="webgl"></canvas> 

如果您希望重復更多,則增加您的texcoords或添加一個倍增器

 const vs = ` void main() { // using a point sprite because it's easy but the concept // is the same. gl_Position = vec4(0, 0, 0, 1); gl_PointSize = 40.0; } `; const fs = ` precision mediump float; // I'm passing these in as uniforms but you can pass them in as varyings // from buffers if that fits your needs better uniform vec2 animatedUV; // animation value uniform vec2 spriteStartUV; // corner uv coord for sprite in atlas uniform vec2 spriteEndUV; // opposite corner uv coord for sprite in atlas uniform sampler2D someTexture; void main() { // this would normally come from a varying but lazy so using point sprite vec2 texcoord = gl_PointCoord.xy * 3.; // this * 3 could already be // in your texcoords vec2 spriteRange = (spriteEndUV - spriteStartUV); vec2 uv = spriteStartUV + fract(texcoord + animatedUV) * spriteRange; vec4 color = texture2D(someTexture, uv); gl_FragColor = color; } `; // create texture atlas with one sprite const ctx = document.querySelector("#atlas").getContext("2d"); const w = ctx.canvas.width; const h = ctx.canvas.height const sx = 30; const sy = 40; const sw = 50; const sh = 60; ctx.fillStyle = "red"; ctx.fillRect(0, 0, w, h); ctx.fillStyle = "blue"; ctx.fillRect(sx, sy, sw, sh); ctx.fillStyle = "yellow"; ctx.font = "45px sans-serif"; ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.fillText("G", sx + sw / 2, sy + sh / 2); // compute texture coords for sprite in atlas const spriteStartUV = [ sx / w, sy / h ]; const spriteEndUV = [ (sx + sw) / w, (sy + sh) / h ]; const gl = document.querySelector("#webgl").getContext("webgl"); const programInfo = twgl.createProgramInfo(gl, [vs, fs]); const tex = twgl.createTexture(gl, { src: ctx.canvas, }); function render(time) { time *= 0.001; // seconds gl.useProgram(programInfo.program); twgl.setUniforms(programInfo, { animatedUV: [time, time * 1.1], spriteStartUV: spriteStartUV, spriteEndUV: spriteEndUV, someTexture: tex, }); gl.drawArrays(gl.POINTS, 0, 1); // draw 1 point requestAnimationFrame(render); } requestAnimationFrame(render); 
 canvas { border: 1px solid black; margin: 2px; } 
 <script src="https://twgljs.org/dist/4.x/twgl.min.js"></script> <canvas id="atlas"></canvas> <canvas id="webgl"></canvas> 

請注意,上面的示例使用制服,但是您可以使用屬性將每個頂點的spriteStartUV,spriteEndUV和其他任何數據輕松使用,並將這些數據添加到緩沖區中。

更新

帶有更多精靈的示例,使其更加清晰,它使用的是紋理圖集

 const vs = ` uniform vec4 u_position; void main() { // using a point sprite because it's easy but the concept // is the same. gl_Position = u_position; gl_PointSize = 40.0; } `; const fs = ` precision mediump float; // I'm passing these in as uniforms but you can pass them in as varyings // from buffers if that fits your needs better uniform vec2 animatedUV; // animation value uniform vec2 spriteStartUV; // corner uv coord for sprite in atlas uniform vec2 spriteEndUV; // opposite corner uv coord for sprite in atlas uniform sampler2D someTexture; void main() { // this would normally come from a varying but lazy so using point sprite vec2 texcoord = gl_PointCoord.xy * 3.; // this * 3 could already be // in your texcoords vec2 spriteRange = (spriteEndUV - spriteStartUV); vec2 uv = spriteStartUV + fract(texcoord + animatedUV) * spriteRange; vec4 color = texture2D(someTexture, uv); gl_FragColor = color; } `; // create texture atlas with 36 sprites const ctx = document.querySelector("#atlas").getContext("2d"); const w = ctx.canvas.width; const h = ctx.canvas.height; ctx.fillStyle = "red"; ctx.fillRect(0, 0, w, h); const sw = 16; const sh = 16; const spritesAcross = w / sw | 0; const spriteData = []; const backgroundColors = [ "#884", "#848", "#488", "#448", "#484", "#488", "#222", ]; "ABCDEFGHIIJKLMNOPQRSTUVWXYZ0123456789".split('').forEach((letter, ndx) => { const sx = ndx % spritesAcross * sw; const sy = (ndx / spritesAcross | 0) * sh; ctx.fillStyle = backgroundColors[ndx % backgroundColors.length]; ctx.fillRect(sx, sy, sw, sh); ctx.fillStyle = "yellow"; ctx.font = "16px sans-serif"; ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.fillText(letter, sx + sw / 2, sy + sh / 2); spriteData.push({ spriteStartUV: [ sx / w, sy / h ], spriteEndUV: [ (sx + sw) / w, (sy + sh) / h ], }); }); // compute texture coords for sprite in atlas const gl = document.querySelector("#webgl").getContext("webgl"); const programInfo = twgl.createProgramInfo(gl, [vs, fs]); const tex = twgl.createTexture(gl, { src: ctx.canvas, }); function render(time) { time *= 0.001; // seconds gl.useProgram(programInfo.program); for (let i = 0; i < 100; ++i) { const spriteInfo = spriteData[i % spriteData.length]; const t = time + i; twgl.setUniforms(programInfo, { u_position: [Math.sin(t * 1.2), Math.sin(t * 1.3), 0, 1], animatedUV: [t, t * 1.1], spriteStartUV: spriteInfo.spriteStartUV, spriteEndUV: spriteInfo.spriteEndUV, someTexture: tex, }); gl.drawArrays(gl.POINTS, 0, 1); // draw 1 point } requestAnimationFrame(render); } requestAnimationFrame(render); 
 canvas { border: 1px solid black; margin: 2px; } 
 <script src="https://twgljs.org/dist/4.x/twgl.min.js"></script> <canvas id="atlas"></canvas> <canvas id="webgl"></canvas> 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM