GLSL 实现一个菲涅尔效果。效果图如下:
代码实现
export const Shader = {
uniforms: {
b: {
type: 'f',
value: 1.0
}, //bias 颜色最亮的位置
p: {
type: 'f',
value: 1.0
}, //power决定了透明度变化速度及方向。
glowColor: {
type: 'c',
value: new THREE.Color("#1da9fc")
},
sweepColor: {
value: new THREE.Color('#00FFFF')
},
blueColor: {
value: new THREE.Color('#20285d')
},
time: {
value: 0.0
}
},
vertexShader: `
attribute vec3 color;
varying vec3 vNormal;
varying vec3 vPositionNormal;
varying vec3 vP;
varying vec2 vUv;
varying vec3 vColor;
void main()
{
vUv = uv;
vColor = color;
vP = position;
vNormal = normalize( normalMatrix * normal );
vPositionNormal = normalize(( modelViewMatrix * vec4(position, 1.0) ).xyz);
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
`,
fragmentShader: `
uniform vec3 glowColor;
uniform vec3 blueColor;
uniform float b;
uniform float p;
uniform vec3 sweepColor;
uniform float time;
varying vec3 vNormal;
varying vec3 vPositionNormal;
varying vec3 vP;
varying vec2 vUv;
varying vec3 vColor;
void main()
{
float a = pow( b - abs(dot(vNormal, vPositionNormal)), p );
// gl_FragColor = vec4( glowColor, a );
vec3 mixColor = mix(blueColor, glowColor, a);
gl_FragColor = vec4(mixColor, 1.0);
// if(abs(time - vP.y) < 1.0) {
// gl_FragColor = vec4(sweepColor, 0.8);
// }
}
`
}
const gltfLoa = new GLTFLoader();
gltfLoa.load('xxx模型.gltf', function (object) {
object.scene.traverse(e => {
e.material = new THREE.ShaderMaterial({
uniforms: Shader.uniforms,
vertexShader: Shader.vertexShader,
fragmentShader: Shader.fragmentShader,
side: THREE.DoubleSide,
// blending: THREE.AdditiveBlending,
transparent: true
})
});
scene.add(object.scene);
})
实现逻辑
先说几个名词:单位向量、法线、点积。不清楚的可以先了解下这个名词。
思路:
- 计算当前摄像机位置的单位向量。
- 计算当前像素点的法向量的单位向量。
- 当前位置向量 和 像素点的法向量 计算点积dot(),可以算出两个向量的夹角。
- 我们根据夹角计算当前颜色的透明度。这样就可以实现菲涅尔效果。