WEBGL中的着色器变量包括以下种类:
- 属性变量(Attribute Variables):这些变量用于接收从应用程序中传递的顶点数据,比如顶点位置和颜色,是只读的不可修改。
- 统一变量(Uniform Variables):这些变量是着色器中的全局变量,用于接收从应用程序中传递的值,比如投影矩阵,旋转矩阵等。
- 纹理坐标变量(Texture Coordinate Variables):这些变量用于指定在纹理图像中采样的位置。
- 法线向量变量(Normal Vector Variables):这些变量用于计算光照效果,用于标识几何体表面的法向量。
- 输出变量(Output Variables):这些变量用于将着色器的输出传递给渲染管线的下一阶段,比如像素着色器的颜色值。
一、varying变量
1.varying变量定义
在WebGL中,varying变量是在顶点着色器和片元着色器之间传递数据的一种特殊类型的变量。它们被用于在顶点着色器和片元着色器之间传递信息,以便在渲染过程中进行插值。在顶点着色器中,varying变量的值被计算并传递到片元着色器中,然后在片元着色器中进行插值,然后被用来确定要绘制的像素的颜色。
Varying变量通常被用于将光照和纹理坐标等信息从顶点着色器传递到片元着色器中。由于它们是在渲染过程中插值的,所以它们可以用来创建平滑的过渡,使得渲染出来的图像更加真实和细腻。
例如,如果你想在三角形中使用纹理映射,那么你需要将纹理坐标从顶点着色器传递到片元着色器中。你可以通过定义一个varying变量来传递这个纹理坐标,然后在片元着色器中使用它来获取纹理的颜色,从而创建一个真实的纹理映射效果。
2.varying执行流程
在WebGL中,varying变量用于在顶点着色器和片元着色器之间传递数据。它们的执行原理如下:
- 在顶点着色器中声明一个varying变量,并对其进行赋值。
- 这个varying变量的值会被传递到片元着色器中。
- 在片元着色器中,可以通过读取这个varying变量的值来进行后续的计算。
- 由于每个像素都会执行片元着色器,因此varying变量的值也会被相应地插值,以便在不同像素之间进行平滑的过渡。
- 最终的像素颜色将由片元着色器中的计算结果和其他因素(如光照)共同决定。
varying变量的执行原理是通过在顶点着色器和片元着色器之间传递数据,使得像素颜色可以根据这些数据进行计算。
3.使用varying绘制彩色三角形
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>varying变量</title>
<script src="../../lib/index.js"></script>
<style>
* {
margin: 0;
padding: 0;
}
canvas {
margin: 50px auto 0;
display: block;
background: yellow;
}
</style>
</head>
<body>
<canvas id="canvas" width="400" height="400">
此浏览器不支持webGL
</canvas>
</body>
</html>
<script>
const ctx = document.getElementById('canvas')
const gl = ctx.getContext('webgl');
//着色器
//创建着色器源码
const VERTEX_SHADER_SOURCE = `
attribute vec4 aPosition;
//需要同时在顶点和片元着色器中声明,将数据从顶点着色器传递到片元着色器
varying vec4 vColor;
void main(){
vColor = aPosition;
//要绘制的坐标
gl_Position = aPosition;
//要绘制的大小(着色器变量使用的是浮点型)
gl_PointSize = 10.0;
}
`; //顶点着色器
const FRAGMENT_SHADER_SOURCE = `
precision lowp float;
varying vec4 vColor;
void main(){
//要绘制的颜色
gl_FragColor = vColor;
}
`; //片元着色器
const program = initShader(gl,VERTEX_SHADER_SOURCE,FRAGMENT_SHADER_SOURCE)
const aPosition = gl.getAttribLocation(program, 'aPosition')
const points = new Float32Array([
-0.5,-0.5,
0.5,-0.5,
0.0,0.5,
])
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
gl.bufferData(gl.ARRAY_BUFFER,points,gl.STATIC_DRAW)
gl.vertexAttribPointer(aPosition,2,gl.FLOAT,false,0,0);
gl.enableVertexAttribArray(aPosition)
gl.drawArrays(gl.TRIANGLES,0,3)
</script>
二、使用纹理渲染图片背景
1.创建纹理对象
纹理对象主要用于存储纹理图像数据。
const texture = gl.createTexture();
同时也可以通过gl.deleteTexture(texture)来删除纹理对象。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>渲染图片背景</title>
<script src="../../lib/index.js"></script>
<style>
* {
margin: 0;
padding: 0;
}
canvas {
margin: 50px auto 0;
display: block;
background: yellow;
}
</style>
</head>
<body>
<canvas id="canvas" width="400" height="400">
此浏览器不支持webGL
</canvas>
</body>
</html>
<script>
const ctx = document.getElementById('canvas')
const gl = ctx.getContext('webgl');
//着色器
//创建着色器源码
const VERTEX_SHADER_SOURCE = `
attribute vec4 aPosition;
attribute vec4 aTex;
varying vec2 vTex;
void main(){
//要绘制的坐标
gl_Position = aPosition;
vTex = vec2(aTex.x,aTex.y);
}
`; //顶点着色器
const FRAGMENT_SHADER_SOURCE = `
precision lowp float;
uniform sampler2D uSampler;
//纹理坐标
varying vec2 vTex;
void main(){
//要绘制的颜色
gl_FragColor = texture2D(uSampler,vTex);
}
`; //片元着色器
const program = initShader(gl,VERTEX_SHADER_SOURCE,FRAGMENT_SHADER_SOURCE)
const aPosition = gl.getAttribLocation(program, 'aPosition')
const aTex = gl.getAttribLocation(program, 'aTex')
const uSampler = gl.getUniformLocation(program, 'uSampler')
const points = new Float32Array([
-0.5,0.5,0.0,1.0,
-0.5,-0.5,0.0,0.0,
0.5,0.5,1.0,1.0,
0.5,-0.5,1.0,0.0,
])
const buffer = gl.createBuffer();
const BYTES = points.BYTES_PER_ELEMENT;
gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
gl.bufferData(gl.ARRAY_BUFFER,points,gl.STATIC_DRAW)
gl.vertexAttribPointer(aPosition,2,gl.FLOAT,false,BYTES*4,0);
gl.vertexAttribPointer(aTex,2,gl.FLOAT,false,BYTES*4,BYTES*2);
gl.enableVertexAttribArray(aPosition)
gl.enableVertexAttribArray(aTex)
const img = new Image();
img.onload = function(){
console.log("加载图片",img)
//创建纹理图像存储纹理数据
const texture = gl.createTexture();
//翻转 图片 Y轴
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1)
//开启一个纹理单元
gl.activeTexture(gl.TEXTURE0);
//绑定纹理对象gl.bindTexture(type,texture)
/*type有两种类型
gl.TEXTURE_2D:二维纹理
gl.TEXTURE_CUBE_MAP:立方体纹理
*/
gl.bindTexture(gl.TEXTURE_2D,texture);
//处理放大缩小的逻辑gl.texParamteri(type,pname,param)
/*type 同上
pname:gl.TEXTURE_MAG_FILTER 放大
gl.TEXTURE_MIN_FILTER 缩小
gl.TEXTURE_WRAP_S 横向(水平填充)
gl.TEXTURE_WRAP_T 纵向(垂直填充)
param:设置给放大和缩小的有 gl.NEAREST 使用像素颜色值
gl.LINEAR 使用四周的加权平均值
设置给填充的有 gl.REPEAT 平铺重复
gl.MIRRORED_REPEAT 镜像对称
gl.CLAMP_TO_EDGE 边缘延伸
*/
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_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);
//配置纹理图集gl.texImage2D(type,level,internalformat,format,dataType,image)
/*
internalformat:图像的内部格式 gl.RGB, gl.RGBA,gl.ALPHA,gl.LUMINANCE(使用物体表面的红绿蓝分量的加权平均值来计算),gl.LUMINANCE_ALPHA
format:纹理的内部格式,必须和internalformat相同
dataType: 纹理的数据类型 gl.UNSIGNED_BYTE,gl.UNSIGNED_SHORT_5_6_5,gl.UNSIGNED_SHORT_4_4_4_4,gl.UNSIGNED_SHORT_5_5_5_1,
*/
gl.texImage2D(gl.TEXTURE_2D,0,gl.RGB,gl.RGB,gl.UNSIGNED_BYTE,img);
gl.uniform1i(uSampler,0)
gl.drawArrays(gl.TRIANGLE_STRIP,0,4)
}
img.src = "../../picture/test.jpg";
</script>
三、使用多重纹理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>使用多重纹理</title>
<script src="../../lib/index.js"></script>
<style>
* {
margin: 0;
padding: 0;
}
canvas {
margin: 50px auto 0;
display: block;
background: yellow;
}
</style>
</head>
<body>
<canvas id="canvas" width="400" height="400">
此浏览器不支持webGL
</canvas>
</body>
</html>
<script>
const ctx = document.getElementById('canvas')
const gl = ctx.getContext('webgl');
//着色器
//创建着色器源码
const VERTEX_SHADER_SOURCE = `
attribute vec4 aPosition;
attribute vec4 aTex;
varying vec2 vTex;
void main(){
//要绘制的坐标
gl_Position = aPosition;
vTex = vec2(aTex.x,aTex.y);
}
`; //顶点着色器
const FRAGMENT_SHADER_SOURCE = `
precision lowp float;
uniform sampler2D uSampler1;
uniform sampler2D uSampler2;
//纹理坐标
varying vec2 vTex;
void main(){
vec4 c1 = texture2D(uSampler1,vTex);
vec4 c2 = texture2D(uSampler2,vTex);
gl_FragColor = c1*c2;
}
`; //片元着色器
const program = initShader(gl,VERTEX_SHADER_SOURCE,FRAGMENT_SHADER_SOURCE)
const aPosition = gl.getAttribLocation(program, 'aPosition')
const aTex = gl.getAttribLocation(program, 'aTex')
const uSampler1 = gl.getUniformLocation(program, 'uSampler1')
const uSampler2 = gl.getUniformLocation(program, 'uSampler2')
const points = new Float32Array([
-0.5,0.5,0.0,1.0,
-0.5,-0.5,0.0,0.0,
0.5,0.5,1.0,1.0,
0.5,-0.5,1.0,0.0,
])
const buffer = gl.createBuffer();
const BYTES = points.BYTES_PER_ELEMENT;
gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
gl.bufferData(gl.ARRAY_BUFFER,points,gl.STATIC_DRAW)
gl.vertexAttribPointer(aPosition,2,gl.FLOAT,false,BYTES*4,0);
gl.vertexAttribPointer(aTex,2,gl.FLOAT,false,BYTES*4,BYTES*2);
gl.enableVertexAttribArray(aPosition)
gl.enableVertexAttribArray(aTex)
Promise.all([getImage(gl,"../../picture/test.jpg",uSampler1,0),
getImage(gl,"../../picture/test2.jpeg",uSampler2,1)])
.then(()=>{
gl.drawArrays(gl.TRIANGLE_STRIP,0,4)
})
</script>
要叠加的图片