一、简介
采用纯WebGL实现纹理贴图,并修改shader,对比Cesium中的实现,从而感受Cesium对WebGL的封装,以及用法上的异同点。
可以对比Cesium 中的Shader解析1https://blog.csdn.net/u014556081/article/details/124577509中用Cesium实现相同功能代码。
二、代码
<!--
纹理映射的过程需要顶点着色器和片元着色器二者的配合:首先在顶点着色器中为每个顶点指定纹理坐标,
然后在片元着色器中根据每个片元的纹理坐标从纹理图像中抽取纹素颜色。
程序主要包括五个部分,已经在代码中用数字标记了出来。
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../lib/webgl-utils.js"></script>
<script src="../lib/webgl-debug.js"></script>
<script src="../lib/cuon-utils.js"></script>
<script src="../lib/cuon-matrix.js"></script>
</head>
<body onload="main()">
<canvas id="webgl" width="400" height="400">
Please use a browser that supports "canvas"
</canvas>
<script>
var VSHADER_SOURCE = /* glsl */ `
attribute vec4 a_Position;
attribute vec2 a_TexCoord;
varying vec2 v_TexCoord;
void main(){
gl_Position=a_Position;
v_TexCoord=a_TexCoord;
}
`;
var FSHADER_SOURCE = /* glsl */ `
#ifdef GL_ES
precision mediump float;
#endif
uniform sampler2D u_Sampler;
uniform float color2;
varying vec2 v_TexCoord;
void main(){
vec4 color =texture2D(u_Sampler,v_TexCoord);
vec2 center=vec2(0.5,0.5);
vec2 pos=vec2(gl_FragCoord.x/400.0,gl_FragCoord.y/400.0);
float dis=distance(center,pos);
if(dis>0.25){
color=vec4(vec3(0),1.0);
}
if(dis<0.1){
color=vec4(vec3(0),1.0);
}
gl_FragColor=color;
}
`;
// 内置变量gl_FragCoord表示WebGL在canvas画布上渲染的所有片元或者说像素的坐标,
// 坐标原点是canvas画布的左上角,x轴水平向右,y竖直向下,
// gl_FragCoord坐标的单位是像素,gl_FragCoord的值是vec2(x,y),
// 通过gl_FragCoord.x、gl_FragCoord.y方式可以分别访问片元坐标的纵横坐标。
function main() {
var canvas = document.getElementById('webgl');
var gl = getWebGLContext(canvas);
if (!gl) {
return;
}
if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
return;
}
var n = initVertexBuffers(gl);
if (n < 0) {
return;
}
// Specify the color for clearing <canvas>
gl.clearColor(0.0, 0.0, 0.0, 1.0);
// Set texture
if (!initTextures(gl, n)) {
console.log('Failed to intialize the texture.');
return;
}
}
// 设置纹理坐标
/*
将纹理坐标传入顶点着色器。我们可以将纹理坐标和顶点坐标写在同一个缓冲区中,成对记录每个顶点的顶点坐标和纹理坐标。
*/
function initVertexBuffers(gl) {
var verticesTexCoords = new Float32Array([
//vertex coord,texture coord
-0.5, 0.5, 0.0, 1.0, //webgl坐标系顶点坐标——左上角
-0.5, -0.5, 0.0, 0.0, //webgl坐标系顶点坐标——左下角
0.5, 0.5, 1.0, 1.0, //webgl坐标系顶点坐标——右上角
0.5, -0.5, 1.0, 0.0, //webgl坐标系顶点坐标——右下角
]);
var n = 4; //the number of vertices
//create the buffer object
var vertexTexCoordBuffer = gl.createBuffer();
if (!vertexTexCoordBuffer) {
return -1;
}
//Bind the buffer object to target
gl.bindBuffer(gl.ARRAY_BUFFER, vertexTexCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, verticesTexCoords, gl.STATIC_DRAW);
var FSIZE = verticesTexCoords.BYTES_PER_ELEMENT;
//Get the storage location of a_Position,assign and enable buffer
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if (a_Position < 0) {
return -1;
}
// undefined vertexAttribPointer(GLuint index, GLint size, GLenum type,
// GLboolean normalized, GLsizei stride, GLintptr offset);
// index:第几个属性,从0开始取,0,1,2,顺序自己定义,例如顶点位置,纹理,法线
// size:一个顶点所有数据的个数,这里每个顶点有两个浮点数属性值,所以是2
// type:顶点描述数据的类型,这里position数组中的数据全部为float,所以是GL_FLOAT
// normalized:是否需要显卡帮忙把数据归一化到-1到+1区间,这里不需要,所以设置GL_FALSE
// stride:一个顶点占有的总的字节数,这里为两个float,所以是FSIZE * 4
// offset:当前指针指向的vertex内部的偏离字节数,可以唯一的标识顶点某个属性的偏移量
// 这里是指向第一个属性,顶点坐标,偏移量为0
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 4, 0);
gl.enableVertexAttribArray(a_Position); //Enable the assignment of the buffer object
//Get the Storge location of a_TexCoord
var a_TexCoord = gl.getAttribLocation(gl.program, 'a_TexCoord');
if (a_TexCoord < 0) {
return -1;
}
//Assign the buffer object to a_TexCoord variable
gl.vertexAttribPointer(a_TexCoord, 2, gl.FLOAT, false, FSIZE * 4, FSIZE * 2);
gl.enableVertexAttribArray(a_TexCoord);
gll = gl;
return n;
}
function initTextures(gl, n) {
var texture = gl.createTexture(); //Create a texture object
if (!texture) {
return false
}
//Get the storge location of u_Sampler
var u_Sampler = gl.getUniformLocation(gl.program, 'u_Sampler');
if (!u_Sampler) {
return;
}
var image = new Image(); //Create the image object
if (!image) {
return;
}
//Register the event handler to be called on loading an image
image.onload = () => {
loadTexture(gl, n, texture, u_Sampler, image);
}
image.src = '../resources/sky.JPG';
return true;
}
function loadTexture(gl, n, texture, u_Sampler, image) {
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1); //Flip the image's y axis
//Enable texture unit0
gl.activeTexture(gl.TEXTURE0);
//Bind the texture object to the target
gl.bindTexture(gl.TEXTURE_2D, texture);
//Set the texture parameters
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
//Set the texture image
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image);
//Set the texture unit 0 to the sampler
gl.uniform1i(u_Sampler, 0);
gl.clear(gl.COLOR_BUFFER_BIT); //Clear canvas
gl.drawArrays(gl.TRIANGLE_STRIP, 0, n); //Draw the rectangle
}
</script>
</body>
</html>
三、效果