一、原理
1.实现环境贴图和漫反射
2.利用法线贴图对环境贴图进行干扰,让环境贴图有扭曲的效果
3.利用环境贴图代替漫反射的基础色
二、效果
20221018_113415 (1).gif
三、代码
//顶点着色器
var skyBox_VS = /*glsl*/ `
attribute vec4 a_Position;
uniform mat4 u_ModelMatrix;
uniform mat4 u_ViewMatrix;
uniform mat4 u_ProjectMatrix;
varying vec3 v_Position;
void main(){
mat4 relativeViewMatrix=u_ViewMatrix;
relativeViewMatrix[3].x=0.0;
relativeViewMatrix[3].y=0.0;
relativeViewMatrix[3].z=0.0;
vec4 clipPosition=u_ProjectMatrix*relativeViewMatrix*u_ModelMatrix * a_Position;
gl_Position =clipPosition;
v_Position=a_Position.rgb;
}`;
//片元着色器
var skyBox_FS = /*glsl*/ `
#ifdef GL_ES
precision mediump float;
#endif
uniform samplerCube u_CubeMapTexture;
uniform vec3 u_AmbitionColor;
varying vec3 v_Position;
void main(){
gl_FragColor=textureCube(u_CubeMapTexture, v_Position);
}`;
var v_shader =/*glsl*/`
attribute vec4 a_Position;
attribute vec2 a_Uv;
attribute vec3 a_Normal;
uniform mat4 u_ModelMatrix;
uniform mat4 u_ViewMatrix;
uniform mat4 u_ProjectMatrix;
uniform mat4 u_NormalMatrix;
varying vec2 v_Uv;
varying vec3 v_Normal;
varying vec3 v_Position;
varying mat3 v_TBN;
void main(){
gl_Position=u_ProjectMatrix*u_ViewMatrix*u_ModelMatrix*a_Position;
v_Uv=a_Uv;
v_Normal=(u_NormalMatrix*vec4(a_Normal,1.0)).xyz;
v_Position=(u_ModelMatrix*a_Position).xyz;
vec3 tanVec=normalize((u_ModelMatrix*vec4(1.0,0.0,0.0,1.0)).xyz);
vec3 bitTan=normalize(cross(tanVec,v_Normal));
v_TBN=mat3(tanVec,bitTan,normalize(v_Normal));
}
`
var f_shader =/*glsl*/`
#ifdef GL_ES
precision mediump float;
#endif
varying vec2 v_Uv;
varying vec3 v_Normal;
varying vec3 v_Position;
uniform sampler2D u_Texture;
uniform vec3 u_ViewPosition;
uniform samplerCube u_CubeMapTexture;
uniform float u_Number;
varying mat3 v_TBN;
void main(){
vec3 lightdir=vec3(1.0,-1.0,0.0);
// vec3 lightColor=vec3(19.0/255.0,133.0/255.0,53.0/255.0);
vec3 lightColor=vec3(1.0);
//获取切线空间法线
vec4 normalColor1=texture2D(u_Texture,vec2(v_Uv.x,3.0*fract(u_Number)+v_Uv.y));
vec4 normalColor2=texture2D(u_Texture,vec2(v_Uv.x,2.0*fract(u_Number)+v_Uv.y));
vec4 normalColor=mix(normalColor1,normalColor2,0.5);
//转化为-1到1
vec3 normal=normalize(normalColor.rgb*2.0-1.0);
vec3 worldNormal=normalize(v_TBN*normal);
//计算反射向量
vec3 viewDir=normalize(v_Position-u_ViewPosition);
float dotL=max(0.0,dot(normalize(-lightdir),worldNormal));
//调整法线,让法线贴图对环境纹理影像有限
worldNormal=mix(worldNormal,v_Normal,0.99);
// worldNormal=vec3(0.0,0.0,1.0);
//计算反射颜色
vec3 reflectDir=reflect(viewDir,worldNormal);
vec3 reflectColor=textureCube(u_CubeMapTexture,reflectDir).rgb;
//计算折射颜色
vec3 refractDir=refract(viewDir,worldNormal,1.0/1.55);
vec3 refractColor=textureCube(u_CubeMapTexture,refractDir).rgb;
// vec3 baseColor=vec3(0.0/255.0,112.0/255.0,192.0/255.0);
vec3 envColor=mix(reflectColor,refractColor,0.3);
//计算漫反射
vec3 diffcuseColor=lightColor*dotL*envColor;
gl_FragColor=vec4(diffcuseColor,0.8);
// gl_FragColor=vec4(envColor,1.0);
}
`
//声明js需要的相关变量
var canvas = document.getElementById("canvas");
var gl = getWebGLContext(canvas);
var boxProgram;
var skyboxProgram
var planeModelMatrix;
var frameNumber = 0
async function main() {
if (!gl) {
console.log("你的浏览器不支持WebGL");
return;
}
skyboxProgram = createProgram(gl, skyBox_VS, skyBox_FS);
if (!skyboxProgram) {
console.warn("创建程序失败!");
return;
}
boxProgram = createProgram(gl, v_shader, f_shader)
if (!boxProgram) {
console.warn("创建立方体程序失败!");
return;
}
//设置透视投影矩阵
var projMatrix = new Matrix4();
projMatrix.setPerspective(30, canvas.width / canvas.height, 0.1, 100);
//设置视角矩阵的相关信息(视点,视线,上方向)
var viewMatrix = new Matrix4();
viewMatrix.setLookAt(0, 1.5, 6, 0, 0, 0, 0, 1, 0);
planeModelMatrix = new Matrix4()
planeModelMatrix.setScale(2, 1, 2)
//开启隐藏面清除
gl.enable(gl.DEPTH_TEST);
// gl.enable(gl.CULL_FACE)
gl.program = skyboxProgram;
gl.useProgram(skyboxProgram);
//获取内置变量的信息
getVariableLocation();
const cube = createCube(gl);
await initCubeTexture(
[
"./image/skybox1/posx.jpg",
"./image/skybox1/negx.jpg",
"./image/skybox1/posy.jpg",
"./image/skybox1/negy.jpg",
"./image/skybox1/posz.jpg",
"./image/skybox1/negz.jpg",
]
)
// await initCubeTexture(
// [
// "./image/skybox/right.jpg",
// "./image/skybox/left.jpg",
// "./image/skybox/top.jpg",
// "./image/skybox/bottom.jpg",
// "./image/skybox/front.jpg",
// "./image/skybox/back.jpg",
// ]
// )
gl.useProgram(boxProgram)
gl.program = boxProgram
//获取内置变量的信息
getVariableLocation();
const plane = createPlane(gl);
//初始化纹理
await initTexture(gl, "./image/waterNormals.jpg", 1);
// await draw(projMatrix, viewMatrix, cube, plane)
//设置底色
// gl.depthFunc(gl.LEQUAL);
//根据时间绘制
var tick = function () {
frameNumber += 0.001
draw(projMatrix, viewMatrix, cube, plane)
//重复请求
requestAnimationFrame(tick)
}
tick()
document.addEventListener("keydown", (e) => {
if (e.key === "ArrowUp") {
planeModelMatrix.rotate(1, 1, 0, 0)
} else if (e.key === "ArrowDown") {
planeModelMatrix.rotate(-1, 1, 0, 0)
} else if (e.key === "ArrowLeft") {
planeModelMatrix.rotate(-1, 0, 1, 0)
} else if (e.key === "ArrowRight") {
planeModelMatrix.rotate(1, 0, 1, 0)
}
});
}
function draw(projMatrix, viewMatrix, cube, plane) {
//清空颜色和深度缓冲区
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.depthMask(false);
gl.useProgram(skyboxProgram)
gl.program = skyboxProgram
//绘制三角形
drawSkyBox(projMatrix, viewMatrix, cube);
gl.depthMask(true);
gl.useProgram(boxProgram)
gl.program = boxProgram
drawBox(projMatrix, viewMatrix, plane)
}
function drawSkyBox(projMatrix, viewMatrix, cube) {
const program = gl.program;
//设置视角矩阵的相关信息(视点,视线,上方向)
//将试图矩阵传给u_ViewMatrix变量
gl.uniformMatrix4fv(program.projectMatrix, false, projMatrix.elements);
//设置模型矩阵的相关信息
var modelMatrix = new Matrix4();
gl.uniformMatrix4fv(program.modelMatrix, false, modelMatrix.elements);
gl.uniformMatrix4fv(program.viewMatrix, false, viewMatrix.elements);
const arrayBuffers = cube.arrayBuffers
//写入缓冲区
arrayBuffers.forEach(arrayBuffer => {
if (arrayBuffer) {
writeAttributeVariable(gl, arrayBuffer.attribute, arrayBuffer)
}
});
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cube.indexBuffer);
//绘制图形
gl.drawElements(gl.TRIANGLES, cube.length, gl.UNSIGNED_BYTE, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
}
function drawBox(projMatrix, viewMatrix, plane) {
const program = gl.program;
//设置模型矩阵的相关信息
// var modelMatrix = new Matrix4();
gl.uniformMatrix4fv(program.modelMatrix, false, planeModelMatrix.elements);
gl.uniformMatrix4fv(program.viewMatrix, false, viewMatrix.elements);
//设置透视投影矩阵
var projMatrix = new Matrix4();
projMatrix.setPerspective(30, canvas.width / canvas.height, 0.1, 100);
//将试图矩阵传给u_ViewMatrix变量
gl.uniformMatrix4fv(program.projectMatrix, false, projMatrix.elements);
//传入眼睛位置
const viewPosition = gl.getUniformLocation(program, 'u_ViewPosition')
gl.uniform3fv(viewPosition, [0, 1.5, 6]);
const number = gl.getUniformLocation(program, "u_Number");
gl.uniform1f(number, frameNumber);
var normalMatrix = new Matrix4()
normalMatrix.transpose(normalMatrix.setInverseOf(planeModelMatrix))
gl.uniformMatrix4fv(program.normalMatrix, false, normalMatrix.elements);
const arrayBuffers = plane.arrayBuffers
arrayBuffers.forEach(arrayBuffer => {
if (arrayBuffer) {
writeAttributeVariable(gl, arrayBuffer.attribute, arrayBuffer)
}
});
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, plane.indexBuffer);
//绘制图形
gl.drawElements(gl.TRIANGLES, plane.length, gl.UNSIGNED_BYTE, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
}```
网友评论