2017-08-21 3 views
0

Je tente de construire un petit jeu 2D en WebGL et Electron. Pour une raison quelconque, ma texture est rendue triple lorsque j'appelle à rendre une seule fois. Je ne peux pas sembler déterminer pourquoi ou si je charge d'une manière ou d'une autre la texture incorrecte et cela déclenche mon problème.Pourquoi WebGL dessine ma texture trois fois au lieu d'une fois?

Le résultat final de mon code est le suivant:

Result of rendering

Mon code de rendu est comme suit (x et y paramètres ne sont pas encore utilisés):

export function render(tex: texture_t, _x: number, _y: number): void { 
    if (!is_valid(tex)) { 
     throw new Error('Invalid value - bad texture'); 
    } 
    if (shader_program == null) { 
     shader_program = program_create_from_sources(default_v_shader, default_f_shader); 
    } 
    const gl = tex.context.context; 
    if (index_buffer == null) { 
     index_buffer = gl.createBuffer(); 
     if (index_buffer == null) { 
      throw new Error('Failed to create default index buffer'); 
     } 
     gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer); 
     gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(index_data), gl.STATIC_DRAW); 
    } else { 
     gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer); 
    } 
    gl.useProgram(shader_program.native); 
    if (vertex_buffer == null) { 
     vertex_buffer = gl.createBuffer(); 
     if (vertex_buffer == null) { 
      throw new Error('Failed to create default vertex buffer'); 
     } 
     gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer); 
     gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertex_data), gl.STATIC_DRAW); 
    } else { 
     gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer); 
    } 
    gl.enableVertexAttribArray(shader_program.attributes.vertex_model); 
    gl.vertexAttribPointer(shader_program.attributes.vertex_model, 3, gl.FLOAT, false, 0, 0); 

    if (uv_buffer == null) { 
     uv_buffer = gl.createBuffer(); 
     if (uv_buffer == null) { 
      throw new Error('Failed to create default UV buffer'); 
     } 
     gl.bindBuffer(gl.ARRAY_BUFFER, uv_buffer); 
     gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(uv_data), gl.STATIC_DRAW); 
    } else { 
     gl.bindBuffer(gl.ARRAY_BUFFER, uv_buffer); 
    } 
    gl.enableVertexAttribArray(shader_program.attributes.uv_model); 
    gl.vertexAttribPointer(shader_program.attributes.uv_model, 2, gl.FLOAT, false, 0, 0); 

    gl.activeTexture(gl.TEXTURE0); 
    gl.bindTexture(gl.TEXTURE_2D, tex.native); 
    gl.uniform1i(shader_program.uniforms.texture, 0); 

    gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); 

    gl.disableVertexAttribArray(shader_program.attributes.uv_model); 
    gl.disableVertexAttribArray(shader_program.attributes.vertex_model); 
} 

Code de chargement:

export function create_empty(): texture_t { 
    const ctx = context_get_current(); 
    if (ctx == null) { 
     throw new Error('Invalid operation - no rendering context'); 
    } 
    const gl = ctx.context; 
    const nat: WebGLTexture|null = gl.createTexture(); 
    if (nat == null) { 
     throw new Error('Invalid operation - unable to create texture'); 
    } 
    return { 
     native: nat, 
     width: 0, 
     height: 0, 
     source: null, 
     context: ctx 
    }; 
} 

export async function create_from_image(src: string): Promise<texture_t> { 
    const p = new Promise<texture_t>((resolve, reject) => { 
     const tex = create_empty(); 
     const gl = tex.context.context; 
     const img = new Image(); 
     img.addEventListener('load',() => { 
      gl.bindTexture(gl.TEXTURE_2D, tex.native); 
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img); 
      tex.source = img.src; 
      tex.width = img.width; 
      tex.height = img.height; 
      resolve(tex); 
     }); 
     img.addEventListener('error', (err) => { 
      destroy(tex); 
      reject(err); 
     }); 
     img.src = src; 
    }); 
    return p; 
} 

Fonction principale:

import * as path from 'path'; 
import {create as context_create, make_current} from './graphics/context'; 
import {texture_t, create_from_image as texture_create_from_image, 
    render as texture_render} from './graphics/texture'; 

const ctx = context_create(); 
const gl = ctx.context; 

make_current(ctx); 

let tex: texture_t|null = null; 

gl.clearColor(0, 0, 0, 1); 
ctx.canvas.width = ctx.canvas.clientWidth; 
ctx.canvas.height = ctx.canvas.clientHeight; 
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); 

function onFrame() { 
    gl.clear(gl.COLOR_BUFFER_BIT); 
    if (tex != null) { 
     texture_render(tex, 0, 0); 
    } 
    requestAnimationFrame(onFrame); 
} 

texture_create_from_image(`file://${path.resolve(__dirname, './images/WebGL_logo.png')}`).then((t) => { 
    tex = t; 
    const gl = tex.context.context; 
    // HACK: Non-power-of-two, so do this. 
    gl.bindTexture(gl.TEXTURE_2D, tex.native); 
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); 
    // gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); 
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 
    requestAnimationFrame(onFrame); 
}); 

Répondre

0

Après avoir joué avec un tas d'options, je l'ai découvert la source du problème. Il semble que l'alpha prémultiplé a été activé par défaut (je n'ai pas spécifié premultipliedAlpha: false dans mes options de création de contexte) et je n'avais pas défini UNPACK_PREMULTIPLIED_ALPHA_WEBGL sur true. Après l'avoir forcé, le problème s'est dissipé. En réglant le paramètre mentionné ci-dessus sur true via un appel au pixelStorei, le problème a également été résolu. La restauration de l'un ou l'autre des changements entraîne la réapparition du problème. Je suis un peu mystifié quant à la raison pour laquelle cet effet se produit avec les paramètres par défaut, mais mon problème est résolu.