首先看一下光照颜色在顶点着色器中的效果:
1、颜色计算放在顶点着色器中
const VSHADER=`
uniform vec3 u_LightColor;
uniform vec3 u_LightDirction;
uniform vec3 u_AmbientLight;
uniform vec3 u_Color;
varying vec4 v_Color;
void main(){
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
//计算变换后的法向量并归一化
vec3 newnormal=normalize(vec3(normalMatrix*normal));
//计算光线方向和法向量的点积
float nDotL=max(dot(u_LightDirction,newnormal),0.0);
//计算漫反射光的颜色
vec3 diffuse=u_LightColor*u_Color.rgb*nDotL;
//计算环境光产生的反射光的颜色
vec3 ambient=u_AmbientLight*u_Color.rgb;
//将以上两者相加作为最终的颜色
v_Color=vec4(diffuse+ambient,1.0);
}
`
const FSHADER=`
precision mediump float;
varying vec4 v_Color;
void main(){
gl_FragColor=v_Color;
}
`
2、颜色计算放在片元着色器中
const VSHADER=`
varying vec3 v_Normal;
void main(){
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
//计算变换后的法向量并归一化
v_Normal=normalize(vec3(normalMatrix*normal));
}
`
const FSHADER=`
precision mediump float;
uniform vec3 u_LightColor;
uniform vec3 u_LightDirction;
uniform vec3 u_AmbientLight;
varying vec3 v_Normal;
uniform vec3 u_Color;
void main(){
//计算光线方向和法向量的点积
float nDotL=max(dot(u_LightDirction,v_Normal),0.0);
//计算漫反射光的颜色
vec3 diffuse=u_LightColor*u_Color.rgb*nDotL;
//计算环境光产生的反射光的颜色
vec3 ambient=u_AmbientLight*u_Color.rgb;
//将以上两者相加作为最终的颜色
gl_FragColor=vec4(diffuse+ambient,1.0);
}
`
从二者的结果来看,把计算放在片元着色器中,效果会更好,颜色界限处会更平滑。
在three.js中使用的代码
let geometry = new THREE.SphereBufferGeometry( 2, 64, 64 );
geometry.computeVertexNormals ()
let geometryMat = new THREE.ShaderMaterial( {
uniforms:{
u_Color:{value:new THREE.Color(0xff0000)},
u_LightColor:{value:this.dirLight.color},
u_LightDirction:{value:this.dirLight.position},
u_AmbientLight:{value:this.ambientLight.color}
},
vertexShader:VSHADER,
fragmentShader:FSHADER,
vertexColors: true
} );
let cube = new THREE.Mesh( geometry, geometryMat );
cube.castShadow=true
cube.position.set(0,0,2)
this.scene.add( cube );
源码地址: