引言
基于之前的知识,这里主要是
- 将顶点的其他数据--如颜色等-传入顶点着色器
- 图元光栅化--在顶点着色器和片元着色器之间的从图形到片元的转化
- 将纹理映射到图形或三维对象的表面上
颜色
三角形颜色
在之前的例子中,我们绘制了三角形的图形,并给它填充了颜色,如果想要颜色是渐变的,则可以把颜色和顶点类似在不同的顶点上设置不同的颜色向量值。
着色器中
const VSHADER_SOURCE = `
attribute vec4 a_position;
attribute vec4 aColor;
varying vec4 vColor;
void main(void){
gl_Position=a_position;
vColor = aColor;
}
`
const FSHADER_SOURCE = `
precision mediump float;
varying vec4 vColor;
void main() {
gl_FragColor = vColor;
}
`
定义了aColor
属性,这样可以再去设置不同顶点上对应的颜色值
let aPsotion = webgl.getAttribLocation(webgl.program, "a_position")
let arr = [
-0.5, 0.5, 0.0, 1.0, 0.0, 0.0, 1.0, // 左上角,红色
-0.5, -0.5, 0.0, 0.0, 1.0, 0.0, 1.0, // 左下角,绿色
0.5, -0.5, 0.0, 0.0, 0.0, 1.0, 1.0, // 右下角,蓝色
]
let vertexArr = new Float32Array(arr)
let trangleBuffer = webgl.createBuffer()
webgl.bindBuffer(webgl.ARRAY_BUFFER, trangleBuffer)
webgl.bufferData(webgl.ARRAY_BUFFER, vertexArr, webgl.STATIC_DRAW)
webgl.enableVertexAttribArray(aPsotion)
webgl.vertexAttribPointer(aPsotion, 3, webgl.FLOAT, false, 7 * Float32Array.BYTES_PER_ELEMENT, 0)
const colorAttributeLocation = webgl.getAttribLocation(webgl.program, "aColor");
webgl.vertexAttribPointer(colorAttributeLocation, 4, webgl.FLOAT, false, 7 * Float32Array.BYTES_PER_ELEMENT, 3 * Float32Array.BYTES_PER_ELEMENT);
webgl.enableVertexAttribArray(colorAttributeLocation);
在这里有两个大的步骤
- 图形装配过程:将顶点坐标构成几何图形
- 光栅化过程:将图形转化成片元
在光栅化结束后,程序开始逐个的片元调用片元着色器, 那么在这三个点之间的颜色,WebGL系统用这3个顶点的颜色内插出来的,这个过程被称为内插过程
具体解析: 在顶点着色器中,三角形的3个顶点的颜色赋给varying
变量v_Color
,然后片元着色器中的varying
变量v_Color
就接收到了内插之后的片元颜色,在片元着色器中,我们把片元的颜色赋值给gl_FragColor
变量,这样就绘制出了一个彩色的三角形。
纹理
什么是纹理?
可以形象的理解成某个物体的“皮肤”,而这个“皮肤”可以看成是一张图片,而这张图片中每一个点是一个片元(纹素),每个片元上涂上合适的颜色。
术语:贴图或是纹理映射
- 准备好需要映射到物体上的纹理图像,例如
PNG
、BMP
、DDS
、HDR
等 - 给几何图形配置的纹理映射方式
- 加载纹理图像,并进行配置,以在
WebGL
中使用 - 在片元着色器中将相应的纹素从纹理中抽取出来,并将纹素中的颜色通过片元进行绘制
纹理坐标
纹理坐标是纹理图像上的坐标,通过纹理坐标可以在纹理图像上获取纹素颜色,WebGL
系统中纹理坐标是二维的,简称st坐标系统
注意:纹理坐标和区域坐标的关系
const vertices = [
// 顶点坐标 // 纹理坐标
-0.5, 0.5, 0.0, 0.0, 1.0, // 左上角
0.5, 0.5, 0.0, 1.0, 1.0, // 右上角
0.5, -0.5, 0.0, 1.0, 0.0, // 右下角
-0.5, -0.5, 0.0, 0.0, 0.0 // 左下角
];
这样你在脑海中就有一个概念了,顶点坐标和纹理坐标的关系映射。 当我们在区域内绘制了纹理图像,你会发现,这个图片和原来的图片是旋转了90°,这个又涉及到了一个概念:图片坐标
特别说明: 图片坐标
以左上角为原点,向右为x轴正方向,向下为y轴正方向。也就是说,对于一个像素点(x,y),x表示横坐标,y表示纵坐标,坐标轴的方向如下图所示:
(0,0)----------------> x
|
|
|
|
v
y
但WebGL
中的坐标向上为y轴正方向,所以导致图片是倒立的。
解决方案
先把解决办法给出来吧,两张方式,选取一种即可
- 在图片的
onload
方法中:webgl.pixelStorei(webgl.UNPACK_FLIP_Y_WEBGL, 1)
- 在片元着色器中
gl_FragColor = texture2D(u_texture, vec2(v_texcoord.x, 1.0 - v_texcoord.y));
其目的都是对纹理图像进行Y轴(T轴)的反转
纹理图像
类似于蒙版效果
实现过程
- 顶点着色器中点的坐标绘制区域
- 纹理坐标用来装图片
- 通过纹理映射
texture2D
将区域换上“皮肤”
着色器设置
const VSHADER_SOURCE = `
attribute vec2 a_position;
varying vec2 v_texcoord;
void main() {
gl_Position = vec4(a_position, 0.0, 1.0);
v_texcoord = a_position * 0.5 + 0.5;
}
`
const FSHADER_SOURCE = `
precision mediump float;
uniform sampler2D u_texture;
varying vec2 v_texcoord;
void main() {
gl_FragColor = texture2D(u_texture, vec2(v_texcoord.x, 1.0 - v_texcoord.y));
}
`
着色器中使用sampler2D
类型的变量来访问纹理数据
看看核心的方法
const texture = webgl.createTexture()
const image = new Image()
image.src = ''
texture.image = image
image.onload = function () {
webgl.bindTexture(webgl.TEXTURE_2D, texture)
webgl.texParameteri(
webgl.TEXTURE_2D,
webgl.TEXTURE_WRAP_S,
webgl.CLAMP_TO_EDGE
)
webgl.texParameteri(
webgl.TEXTURE_2D,
webgl.TEXTURE_WRAP_T,
webgl.CLAMP_TO_EDGE
)
webgl.texParameteri(
webgl.TEXTURE_2D,
webgl.TEXTURE_MIN_FILTER,
webgl.LINEAR
)
webgl.texImage2D(
webgl.TEXTURE_2D,
0,
webgl.RGBA,
webgl.RGBA,
webgl.UNSIGNED_BYTE,
texture.image
)
const textureLoc = webgl.getUniformLocation(webgl.program, 'u_texture');
webgl.uniform1i(textureLoc, 0);
draw()
webgl.drawArrays(webgl.TRIANGLE_STRIP, 0, 4);
}
texParameteri() 设置纹理图片的参数
参数:
TEXTURE_WRAP_T
、CLAMP_TO_EDGE
: 设置纹理 S/T 轴方向上的边缘环绕方式为 CLAMP_TO_EDGE,即在超出边缘的部分使用纹理边缘的像素颜色填充.- TEXTURE_MIN_FILTER、
LINEAR
: 设置纹理的缩小过滤方式为 LINEAR,即当纹理需要被缩小时,使用线性过滤的方式得到缩小后的像素颜色值.
texImage2D 加载纹理图片
- 第一个参数是纹理类型
- 第二个参数是细节级别
- 第三个参数是纹理格式
- 第四个参数也是纹理格式
- 第五个参数是纹理数据的类型
- 最后一个参数是要加载的纹理图片
这里使用了 RGBA 格式,表示红、绿、蓝和透明度,使用 UNSIGNED_BYTE 数据类型,表示每个颜色分量使用一个字节存储
uniform1i()
- location:表示要传递给哪个
uniform
变量的位置 - value:表示要传递的整数值
注意哦! 这里的value
可不能随便个整数
在WebGL中,纹理单元编号从0开始,最多可以使用16个纹理单元。因此,如果你想使用第一个纹理单元,就需要将value设置为0;如果你想使用第二个纹理单元,就需要将value设置为1
本想把多重纹理放在这一篇,但发现篇幅会很长,所以放在了下一篇,主要实现多个图片的叠加,当然是在纹理层面上的叠加了。
我们可以先看看效果
以上就是WebGL 颜色与纹理使用介绍的详细内容,更多关于WebGL 颜色纹理的资料请关注编程网其它相关文章!