WebGL:无法显示两个纹理

WebGL:无法显示两个纹理,webgl,textures,skybox,Webgl,Textures,Skybox,我试图渲染一个纹理立方体(使用顶点、索引和tex坐标),周围有一个纹理天空框(使用立方体贴图),但不知怎的,我总是收到以下错误消息: WebGL:无效的\u操作:bindTexture:纹理不能用于多个目标 我有两种纹理,可能是错误地使用了gl.activeTexture,但我无法理解 如你所见,在天空盒似乎被画上之前,纹理立方体会快速闪烁 带有此代码的临时(24小时)网站: 有什么想法吗 <!-- Licensed under a BSD license. See license.htm

我试图渲染一个纹理立方体(使用顶点、索引和tex坐标),周围有一个纹理天空框(使用立方体贴图),但不知怎的,我总是收到以下错误消息:

WebGL:无效的\u操作:bindTexture:纹理不能用于多个目标

我有两种纹理,可能是错误地使用了gl.activeTexture,但我无法理解

如你所见,在天空盒似乎被画上之前,纹理立方体会快速闪烁

带有此代码的临时(24小时)网站:

有什么想法吗

<!-- Licensed under a BSD license. See license.html for license -->
<!-- src: https://webglfundamentals.org/ -->
<!DOCTYPE html>
<html>
    <head>
        <meta charset = "utf-8">
        <meta name = "viewport" content = "width=device-width, initial-scale=1.0, user-scalable=yes">
        <title> WebGL - Textures - Data Texture 3 x2</title>
        <link type = "text/css" href = "./webgl-tutorials.css" rel = "stylesheet" />
    </head>
    <body>
        <div class = "description">
            A 3 x2 texture <br />
        </div>
        <canvas id = "canvas"></canvas>
    </body>
    <!-- vertex shader -->
    <script id = "3d-vertex-shader" type = "x-shader/x-vertex">
        attribute vec4 a_position;
        attribute vec2 a_texcoord;
        uniform mat4 u_matrix;
        varying vec2 v_texcoord;
        void main()
        {
            // Multiply the position by the matrix.
            gl_Position = u_matrix * a_position;
            // Pass the texcoord to the fragment shader.
            v_texcoord = a_texcoord;
        }
    </script>
    <!-- fragment shader -->
    <script id = "3d-fragment-shader" type = "x-shader/x-fragment">
        precision mediump float;
        // Passed in from the vertex shader.
        varying vec2 v_texcoord;
        // The texture.
        uniform sampler2D u_texture;
        void main()
        {
            gl_FragColor = texture2D(u_texture, v_texcoord);
        }
    </script>
    <!--skybox vertex shader-->
    <script id="skybox-vertex-shader" type="x-shader/x-vertex">
        attribute vec4 a_position;
        varying vec4 v_position;
        void main() 
        {
          v_position = a_position;
          gl_Position = a_position;
        }
    </script>
    <!--skybox fragment shader-->
    <script id="skybox-fragment-shader" type="x-shader/x-fragment">
        precision mediump float;
        uniform samplerCube u_skybox;
        uniform mat4 u_viewDirectionProjectionInverse;
        varying vec4 v_position;
        void main() 
        {
          vec4 t = u_viewDirectionProjectionInverse * v_position;
          gl_FragColor = textureCube(u_skybox, normalize(t.xyz / t.w));
        }
    </script>
    <script src = "./webgl-utils.js"></script>
    <script src = "./m4.js"></script>
    <script src = "./primitives.js"></script>
    <script type = "module">
        "use strict";
        function main()
        {
            // Get A WebGL context
            /** @type {HTMLCanvasElement} */
            var canvas = document.getElementById("canvas");
            var gl = canvas.getContext("webgl");
            if (!gl)
            {
                return;
            }
            // setup GLSL program
            var program = webglUtils.createProgramFromScripts(gl, ["3d-vertex-shader", "3d-fragment-shader"]);
            // look up where the vertex data needs to go.
            var positionLocation = gl.getAttribLocation(program, "a_position");
            var texcoordLocation = gl.getAttribLocation(program, "a_texcoord");
            // lookup uniforms
            var matrixLocation = gl.getUniformLocation(program, "u_matrix");
            var textureLocation = gl.getUniformLocation(program, "u_texture");

            //create program for skybox
            const skyboxProgramInfo = webglUtils.createProgramInfo(gl, ["skybox-vertex-shader", "skybox-fragment-shader"]);
            var sb_textureLocation = gl.getUniformLocation(skyboxProgramInfo.program, "u_skybox");
            // create buffers and fill with vertex data
            const cubeBufferInfo = primitives.createCubeBufferInfo(gl, 1);
            const quadBufferInfo = primitives.createXYQuadBufferInfo(gl);
            // Create a texture.
            const sb_texture = gl.createTexture();
            gl.activeTexture(gl.TEXTURE0 + 1);
            gl.bindTexture(gl.TEXTURE_CUBE_MAP, sb_texture);
            const faceInfos = 
            [
                { target: gl.TEXTURE_CUBE_MAP_POSITIVE_X, url: './pos-x.jpg', },
                { target: gl.TEXTURE_CUBE_MAP_NEGATIVE_X, url: './neg-x.jpg', },
                { target: gl.TEXTURE_CUBE_MAP_POSITIVE_Y, url: './pos-y.jpg', },
                { target: gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, url: './neg-y.jpg', },
                { target: gl.TEXTURE_CUBE_MAP_POSITIVE_Z, url: './pos-z.jpg', },
                { target: gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, url: './neg-z.jpg', },
            ];
            faceInfos.forEach((faceInfo) => 
            {
                const {target, url} = faceInfo;
                // Upload the canvas to the cubemap face.
                const level = 0;
                const internalFormat = gl.RGBA;
                const width = 512;
                const height = 512;
                const format = gl.RGBA;
                const type = gl.UNSIGNED_BYTE;
                // setup each face so it's immediately renderable
                gl.texImage2D(target, level, internalFormat, width, height, 0, format, type, null);
                // Asynchronously load an image
                const image = new Image();
                image.src = url;
                image.addEventListener('load', function() 
                {
                    // Now that the image has loaded make copy it to the skybox texture.
                    gl.activeTexture(gl.TEXTURE0 + 1);
                    gl.bindTexture(gl.TEXTURE_CUBE_MAP, sb_texture);
                    gl.texImage2D(target, level, internalFormat, format, type, image);
                    gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
                });
            });
            gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
            gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);


            // Create a buffer for positions
            var positionBuffer = gl.createBuffer();
            // Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer)
            gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
            // Put the positions in the buffer
            setGeometry(gl);

            // Create a buffer for positions
            var indexBuffer = gl.createBuffer();
            // Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer)
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
            // Put the positions in the buffer
            setIndices(gl);

            // provide texture coordinates for the rectangle.
            var texcoordBuffer = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);
            // Set Texcoords.
            setTexcoords(gl);
            // Create a texture.
            var texture = gl.createTexture();
            //void gl.bindTexture(target, texture);
            gl.activeTexture(gl.TEXTURE0);
            gl.bindTexture(gl.TEXTURE_2D, texture);
            // fill texture with 3x2 pixels
            const level = 0;
            const internalFormat = gl.RGB;
            const width = 2;                
            const height = 2;               
            const border = 0;
            const format = gl.RGB;          
            const type = gl.UNSIGNED_BYTE;
            const data = new Uint8Array     
            ([
                255, 0, 0,      0, 255, 0,
                0, 0, 255,      128, 128, 128,
            ]);
            const alignment = 1;
            gl.pixelStorei(gl.UNPACK_ALIGNMENT, alignment);
            gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, width, height, border, format, type, data);
            // set the filtering so we don't need mips and it's not filtered
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
            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);

            function degToRad(d)
            {
                return d * Math.PI / 180;
            }
            var fieldOfViewRadians = degToRad(60);
            var modelXRotationRadians = degToRad(0);
            var modelYRotationRadians = degToRad(0);
            // Get the starting time.
            var then = 0;
            requestAnimationFrame(drawScene);
            // Draw the scene.
            function drawScene(time)
            {
                // convert to seconds
                time *= 0.001;
                // Subtract the previous time from the current time
                var deltaTime = time - then;
                // Remember the current time for the next frame.
                then = time;
                webglUtils.resizeCanvasToDisplaySize(gl.canvas);
                // Tell WebGL how to convert from clip space to pixels
                gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
                gl.enable(gl.CULL_FACE);
                gl.enable(gl.DEPTH_TEST);
                // Animate the rotation
                modelYRotationRadians += -0.7 * deltaTime;
                modelXRotationRadians += -0.4 * deltaTime;
                // Clear the canvas AND the depth buffer.
                gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
                // Tell it to use our program (pair of shaders)
                gl.useProgram(program);

                // Turn on the position attribute
                gl.enableVertexAttribArray(positionLocation);
                // Bind the position buffer.
                gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
                // Tell the position attribute how to get data out of positionBuffer (ARRAY_BUFFER)
                var size = 3; // 3 components per iteration
                var type = gl.FLOAT; // the data is 32bit floats
                var normalize = false; // don't normalize the data
                var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
                var offset = 0; // start at the beginning of the buffer
                gl.vertexAttribPointer( positionLocation, size, type, normalize, stride, offset);

                // Turn on the teccord attribute
                gl.enableVertexAttribArray(texcoordLocation);
                // Bind the position buffer.
                gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);
                // Tell the position attribute how to get data out of positionBuffer (ARRAY_BUFFER)
                var size = 2; // 2 components per iteration
                var type = gl.FLOAT; // the data is 32bit floats
                var normalize = false; // don't normalize the data
                var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
                var offset = 0; // start at the beginning of the buffer
                gl.vertexAttribPointer( texcoordLocation, size, type, normalize, stride, offset);

                // Compute the projection matrix
                var aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
                var projectionMatrix = m4.perspective(fieldOfViewRadians, aspect, 1, 2000);
                var cameraPosition = [0, 0, 2];
                var up = [0, 1, 0];
                var target = [0, 0, 0];
                // Compute the camera's matrix using look at.
                var cameraMatrix = m4.lookAt(cameraPosition, target, up);
                // Make a view matrix from the camera matrix.
                var viewMatrix = m4.inverse(cameraMatrix);
                var viewProjectionMatrix = m4.multiply(projectionMatrix, viewMatrix);
                var matrix = m4.xRotate(viewProjectionMatrix, modelXRotationRadians);
                matrix = m4.yRotate(matrix, modelYRotationRadians);
                // Set the matrix.
                gl.uniformMatrix4fv(matrixLocation, false, matrix);
                // Tell the shader to use texture unit 0 for u_texture
                gl.uniform1i(textureLocation, 0);
                // Draw the geometry.
                gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);

                // Skybox: we only care about direction so remove the translation
                var viewDirectionMatrix = m4.copy(viewMatrix);
                viewDirectionMatrix[12] = 0;
                viewDirectionMatrix[13] = 0;
                viewDirectionMatrix[14] = 0;
                var viewDirectionProjectionMatrix = m4.multiply(projectionMatrix, viewDirectionMatrix);
                var viewDirectionProjectionInverseMatrix = m4.inverse(viewDirectionProjectionMatrix);
                // draw the skybox
                gl.useProgram(skyboxProgramInfo.program);
                webglUtils.setBuffersAndAttributes(gl, skyboxProgramInfo, quadBufferInfo);
                webglUtils.setUniforms(skyboxProgramInfo, {
                  u_viewDirectionProjectionInverse: viewDirectionProjectionInverseMatrix,
                  u_skybox: texture,
                });
                // Tell the shader to use texture unit 0 for u_texture
                gl.uniform1i(sb_textureLocation, 1);
                webglUtils.drawBufferInfo(gl, quadBufferInfo);

                requestAnimationFrame(drawScene);
            }
        }

        // Fill the buffer with the values that define a cube.
        function setGeometry(gl)
        {
            var positions = new Float32Array
            ([  
                // Front face
                -0.5, -0.5,  0.5,
                 0.5, -0.5,  0.5,
                 0.5,  0.5,  0.5,
                -0.5,  0.5,  0.5,
                // Back face
                -0.5, -0.5, -0.5,
                -0.5,  0.5, -0.5,
                 0.5,  0.5, -0.5,
                 0.5, -0.5, -0.5,
                // Top face
                -0.5,  0.5, -0.5,
                -0.5,  0.5,  0.5,
                 0.5,  0.5,  0.5,
                 0.5,  0.5, -0.5,
                // Bottom face
                -0.5, -0.5, -0.5,
                 0.5, -0.5, -0.5,
                 0.5, -0.5,  0.5,
                -0.5, -0.5,  0.5,
                // Right face
                 0.5, -0.5, -0.5,
                 0.5,  0.5, -0.5,
                 0.5,  0.5,  0.5,
                 0.5, -0.5,  0.5,
                // Left face
                -0.5, -0.5, -0.5,
                -0.5, -0.5,  0.5,
                -0.5,  0.5,  0.5,
                -0.5,  0.5, -0.5,
            ]);
            gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
        }

        // Fill the buffer with texture coordinates the cube.
        function setTexcoords(gl)
        {
            gl.bufferData
            (
                gl.ARRAY_BUFFER,
                new Float32Array
                ([
                    // Front
                    0.0,  0.0,
                    1.0,  0.0,
                    1.0,  1.0,
                    0.0,  1.0,
                    // Back
                    0.0,  0.0,
                    1.0,  0.0,
                    1.0,  1.0,
                    0.0,  1.0,
                    // Top
                    0.0,  0.0,
                    1.0,  0.0,
                    1.0,  1.0,
                    0.0,  1.0,
                    // Bottom
                    0.0,  0.0,
                    1.0,  0.0,
                    1.0,  1.0,
                    0.0,  1.0,
                    // Right
                    0.0,  0.0,
                    1.0,  0.0,
                    1.0,  1.0,
                    0.0,  1.0,
                    // Left
                    0.0,  0.0,
                    1.0,  0.0,
                    1.0,  1.0,
                    0.0,  1.0,
                ]),
            gl.STATIC_DRAW);
        }


        // Fill the buffer with vertex indices
        function setIndices(gl)
        {
            var indices = new Uint16Array
            ([  
                0,  1,  2,      0,  2,  3,    // front
                4,  5,  6,      4,  6,  7,    // back
                8,  9,  10,     8,  10, 11,   // top
                12, 13, 14,     12, 14, 15,   // bottom
                16, 17, 18,     16, 18, 19,   // right
                20, 21, 22,     20, 22, 23,   // left
            ]);
            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
        }

        main();
    </script>
</html>

WebGL-纹理-数据纹理3 x2
3×2纹理
属性向量4 a_位置; 属性向量2 a_texcoord; 均匀mat4u_矩阵; 可变矢量2 v_texcoord; void main() { //将位置乘以矩阵。 gl_位置=u_矩阵*a_位置; //将texcoord传递给片段着色器。 v_texcoord=a_texcoord; } 精密中泵浮子; //从顶点着色器传入。 可变矢量2 v_texcoord; //纹理。 均匀的二维u_纹理; void main() { gl_FragColor=纹理2D(u_纹理,v_texcoord); } 属性向量4 a_位置; 可变vec4 v_位置; void main() { v_位置=a_位置; gl_位置=a_位置; } 精密中泵浮子; 统一采样立方体u_天空盒; 均匀mat4 u_视图方向投影反转; 可变vec4 v_位置; void main() { vec4 t=u_视图方向投影反转*v_位置; gl_FragColor=textureCube(u_skybox,normalize(t.xyz/t.w)); } “严格使用”; 函数main() { //获取WebGL上下文 /**@type{HTMLCanvasElement}*/ var canvas=document.getElementById(“canvas”); var gl=canvas.getContext(“webgl”); 如果(!gl) { 回来 } //安装GLSL程序 var program=webglUtils.createProgramFromScripts(gl,[“3d顶点着色器”、“3d片段着色器”]); //查找顶点数据需要去的地方。 var positionLocation=gl.GetAttriblLocation(程序,“a_位置”); var texcoordLocation=gl.getAttribLocation(程序,“a_texcoord”); //查找制服 var matrixLocation=gl.getUniformLocation(程序,“u_矩阵”); var textureLocation=gl.getUniformLocation(程序,“u_纹理”); //为skybox创建程序 const skyboxProgramInfo=webglUtils.createProgramInfo(gl,[“SkyboxVertex着色器”、“SkyboxFragment着色器”]); var sb_textureLocation=gl.getUniformLocation(skyboxProgramInfo.program,“u_skybox”); //创建缓冲区并用顶点数据填充 const cubeBufferInfo=primitives.createCubeBufferInfo(gl,1); const quadBufferInfo=primitives.createXYQuadBufferInfo(gl); //创建一个纹理。 const sb_texture=gl.createTexture(); gl.activeTexture(gl.TEXTURE0+1); gl.bindTexture(gl.TEXTURE\u CUBE\u MAP,sb\u TEXTURE); 常量faceInfos= [ {目标:gl.TEXTURE\u CUBE\u MAP\u POSITIVE\u X,url:'./pos-X.jpg',}, {目标:gl.TEXTURE\u CUBE\u MAP\u NEGATIVE\u X,url:'./neg-X.jpg',}, {目标:gl.TEXTURE\u CUBE\u MAP\u POSITIVE\u Y,url:'./pos-Y.jpg',}, {目标:gl.TEXTURE\u CUBE\u MAP\u NEGATIVE\u Y,url:'./neg-Y.jpg',}, {目标:gl.TEXTURE\u CUBE\u MAP\u POSITIVE\u Z,url:'./pos-Z.jpg',}, {目标:gl.TEXTURE_CUBE_MAP_NEGATIVE_Z,url:'./neg-Z.jpg',}, ]; faceInfos.forEach((faceInfo)=> { const{target,url}=faceInfo; //将画布上载到立方体贴图面。 常数级=0; const internalFormat=gl.RGBA; 常数宽度=512; 常数高度=512; 常量格式=gl.RGBA; 常量类型=gl.无符号字节; //设置每个面,使其立即可渲染 gl.texImage2D(目标、级别、内部格式、宽度、高度、0、格式、类型、空); //异步加载映像 常量图像=新图像(); image.src=url; image.addEventListener('load',function()) { //现在图像已加载,请将其复制到skybox纹理。 gl.activeTexture(gl.TEXTURE0+1); gl.bindTexture(gl.TEXTURE\u CUBE\u MAP,sb\u TEXTURE); gl.texImage2D(目标、级别、内部格式、格式、类型、图像); gl.generateMipmap(gl.TEXTURE\u CUBE\u MAP); }); }); gl.generateMipmap(gl.TEXTURE\u CUBE\u MAP); gl.texParameteri(gl.TEXTURE\u CUBE\u MAP、gl.TEXTURE\u MIN\u FILTER、gl.LINEAR\u MIPMAP\u LINEAR); //为位置创建缓冲区 var positionBuffer=gl.createBuffer(); //将其绑定到ARRAY\u BUFFER(将其视为ARRAY\u BUFFER=positionBuffer) gl.bindBuffer(gl.ARRAY\u BUFFER,positionBuffer); //把位置放在缓冲器里 集合几何(gl); //为位置创建缓冲区 var indexBuffer=gl.createBuffer(); //将其绑定到ARRAY\u BUFFER(将其视为ARRAY\u BUFFER=positionBuffer) gl.bindBuffer(gl.ELEMENT\u ARRAY\u BUFFER,indexBuffer); //把位置放在缓冲器里
      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.uniform1i(sb_textureLocation, 1);
        webglUtils.setUniforms(skyboxProgramInfo, {
          u_viewDirectionProjectionInverse: viewDirectionProjectionInverseMatrix,
          u_skybox: texture,      // wrong---------------
          u_skybox: sb_texture,   // right---------------
        });
      webglUtils.setBuffersAndAttributes(gl, skyboxProgramInfo, quadBufferInfo);
        webglUtils.setUniforms(skyboxProgramInfo, {
          u_viewDirectionProjectionInverse: viewDirectionProjectionInverseMatrix,
          u_skybox: texture,
        });
 gl.uniformMatrix4fv(u_viewDirectionProjectionInverseLocation, false, viewDirectionProjectionInverseMatrix);
 gl.activeTexture(gl.TEXTURE0 + 0);
 gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
 gl.uniform1i(u_skyboxLocation, 0);
For each texture the shaders used by the next draw call need
    gl.activeTexture(gl.TEXTURE0 + n);
    gl.bindTexture(targetTypeForTexture, texture);
    gl.uniform1i(n);