理论基础:
效果:
源码:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><!-- 引入gl-matrix.js库,用于 WebGL 中的矩阵运算 --><script src="gl-matrix.js"></script><script>// 顶点着色器程序let vertexstring = `attribute vec4 a_position; // 顶点位置属性uniform mat4 u_formMatrix; // 变换矩阵attribute vec4 a_Normal; // 顶点法线属性uniform vec3 u_PointLightPosition; // 点光源位置uniform vec3 u_DiffuseLight; // 散射光颜色uniform vec3 u_AmbientLight; // 环境光颜色varying vec4 v_Color; // 传递给片段着色器的颜色void main(void){gl_Position = u_formMatrix * a_position; // 应用变换矩阵vec3 normal = normalize(a_Normal.xyz); // 法线归一化vec3 lightDirection = normalize(u_PointLightPosition - vec3(gl_Position.xyz)); // 计算光源方向float nDotL = max(dot(lightDirection, normal), 0.0); // 计算法线和光源方向的点积vec3 diffuse = u_DiffuseLight * vec3(1.0,0,1.0)* nDotL; // 计算散射光vec3 ambient = u_AmbientLight * vec3(1.0,0,1.0); // 计算环境光v_Color = vec4(diffuse + ambient, 1); // 结合散射光和环境光}`;// 片段着色器程序let fragmentstring = `precision mediump float; // 精度声明varying vec4 v_Color; // 从顶点着色器接收的颜色void main(void){gl_FragColor =v_Color; // 设置片断颜色}`;// WebGL上下文和一些变量的声明var webgl;var angle = 45;var webglDiv;var indices;var g_joint1Angle = 0.0;var ANGLE_STEP = 3.0;var g_arm1Angle = -90.0;// 初始化函数,设置WebGL环境function init() {// 初始化WebGLinitWebgl();// 初始化着色器initShader();// 初始化数据initBuffer();// 初始化事件initEvent();// 清空画板clearn();// 创建光源initLight();// 绘制图形draw();}// 初始化WebGL上下文function initWebgl() {webglDiv = document.getElementById('myCanvas');webgl = webglDiv.getContext("webgl");webgl.viewport(0, 0, webglDiv.clientWidth, webglDiv.clientHeight);}// 初始化着色器function initShader() {// 创建顶点着色器和片段着色器let vsshader = webgl.createShader(webgl.VERTEX_SHADER);let fsshader = webgl.createShader(webgl.FRAGMENT_SHADER);// 设置着色器源码webgl.shaderSource(vsshader, vertexstring);webgl.shaderSource(fsshader, fragmentstring);// 编译着色器webgl.compileShader(vsshader);webgl.compileShader(fsshader);// 检查着色器编译状态if (!webgl.getShaderParameter(vsshader, webgl.COMPILE_STATUS)) {var err = webgl.getShaderInfoLog(vsshader);alert(err);return;}if (!webgl.getShaderParameter(fsshader, webgl.COMPILE_STATUS)) {var err = webgl.getShaderInfoLog(fsshader);alert(err);return;}// 创建程序并附加着色器let program = webgl.createProgram();webgl.attachShader(program, vsshader);webgl.attachShader(program, fsshader)webgl.linkProgram(program);webgl.useProgram(program);webgl.program = program;}// 清空画板并设置背景色和深度测试function clearn() {webgl.clearColor(0, 0, 0, 1);webgl.clear(webgl.COLOR_BUFFER_BIT | webgl.DEPTH_BUFFER_BIT);webgl.enable(webgl.DEPTH_TEST);}// 初始化变换矩阵function initTransformation(angele, rotateArr, ModelMatrix = glMatrix.mat4.create()) {let ProjMatrix = glMatrix.mat4.create();glMatrix.mat4.identity(ProjMatrix);glMatrix.mat4.perspective(ProjMatrix, angle * Math.PI / 180, webglDiv.clientWidth / webglDiv.clientHeight, 1, 1000); // 设置透视投影let uniformMatrix1 = webgl.getUniformLocation(webgl.program, "u_formMatrix");glMatrix.mat4.rotate(ModelMatrix, ModelMatrix, degreesToRads(angele), rotateArr); // 旋转模型矩阵let ViewMatrix = glMatrix.mat4.create();glMatrix.mat4.identity(ViewMatrix);glMatrix.mat4.lookAt(ViewMatrix, [50, 50, 50], [0, 0, 0], [0, 1, 0]); // 设置视图矩阵let mvMatrix = glMatrix.mat4.create();glMatrix.mat4.identity(mvMatrix);glMatrix.mat4.multiply(mvMatrix, ViewMatrix, ModelMatrix); // 计算模型视图矩阵let mvpMatrix = glMatrix.mat4.create();glMatrix.mat4.identity(mvpMatrix);glMatrix.mat4.multiply(mvpMatrix, ProjMatrix, mvMatrix); // 计算模型视图投影矩阵webgl.uniformMatrix4fv(uniformMatrix1, false, mvpMatrix);return ModelMatrix;}// 初始化事件监听function initEvent() {document.onkeydown = keydown;}// 初始化光源function initLight() {let u_DiffuseLight = webgl.getUniformLocation(webgl.program, 'u_DiffuseLight');webgl.uniform3f(u_DiffuseLight, 1.0, 1.0, 1.0); // 设置散射光颜色let u_LightDirection = webgl.getUniformLocation(webgl.program, 'u_PointLightPosition');webgl.uniform3fv(u_LightDirection, [3.0, 3.0, 4.0]); // 设置点光源位置let u_AmbientLight = webgl.getUniformLocation(webgl.program, 'u_AmbientLight');webgl.uniform3f(u_AmbientLight, 0.8, 0.8, 0.8); // 设置环境光颜色}// 初始化缓冲区function initBuffer() {// 顶点数据var vertices = new Float32Array([// 顶点坐标]);// 法线数据var normals = new Float32Array([// 法线坐标]);// 顶点索引indices = new Uint8Array([// 顶点索引]);// 创建顶点位置缓冲区let pointPosition = new Float32Array(vertices);let aPsotion = webgl.getAttribLocation(webgl.program, "a_position");let triangleBuffer = webgl.createBuffer();webgl.bindBuffer(webgl.ARRAY_BUFFER, triangleBuffer);webgl.bufferData(webgl.ARRAY_BUFFER, pointPosition, webgl.STATIC_DRAW);webgl.enableVertexAttribArray(aPsotion);webgl.vertexAttribPointer(aPsotion, 3, webgl.FLOAT, false, 0, 0);// 创建法线缓冲区let aNormal = webgl.getAttribLocation(webgl.program, "a_Normal");let normalsBuffer = webgl.createBuffer();let normalsArr = new Float32Array(normals);webgl.bindBuffer(webgl.ARRAY_BUFFER, normalsBuffer);webgl.bufferData(webgl.ELEMENT_ARRAY_BUFFER, normalsArr, webgl.STATIC_DRAW);webgl.enableVertexAttribArray(aNormal);webgl.vertexAttribPointer(aNormal, 3, webgl.FLOAT, false, 0, 0);// 创建索引缓冲区let indexBuffer = webgl.createBuffer();let indices1 = new Uint8Array(indices);webgl.bindBuffer(webgl.ELEMENT_ARRAY_BUFFER, indexBuffer);webgl.bufferData(webgl.ELEMENT_ARRAY_BUFFER, indices1, webgl.STATIC_DRAW);}// 按键事件处理函数function keydown(ev) {switch (ev.keyCode) {// 按键事件,控制关节角度}clearn()draw();}
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><!-- 引入gl-matrix.js库,用于 WebGL 中的矩阵运算 --><script src="gl-matrix.js"></script><script>// 顶点着色器程序let vertexstring = `attribute vec4 a_position; // 顶点位置属性uniform mat4 u_formMatrix; // 变换矩阵attribute vec4 a_Normal; // 顶点法线属性uniform vec3 u_PointLightPosition; // 点光源位置uniform vec3 u_DiffuseLight; // 散射光颜色uniform vec3 u_AmbientLight; // 环境光颜色varying vec4 v_Color; // 传递给片段着色器的颜色void main(void){gl_Position = u_formMatrix * a_position; // 应用变换矩阵vec3 normal = normalize(a_Normal.xyz); // 法线归一化vec3 lightDirection = normalize(u_PointLightPosition - vec3(gl_Position.xyz)); // 计算光源方向float nDotL = max(dot(lightDirection, normal), 0.0); // 计算法线和光源方向的点积vec3 diffuse = u_DiffuseLight * vec3(1.0,0,1.0)* nDotL; // 计算散射光vec3 ambient = u_AmbientLight * vec3(1.0,0,1.0); // 计算环境光v_Color = vec4(diffuse + ambient, 1); // 结合散射光和环境光}`;// 片段着色器程序let fragmentstring = `precision mediump float; // 精度声明varying vec4 v_Color; // 从顶点着色器接收的颜色void main(void){gl_FragColor = v_Color; // 设置片断颜色}`;// WebGL上下文和一些变量的声明var webgl;var angle = 45;var webglDiv;var indices;// 各个关节的角度变量var g_joint1Angle = 86.0;var ANGLE_STEP = 3.0;var g_arm1Angle = 160.0;var g_palm1Angle = 0.0;var g_finger1Angle = 0.0;var g_chest1Angle = 0;// 初始化函数,设置WebGL环境function init() {// 初始化WebGLinitWebgl();// 初始化着色器initShader();// 清空画板clearn();// 创建光源initLight();// 绘制头部drawHead()// 初始化数据initBuffer();// 初始化事件initEvent();// 绘制图形let drawMatrix = chestDraw();let drawMatrixCopy = drawMatrix.slice(0);drawLeft(drawMatrix);drawRight(drawMatrixCopy);}// 初始化WebGL上下文function initWebgl() {webglDiv = document.getElementById('myCanvas');webgl = webglDiv.getContext("webgl");webgl.viewport(0, 0, webglDiv.clientWidth, webglDiv.clientHeight);}// 初始化着色器function initShader() {// 创建顶点着色器和片段着色器let vsshader = webgl.createShader(webgl.VERTEX_SHADER);let fsshader = webgl.createShader(webgl.FRAGMENT_SHADER);// 设置着色器源码webgl.shaderSource(vsshader, vertexstring);webgl.shaderSource(fsshader, fragmentstring);// 编译着色器webgl.compileShader(vsshader);webgl.compileShader(fsshader);// 检查着色器编译状态if (!webgl.getShaderParameter(vsshader, webgl.COMPILE_STATUS)) {var err = webgl.getShaderInfoLog(vsshader);alert(err);return;}if (!webgl.getShaderParameter(fsshader, webgl.COMPILE_STATUS)) {var err = webgl.getShaderInfoLog(fsshader);alert(err);return;}// 创建程序并附加着色器let program = webgl.createProgram();webgl.attachShader(program, vsshader);webgl.attachShader(program, fsshader);webgl.linkProgram(program);webgl.useProgram(program);webgl.program = program;}// 清空画板并设置背景色和深度测试function clearn() {webgl.clearColor(0, 0, 0, 1);webgl.clear(webgl.COLOR_BUFFER_BIT | webgl.DEPTH_BUFFER_BIT);webgl.enable(webgl.DEPTH_TEST);}// 初始化变换矩阵function initTransformation(angle, rotateArr, ModelMatrix = glMatrix.mat4.create()) {let ProjMatrix = glMatrix.mat4.create();glMatrix.mat4.identity(ProjMatrix);glMatrix.mat4.perspective(ProjMatrix, angle * Math.PI / 180, webglDiv.clientWidth / webglDiv.clientHeight, 1, 1000); // 设置透视投影let uniformMatrix1 = webgl.getUniformLocation(webgl.program, "u_formMatrix");glMatrix.mat4.rotate(ModelMatrix, ModelMatrix, degreesToRads(angle), rotateArr);let ViewMatrix = glMatrix.mat4.create();glMatrix.mat4.identity(ViewMatrix);glMatrix.mat4.lookAt(ViewMatrix, [0, 0, 100], [0, 0, 0], [0, 1, 0]); // 设置视图矩阵let mvMatrix = glMatrix.mat4.create();glMatrix.mat4.identity(mvMatrix);glMatrix.mat4.multiply(mvMatrix, ViewMatrix, ModelMatrix); // 计算模型视图矩阵let mvpMatrix = glMatrix.mat4.create();glMatrix.mat4.identity(mvpMatrix);glMatrix.mat4.multiply(mvpMatrix, ProjMatrix, mvMatrix); // 计算模型视图投影矩阵webgl.uniformMatrix4fv(uniformMatrix1, false, mvpMatrix);return ModelMatrix;}// 初始化事件监听function initEvent() {document.onkeydown = keydown;}// 初始化光源function initLight() {let u_DiffuseLight = webgl.getUniformLocation(webgl.program, 'u_DiffuseLight');webgl.uniform3f(u_DiffuseLight, 1.0, 1.0, 1.0); // 设置散射光颜色let u_LightDirection = webgl.getUniformLocation(webgl.program, 'u_PointLightPosition');webgl.uniform3fv(u_LightDirection, [3.0, 3.0, 4.0]); // 设置点光源位置let u_AmbientLight = webgl.getUniformLocation(webgl.program, 'u_AmbientLight');webgl.uniform3f(u_AmbientLight, 0.8, 0.8, 0.8); // 设置环境光颜色}// 初始化缓冲区function initBuffer() {// 顶点数据var vertices = new Float32Array([// 顶点坐标]);// 法线数据var normals = new Float32Array([// 法线坐标]);// 顶点索引indices = new Uint8Array([// 顶点索引]);// 创建顶点位置缓冲区let pointPosition = new Float32Array(vertices);let aPosition = webgl.getAttribLocation(webgl.program, "a_position");let triangleBuffer = webgl.createBuffer();webgl.bindBuffer(webgl.ARRAY_BUFFER, triangleBuffer);webgl.bufferData(webgl.ARRAY_BUFFER, pointPosition, webgl.STATIC_DRAW);webgl.enableVertexAttribArray(aPosition);webgl.vertexAttribPointer(aPosition, 3, webgl.FLOAT, false, 0, 0);// 创建法线缓冲区let aNormal = webgl.getAttribLocation(webgl.program, "a_Normal");let normalsBuffer = webgl.createBuffer();let normalsArr = new Float32Array(normals);webgl.bindBuffer(webgl.ARRAY_BUFFER, normalsBuffer);webgl.bufferData(webgl.ARRAY_BUFFER, normalsArr, webgl.STATIC_DRAW);webgl.enableVertexAttribArray(aNormal);webgl.vertexAttribPointer(aNormal, 3, webgl.FLOAT, false, 0, 0);// 创建索引缓冲区let indexBuffer = webgl.createBuffer();let indices1 = new Uint8Array(indices);webgl.bindBuffer(web
void gl.drawElements(mode, count, type, offset);