光照
首先的作用就是让立方体有棱角
光照分为:
点光源(灯泡,火焰等)定义一个点光源需要光源的位置,光线方向以及颜色,照射点的位置不同,光的方向也不同
平行光(太阳光)只需要光照方向和光照颜色
环境光:光源发出后,经过其他物体的反射,照到物体表面上的光线。环境光强度差距非常小,没有必要精确计算光线强度,只需要定义光照颜色
环境反射:环境反射是针对环境光而言的,环境反射中,环境光照射物体各方面均匀,强度相等,反射的方向就是入射光的反方向,最终物体的颜色只跟入射光颜色和基底色有关 环境光颜色 = 入射光颜色 * 基底色
漫反射:漫反射中反射光的颜色取决于入射光的颜色,表面基底色,还有入射光与物体表面的法向量的入射角 漫反射颜色 = 入射光颜色 * 基底色 * cos deg 光线方向和法线方向的点积 = cos deg
const VERTEX_SHADER_SOURCE = `
attribute vec4 aPosition;
//法向量,需要计算
attribute vec4 aNormal;
varying vec4 vColor;
uniform mat4 mat;
void main(){
//定义点光源的颜色
vec3 uPointLightColor = vec3(1.0,1.0,0.0);
//定义点光源的位置
vec3 uPointLightPosition = vec3(-5.0,6.0,10.0);
//环境光
vec3 uAmbientLightColor = vec3(0.2,0.2,0.2);
//物体表面颜色
vec4 aColor = vec4(1.0,0.0,0.0,1.0);
//顶点的世界坐标
vec4 vertexPosition = mat * aPosition;
//点光源的方向(点光源的位置和世界坐标的差值取得)
vec3 lightDirection = normalize(uPointLightPosition-vec3(vertexPosition));
//环境反射
vec3 ambient = uAmbientLightColor * vec3(aColor);
//计算入射角 光线方向和法线方向的点积
float dotDeg = dot(lightDirection,vec3(aNormal));
//漫反射光的颜色
vec3 diffuseColor = uPointLightColor * vec3(aColor) * dotDeg;
gl_Position =vertexPosition;
//环境反射和漫反射相加就是看到的物体表面的颜色
vColor = vec4(ambient + diffuseColor,aColor.a);
}
` //顶点着色器
//创建法向量数据,数据需要和顶点数据保持一致(4份)
const normal = new Float32Array([
0.0,0.0,1.0,0.0,0.0,1.0,0.0,0.0,1.0,0.0,0.0,1.0,//前
0.0,0.0,-1.0,0.0,0.0,-1.0,0.0,0.0,-1.0,0.0,0.0,-1.0,//后
-1.0,0.0,0.0,-1.0,0.0,0.0,-1.0,0.0,0.0,-1.0,0.0,0.0,//右
1.0,0.0,0.0,1.0,0.0,0.0,1.0,0.0,0.0,1.0,0.0,0.0,//左
0.0,1.0,0.0,0.0,1.0,0.0,0.0,1.0,0.0,0.0,1.0,0.0,//上
0.0,-1.0,0.0,0.0,-1.0,0.0,0.0,-1.0,0.0,0.0,-1.0,0.0,//下
])
const normalBuffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer)
gl.bufferData(gl.ARRAY_BUFFER, normal, gl.STATIC_DRAW)
gl.vertexAttribPointer(aNormal, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(aNormal)
...
gl.enable(gl.DEPTH_TEST)
添加光源的代码,没有效果。开启gl.DEPTH_TEST后可以正常显示
雾化
表示距离越远看的越模糊,雾化实现 通过某点和视点的距离,距离越远,雾化程度越高,这种雾化叫线性雾化,某一点的雾化程度叫做雾化因子
雾化因子计算: 雾化因子 = (终点 - 当前点)/(终点 - 起点)
物体颜色计算: 颜色 = 物体颜色 * 雾化因子 + 雾化颜色 * (1 - 雾化因子)
const start = 0
const end = 200
const FogColor = new Float32Array([0.0,0.0,0.0])
const FogDist = new Float32Array([start,end])
const uFogColor = gl.getUniformLocation(program, 'uFogColor')
const uFogDist = gl.getUniformLocation(program, 'uFogDist')
const matrix = getViewMatrix(3, 3, 5, 0.0, 0.0, 0.0, 0.0, 0.6, 0.0)
const perspective = getPerspective(30, ctx.width / ctx.height, 100, 1)
gl.uniformMatrix4fv(mat, false,mixMatrix(perspective, matrix));
gl.uniform3fv(uFogColor,FogColor)
function draw(){
FogDist[1] -=1
if(FogDist[1]>start){
FogDist[1]=end
}
// gl.enable(gl.DEPTH_TEST)
gl.uniform2fv(uFogDist,FogDist)
gl.drawElements(gl.TRIANGLES, index.length,gl.UNSIGNED_BYTE,0);
requestAnimationFrame(draw)
}
draw()
着色器代码
const FRAGMENT_SHADER_SOURCE = `
precision lowp float;
varying float vDist;
varying vec4 vColor;
//雾化颜色
uniform vec3 uFogColor;
//起点到终点的距离,第一个是起点,第二个是终点
uniform vec2 uFogDist;
void main(){
//计算雾化因子
float fogFactor = (uFogDist.y-vDist)/(uFogDist.y-uFogDist.x);
//计算颜色
//mix 线性混合计算mix(x,y,z) x*(1-z) + y*z
vec3 color = mix(uFogColor,vec3(vColor),fogFactor);
gl_FragColor = vec4(color,vColor.a);
}
`//片元着色器
没有视频中的效果,不知道为什么
绘制圆点
绘制圆点需要修改片元着色器
计算距离+判断:
const FRAGMENT_SHADER_SOURCE = `
precision lowp float;
void main(){
//计算距离(当前绘制的点和定义的范围的距离)
// 当前绘制的点的位置
float dis = distance(gl_PointCoord,vec2(0.5,0.5));
// 大于为白色,没有大于为红色
if(dis>0.5){
gl_FragColor = vec4(1.0,1.0,1.0,1.0);
//或者使用discard
//大于 0.5直接放弃绘制
discard;
}
else{
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
}
`//片元着色器
绘制半透明物体
直接将rgba中的a改小并不能实现效果,只会让颜色变模糊
//着色器中需要改变vColor的alpha
gl.enable(gl.BLEND)
gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_CONSTANT_ALPHA)
//删掉 gl.enable(gl.DEPTH_TEST)