为什么WebGL绘制我的纹理三次而不是一次?

时间:2017-08-21 15:54:34

标签: webgl

我正在尝试在WebGL和Electron中构建一个小型2D游戏。出于某种原因,当我调用渲染一次时,我的纹理被三重渲染。我似乎无法确定为什么或者我是否以某种方式加载纹理错误并且触发了我的问题。

我的代码的最终结果如下:

Result of rendering

我的渲染代码如下(xy参数尚未使用):

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);
}

正在加载代码:

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;
}

主要功能:

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);
});

1 个答案:

答案 0 :(得分:0)

在玩了很多选项后,我发现了问题的根源。默认情况下启用了预乘alpha(我没有在我的上下文创建选项中指定premultipliedAlpha: false)并且我没有将UNPACK_PREMULTIPLIED_ALPHA_WEBGL设置为true

强制关闭后,问题就消失了。通过调用true将上述参数设置为pixelStorei也会导致问题消失。还原任一更改都会导致问题再次出现。关于使用默认设置发生此效果的原因,我有点神秘,但我的问题已经解决了。