WebGL texImage2D问题:如何在单元/对象上获得纹理?

时间:2017-04-20 02:29:46

标签: javascript textures webgl glteximage2d

所以我正在寻找WebGL纹理/ 3D渲染方面的帮助。

我的代码(我到目前为止所做的)是创建一个纹理块/立方体的3D迷宫,用户可以通过箭头键或WASD导航。我认为我遇到的问题就是texImage2d()。我相信。

我尝试过像

这样的事情
 var stonePic = document.getElementById("stoneTex");
 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, stonePic));

没有效果,导致this

我也试过

var stonePic = new Image();
stonePic.src = "stoneWall2.png";

导致了同样的错误。

我做错了什么?我能解决它吗?

<HTML>
    <HEAD>
        <TITLE>Brick Wall Maze</TITLE>
    <SCRIPT>

    //VERTEX SHADER TEXT
    var vertexShaderText = 
    [
        'precision mediump float;',
        '',
        'attribute vec3 vertPosition;',
        'attribute vec2 vertTexCoord;',
        'varying vec2 fragTexCoord;',
        'uniform vec3 theta;',
        'uniform vec3 trans;',
        'uniform float thetaC;',
        'uniform vec3 camLoc;',
        'void main()',
        '{',
        'fragTexCoord = vertTexCoord;',
        'vec3 c = cos(theta);',
        'vec3 s = sin(theta);',
        '',
        'mat4 ry = mat4(c.y,0.0,-1.0*s.y,0.0, 0.0,1.0,0.0,0.0, s.y,0.0,c.y,0.0, 0.0,0.0,0.0,1.0);',
        'mat4 translate = mat4(1,0,0,0, 0,1,0,0, 0,0,1,0, trans.x,trans.y,trans.z,1);',
        'vec4 tempLoc = vec4(vertPosition, 1.0);',

        'float l = -1.0;',
        'float r = 1.0;',
        'float t = 1.0;',
        'float b = -1.0;',
        'float f = 100.0;',
        'float n = 1.0;',
        'mat4 perspective  = mat4(2.0*n/(r-l),0,0,0,  0,2.0*n/(t-b),0,0, (r+l)/(r-l),(t+b)/(t-b),-1.0*(f+n)/(f-n),-1.0,   0,0,-2.0*f*n/(f-n),0);',

        'float tempc = cos(thetaC);',
        'float temps = sin(thetaC);',
        'mat4 camRY = mat4(tempc,0,-1.0*temps,0, 0,1,0,0, temps,0,tempc,0, 0,0,0,1);',
        'mat4 viewM = mat4(1.0,0,0,0, 0,1.0,0,0, 0,0,1.0,0, camLoc.x,camLoc.y,camLoc.z,1.0);',
        'gl_Position = perspective * camRY * viewM * translate * ry * tempLoc;',
        '}'
    ].join("\n");

    // FRAGMENT SHADER TEXT
    var fragmentShaderText = 
    [
        'precision mediump float;',
        'varying vec2 fragTexCoord;',
        'uniform sampler2D sampler;',
        'void main()',
        '{',
        'gl_FragColor = texture2D(sampler, fragTexCoord);',
        '}'
    ].join('\n');

    // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~

    function initializeGL()
    {   
        var canvas = document.getElementById("screen"); 
        var gl =  canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
        if (!gl) { alert("WEBGL IS NOT AVAILABLE"); }

        gl.viewport(0, 0, canvas.width, canvas.height);
        gl.clearColor(0.5, 0.7, 0.6 ,1.0);
        gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);
        gl.enable(gl.DEPTH_TEST);

        return gl;
    }

    function initializeShaders(gl)
    {
        // VERTEX SHADER
        var vertexShader = gl.createShader(gl.VERTEX_SHADER);
        gl.shaderSource(vertexShader, vertexShaderText);
        gl.compileShader(vertexShader);
        if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
            console.log("ERROR: ",gl.getShaderInfoLog(vertexShader));
        }

        // FRAGMENT SHADER
        var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
        gl.shaderSource(fragmentShader,fragmentShaderText);
        gl.compileShader(fragmentShader);
        if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
            console.log("ERROR: ",gl.getShaderInfoLog(fragmentShader));
        }

        // PROGRAM
        var program = gl.createProgram();
        gl.attachShader(program, vertexShader);
        gl.attachShader(program, fragmentShader);

        gl.linkProgram(program);
        if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
            console.error("ERROR", gl.getShaderInfoLog(program));
        }

        gl.validateProgram(program);
        if (!gl.getProgramParameter(program, gl.VALIDATE_STATUS)) {
            console.error("ERROR", gl.getShaderInfoLog(program));
        }

        return program;
    }

    // var brickTexture;
    var stoneTexture;

    function setupIndBuffers(gl, program, buffer)
    {
        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);     
        positionAttributeLocation = gl.getAttribLocation(program, "vertPosition");
        texCoordAttributeLocation = gl.getAttribLocation(program, "vertTexCoord");
        gl.vertexAttribPointer(
        positionAttributeLocation, //ATTRIBUTE LOCATION
        3, //NUMBER of elements per attribute
        gl.FLOAT, //TYPES OF ELEMENTS
        gl.FALSE,
        5*Float32Array.BYTES_PER_ELEMENT, //SIZE OF AN INDIVIDUAL VERTEX
        0 //OFFSET
        );


        gl.vertexAttribPointer(
        texCoordAttributeLocation, //ATTRIBUTE LOCATION
        2, //NUMBER of elements per attribute
        gl.FLOAT, //TYPES OF ELEMENTS
        gl.FALSE,
        5*Float32Array.BYTES_PER_ELEMENT, //SIZE OF AN INDIVIDUAL VERTEX
        3*Float32Array.BYTES_PER_ELEMENT //OFFSET
        );

        gl.enableVertexAttribArray(positionAttributeLocation);
        gl.enableVertexAttribArray(texCoordAttributeLocation);
    }

    function setupVertices(gl, program)
    {
        /*
        // Brick Texture
        brickTexture = gl.createTexture();
        gl.bindTexture(gl.TEXTURE_2D, brickTexture);

        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.MIRRORED_REPEAT);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);

        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);

        var brickArray = [];

        for (i = 0; i < 16; i++) {
            for (j = 0; j < 16; j++) {
                if (i == 0 || j == 0) {
                    // Push Black
                    brickArray.push(0, 0, 255);
                }
                else {
                    // Push Red
                    brickArray.push(220, 30, 30, 255);
                }
            }
        }

        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(brickArray));
        gl.bindTexture(gl.TEXTURE_2D, null);
        */

        // ~ ~ ~ ~ ~
        // STONE TEXTURE
        stoneTexture = gl.createTexture();
        gl.bindTexture(gl.TEXTURE_2D, stoneTexture);

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

        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);

        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, stonePic);

        gl.bindTexture(gl.TEXTURE_2D, null);
    }

    /*
    brickVertices = 
    [
        // X, Y, Z     U, V,               

        // Top
        -1.0, 1.0, -1.0,   0.0, 0.0,
        -1.0, 1.0, 1.0,    0.0, 10,
        1.0, 1.0, 1.0,     10, 10,
        1.0, 1.0, -1.0,    10, 0.0,

        // Left
        -1.0, 1.0, 1.0,    10,10,
        -1.0, -1.0, 1.0,   0,10,
        -1.0, -1.0, -1.0,  0,0,
        -1.0, 1.0, -1.0,   10,0,

        // Right
        1.0, 1.0, 1.0,    10,10,
        1.0, -1.0, 1.0,   0,10,
        1.0, -1.0, -1.0,  0,0,
        1.0, 1.0, -1.0,   10,0,

        // Front
        1.0, 1.0, 1.0,     10,10,
        1.0, -1.0, 1.0,    10,0,
        -1.0, -1.0, 1.0,   0,0,
        -1.0, 1.0, 1.0,    0,10,

        // Back
        1.0, 1.0, -1.0,     10,10,
        1.0, -1.0, -1.0,    10,0,
        -1.0, -1.0, -1.0,   0,0,
        -1.0, 1.0, -1.0,    0,10,

        // Bottom
        -1.0, -1.0, -1.0,   0,0,
        -1.0, -1.0, 1.0,    0,10,
        1.0, -1.0, 1.0,     10,10,
        1.0, -1.0, -1.0,    10,0,
    ];
    */

    stoneVertices =
    [
        // X, Y, Z     U, V,

        // Top
        -1.0, 1.0, -1.0,   0.0, 0.0,
        -1.0, 1.0, 1.0,    0.0, 1.0,
        1.0, 1.0, 1.0,     1.0, 1.0,
        1.0, 1.0, -1.0,    1.0, 0.0,

        // Left
        -1.0, 1.0, 1.0,    1,1,
        -1.0, -1.0, 1.0,   0,1,
        -1.0, -1.0, -1.0,  0,0,
        -1.0, 1.0, -1.0,   1,0,

        // Right
        1.0, 1.0, 1.0,    1,1,
        1.0, -1.0, 1.0,   0,1,
        1.0, -1.0, -1.0,  0,0,
        1.0, 1.0, -1.0,   1,0,

        // Front
        1.0, 1.0, 1.0,     1,1,
        1.0, -1.0, 1.0,    1,0,
        -1.0, -1.0, 1.0,   0,0,
        -1.0, 1.0, 1.0,    0,1,

        // Back
        1.0, 1.0, -1.0,     1,1,
        1.0, -1.0, -1.0,    1,0,
        -1.0, -1.0, -1.0,   0,0,
        -1.0, 1.0, -1.0,    0,1,

        // Bottom
        -1.0, -1.0, -1.0,   0,0,
        -1.0, -1.0, 1.0,    0,1,
        1.0, -1.0, 1.0,     1,1,
        1.0, -1.0, -1.0,    1,0,
        ];

    /*
    stoneVertices =
    [
        // X, Y, Z     U, V,               

        // Top
        -1.0, 1.0, -1.0,   0.0, 0.0,
        -1.0, 1.0, 1.0,    0.0, 1.0,
        1.0, 1.0, 1.0,     1.0, 1.0,
        1.0, 1.0, -1.0,    1.0, 0.0,

        // Left
        -1.0, 1.0, 1.0,    1,1,
        -1.0, -1.0, 1.0,   0,1,
        -1.0, -1.0, -1.0,  0,0,
        -1.0, 1.0, -1.0,   1,0,

        // Right
        1.0, 1.0, 1.0,    1,1,
        1.0, -1.0, 1.0,   0,1,
        1.0, -1.0, -1.0,  0,0,
        1.0, 1.0, -1.0,   1,0,

        // Front
        1.0, 1.0, 1.0,     1,1,
        1.0, -1.0, 1.0,    1,0,
        -1.0, -1.0, 1.0,   0,0,
        -1.0, 1.0, 1.0,    0,1,

        // Back
        1.0, 1.0, -1.0,     1,1,
        1.0, -1.0, -1.0,    1,0,
        -1.0, -1.0, -1.0,   0,0,
        -1.0, 1.0, -1.0,    0,1,

        // Bottom
        -1.0, -1.0, -1.0,   0,0,
        -1.0, -1.0, 1.0,    0,1,
        1.0, -1.0, 1.0,     1,1,
        1.0, -1.0, -1.0,    1,0,
        ];
        */

        class Cube
        {
            constructor(test)
            {
                this.tranLoc = gl.getUniformLocation(program, "trans");
                this.thetaLoc = gl.getUniformLocation(program, "theta");
                this.loc = [0, 0, 0];

                if(test) {
                    this.verts = stoneBuffer;
                    this.texture = stoneTexture;
                }
                /*else {
                    this.verts = stoneBuffer;
                    this.texture = stoneTexture;
                }*/

                this.boxIndices =
                [
                    // Top
                    0, 1, 2,
                    0, 2, 3,
                    // Left
                    5, 4, 6,
                    6, 4, 7,
                    // Right
                    8, 9, 10,
                    8, 10, 11,
                    // Front
                    13, 12, 14,
                    15, 14, 12,
                    // Back
                    16, 17, 18,
                    16, 18, 19,
                    // Bottom
                    21, 20, 22,
                    22, 20, 23
                ];

                this.iBuffer = gl.createBuffer();

                gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.iBuffer);
                gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array(this.boxIndices), gl.STATIC_DRAW);
                gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);   
            }

            render()
            {
                if (this.texture == stoneTexture) {
                    //gl.bindBuffer(gl.ARRAY_BUFFER,brickBuffer);
                    setupIndBuffers(gl, program, stoneBuffer);
                }
                /*else {
                    //gl.bindBuffer(gl.ARRAY_BUFFER,this.crateBuffer);
                    setupIndBuffers(gl, program, brickBuffer);
                }*/

                gl.bindTexture(gl.TEXTURE_2D, this.texture);
                gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.iBuffer);
                var thetaV = [0, 0, 0];
                gl.uniform3fv(this.tranLoc, new Float32Array(this.loc));
                gl.uniform3fv(this.thetaLoc, new Float32Array(thetaV));
                gl.drawElements(gl.TRIANGLES, this.boxIndices.length, gl.UNSIGNED_BYTE, 0);
                gl.bindTexture(gl.TEXTURE_2D, null);    
                gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
                gl.bindBuffer(gl.ARRAY_BUFFER, null);
            }
        }

    </SCRIPT>
    </HEAD>

    <BODY>
        <CANVAS ID = "screen" WIDTH = "800" HEIGHT = "600" ALT = "Your browser does not support canvas."/>
        <IMG ID = "stoneTex" SRC = "stoneWall2.png" WIDTH = "50" HEIGHT = "50" ALT = "tex"/>

    <SCRIPT>
    //Init GL System
    var gl = initializeGL();
    var program = initializeShaders(gl);
    setupVertices(gl, program);
    gl.useProgram(program);
    //var stonePic = document.getElementById("stoneTex");

    // SETUP BRICK BUFFER
    /*var brickBuffer = gl.createBuffer();
    setupIndBuffers(gl, program, brickBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(brickVertices), gl.STATIC_DRAW);
    gl.bindBuffer(gl.ARRAY_BUFFER, null);
    */

    // SETUP STONE BUFFER
    var stoneBuffer = gl.createBuffer();
    setupIndBuffers(gl, program, stoneBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(stoneVertices), gl.STATIC_DRAW);
    gl.bindBuffer(gl.ARRAY_BUFFER, null);

    // Initialize and render actual objects.
    var x = new Cube(true);
    x.loc = [-5, 0, -10];
    //var y = new Cube(false);
    //y.loc = [5, 0, -10];

    var loop = function()
    {
        gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);
        x.render();
        requestAnimationFrame(loop);
    }

    requestAnimationFrame(loop);
    </SCRIPT>
    </BODY>
    </HTML>

1 个答案:

答案 0 :(得分:0)

你做错了不是等待图片加载。 Web浏览器中的图像是异步下载的。这意味着您必须等到他们下载才能调用gl.texImage2D

通常我会做这样的事情

// Create a texture.
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
 
// Fill the texture with a 1x1 blue pixel.
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE,
              new Uint8Array([0, 0, 255, 255]));
 
// Asynchronously load an image
var image = new Image();
image.src = "resources/f-texture.png";
image.addEventListener('load', function() {
  // Now that the image has loaded make copy it to the texture.
  gl.bindTexture(gl.TEXTURE_2D, texture);
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA,gl.UNSIGNED_BYTE, image);
  // if it's a power of 2 in both dimensions then
  // we can generate mips, otherwise we'd have to do other things
  gl.generateMipmap(gl.TEXTURE_2D);
});

texture现在是一个纹理,您可以立即开始渲染它。当图像下载完成后,其内容将被复制到纹理中。此时您需要再次渲染,或者,如果像大多数WebGL应用程序一样,以及问题中的那个,您将继续渲染,那么它将在您的应用下次渲染时自动显示

See these articles