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