想要将位置信息从javascript程序中传给顶点着色器。有两种方式可做到:attribute变量和uniform变量。
attribute变量传输时那些与顶点相关的数据,uniform变量传输的是哪些所有顶点相同(与顶点无关)的数据。例如attribute vec4 a_Position, attribute变量a_Position的类型为vec4。一般attribute变量都以a_开头,而uniform变量以u_开头。
attribute变量是只能在vertex shader中使用的变量。(它不能在fragment shader中声明attribute变量,也不能被fragment shader中使用)
一般用attribute变量来表示一些顶点的数据,如:顶点坐标,法线,纹理坐标,顶点颜色等。
函数void gl.bindAttribLocation(program, index, name);来绑定每个attribute变量的位置,
program要绑定的WebGLProgram 对象。index指定要绑定的通用顶点的索引。name指定要绑定到通用顶点索引的变量的名称。
gl.bindAttribLocation(program, colorLocation, ‘vColor’);
函数glVertexAttribPointer()为每个attribute变量赋值。
如何获取attribute变量的存储位置?
var a_Position = gl.getAttribLocation(gl.program, ‘a_Position’) 返回了前面指定对象中的某属性的下标指向位置。
如何给顶点位置设置值?
gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0);
以下是例子:
uniform mat4 u_matViewProjection;
attribute vec4 a_position;
attribute vec2 a_texCoord0;
void main(void)
{
gl_Position = u_matViewProjection * a_position;
}
uniform变量在vertex和fragment两者之间声明方式完全一样,则它可以在vertex和fragment共享使用。(相当于一个被vertex和fragment shader共享的全局变量)
uniform变量一般用来表示:变换矩阵,材质,光照参数和颜色等信息。
以下是例子:
uniform mat4 viewProjMatrix; //投影+视图矩阵
uniform mat4 viewProj//投影坐标系
uniform mat4 viewMatrix; //视图矩阵
uniform vec3 lightPosition; //光源位置
varying变量是vertex和fragment shader之间做数据传递用的。一般vertex shader修改varying变量的值,然后fragment shader使用该varying变量的值。因此varying变量在vertex和fragment shader二者之间的声明必须是一致的。application不能使用此变量。
以下是例子:
// Vertex shader
uniform mat4 u_matViewProjection;
attribute vec4 a_position;
attribute vec2 a_texCoord0;
varying vec2 v_texCoord; // Varying in vertex shader
void main(void)
{
gl_Position = u_matViewProjection * a_position;
v_texCoord = a_texCoord0;
}
// Fragment shader
precision mediump float;
varying vec2 v_texCoord; // Varying in fragment shader
uniform sampler2D s_baseMap;
uniform sampler2D s_lightMap;
void main()
{
vec4 baseColor;
vec4 lightColor;
baseColor = texture2D(s_baseMap, v_texCoord);
lightColor = texture2D(s_lightMap, v_texCoord);
gl_FragColor = baseColor * (lightColor + 0.25);
}
2.什么是着色器
WebGL有两种着色器:
3.GLSE中的数据类型
float:表示浮点数
vec4:表示有四个浮点数组成的矢量
mat4:4*4矩阵(WebGL中矩阵是列主序的)
必须注意的是,如果WebGL需要的参数是浮点类型,例如10.0。如果传递10会报错,因为10被认为是整数。
4.vec4函数
我们在使用WebGL时,会给顶点着色器参数赋值,gl_Position的数据类型为vec4,gl_Position = vec4(0.0,
0.0, 0.0, 1.0)。但实际需要的位置坐标只有三个(x,y,z)值。幸好WebGL提供了vec4函数。由4个分量组成的矢量被称为齐次坐标,他能够提高三维数据的效率,在三维图形系统大量使用。如果最后一个分量设置为1.0,那么齐次坐标可以表示前三个分量为坐标值的那个点。所有当需要用齐次坐标表示顶点时,只需要将最后一个分量设置为1.0就可以了。
5.gl.drawArrays(mode, first, count)函数
mode:指定绘制的方式,
gl.POINTS: 绘制一系列点。
gl.LINE_STRIP: 绘制一个线条。即,绘制一系列线段,上一点连接下一点。
gl.LINE_LOOP: 绘制一个线圈。即,绘制一系列线段,上一点连接下一点,并且最后一点与第一个点相连。
gl.LINES: 绘制一系列单独线段。每两个点作为端点,线段之间不连接。
gl.TRIANGLE_STRIP:绘制一个三角带。
gl.TRIANGLE_FAN:绘制一个三角扇。
gl.TRIANGLES: 绘制一系列三角形。每三个点作为顶点。
first:指定从哪个顶点开始绘制(整形数)
count:指定绘制需要用到多少个顶点(整形数
6.清空绘图区
清空绘图区是使用指定的背景颜色填充canvas,使用gl.clearColor设置背景色。gl.clearColor(red, green, blue, alpha)。openGL的颜色取值返回是0-1。 调用gl.clear()函数,用clearColor指定的背景色清空绘图区域。gl.clear(g.COLOR_BUFFRE_BIT),清理绘图区域实际上在清理颜色缓冲区(color buffer),传递的gl.COLOR_BUFFER_BIT就是在告诉WebGL清理颜色缓冲区。缓冲区还包括:gl.COLOR_BUFFER_BIT颜色缓冲区、gl.DEPTH_BUFFER_BIT深度缓冲区、gl.STENCIL_BUFFER_BIT模板缓冲区。清理函数分别为gl.clearColor(red,green,blue,alpha)、gl.clearDepth(depth)、gl.clearStencil(s)。
7.gl.getAttribLocation(program, name)函数
program:指定包含顶点着色器和片元着色器的着色器程序对象
name:想要获取存储地址的attribute变量的名称
返回值:大于等于0,attribute变量的存储地址;小于0,指定的attribute变量不存在
8.gl.vertexAttrib4f(location, v0, v1, v2, v3)函数
location:指定将要修改的attribute变量的存储位置
v0:attribute变量的第一个分量的值
v1:attribute变量的第二个分量的值
v2:attribute变量的第三个分量的值
v2:attribute变量的第四个分量的值
说明:gl.vertexAttrib3f有几个同族函数。gl.vertexAttrib1f(location, v0),gl.vertexAttrib2f(location, v0, v1),gl.vertexAttrib3f(location,
v0, v1, v2)。gl.vertexAttrib4fv(location,[])??
9.gl.getUniformLocation(program, name)
program:指定包含顶点着色器和片元着色器的着色器程序对象
name:想要获取存储地址的uniform变量的名称返回值:not-null,指定的uniform变量的位置;null,指定的uniform变量不存在,或者其命名以gl_或者webgl_前缀。
说明:getUniformLocation和getAttribLocation的区别在于为null和-1,如果变量不存在时。
10.gl.uniform4f(location, v0, v1, v2, v3)
向location位置处的变量赋值,参数和vertexAttrib4f函数参数相似。
11.gl.uniform4fv(location, [v0, v1, v2, v3])
向location位置处的变量赋值,参数是以数组的形式传入。
11.gl.uniformMatrix4fv(location, transpose, array)
将array表示的4*4矩阵分配给由location指定的uniform变量。参数:
location:uniform变量的存储位置。
Transpose(转置):在WebGL中必须指定为false
array:带传输的类型化数组,4*4矩阵按列主序存储在其中
12.gl.FragCoord
该内置变量的第一个分量和第二个分量表示片元在
13.gl.drawingBufferWidth/gl.drawingBufferHeight
分别表示颜色缓冲区的宽度和高度
(1)GLSL的修饰符与基本数据类型
const:用于声明非可写的编译时常量变量;
attribute:用于经常更改的信息,只能在顶点着色器中使用;
uniform:用于外部程序传递给shader的变量,shader只能用,不能改;
varying:用于从顶点着色器向片元着色器传递数据的变量。
然后是基本数据类型,int、float、bool。注意float可以指定精度:
highp:32bit,一般用于顶点坐标(vertex coordinate);
medium:16bit,一般用于纹理坐标(texture coordinate);
lowp:8bit,一般用于颜色表示。
接下来是向量类型。
vec4:4分量浮点向量;
ivec4:4分量整数向量;
uvec4:4分量无符号整数向量;
bvec4:4分量布尔向量;
四维向量:
attribute vec4 position;
矩阵类型,所有的矩阵类型都只支持浮点数,不支持整数或者布尔矩阵:
uniform lowp mat4 colorMatrix;
纹理类型,一般仅在Fragment Shader中使用这个类型,二维纹理的声明方式如下:
uniform sampler2D texSampler;
最后是varing,用于在Vertex Shader和Fragment Shader中传递参数。首先在VS中声明这个类型的变量代表纹理的坐标点,并且对这个变量进行赋值,代码如下:
attribute vec2 texcoord;
varying vec2 v_texcoord;
void main(void)
{
v_texcoord = texcoord;
}
紧接着在FS中也声明同名的变量,然后使用texture2D方法取出二维纹理中该纹理坐标点上的像素值,代码如下:
varying vec2 v_texcoord;
vec4 texel = texture2D(texSampler, v_texcoord);
取出了该坐标点上的像素值之后,就可以进行像素变化操作了,比如说提高对比度,最终将改变的像素值赋给gl_FragColor。
(2)GLSL的内置函数与内置变量
最常见的内置变量是两个Shader的输出变量,首先是VS的:
vec4 gl_position;
上述代码用来设置顶点转换到屏幕坐标的位置,VS一定要去更新这个数值。
float gl_pointSize;
在粒子效果的场景下,需要为粒子设置大小,改变该内置变量的值就是为了设置每一个粒子矩形的大小。
其次是FS的内置变量:
vec4 gl_FragColor;
上述代码用于指定当前纹理坐标所代表的像素点的最终颜色值。
(3)其他
sampler2D类型,其实就是纹理数据。另外还有一个方法texture2D,第一个参数是纹理数据,第二个参数是纹理坐标,这个方法就是在纹理数据中取出当前片段对应在纹理数据中位置上的数据颜色。
getAttribLocation用于获取着色器中声明的变量,然后对其进行赋值
var aposLocation = gl.getAttribLocation(program,‘apos’);
gl.vertexAttribPointer(aposLocation,2,gl.FLOAT,false,0,0);
以上代码第一行用于获取着色器变量对象
第二行用于将缓冲区数据传给着色器对象
其中缓冲区数据传递代码如下
var buffer=gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
gl.bufferData(gl.ARRAY_BUFFER,data,gl.STATIC_DRAW);
第一行用于创建一个缓冲区
第二行用于关联某一个缓冲区
第三行用于将data数据传给绑定的缓冲区
之所以要弄这种先创建缓冲区然后再绑定某一缓冲区是可以创建多个缓冲区,然后绑定特定的缓冲区
以上整个过程为以缓冲区为中间容器,先将外部数据传到缓冲区,然后将缓冲区数据传到内部着色器变量
buffer相关解释
1.纹理坐标
纹理坐标是纹理图像上的坐标,通过纹理坐标可以在纹理图像上获取纹理颜色。WebGL系统中的纹理坐标系统是二维的,如图所示。为了将纹理坐标和广泛使用的x、y坐标区分开来,WebGL使用s和t命名纹理坐标(st坐标系统)。
纹理图像的四个角坐标为左下角(0.0,0.0),右下角(1.0,0.0),右上角(1.0, 1.0)和左上角(0.0, 1.0)。纹理坐标很通用,因为坐标值与图像自身的尺寸无关,不管是128*128还是128*256
的图像,右上角的纹理坐标始终是(1.0, 1.0)。
2.纹理映射步骤
1.准备好映射到几何图形上的纹理图像。
2.为几何图形配置纹理映射方式。
3.加载纹理图像,对其进行写配置,以在WebGL中使用它。
4.在片元着色器中将相应的纹理从纹理中抽取出来,并将纹素的颜色赋给片元。
3.gl.createTexture()
创建纹理对象以存储纹理图像。
4.gl.deleteTexture()
使用textur删除纹理对象。如果删除一个已经被删除的纹理对象,不会报错也不会产生任何影响。
5.gl.pixelStorei(pname, param)
使用pname和param指定的方式处理加载得到的图像。参数
pname:可以是以下二者之一。gl.UNPACK_FLIP_Y_WEBGL,对图像进行Y轴反转。默认值为false;gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL,将图像RGB颜色值的每一个分量乘以A。默认为false;WEBGL,默认值为false。
param:指定非0(true)或0(false)。必须为整数。
例如:gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1),将图像进行Y轴反转。由于WebGL纹理坐标系统中的t轴的方向和PNG、BMP、JPG等格式图片的坐标系的Y轴方向相反。因此,只有将图像的Y轴进行反转,才能够正确地将图像映射到图形上。
6.gl.activeTexture(texUnit)
激活texUnit指定的纹理单元。参数:
texUnit:指定准备激活的纹理单元:gl.TEXTURE0、gl.TEXTURE1…、gl.TEXTURE7。最后的数字表示纹理单元的编号
系统支持的纹理单元个数取决于硬件和浏览器的WebGL实现,但在默认情况下,WebGL至少支持8个纹理单元。
7.gl.bindTexture(target, texture)
开启texture指定的纹理对象,并将其绑定到target上。此外,如果已经通过gl.activeTexture()激活了某个纹理单元,则纹理对象也会绑定到这个纹理单元上。
参数:
target:gl.TEXTURE_2D或gl.TEXTURE_BUVE_MAP
texture:表示绑定的纹理对象
例如,之前执行了gl.activeTexture(gl.TEXTURE0)函数,激活了第0个纹理单元。现在执行gl.bindTexture(gl.TEXTURE_2D, texture)。那么纹理对象texture也会绑定到纹理单元gl.TEXTURE0上。
8.gl.texParameteri(target, pname, param)
将param的值赋给绑定到目标的纹理对象的pname参数上。参数:
target:gl.TEXTURE_2D或gl.TEXTURE_CUBE_MAP
pname:纹理参数
param:纹理参数的值
pname可指定4个纹理参数:
放大方法(gl.TEXTURE_MAP_FILTER):当纹理的绘制范围比纹理本身更大时,如何获取纹理颜色。比如说,将16*16的纹理图像映射到32*32像素的空间时,纹理的尺寸变为原始的两倍。默认值为gl.LINEAR。
缩小方法(gl.TEXTURE_MIN_FILTER): 当纹理的绘制返回比纹理本身更小时,如何获取纹素颜色。比如说,你将32*32的纹理图像映射到16*16像素空间里,纹理的尺寸就只有原始的一般。默认值为gl.NEAREST_MIPMAP_LINEAR。
水平填充方法(gl.TEXTURE_WRAP_S):这个参数表示,如何对纹理图像左侧或右侧区域进行填充。默认值为gl.REPEAT。
垂直填充方法(gl.TEXTURE_WRAP_T):这个参数表示,如何对纹理图像上方和下方的区域进行填充。默认值为gl.REPEAT。
可以赋给gl.TEXTURE_MAP_FILTER和gl.TEXTURE_MIN_FILTER参数的值包括:
gl.NEAREST: 使用原纹理上距离映射后像素中心最新的那个像素的颜色值,作为新像素的值。
gl.LINEAR: 使用距离新像素中心最近的四个像素的颜色值的加权平均,作为新像素的值(和gl.NEAREST相比,该方法图像质量更好,但也会有较大的开销。)
可以赋给gl.TEXTURE_WRAP_S和gl.TEXTURE_WRAP_T的常量:
gl.REPEAT:平铺式的重复纹理
gl.MIRRORED_REPEAT:镜像对称的重复纹理
gl.CLAMP_TO_EDGE:使用纹理图像边缘值
9.gl.texImage2D(target, level, internalformat, format, type, image)
将image指定的图像分配给绑定到目标上的纹理对象。参数:
target:gl.TEXTURE_2D或gl.TEXTURE_CUBE
level:传入0(实际上,该参数是为金字塔纹理准备的)
internalformat:图像的内部格式
format:纹理数据格式,必须使用与internalformat相同的值
type:纹理数据的类型
image:包含纹理图像的Image对象
纹理数据格式包含: gl.RGB(红、l绿色、蓝)、
gl.RGBA(红、l绿色、蓝、透明度)、
gl.ALPHA(0.0, 0.0, 0.0, 透明度)、
gl.LUMINANCE、gl.LUMINANCE_ALPHA。
如果纹理图片是JPG格式,该格式将每个像素用RGB三个分量表示,所以参数指定为gl.RGB。其他格式,例如PNG为gl.RGBA、BMP格式为gl.RGB。
type参数指定了纹理数据类型,通常我们使用gl.UNSIGNED_BYTE数据类型。所有数据格式如下:
gl.UNSIGNED_BYTE:无符号整形,每个颜色分量占据1字节
gl.UNSIGNED_SHORT_5_6_5:RGB每个分量分别占据5、6、5比特
gl.UNSIGNED_SHORT_4_4_4_:RGBA每个分量分别占据4、4、4、4比特
gl.UNSIGEND_SHORT_5_5_5_1: RGBA,RGB每个分量个占据5比特,A分量占据1比特
10.专用于纹理的数据类型
sampler2D:绑定到gl.TEXTURE_2D上的纹理数据类型
samplerCube:绑定到gl.TEXTURE_CUBE_MAP上的纹理数据类型
11.gl.uniform1i(location, texUnit)
textUnit单元的纹理传递给着色器。参数:
location:纹理对象的地址
texUnit:纹理单元编号
例如gl.uniform1i(u_Sampler, 0),将0号纹理传递给着色器中的取样器变量
12.vec4 texture2D(smapler2D sampler, vec2 coord)
从sampler指定的纹理上获取coord指定的纹理坐标处的像素颜色。参数:
sampler:指定纹理单元编号
coord:指定纹理坐标
返回值:纹理坐标处像素的颜色值,其格式由gl.texImage2D()的inernalformat参数决定。下面列出了不同参数下的返回值。如果由于某些愿意能导致纹理图像不可使用,那就返回(0.0, 0.0, 0.0 1.0)。
internalformat/返回值
gl.RGB/(R,G,B,1.0)
gl.RBGA/(R,G,B,A)
gl.ALPHA(0.0, 0.0, 0.0, A)
gl.LUMINANCE/(L, L, L, 1.0)
gl.LUMINANCE_ALPHA/(L, L, L, A)
13.texImage2D(target, level, internalformat, width, height, border, format, type, offset)
将image指定的图像分配给绑定到目标上的纹理对象。是WebGL2.0的函数,主要区分WebGL1.0的同名函数区别。参数:
target:gl.TEXTURE_2D或gl.TEXTURE_CUBE
level:传入0(实际上,该参数是为金字塔纹理准备的)
internalformat:图像的内部格式
文理绘制宽度
height:纹理绘制高度
format:纹理数据格式,必须使用与internalformat相同的值
type:纹理数据的类型
image:包含纹理图像的Image对象
var persp = mat4.create();创建矩阵
mat4.perspective(45, 4/3, 1, 100, persp);创建投影矩阵
gl.uniformMatrix4fv(perspectiveUniform, false, persp);
var modelViewPersp = mat4.create();
mat4.multiply(modelView, persp,modelViewPersp);
modelViewPersp变量是 modelView 与 persp叉乘
var modelView = mat4.create(); mat4.identity(modelView); 矩阵单元化
mat4.translate(modelView, [0, 0, -10]); 向Z轴方向移动10个单位
mat4.rotate(modelView, Math.PI/2, [0, 1, 0]); 旋转90度围着y轴
mat4.scale(modelView, [2, 2, 2]); xyz扩大2倍
mat4.identity(modelView);//将矩阵设置为单位阵
秒针每分钟转360度 每秒钟转6度
分针每分钟6度
每秒钟0.1度
时针每分钟0.5度
每秒钟转0.5/60度
1度 = PI/180 弧度
水平视角、垂直视角和可视深度定义了可视空间。
mat4.ortho(left, right, bottom, top, near, far, projMat4)near far 必须是正数
?
perspective(out, fovy, aspect, near, far)
正射投影的好处是用户可以方便地比较场景中物体( 比如两个原子的模型)的大小,这是因为物体看上去的大小与其所在的位置没有关系。在建筑平面图等技术绘图的相关场合,应当使用这种投影。
在透视投影下,产生的三维场景看上去更是有深度感,更加自然,因为我们平时观察真实世界用的也是透视投影。在大多数情况下,比如三维射击类游戏中,我们都应当采用透视投影。
//角度小,看到的物体大,角度大,看到的物体小。
let arr = [
1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, //前面
1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, //右
-1, 1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, //后
-1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, //左
-1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, 1, //上
-1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, //下
]
漫反射颜色 = 入射颜色 x 表面基底色 x cosθ
环境反射颜色 = 入射颜色 x 表面基底色
入射光线向量 = 顶点坐标-点光源坐标
环境光:指那些经光源(点光源或者平行光源)发出后,被墙壁等物体多次反射,然后照射到物体表面上的光。环境光从各个角度照射物体,其强度都是一致的。环境光不需要指定位置和方向,只需要指定颜色即可。
x=rsinθcosφ
y=rsinθsinφ
z=rcosθ
θ = 180 * latitudeNum/latitudeTotalNum//纬度
φ = 360 * longitudeNum/longitudeTotalNum//经度