1. <!DOCTYPE HTML>
  2. <html lang="en">
  3. <head>
  4. <title>Listing 7-3 and 7-4, Texturing and Lighting With the Phong Reflection Model.</title>
  5. <script src="./lib/webgl-debug.js"></script>
  6. <script src="./lib/glMatrix.js"></script>
  7. <script src="./lib/webgl-utils.js"></script>
  8.  
  9. <meta charset="utf-8">
  10. <script id="shader-vs" type="x-shader/x-vertex">
  11. // Vertex shader implemented to perform lighting according to the
  12. // Phong reflection model. Forwards texture coordinates to fragment
  13. // shader.
  14. attribute vec3 aVertexPosition;
  15. attribute vec3 aVertexNormal;
  16. attribute vec2 aTextureCoordinates;
  17.  
  18. uniform mat4 uMVMatrix;
  19. uniform mat4 uPMatrix;
  20. uniform mat3 uNMatrix;
  21.  
  22. uniform vec3 uLightPosition;
  23. uniform vec3 uAmbientLightColor;
  24. uniform vec3 uDiffuseLightColor;
  25. uniform vec3 uSpecularLightColor;
  26.  
  27. varying vec2 vTextureCoordinates;
  28. varying vec3 vLightWeighting;
  29.  
  30. const float shininess = 32.0;
  31.  
  32. void main() {
  33. // Get the vertex position in eye coordinates
  34. vec4 vertexPositionEye4 = uMVMatrix * vec4(aVertexPosition, 1.0);
  35. vec3 vertexPositionEye3 = vertexPositionEye4.xyz / vertexPositionEye4.w;
  36.  
  37. // Calculate the vector (l) to the light source
  38. vec3 vectorToLightSource = normalize(uLightPosition - vertexPositionEye3);
  39.  
  40. // Transform the normal (n) to eye coordinates
  41. vec3 normalEye = normalize(uNMatrix * aVertexNormal);
  42.  
  43. // Calculate n dot l for diffuse lighting
  44. float diffuseLightWeightning = max(dot(normalEye,
  45. vectorToLightSource), 0.0);
  46.  
  47. // Calculate the reflection vector (r) that is needed for specular light
  48. vec3 reflectionVector = normalize(reflect(-vectorToLightSource,
  49. normalEye));
  50.  
  51. // The camera in eye coordinates is located in the origin and is pointing
  52. // along the negative z-axis. Calculate viewVector (v) in eye coordinates as:
  53. // (0.0, 0.0, 0.0) - vertexPositionEye3
  54. vec3 viewVectorEye = -normalize(vertexPositionEye3);
  55.  
  56. float rdotv = max(dot(reflectionVector, viewVectorEye), 0.0);
  57.  
  58. float specularLightWeightning = pow(rdotv, shininess);
  59.  
  60. // Sum up all three reflection components and send to the fragment shader
  61. vLightWeighting = uAmbientLightColor +
  62. uDiffuseLightColor * diffuseLightWeightning +
  63. uSpecularLightColor * specularLightWeightning;
  64.  
  65. // Finally transform the geometry
  66. gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
  67. vTextureCoordinates = aTextureCoordinates;
  68. }
  69. </script>
  70.  
  71. <!--片元着色器-->
  72. <script id="shader-fs" type="x-shader/x-fragment">
  73. precision mediump float;
  74.  
  75. varying vec2 vTextureCoordinates;
  76. varying vec3 vLightWeighting;
  77. uniform sampler2D uSampler;
  78.  
  79. void main() {
  80. vec4 texelColor = texture2D(uSampler, vTextureCoordinates);
  81.  
  82. //结合了纹理和光照的片段着色器(vLightWeighting包含已经计算得到的环境光和漫反射光)
  83. gl_FragColor = vec4(vLightWeighting.rgb * texelColor.rgb, texelColor.a);
  84. }
  85. </script>
  86.  
  87. <script type="text/javascript">
  88. // globals
  89. var gl;
  90. var pwgl = {};
  91. // Keep track of ongoing image loads to be able to handle lost context
  92. pwgl.ongoingImageLoads = [];
  93. var canvas;
  94.  
  95. function createGLContext(canvas) {
  96. var names = ["webgl", "experimental-webgl"];
  97. var context = null;
  98. for (var i=0; i < names.length; i++) {
  99. try {
  100. context = canvas.getContext(names[i]);
  101. } catch(e) {}
  102. if (context) {
  103. break;
  104. }
  105. }
  106. if (context) {
  107. context.viewportWidth = canvas.width;
  108. context.viewportHeight = canvas.height;
  109. } else {
  110. alert("Failed to create WebGL context!");
  111. }
  112. return context;
  113. }
  114.  
  115. function loadShaderFromDOM(id) {
  116. var shaderScript = document.getElementById(id);
  117.  
  118. // If we don't find an element with the specified id
  119. // we do an early exit
  120. if (!shaderScript) {
  121. return null;
  122. }
  123.  
  124. // Loop through the children for the found DOM element and
  125. // build up the shader source code as a string
  126. var shaderSource = "";
  127. var currentChild = shaderScript.firstChild;
  128. while (currentChild) {
  129. if (currentChild.nodeType == 3) { // 3 corresponds to TEXT_NODE
  130. shaderSource += currentChild.textContent;
  131. }
  132. currentChild = currentChild.nextSibling;
  133. }
  134.  
  135. var shader;
  136. if (shaderScript.type == "x-shader/x-fragment") {
  137. shader = gl.createShader(gl.FRAGMENT_SHADER);
  138. } else if (shaderScript.type == "x-shader/x-vertex") {
  139. shader = gl.createShader(gl.VERTEX_SHADER);
  140. } else {
  141. return null;
  142. }
  143.  
  144. gl.shaderSource(shader, shaderSource);
  145. gl.compileShader(shader);
  146.  
  147. if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS) &&
  148. !gl.isContextLost()) {
  149. alert(gl.getShaderInfoLog(shader));
  150. return null;
  151. }
  152. return shader;
  153. }
  154.  
  155. function setupShaders() {
  156. var vertexShader = loadShaderFromDOM("shader-vs");
  157. var fragmentShader = loadShaderFromDOM("shader-fs");
  158.  
  159. var shaderProgram = gl.createProgram();
  160. gl.attachShader(shaderProgram, vertexShader);
  161. gl.attachShader(shaderProgram, fragmentShader);
  162. gl.linkProgram(shaderProgram);
  163.  
  164. if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS) &&
  165. !gl.isContextLost()) {
  166. alert("Failed to link shaders: " + gl.getProgramInfoLog(shaderProgram));
  167. }
  168.  
  169. gl.useProgram(shaderProgram);
  170. pwgl.vertexPositionAttributeLoc =
  171. gl.getAttribLocation(shaderProgram, "aVertexPosition");
  172.  
  173. pwgl.vertexNormalAttributeLoc =
  174. gl.getAttribLocation(shaderProgram, "aVertexNormal");
  175.  
  176. pwgl.vertexTextureAttributeLoc =
  177. gl.getAttribLocation(shaderProgram, "aTextureCoordinates");
  178.  
  179. pwgl.uniformMVMatrixLoc =
  180. gl.getUniformLocation(shaderProgram, "uMVMatrix");
  181.  
  182. pwgl.uniformProjMatrixLoc =
  183. gl.getUniformLocation(shaderProgram, "uPMatrix");
  184.  
  185. pwgl.uniformNormalMatrixLoc =
  186. gl.getUniformLocation(shaderProgram, "uNMatrix");
  187.  
  188. pwgl.uniformSamplerLoc =
  189. gl.getUniformLocation(shaderProgram, "uSampler");
  190.  
  191. pwgl.uniformLightPositionLoc =
  192. gl.getUniformLocation(shaderProgram, "uLightPosition");
  193.  
  194. pwgl.uniformAmbientLightColorLoc =
  195. gl.getUniformLocation(shaderProgram, "uAmbientLightColor");
  196.  
  197. pwgl.uniformDiffuseLightColorLoc =
  198. gl.getUniformLocation(shaderProgram, "uDiffuseLightColor");
  199.  
  200. pwgl.uniformSpecularLightColorLoc =
  201. gl.getUniformLocation(shaderProgram, "uSpecularLightColor");
  202.  
  203. gl.enableVertexAttribArray(pwgl.vertexPositionAttributeLoc);
  204. gl.enableVertexAttribArray(pwgl.vertexNormalAttributeLoc);
  205. gl.enableVertexAttribArray(pwgl.vertexTextureAttributeLoc);
  206.  
  207. pwgl.modelViewMatrix = mat4.create();
  208. pwgl.projectionMatrix = mat4.create();
  209. pwgl.modelViewMatrixStack = [];
  210. }
  211.  
  212. function pushModelViewMatrix() {
  213. var copyToPush = mat4.create(pwgl.modelViewMatrix);
  214. pwgl.modelViewMatrixStack.push(copyToPush);
  215. }
  216.  
  217. function popModelViewMatrix() {
  218. if (pwgl.modelViewMatrixStack.length == 0) {
  219. throw "Error popModelViewMatrix() - Stack was empty ";
  220. }
  221. pwgl.modelViewMatrix = pwgl.modelViewMatrixStack.pop();
  222. }
  223.  
  224. function setupFloorBuffers() {
  225. pwgl.floorVertexPositionBuffer = gl.createBuffer();
  226. gl.bindBuffer(gl.ARRAY_BUFFER, pwgl.floorVertexPositionBuffer);
  227.  
  228. var floorVertexPosition = [
  229. // Plane in y=0
  230. 5.0, 0.0, 5.0, //v0
  231. 5.0, 0.0, -5.0, //v1
  232. -5.0, 0.0, -5.0, //v2
  233. -5.0, 0.0, 5.0]; //v3
  234.  
  235. gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(floorVertexPosition),
  236. gl.STATIC_DRAW);
  237.  
  238. pwgl.FLOOR_VERTEX_POS_BUF_ITEM_SIZE = 3;
  239. pwgl.FLOOR_VERTEX_POS_BUF_NUM_ITEMS = 4;
  240.  
  241. //指定地板的法向量的方向
  242. // Specify normals to be able to do lighting calculations
  243. pwgl.floorVertexNormalBuffer = gl.createBuffer();
  244. gl.bindBuffer(gl.ARRAY_BUFFER, pwgl.floorVertexNormalBuffer);
  245.  
  246. var floorVertexNormals = [
  247. 0.0, 1.0, 0.0, //v0
  248. 0.0, 1.0, 0.0, //v1
  249. 0.0, 1.0, 0.0, //v2
  250. 0.0, 1.0, 0.0]; //v3
  251.  
  252. gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(floorVertexNormals),
  253. gl.STATIC_DRAW);
  254.  
  255. pwgl.FLOOR_VERTEX_NORMAL_BUF_ITEM_SIZE = 3;
  256. pwgl.FLOOR_VERTEX_NORMAL_BUF_NUM_ITEMS = 4;
  257.  
  258. // Setup texture coordinates buffer
  259. pwgl.floorVertexTextureCoordinateBuffer = gl.createBuffer();
  260. gl.bindBuffer(gl.ARRAY_BUFFER, pwgl.floorVertexTextureCoordinateBuffer);
  261. var floorVertexTextureCoordinates = [
  262. 2.0, 0.0,
  263. 2.0, 2.0,
  264. 0.0, 2.0,
  265. 0.0, 0.0
  266. ];
  267.  
  268. gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(floorVertexTextureCoordinates),
  269. gl.STATIC_DRAW);
  270.  
  271. pwgl.FLOOR_VERTEX_TEX_COORD_BUF_ITEM_SIZE = 2;
  272. pwgl.FLOOR_VERTEX_TEX_COORD_BUF_NUM_ITEMS = 4;
  273.  
  274. // Setup index buffer
  275. pwgl.floorVertexIndexBuffer = gl.createBuffer();
  276. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, pwgl.floorVertexIndexBuffer);
  277. var floorVertexIndices = [0, 1, 2, 3];
  278.  
  279. gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(floorVertexIndices),
  280. gl.STATIC_DRAW);
  281.  
  282. pwgl.FLOOR_VERTEX_INDEX_BUF_ITEM_SIZE = 1;
  283. pwgl.FLOOR_VERTEX_INDEX_BUF_NUM_ITEMS = 4;
  284. }
  285.  
  286. function setupCubeBuffers() {
  287. pwgl.cubeVertexPositionBuffer = gl.createBuffer();
  288. gl.bindBuffer(gl.ARRAY_BUFFER, pwgl.cubeVertexPositionBuffer);
  289.  
  290. var cubeVertexPosition = [
  291. // Front face
  292. 1.0, 1.0, 1.0, //v0
  293. -1.0, 1.0, 1.0, //v1
  294. -1.0, -1.0, 1.0, //v2
  295. 1.0, -1.0, 1.0, //v3
  296.  
  297. // Back face
  298. 1.0, 1.0, -1.0, //v4
  299. -1.0, 1.0, -1.0, //v5
  300. -1.0, -1.0, -1.0, //v6
  301. 1.0, -1.0, -1.0, //v7
  302.  
  303. // Left face
  304. -1.0, 1.0, 1.0, //v8
  305. -1.0, 1.0, -1.0, //v9
  306. -1.0, -1.0, -1.0, //v10
  307. -1.0, -1.0, 1.0, //v11
  308.  
  309. // Right face
  310. 1.0, 1.0, 1.0, //12
  311. 1.0, -1.0, 1.0, //13
  312. 1.0, -1.0, -1.0, //14
  313. 1.0, 1.0, -1.0, //15
  314.  
  315. // Top face
  316. 1.0, 1.0, 1.0, //v16
  317. 1.0, 1.0, -1.0, //v17
  318. -1.0, 1.0, -1.0, //v18
  319. -1.0, 1.0, 1.0, //v19
  320.  
  321. // Bottom face
  322. 1.0, -1.0, 1.0, //v20
  323. 1.0, -1.0, -1.0, //v21
  324. -1.0, -1.0, -1.0, //v22
  325. -1.0, -1.0, 1.0, //v23
  326. ];
  327.  
  328. gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(cubeVertexPosition),
  329. gl.STATIC_DRAW);
  330.  
  331. pwgl.CUBE_VERTEX_POS_BUF_ITEM_SIZE = 3;
  332. pwgl.CUBE_VERTEX_POS_BUF_NUM_ITEMS = 24;
  333.  
  334. // Specify normals to be able to do lighting calculations
  335. pwgl.cubeVertexNormalBuffer = gl.createBuffer();
  336. gl.bindBuffer(gl.ARRAY_BUFFER, pwgl.cubeVertexNormalBuffer);
  337.  
  338. //指定立方体的每一个面的法向量
  339. var cubeVertexNormals = [
  340. // Front face
  341. 0.0, 0.0, 1.0, //v0
  342. 0.0, 0.0, 1.0, //v1
  343. 0.0, 0.0, 1.0, //v2
  344. 0.0, 0.0, 1.0, //v3
  345.  
  346. // Back face
  347. 0.0, 0.0, -1.0, //v4
  348. 0.0, 0.0, -1.0, //v5
  349. 0.0, 0.0, -1.0, //v6
  350. 0.0, 0.0, -1.0, //v7
  351.  
  352. // Left face
  353. -1.0, 0.0, 0.0, //v8
  354. -1.0, 0.0, 0.0, //v9
  355. -1.0, 0.0, 0.0, //v10
  356. -1.0, 0.0, 0.0, //v11
  357.  
  358. // Right face
  359. 1.0, 0.0, 0.0, //12
  360. 1.0, 0.0, 0.0, //13
  361. 1.0, 0.0, 0.0, //14
  362. 1.0, 0.0, 0.0, //15
  363.  
  364. // Top face
  365. 0.0, 1.0, 0.0, //v16
  366. 0.0, 1.0, 0.0, //v17
  367. 0.0, 1.0, 0.0, //v18
  368. 0.0, 1.0, 0.0, //v19
  369.  
  370. // Bottom face
  371. 0.0, -1.0, 0.0, //v20
  372. 0.0, -1.0, 0.0, //v21
  373. 0.0, -1.0, 0.0, //v22
  374. 0.0, -1.0, 0.0, //v23
  375. ];
  376.  
  377. gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(cubeVertexNormals),
  378. gl.STATIC_DRAW);
  379.  
  380. pwgl.CUBE_VERTEX_NORMAL_BUF_ITEM_SIZE = 3;
  381. pwgl.CUBE_VERTEX_NORMAL_BUF_NUM_ITEMS = 24;
  382.  
  383. // Setup buffer with texture coordinates
  384. pwgl.cubeVertexTextureCoordinateBuffer = gl.createBuffer();
  385. gl.bindBuffer(gl.ARRAY_BUFFER, pwgl.cubeVertexTextureCoordinateBuffer);
  386. var textureCoordinates = [
  387. //Front face
  388. 0.0, 0.0, //v0
  389. 1.0, 0.0, //v1
  390. 1.0, 1.0, //v2
  391. 0.0, 1.0, //v3
  392.  
  393. // Back face
  394. 0.0, 1.0, //v4
  395. 1.0, 1.0, //v5
  396. 1.0, 0.0, //v6
  397. 0.0, 0.0, //v7
  398.  
  399. // Left face
  400. 0.0, 1.0, //v8
  401. 1.0, 1.0, //v9
  402. 1.0, 0.0, //v10
  403. 0.0, 0.0, //v11
  404.  
  405. // Right face
  406. 0.0, 1.0, //v12
  407. 1.0, 1.0, //v13
  408. 1.0, 0.0, //v14
  409. 0.0, 0.0, //v15
  410.  
  411. // Top face
  412. 0.0, 1.0, //v16
  413. 1.0, 1.0, //v17
  414. 1.0, 0.0, //v18
  415. 0.0, 0.0, //v19
  416.  
  417. // Bottom face
  418. 0.0, 1.0, //v20
  419. 1.0, 1.0, //v21
  420. 1.0, 0.0, //v22
  421. 0.0, 0.0, //v23
  422. ];
  423.  
  424. gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordinates),gl.STATIC_DRAW);
  425. pwgl.CUBE_VERTEX_TEX_COORD_BUF_ITEM_SIZE = 2;
  426. pwgl.CUBE_VERTEX_TEX_COORD_BUF_NUM_ITEMS = 24;
  427.  
  428. pwgl.cubeVertexIndexBuffer = gl.createBuffer();
  429. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, pwgl.cubeVertexIndexBuffer);
  430. var cubeVertexIndices = [
  431. 0, 1, 2, 0, 2, 3, // Front face
  432. 4, 6, 5, 4, 7, 6, // Back face
  433. 8, 9, 10, 8, 10, 11, // Left face
  434. 12, 13, 14, 12, 14, 15, // Right face
  435. 16, 17, 18, 16, 18, 19, // Top face
  436. 20, 22, 21, 20, 23, 22 // Bottom face
  437. ];
  438. gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cubeVertexIndices),
  439. gl.STATIC_DRAW);
  440. pwgl.CUBE_VERTEX_INDEX_BUF_ITEM_SIZE = 1;
  441. pwgl.CUBE_VERTEX_INDEX_BUF_NUM_ITEMS = 36;
  442. }
  443.  
  444. function textureFinishedLoading(image, texture) {
  445. gl.bindTexture(gl.TEXTURE_2D, texture);
  446. gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
  447.  
  448. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE,
  449. image);
  450.  
  451. gl.generateMipmap(gl.TEXTURE_2D);
  452.  
  453. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  454. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  455.  
  456. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.MIRRORED_REPEAT);
  457. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);
  458. gl.bindTexture(gl.TEXTURE_2D, null);
  459. }
  460.  
  461. function loadImageForTexture(url, texture) {
  462. var image = new Image();
  463. image.onload = function() {
  464. pwgl.ongoingImageLoads.splice(pwgl.ongoingImageLoads.indexOf(image), 1);
  465. textureFinishedLoading(image, texture);
  466. }
  467. pwgl.ongoingImageLoads.push(image);
  468. image.src = url;
  469. }
  470.  
  471. function setupTextures() {
  472. // Texture for the table
  473. pwgl.woodTexture = gl.createTexture();
  474. loadImageForTexture("./resources/wood_128x128.jpg", pwgl.woodTexture);
  475.  
  476. // Texture for the floor
  477. pwgl.groundTexture = gl.createTexture();
  478. loadImageForTexture("./resources/wood_floor_256.jpg", pwgl.groundTexture);
  479.  
  480. // Texture for the box on the table
  481. pwgl.boxTexture = gl.createTexture();
  482. loadImageForTexture("./resources/wicker_256.jpg", pwgl.boxTexture);
  483.  
  484. //创建一个立方体
  485. pwgl.colorCube = gl.createTexture();
  486. loadImageForTexture("./resources/xiuxiuba.bmp", pwgl.colorCube);
  487. }
  488.  
  489. function setupBuffers() {
  490. setupFloorBuffers();
  491. setupCubeBuffers();
  492. }
  493.  
  494. //设置光源位置,环境光颜色,漫反射光颜色,镜面反射光
  495. function setupLights() {
  496. gl.uniform3fv(pwgl.uniformLightPositionLoc, [0.0, 20.0, 0.0]);
  497. gl.uniform3fv(pwgl.uniformAmbientLightColorLoc, [0.2, 0.2, 0.2]);
  498. gl.uniform3fv(pwgl.uniformDiffuseLightColorLoc, [0.7, 0.7, 0.7]);
  499. gl.uniform3fv(pwgl.uniformSpecularLightColorLoc, [0.8, 0.8, 0.8]);
  500. }
  501.  
  502. function uploadModelViewMatrixToShader() {
  503. gl.uniformMatrix4fv(pwgl.uniformMVMatrixLoc, false, pwgl.modelViewMatrix);
  504. }
  505.  
  506. function uploadProjectionMatrixToShader() {
  507. gl.uniformMatrix4fv(pwgl.uniformProjMatrixLoc,
  508. false, pwgl.projectionMatrix);
  509. }
  510.  
  511. //上传法向量的矩阵到着色器
  512. function uploadNormalMatrixToShader() {
  513. var normalMatrix = mat3.create();
  514. //计算矩阵的逆
  515. mat4.toInverseMat3(pwgl.modelViewMatrix, normalMatrix);
  516. //计算转置矩阵
  517. mat3.transpose(normalMatrix);
  518. //把法向量矩阵传给着色器
  519. gl.uniformMatrix3fv(pwgl.uniformNormalMatrixLoc, false, normalMatrix);
  520. }
  521.  
  522. function drawFloor() {
  523. // Bind position buffer
  524. gl.bindBuffer(gl.ARRAY_BUFFER, pwgl.floorVertexPositionBuffer);
  525. gl.vertexAttribPointer(pwgl.vertexPositionAttributeLoc,
  526. pwgl.FLOOR_VERTEX_POS_BUF_ITEM_SIZE,
  527. gl.FLOAT, false, 0, 0);
  528.  
  529. // Bind normal buffer
  530. gl.bindBuffer(gl.ARRAY_BUFFER, pwgl.floorVertexNormalBuffer);
  531. gl.vertexAttribPointer(pwgl.vertexNormalAttributeLoc,
  532. pwgl.FLOOR_VERTEX_NORMAL_BUF_ITEM_SIZE,
  533. gl.FLOAT, false, 0, 0);
  534.  
  535. // Bind texture coordinate buffer
  536. gl.bindBuffer(gl.ARRAY_BUFFER, pwgl.floorVertexTextureCoordinateBuffer);
  537. gl.vertexAttribPointer(pwgl.vertexTextureAttributeLoc,
  538. pwgl.FLOOR_VERTEX_TEX_COORD_BUF_ITEM_SIZE,
  539. gl.FLOAT, false, 0, 0);
  540.  
  541. gl.activeTexture(gl.TEXTURE0);
  542. gl.bindTexture(gl.TEXTURE_2D, pwgl.groundTexture);
  543.  
  544. // Bind index buffer and draw the floor
  545. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, pwgl.floorVertexIndexBuffer);
  546. gl.drawElements(gl.TRIANGLE_FAN, pwgl.FLOOR_VERTEX_INDEX_BUF_NUM_ITEMS,
  547. gl.UNSIGNED_SHORT, 0);
  548. }
  549.  
  550. function drawCube(texture) {
  551. // Bind position buffer
  552. gl.bindBuffer(gl.ARRAY_BUFFER, pwgl.cubeVertexPositionBuffer);
  553. gl.vertexAttribPointer(pwgl.vertexPositionAttributeLoc,
  554. pwgl.CUBE_VERTEX_POS_BUF_ITEM_SIZE,
  555. gl.FLOAT, false, 0, 0);
  556.  
  557. // Bind normal buffer
  558. gl.bindBuffer(gl.ARRAY_BUFFER, pwgl.cubeVertexNormalBuffer);
  559. gl.vertexAttribPointer(pwgl.vertexNormalAttributeLoc,
  560. pwgl.CUBE_VERTEX_NORMAL_BUF_ITEM_SIZE,
  561. gl.FLOAT, false, 0, 0);
  562.  
  563. // Bind texture coordinate buffer
  564. gl.bindBuffer(gl.ARRAY_BUFFER, pwgl.cubeVertexTextureCoordinateBuffer);
  565. gl.vertexAttribPointer(pwgl.vertexTextureAttributeLoc,
  566. pwgl.CUBE_VERTEX_TEX_COORD_BUF_ITEM_SIZE,
  567. gl.FLOAT, false, 0, 0);
  568.  
  569. gl.activeTexture(gl.TEXTURE0);
  570. gl.bindTexture(gl.TEXTURE_2D, texture);
  571.  
  572. // Bind index buffer and draw cube
  573. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, pwgl.cubeVertexIndexBuffer);
  574.  
  575. gl.drawElements(gl.TRIANGLES, pwgl.CUBE_VERTEX_INDEX_BUF_NUM_ITEMS,
  576. gl.UNSIGNED_SHORT, 0);
  577. }
  578.  
  579. function drawTable(){
  580. // Draw a simple table by modifying the modelview matrix
  581. // (translate and scale) and then use the function drawCube()
  582. // to draw a table top and four table legs.
  583.  
  584. pushModelViewMatrix();
  585. mat4.translate(pwgl.modelViewMatrix, [0.0, 1.0, 0.0], pwgl.modelViewMatrix);
  586. mat4.scale(pwgl.modelViewMatrix, [2.0, 0.1, 2.0], pwgl.modelViewMatrix);
  587. uploadModelViewMatrixToShader();
  588. uploadNormalMatrixToShader();
  589. // Draw the actual cube (now scaled to a cuboid) with woodTexture
  590. drawCube(pwgl.woodTexture);
  591. popModelViewMatrix();
  592.  
  593. // Draw the table legs
  594. for (var i=-1; i<=1; i+=2) {
  595. for (var j= -1; j<=1; j+=2) {
  596. pushModelViewMatrix();
  597. mat4.translate(pwgl.modelViewMatrix, [i*1.9, -0.1, j*1.9], pwgl.modelViewMatrix);
  598. mat4.scale(pwgl.modelViewMatrix, [0.1, 1.0, 0.1], pwgl.modelViewMatrix);
  599. uploadModelViewMatrixToShader();
  600. uploadNormalMatrixToShader();
  601. drawCube(pwgl.woodTexture);
  602. popModelViewMatrix();
  603. }
  604. }
  605. }
  606.  
  607. //var currentAngle;
  608. function draw(currentTime) {
  609. pwgl.requestId = requestAnimFrame(draw);
  610. if (currentTime === undefined) {
  611. currentTime = Date.now();
  612. }
  613. currentTime = Date.now();
  614.  
  615. // Update FPS if a second or more has passed since last FPS update
  616. if(currentTime - pwgl.previousFrameTimeStamp >= 1000) {
  617. pwgl.fpsCounter.innerHTML = pwgl.nbrOfFramesForFPS;
  618. pwgl.nbrOfFramesForFPS = 0;
  619. pwgl.previousFrameTimeStamp = currentTime;
  620. }
  621.  
  622. gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
  623. gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  624. mat4.perspective(60, gl.viewportWidth / gl.viewportHeight,
  625. 1, 100.0, pwgl.projectionMatrix);
  626. mat4.identity(pwgl.modelViewMatrix);
  627. mat4.lookAt([8, 12, 8],[0, 0, 0], [0, 1,0], pwgl.modelViewMatrix);
  628. mat4.rotateY(pwgl.modelViewMatrix, pwgl.yRot, pwgl.modelViewMatrix);
  629.  
  630. //旋转
  631. pwgl.yRot += 0.01;
  632. //鼠标移动
  633. mat4.rotateX(pwgl.modelViewMatrix, pwgl.currentAngle[0], pwgl.modelViewMatrix);
  634. mat4.rotateY(pwgl.modelViewMatrix, pwgl.currentAngle[1], pwgl.modelViewMatrix);
  635. //鼠标滚轮
  636. mat4.translate(pwgl.modelViewMatrix, [0, 0, pwgl.zTri], pwgl.modelViewMatrix);
  637.  
  638. uploadModelViewMatrixToShader();
  639. uploadProjectionMatrixToShader();
  640. uploadNormalMatrixToShader();
  641. gl.uniform1i(pwgl.uniformSamplerLoc, 0);
  642.  
  643. drawFloor();
  644.  
  645. // Draw table
  646. pushModelViewMatrix();
  647. mat4.translate(pwgl.modelViewMatrix, [0.0, 1.1, 0.0], pwgl.modelViewMatrix);
  648. uploadModelViewMatrixToShader();
  649. uploadNormalMatrixToShader();
  650. drawTable();
  651. popModelViewMatrix();
  652.  
  653. // Calculate the position for the box that is initially
  654. // on top of the table but will then be moved during animation
  655. pushModelViewMatrix();
  656. if (currentTime === undefined) {
  657. currentTime = Date.now();
  658. }
  659. if (pwgl.animationStartTime === undefined) {
  660. pwgl.animationStartTime = currentTime;
  661. }
  662. // Update the position of the box
  663. if (pwgl.y < 5) {
  664. // First move the box vertically from its original position on top of
  665. // the table (where y = 2.7) to 5 units above the floor (y = 5).
  666. // Let this movement take 3 seconds
  667. pwgl.y = 2.7 + (currentTime - pwgl.animationStartTime)/3000 * (5.0-2.7);
  668. }
  669. else {
  670. // Then move the box in a circle where one revolution takes 2 seconds
  671. pwgl.angle = (currentTime - pwgl.animationStartTime)/2000*2*Math.PI % (2*Math.PI);
  672.  
  673. pwgl.x = Math.cos(pwgl.angle) * pwgl.circleRadius;
  674. pwgl.z = Math.sin(pwgl.angle) * pwgl.circleRadius;
  675. }
  676.  
  677. mat4.translate(pwgl.modelViewMatrix, [pwgl.x, pwgl.y, pwgl.z], pwgl.modelViewMatrix);
  678. mat4.scale(pwgl.modelViewMatrix, [0.5, 0.5, 0.5], pwgl.modelViewMatrix);
  679. uploadModelViewMatrixToShader();
  680. uploadNormalMatrixToShader();
  681. drawCube(pwgl.boxTexture);
  682. popModelViewMatrix();
  683.  
  684. // Update number of drawn frames to be able to count fps
  685. pwgl.nbrOfFramesForFPS++;
  686. }
  687.  
  688. function handleContextLost(event) {
  689. event.preventDefault();
  690. cancelRequestAnimFrame(pwgl.requestId);
  691.  
  692. // Ignore all ongoing image loads by removing
  693. // their onload handler
  694. for (var i = 0; i < pwgl.ongoingImageLoads.length; i++) {
  695. pwgl.ongoingImageLoads[i].onload = undefined;
  696. }
  697. pwgl.ongoingImageLoads = [];
  698. }
  699.  
  700. function init() {
  701. // Initialization that is performed during first startup, but when the
  702. // event webglcontextrestored is received is included in this function.
  703. setupShaders();
  704. setupBuffers();
  705. setupLights();
  706. setupTextures();
  707. gl.clearColor(0.0, 0.0, 0.0, 1.0);
  708. gl.enable(gl.DEPTH_TEST);
  709.  
  710. // Initialize some varibles for the moving box
  711. pwgl.x = 0.0;
  712. pwgl.y = 2.7;
  713. pwgl.z = 0.0;
  714. pwgl.circleRadius = 4.0;
  715. pwgl.angle = 0;
  716.  
  717. //Y轴旋转角度
  718. pwgl.yRot = 0;
  719. //Z轴移动角度
  720. pwgl.zTri = 0;
  721.  
  722. // Initialize some variables related to the animation
  723. pwgl.animationStartTime = undefined;
  724. pwgl.nbrOfFramesForFPS = 0;
  725. pwgl.previousFrameTimeStamp = Date.now();
  726. }
  727.  
  728. function handleContextRestored(event) {
  729. init();
  730. pwgl.requestId = requestAnimFrame(draw,canvas);
  731. }
  732.  
  733. //处理鼠标的事件
  734. var dragging = false; // Dragging or not
  735. var lastX = -1, lastY = -1; // Last position of the mouse
  736. function handleMouseDown(ev) {
  737. var x = ev.clientX, y = ev.clientY;
  738. // Start dragging if a moue is in <canvas>
  739. var rect = ev.target.getBoundingClientRect();
  740. if (rect.left <= x && x < rect.right && rect.top <= y && y < rect.bottom) {
  741. lastX = x; lastY = y;
  742. dragging = true;
  743. }
  744. }
  745. function handleMouseMove(ev) {
  746. var x = ev.clientX, y = ev.clientY;
  747. if (dragging) {
  748. var factor = 100/canvas.height; // The rotation ratio
  749. var dx = factor * (x - lastX);
  750. var dy = factor * (y - lastY);
  751. // Limit x-axis rotation angle to -90 to 90 degrees
  752. pwgl.currentAngle[0] = Math.max(Math.min(pwgl.currentAngle[0] + dy, 90.0), -90.0);
  753. pwgl.currentAngle[1] = pwgl.currentAngle[1] + dx;
  754. }
  755. lastX = x, lastY = y;
  756. }
  757. function handleMouseUp() {
  758. dragging = false;
  759. }
  760.  
  761. /*
  762. * 在非firefox浏览器中,滚轮向上滚动返回的数值是120,向下滚动返回-120
  763. 而在firefox浏览器中,滚轮向上滚动返回的数值是-3,向下滚动返回3
  764. * */
  765. //鼠标滚轮
  766. var scrollFunc = function (e) {
  767. e = e || window.event;
  768.  
  769. var t1 = document.getElementById("wheelDelta");
  770. var t2 = document.getElementById("detail");
  771. if (e.wheelDelta) {//IE/Opera/Chrome
  772. t1.value = "IE、Opera、Safari、Chrome";
  773. t2.value = e.wheelDelta;
  774. if (e.wheelDelta == 120){
  775. pwgl.zTri += 1.0;
  776. } else {
  777. pwgl.zTri -= 1.0;
  778. }
  779. } else if (e.detail) {//Firefox
  780. t1.value = "Firefox";
  781. t2.value = e.detail;
  782. if (e.wheelDelta == -3){
  783. pwgl.zTri += 1.0;
  784. } else {
  785. pwgl.zTri -= 1.0;
  786. }
  787. }
  788. //ScrollText(direct);
  789.  
  790. }
  791. /*注册事件*/
  792. if (document.addEventListener) {
  793. document.addEventListener('DOMMouseScroll', scrollFunc, false);
  794. }//W3C
  795. window.onmousewheel = document.onmousewheel = scrollFunc;//IE/Opera/Chrome/Safari
  796.  
  797. function startup() {
  798. canvas = document.getElementById("myGLCanvas");
  799. canvas = WebGLDebugUtils.makeLostContextSimulatingContext(canvas);
  800.  
  801. canvas.addEventListener('webglcontextlost', handleContextLost, false);
  802. canvas.addEventListener('webglcontextrestored', handleContextRestored, false);
  803. //canvas.addEventListener("", )
  804. canvas.addEventListener('mousedown', handleMouseDown, false);
  805. canvas.addEventListener('mousemove', handleMouseMove, false);
  806. canvas.addEventListener('mouseup', handleMouseUp, false);
  807. //canvas.addEventListener('onmousewheel', handlemosew)
  808.  
  809. gl = createGLContext(canvas);
  810. init();
  811.  
  812. //注册一个事件响应的函数【鼠标移动控制】
  813. pwgl.currentAngle = [0.0, 0.0];
  814. //initEventHandlers(canvas, currentAngle);
  815.  
  816. pwgl.fpsCounter = document.getElementById("fps");
  817.  
  818. // Uncomment the three lines of code below to be able to test lost context
  819. // window.addEventListener('mousedown', function() {
  820. // canvas.loseContext();
  821. // });
  822.  
  823. // Draw the complete scene
  824. draw();
  825. }
  826. </script>
  827.  
  828. </head>
  829.  
  830. <body onload="startup();">
  831. <canvas id="myGLCanvas" width="500" height="500"></canvas>
  832. <div id="fps-counter">
  833. FPS: <span id="fps">--</span>
  834. </div>
  835. <p><label for="wheelDelta"> 浏览器类型:</label>(IE/Opera)<input type="text" id="wheelDelta"/></p>
  836. <p><label for="detail"> 滚动值:</label><input type="text" id="detail"/></p>
  837. </body>
  838.  
  839. </html>

WEBGL学习【十二】鼠标操作场景的更多相关文章

  1. (转)SpringMVC学习(十二)——SpringMVC中的拦截器

    http://blog.csdn.net/yerenyuan_pku/article/details/72567761 SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter, ...

  2. webgl学习笔记二-绘图多点

    写在前面 建议先看下第一篇webgl学习笔记一-绘图单点 第一篇文章,介绍了如何用webgl绘图一个点.接下来本文介绍的是如何绘制多个点.形成一个面. webgl提供了一种很方便的机制,即缓冲区对象, ...

  3. Scala学习十二——高阶函数

    一.本章要点 在Scala中函数是”头等公民“(可以作为参数,返回值,赋值给其他); 可以创建匿名函数,通常还会交给其他函数; 函数参数可以给出需要稍后执行的行为; 许多集合方法都接受函数参数,将函数 ...

  4. Selenium基础知识(二)鼠标操作

    一.鼠标操作 这个需要使用webdriver下的ActionChains类,这个类是操作鼠标操作的: from selenium.webdriver import ActionChains 鼠标操作可 ...

  5. WebGL学习笔记二——绘制基本图元

    webGL的基本图元点.线.三角形 gl.drawArrays(mode, first,count) first,代表从第几个点开始绘制即顶点的起始位置 count,代表绘制的点的数量. mode,代 ...

  6. python学习笔记(十 二)、操作数据库

    每一种语言都少不了多数据库进行各种操作. python支持多种数据库.有关python支持的数据库清单,请参阅:https://wiki.python.org/moin/DatabaseInterfa ...

  7. JavaWeb学习 (十二)————使用Session防止表单重复提交

    在平时开发中,如果网速比较慢的情况下,用户提交表单后,发现服务器半天都没有响应,那么用户可能会以为是自己没有提交表单,就会再点击提交按钮重复提交表单,我们在开发中必须防止表单重复提交. 一.表单重复提 ...

  8. Selenium2学习(二)-- 操作浏览器基本方法

    前面已经把环境搭建好了,这从这篇开始,正式学习selenium的webdriver框架.我们平常说的 selenium自动化,其实它并不是类似于QTP之类的有GUI界面的可视化工具,我们要学的是web ...

  9. Selenium(十二):操作Cookie、调用JavaScript、HTML5的视频播放

    1. 操作Cookie 有时候我们想要验证浏览器中cookie是否正确,因为基于真实cookie的测试是无法通过白盒和集成测试的.WebDriver提供了操作Cookie的相关方法,可以读取.添加和删 ...

随机推荐

  1. 0120Keeplived实现自动切换Mysql服务

    转自http://biancheng.dnbcw.info/mysql/381020.html Keepalived+mysql 自动切换网络结构:VIP 192.168.88.200mysq11 1 ...

  2. Python 字符串 String 内建函数大全(1)

    关于 Python 的字符串处理相关的方法还是许多的.因为我正在学习 Python,于是就把 Python 中这些混杂的用于 string 的函数总结出来,在自己忘记的时候便于查找,希望对于有相似需求 ...

  3. 【Android界面实现】SlidingMenu最新版本号使用具体解释

    转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992 在非常久之前的一篇文章中,简单的介绍了一下开源项目SlidingMenu控件的使用,这一篇文章,将比較具体的 ...

  4. linux高级技巧:rsync同步(二)

    1.配置两个节点同步         上个帖子已经展示了同步一个主机的方法.这次我们再加入一个要同步的主机. 方法上并无二质.         1.首先显示我们的控制台:                ...

  5. luogu1315 观光公交

    题目大意 一个公交车在一条线上从1站.2站走到n站,站站间有距离.另有m个乘客在时间点t在a站等候要到b站.对于一个站,如果车比人早到,则车等人,如果人比车早到,则人等车(我一开始做题时把这个情况当作 ...

  6. linux下图片转换工具[【转】

    本文转载自:https://linux.cn/article-8014-1.html 计算机术语中,批处理指的是用一个非交互式的程序来执行一序列的任务的方法.这篇教程里,我们会使用 Linux 命令行 ...

  7. Floyed理解

    Floyed理解 Floyd算法的本质是动态规划,其转移方程为:f(k,i,j) = min( f(k-1,i,j), f(k-1,i,k)+f(k-1,k,j) ). f(k-1,i,j)表示经过前 ...

  8. 怎样才是一个基本水平的java程序员?

    怎样才是一个基本水平的java程序员? 熟悉常用的数据结构,包括数组,链表,树,哈希表等. 熟悉结构化编程和面向对象编程. 能够阅读UML设计图,根据UML语义进行编码 了解RDBMS和SQL的使用, ...

  9. PHP 和 Java 的主要区别有哪些?

    PHP 和 Java 的主要区别有哪些? 其实Java方面我要学的真的还有很多,要是有大项目的机会和经验就好,所以提前我肯定要把基础打扎实. 我要学的还有很多,比如前段,后端,还有linux,还有肯定 ...

  10. 使用python进行re拆分网页内容

    这里简短的总结一下而不是完全的罗列python的re模块,python的re具有强大的功能,如下是一个从我们学校抓取数据然后拆分的程序,代码如下: import httplib import urll ...