本文共 14156 字,大约阅读时间需要 47 分钟。
<html>
<head> <meta http-equiv="content-type" content="text/html; charset=gb2312"> <script type="text/javascript" src="glMatrix-0.9.5.js"></script><script type="text/javascript" src="glt.js"></script>
<script type="text/javascript" src="gl-0.1.js"></script> <script type="text/javascript" src="loadData.js"></script><!--加载数据的代码移动到了这个js文件中--><script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 a_v3Position; attribute vec3 a_v3Normal; uniform mat4 u_m4ModelView; varying vec3 v_v3TexCoord; uniform int u_iShadowMode; varying vec3 v_v3Position; varying vec3 v_v3Normal;void main(void)
{ gl_Position = u_m4ModelView * vec4(a_v3Position, 1.0); if(u_iShadowMode == 0) { v_v3TexCoord = a_v3Position; v_v3Position = a_v3Position; v_v3Normal = vec3(u_m4ModelView * vec4(a_v3Normal, 1.0)); } } </script><script id="shader-fs" type="x-shader/x-fragment">
#ifdef GL_FRAGMENT_PRECISION_HIGH precision highp float; #else precision mediump float; #endif uniform samplerCube u_samplerCube; varying vec3 v_v3TexCoord; uniform int u_iShadowMode; varying vec3 v_v3Position; varying vec3 v_v3Normal; uniform bool u_bUseLighting; uniform vec3 u_v3AmbientScale; uniform vec3 u_v3PointLightPosition; uniform vec3 u_v3PointLightScale;void main(void)
{ if(u_iShadowMode == 0) { vec3 v3ColorScale; if(!u_bUseLighting) v3ColorScale = vec3(1.0, 1.0, 1.0); else { vec3 v3PLV = u_v3PointLightPosition - v_v3Position; if(dot(v_v3Normal, v3PLV) > 0.0)//可以被点光源照射到 { //求出顶点到点光源的距离,假设在距离0-1.5范围内线性衰减;当然也可以使用其他的光照公式 float f = max(0.0, 1.0 - length(v3PLV) / 2.0);//要注意的是,示例中旋转的只有立方体,光源的位置并没有变动 v3ColorScale = u_v3AmbientScale + u_v3PointLightScale * f;//将衰减后的点光源颜色比例合并到环境光 } else v3ColorScale = u_v3AmbientScale; } vec4 color = textureCube(u_samplerCube, v_v3TexCoord); gl_FragColor = vec4(color.rgb * v3ColorScale, color.a); } else if(u_iShadowMode == 1) gl_FragColor = vec4(0.7, 0.7, 0.7, 1.0); else if(u_iShadowMode == 2) gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); else if(u_iShadowMode == 3) gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0); else if(u_iShadowMode == 4) gl_FragColor = vec4(0.0, 0.5, 0.5, 1.0); } </script><script>
var mouseDown = false;
var mousePosition = [0, 0]; var rotateMat4 = null; var rotatePosV3 = [0, 0, 0];;//记录离圆心的偏移,2D,弄成vec3只是为了方便执行加减操作var textureObject = null;
var shadowMat4 = null;//预先计算好的阴影矩阵 var jsConeMat4 = null; var perspectiveMat4 = null;//预先计算好的投影矩阵function LoadData()
{ LoadCubeData("cube", "cubeIndex", "cubeNormals"); LoadTextureData(); LoadShadowPlaneData("shadowPlane", "shadowMat4"); LoadConeData("cone", "jsConeMat4"); LoadPerspectiveMat4("perspectiveMat4");rotateMat4 = mat4.create();
mat4.identity(rotateMat4);return 0;
}function RenderScene()
{ webgl.clearColor(0.0, 0.0, 0.0, 1.0); webgl.clearDepth(1.0); webgl.depthMask(true); webgl.disable(webgl.BLEND); webgl.clear(webgl.COLOR_BUFFER_BIT|webgl.DEPTH_BUFFER_BIT); webgl.texParameteri(webgl.TEXTURE_CUBE_MAP, webgl.TEXTURE_MIN_FILTER, webgl.NEAREST); webgl.texParameteri(webgl.TEXTURE_CUBE_MAP, webgl.TEXTURE_MAG_FILTER, webgl.NEAREST); webgl.texParameteri(webgl.TEXTURE_CUBE_MAP, webgl.TEXTURE_WRAP_S, webgl.CLAMP_TO_EDGE); webgl.texParameteri(webgl.TEXTURE_CUBE_MAP, webgl.TEXTURE_WRAP_T, webgl.CLAMP_TO_EDGE);oJSWebGL.BindTextureUnit(webgl.TEXTURE0, webgl.TEXTURE_CUBE_MAP, textureObject);//直观
webgl.uniform1i(oJSWebGLProgram.u_samplerCube, 0); webgl.frontFace(webgl.CW); webgl.cullFace(webgl.BACK); webgl.enable(webgl.CULL_FACE);//画平面
webgl.disable(webgl.DEPTH_TEST);//相当于地面,禁止深度测试,此时深度缓冲中值保持1.0不变,表示可以被任何其它物体所遮挡 oJSWebGL.JS_VertexAttribPointer(oJSWebGLProgram.a_v3Position, "shadowPlane", 0, 0); webgl.enableVertexAttribArray(oJSWebGLProgram.a_v3Position); webgl.disableVertexAttribArray(oJSWebGLProgram.a_v3Normal); webgl.uniform1i(oJSWebGLProgram.u_iShadowMode, 2); //只需要透视投影 webgl.uniformMatrix4fv(oJSWebGLProgram.u_m4ModelView, false, perspectiveMat4); webgl.drawArrays(webgl.TRIANGLE_FAN, 0, 4);var jsMatrix = new CJSMat4();
//画立方体 //先旋转,再透视投影 oJSWebGL.JS_VertexAttribPointer(oJSWebGLProgram.a_v3Position, "cube", 0, 0); oJSWebGL.JS_SetCurrentBuffer("cubeIndex"); webgl.enableVertexAttribArray(oJSWebGLProgram.a_v3Position); //画阴影 webgl.disable(webgl.DEPTH_TEST); webgl.uniform1i(oJSWebGLProgram.u_iShadowMode, 1); webgl.disableVertexAttribArray(oJSWebGLProgram.a_v3Normal); jsMatrix.Identity(); jsMatrix.Scale([0.5, 0.5, 0.5]); jsMatrix.Transform(rotateMat4, shadowMat4, perspectiveMat4); webgl.uniformMatrix4fv(oJSWebGLProgram.u_m4ModelView, false, jsMatrix.GetValue()); webgl.drawElements(webgl.TRIANGLES, 36, webgl.UNSIGNED_BYTE, 0); //画立方体 webgl.uniform1i(oJSWebGLProgram.u_bUseLighting, document.getElementById("lighting").checked); webgl.uniform3f(oJSWebGLProgram.u_v3AmbientScale, parseFloat(document.getElementById("ambientR").value), parseFloat(document.getElementById("ambientG").value), parseFloat(document.getElementById("ambientB").value)); webgl.uniform3fv(oJSWebGLProgram.u_v3PointLightPosition, [-1, 1, 0]); webgl.uniform3f(oJSWebGLProgram.u_v3PointLightScale, parseFloat(document.getElementById("pointR").value), parseFloat(document.getElementById("pointG").value), parseFloat(document.getElementById("pointB").value)); webgl.enable(webgl.DEPTH_TEST); webgl.depthFunc(webgl.LEQUAL); webgl.depthMask(true); webgl.uniform1i(oJSWebGLProgram.u_iShadowMode, 0); jsMatrix.Identity(); jsMatrix.Scale([0.5, 0.5, 0.5]); jsMatrix.Transform(rotateMat4, perspectiveMat4); webgl.uniformMatrix4fv(oJSWebGLProgram.u_m4ModelView, false, jsMatrix.GetValue()); oJSWebGL.JS_VertexAttribPointer(oJSWebGLProgram.a_v3Normal, "cubeNormals", 0, 0); webgl.enableVertexAttribArray(oJSWebGLProgram.a_v3Normal); webgl.drawElements(webgl.TRIANGLES, 36, webgl.UNSIGNED_BYTE, 0); //画圆锥 webgl.enable(webgl.DEPTH_TEST); webgl.depthFunc(webgl.LEQUAL); webgl.uniform1i(oJSWebGLProgram.u_iShadowMode, 3); jsMatrix.Identity(); jsMatrix.Transform(jsConeMat4, rotateMat4, perspectiveMat4); webgl.uniformMatrix4fv(oJSWebGLProgram.u_m4ModelView, false, jsMatrix.GetValue()); oJSWebGL.JS_VertexAttribPointer(oJSWebGLProgram.a_v3Position, "cone", 0, 0); webgl.enableVertexAttribArray(oJSWebGLProgram.a_v3Position); webgl.disableVertexAttribArray(oJSWebGLProgram.a_v3Normal); webgl.drawArrays(webgl.TRIANGLE_FAN, 0, 14); //画大立方体,除了混合指令,其他基本上和画小立方体相同 oJSWebGL.JS_VertexAttribPointer(oJSWebGLProgram.a_v3Position, "cube", 0, 0); oJSWebGL.JS_SetCurrentBuffer("cubeIndex"); webgl.enableVertexAttribArray(oJSWebGLProgram.a_v3Position); webgl.disableVertexAttribArray(oJSWebGLProgram.a_v3Normal); webgl.enable(webgl.DEPTH_TEST); webgl.depthFunc(webgl.LEQUAL); webgl.depthMask(false); webgl.uniform1i(oJSWebGLProgram.u_iShadowMode, 4); jsMatrix.Identity(); jsMatrix.Transform(rotateMat4, perspectiveMat4); webgl.uniformMatrix4fv(oJSWebGLProgram.u_m4ModelView, false, jsMatrix.GetValue()); oJSWebGL.JS_VertexAttribPointer(oJSWebGLProgram.a_v3Normal, "cubeNormals", 0, 0); //设置混合 webgl.enable(webgl.BLEND);//首先要启用混合 webgl.blendEquation(webgl.FUNC_ADD);//相加 webgl.blendFunc(webgl.SRC_COLOR, webgl.DST_COLOR);//源色和现有色的相加 webgl.drawElements(webgl.TRIANGLES, 36, webgl.UNSIGNED_BYTE, 0); }//这些事件代码仍然只适合FF浏览器
function OnMouseDown(e) { mouseDown = true; mousePosition = [parseInt(e.screenX), parseInt(e.screenY)]; } function OnMouseUp(e) { mouseDown = false; vec3.add(rotatePosV3, [parseInt(e.screenX)-mousePosition[0], parseInt(e.screenY)-mousePosition[1], 0]); } function OnMouseMove(e) { if(!mouseDown) return; var tV3 = []; vec3.add(rotatePosV3, [parseInt(e.screenX)-mousePosition[0], parseInt(e.screenY)-mousePosition[1], 0], tV3);//上次偏移加拖动形成的临时偏移成为本次拖动的最终偏移 mat4.identity(rotateMat4);//首先设置为单位矩阵,然后再构造成旋转矩阵 if(tV3[0] == 0 && tV3[1] == 0) return; //根据位移,计算出当前的方向 var v3 = null; var wh = oJSWebGL.Viewport(); var r = Math.min(wh[0], wh[1])/2; var l = Math.sqrt(tV3[0]*tV3[0] + tV3[1] * tV3[1]); if(l <= r) v3 = [tV3[0], tV3[1], Math.sqrt(r*r - l*l)]; else v3 = [r*tV3[0]/l, r*tV3[1]/l, 0]; v3[1] = - v3[1]; var radians = Math.acos(vec3.dot([0,0,1], v3)/r); var vn = []; gltGetNormalVector([0,0,0], [0,0,1], v3, vn);//或vec3.cross([0,0,1], v3, vn); mat4.rotate(rotateMat4, radians, vn); }var oJSWebGL = null;
var oJSWebGLProgram = null; var webgl = null;function Init()
{ oJSWebGL = new CJSWebGL ('myCanvas'); try { if(!oJSWebGL.Init()) throw oJSWebGL.error;webgl = oJSWebGL.webgl;
oJSWebGLProgram = oJSWebGL.JS_SetupProgramObject("shader-vs", "shader-fs", true);if(oJSWebGLProgram == null) throw oJSWebGL.error;//如果oJSWebGLProgram生成成功,则各个活动属性和活动uniform的位置/索引都将自动保存到oJSWebGLProgram对象下的同名变量
if(LoadData() != 0) throw "error:LoadData()!"; oJSWebGL.SetMouseCallback(OnMouseDown, OnMouseMove, OnMouseUp); oJSWebGL.SetRender(RenderScene, 300); } catch(e){alert(e);} }</script>
</head> <body οnlοad='Init()'> <p>将加载数据的代码转到了loadData.js文件中。<br> <canvas id="myCanvas" style="border:1px solid red;" width='600px' height='450px'></canvas><table> <tr><td>光照控制:</td><td colspan=3><input type="checkbox" id="lighting" checked />启用光照</td></tr> <tr><td>环境光(比例):</td> <td>R: <input type="text" id="ambientR" value="0.5"></td> <td>G: <input type="text" id="ambientG" value="0.5"></td> <td>B: <input type="text" id="ambientB" value="0.5"></td></tr> <tr><td>点光源(比例):</td> <td>R: <input type="text" id="pointR" value="1.0"></td> <td>G: <input type="text" id="pointG" value="1.0"></td> <td>B: <input type="text" id="pointB" value="1.0"></td></tr> </table><br> <img id="myTexture1" src='cubeTexture1.bmp'> <img id="myTexture2" src='cubeTexture2.bmp'> <img id="myTexture3" src='cubeTexture3.bmp'><br> <img id="myTexture4" src='cubeTexture4.bmp'> <img id="myTexture5" src='cubeTexture5.bmp'> <img id="myTexture6" src='cubeTexture6.bmp'> </body> </html>
loadData.js文件的内容:
function LoadTriangleData(bufferName)
{ var jsTriangleData = [ 0.0, 1.0, 0.0,//上顶点 1.0, 0.0, 0.0,//右顶点 -1.0, -1.0, 0.0];//左顶点 oJSWebGL.JS_LoadArrayBuffer(bufferName, new Float32Array(jsTriangleData), webgl.STATIC_DRAW, 3, webgl.FLOAT, false); } function LoadCubeData(cubeBufferName, cubeIndexBufferName, cubeNormalsBufferName) //"cube", "cubeIndex", "cubeNormals" { var jsCubeData = [ // Front face -0.3, -0.3, 0.3, 0.3, -0.3, 0.3, 0.3, 0.3, 0.3, -0.3, 0.3, 0.3,// Back face
-0.3, -0.3, -0.3, -0.3, 0.3, -0.3, 0.3, 0.3, -0.3, 0.3, -0.3, -0.3,// Top face
-0.3, 0.3, -0.3, -0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, -0.3,// Bottom face
-0.3, -0.3, -0.3, 0.3, -0.3, -0.3, 0.3, -0.3, 0.3, -0.3, -0.3, 0.3,// Right face
0.3, -0.3, -0.3, 0.3, 0.3, -0.3, 0.3, 0.3, 0.3, 0.3, -0.3, 0.3,// Left face
-0.3, -0.3, -0.3, -0.3, -0.3, 0.3, -0.3, 0.3, 0.3, -0.3, 0.3, -0.3,];
oJSWebGL.JS_LoadArrayBuffer(cubeBufferName, new Float32Array(jsCubeData), webgl.STATIC_DRAW, 3, webgl.FLOAT, false);//加载之后,可以通过oJSWebGL.jsBuffers.cube进行访问var jsCubeIndex = [
2, 1, 0, 3, 2, 0, // Front face 6, 5, 4, 7, 6, 4, // Back face 10, 9, 8, 11, 10, 8, // Top face 14, 13, 12, 15, 14, 12, // Bottom face 18, 17, 16, 19, 18, 16, // Right face 22, 21, 20, 23, 22, 20 // Left face ]; oJSWebGL.JS_LoadElementArrayBuffer(cubeIndexBufferName, new Uint8Array(jsCubeIndex), webgl.STATIC_DRAW, 3, webgl.UNSIGNED_BYTE, false);//加载之后,可以通过oJSWebGL.jsBuffers.cubeIndex进行访问 var jsCubeNormals = [ // Front face 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0,// Back face
0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0,// Top face
0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,// Bottom face
0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0,// Right face
1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0,// Left face
-1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, ]; oJSWebGL.JS_LoadArrayBuffer(cubeNormalsBufferName, new Float32Array(jsCubeNormals), webgl.STATIC_DRAW, 3, webgl.FLOAT, false);//加载之后,可以通过oJSWebGL.jsBuffers.cubeNormals进行访问 } function LoadTextureData() { textureObject = webgl.createTexture(); webgl.bindTexture(webgl.TEXTURE_CUBE_MAP, textureObject); webgl.texImage2D(webgl.TEXTURE_CUBE_MAP_POSITIVE_X, 0, webgl.RGB, webgl.RGB, webgl.UNSIGNED_BYTE, document.getElementById('myTexture1')); webgl.texImage2D(webgl.TEXTURE_CUBE_MAP_NEGATIVE_X, 0, webgl.RGB, webgl.RGB, webgl.UNSIGNED_BYTE, document.getElementById('myTexture2')); webgl.texImage2D(webgl.TEXTURE_CUBE_MAP_POSITIVE_Y, 0, webgl.RGB, webgl.RGB, webgl.UNSIGNED_BYTE, document.getElementById('myTexture3')); webgl.texImage2D(webgl.TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, webgl.RGB, webgl.RGB, webgl.UNSIGNED_BYTE, document.getElementById('myTexture4')); webgl.texImage2D(webgl.TEXTURE_CUBE_MAP_POSITIVE_Z, 0, webgl.RGB, webgl.RGB, webgl.UNSIGNED_BYTE, document.getElementById('myTexture5')); webgl.texImage2D(webgl.TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, webgl.RGB, webgl.RGB, webgl.UNSIGNED_BYTE, document.getElementById('myTexture6')); } function LoadShadowPlaneData(bufferName, shadowMat4Name) //"shadowPlane", "shadowMat4" { var jsShadowPlaneData = [-1.0, -1.0, 1.0, -1.0,-0.25,-1.0, 1.0,-0.25,-1.0, 1.0, -1.0, 1.0]; oJSWebGL.JS_LoadArrayBuffer(bufferName, new Float32Array(jsShadowPlaneData), webgl.STATIC_DRAW, 3, webgl.FLOAT, false); eval(shadowMat4Name+" = mat4.create();"); eval("gltMakeShadowMatrix([[-1, -1, 1], [1, -1, 1], [0, -0.25, -1]], [-1, 1, 0, 1], "+shadowMat4Name+");"); } function LoadConeData(coneBufferName, jsConeMat4Name) //"cone", "jsConeMat4" { var jsConeData = [0, 0.2, 0];//圆锥的顶部顶点为(0, 0.2, 0) for(var i=0; i<13; ++i)//计算圆锥顶部圆面上的12个点;圆的半径为0.1 { //保证各个顶点为顺时针顺序 var radians = -i*30*Math.PI/180; jsConeData[jsConeData.length] = parseInt(0.1 * Math.cos(radians)*1000)/1000; jsConeData[jsConeData.length] = 0; jsConeData[jsConeData.length] = -parseInt(0.1 * Math.sin(radians)*1000)/1000; } oJSWebGL.JS_LoadArrayBuffer(coneBufferName, new Float32Array(jsConeData), webgl.STATIC_DRAW, 3, webgl.FLOAT, false); eval(jsConeMat4Name+" = new CJSMat4();"); eval(jsConeMat4Name+".Identity();"); eval(jsConeMat4Name+".RotateX(Math.PI/2);"); eval(jsConeMat4Name+".Translate([0, 0, 0.3]);"); } function LoadPerspectiveMat4(mat4Name)//"perspectiveMat4" { var lookAtMat4 = mat4.create(); mat4.lookAt([0, 0, 1], [0,0,0], [0,1,0], lookAtMat4); eval(mat4Name+" = mat4.create();"); var wh = oJSWebGL.Viewport(); eval("mat4.perspective(60, wh[0]/wh[1], 0.1, 2, "+mat4Name+");"); eval("mat4.multiply("+mat4Name+", lookAtMat4, "+mat4Name+");"); }
转载地址:http://xrami.baihongyu.com/