Mercurial > hg > LGMap
comparison geotemco/lib/excanvas/examples/example2.html @ 0:57bde4830927
first commit
author | Zoe Hong <zhong@mpiwg-berlin.mpg.de> |
---|---|
date | Tue, 24 Mar 2015 11:37:17 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:57bde4830927 |
---|---|
1 <!-- | |
2 Copyright 2006 Google Inc. | |
3 | |
4 Licensed under the Apache License, Version 2.0 (the "License"); | |
5 you may not use this file except in compliance with the License. | |
6 You may obtain a copy of the License at | |
7 | |
8 http://www.apache.org/licenses/LICENSE-2.0 | |
9 | |
10 Unless required by applicable law or agreed to in writing, software | |
11 distributed under the License is distributed on an "AS IS" BASIS, | |
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 See the License for the specific language governing permissions and | |
14 limitations under the License. | |
15 --> | |
16 <html> | |
17 <head> | |
18 <title>ExplorerCanvas Example 1</title> | |
19 <!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]--> | |
20 <script type="text/javascript"> | |
21 /* -------------------------------------------------------------------- */ | |
22 | |
23 var canvas, ctx; | |
24 var canvasWidth, halfCanvasWidth; | |
25 var canvasHeight, halfCanvasHeight; | |
26 | |
27 var space; // 3D Engine | |
28 var scene; // 3D Scene | |
29 | |
30 /* -------------------------------------------------------------------- */ | |
31 | |
32 /** | |
33 * Space is a simple 3D system. | |
34 * | |
35 * Y+ = up | |
36 * Z+ = into screen | |
37 * X+ = right | |
38 */ | |
39 function Space() { | |
40 this.m = this.createMatrixIdentity(); | |
41 this.mStack = []; | |
42 } | |
43 | |
44 Space.prototype.createMatrixIdentity = function() { | |
45 return [ | |
46 [1, 0, 0, 0], | |
47 [0, 1, 0, 0], | |
48 [0, 0, 1, 0], | |
49 [0, 0, 0, 1] | |
50 ]; | |
51 } | |
52 | |
53 /** | |
54 * Multiplies two 4x4 matricies together. | |
55 */ | |
56 Space.prototype.matrixMultiply = function(m1, m2) { | |
57 var result = this.createMatrixIdentity(); | |
58 | |
59 var width = m1[0].length; | |
60 var height = m1.length; | |
61 | |
62 if (width != m2.length) { | |
63 // error | |
64 } | |
65 | |
66 for (var x = 0; x < width; x++) { | |
67 for (var y = 0; y < height; y++) { | |
68 var sum = 0; | |
69 | |
70 for (var z = 0; z < width; z++) { | |
71 sum += m1[y][z] * m2[z][x]; | |
72 } | |
73 | |
74 result[y][x] = sum; | |
75 } | |
76 } | |
77 | |
78 return result; | |
79 } | |
80 | |
81 /** | |
82 * Transforms a coordinate using the current transformation | |
83 * matrix, then flattens it using the projection matrix. | |
84 */ | |
85 Space.prototype.flatten = function(point) { | |
86 var p = [[point.x, point.y, point.z, 1]]; | |
87 var pm = this.matrixMultiply(p, this.m); | |
88 | |
89 point.tx = pm[0][0]; | |
90 point.ty = pm[0][1]; | |
91 point.tz = pm[0][2]; | |
92 | |
93 // lazy projection | |
94 point.fx = halfCanvasWidth + (canvasWidth * point.tx / point.tz); | |
95 point.fy = halfCanvasHeight -(canvasWidth * point.ty / point.tz); | |
96 } | |
97 | |
98 /** | |
99 * Translate (move) the current transformation matrix | |
100 */ | |
101 Space.prototype.translate = function(x, y, z) { | |
102 var m = [ | |
103 [1, 0, 0, 0], | |
104 [0, 1, 0, 0], | |
105 [0, 0, 1, 0], | |
106 [x, y, z, 1] | |
107 ]; | |
108 | |
109 this.m = this.matrixMultiply(m, this.m); | |
110 } | |
111 | |
112 /** | |
113 * Rotate the current transformation matrix. Rotations are | |
114 * world-oriented, and occur in y,x,z order. | |
115 */ | |
116 Space.prototype.rotate = function(x, y, z) { | |
117 if (y) { | |
118 var cosY = Math.cos(y); | |
119 var sinY = Math.sin(y); | |
120 var rotY = [ | |
121 [cosY, 0, sinY, 0], | |
122 [0, 1, 0, 0], | |
123 [-sinY, 0, cosY, 0], | |
124 [0, 0, 0, 1] | |
125 ]; | |
126 | |
127 this.m = this.matrixMultiply(this.m, rotY); | |
128 } | |
129 | |
130 if (x) { | |
131 var cosX = Math.cos(x); | |
132 var sinX = Math.sin(x); | |
133 var rotX = [ | |
134 [1, 0, 0, 0], | |
135 [0, cosX, -sinX, 0], | |
136 [0, sinX, cosX,0], | |
137 [0, 0, 0, 1] | |
138 ]; | |
139 this.m = this.matrixMultiply(this.m, rotX); | |
140 } | |
141 | |
142 if (z) { | |
143 var cosZ = Math.cos(z); | |
144 var sinZ = Math.sin(z); | |
145 var rotZ = [ | |
146 [cosZ, -sinZ, 0, 0], | |
147 [sinZ, cosZ, 0, 0], | |
148 [0, 0, 1, 0], | |
149 [0, 0, 0, 1] | |
150 ]; | |
151 | |
152 this.m = this.matrixMultiply(this.m, rotZ); | |
153 } | |
154 } | |
155 | |
156 /** | |
157 * Pushes the current transformation onto the stack | |
158 */ | |
159 Space.prototype.push = function() { | |
160 this.mStack.push(this.m); | |
161 this.m = [ | |
162 [this.m[0][0], this.m[0][1], this.m[0][2], this.m[0][3]], | |
163 [this.m[1][0], this.m[1][1], this.m[1][2], this.m[1][3]], | |
164 [this.m[2][0], this.m[2][1], this.m[2][2], this.m[2][3]], | |
165 [this.m[3][0], this.m[3][1], this.m[3][2], this.m[3][3]] | |
166 ]; | |
167 } | |
168 | |
169 /** | |
170 * Pops the end off the transformation stack | |
171 */ | |
172 Space.prototype.pop = function() { | |
173 this.m = this.mStack.pop(); | |
174 } | |
175 | |
176 /* -------------------------------------------------------------------- */ | |
177 | |
178 /** | |
179 * A 3d coordinate | |
180 */ | |
181 function Point(x, y, z) { | |
182 this.x = x; | |
183 this.y = y; | |
184 this.z = z; | |
185 | |
186 // Relative to camera coordinates | |
187 this.tx; | |
188 this.ty; | |
189 this.tz; | |
190 | |
191 // Flattened coordinates | |
192 this.fx; | |
193 this.fy; | |
194 } | |
195 | |
196 /** | |
197 * A Shape is made up of polygons | |
198 */ | |
199 function Shape() { | |
200 this.points = []; | |
201 this.polygons = []; | |
202 } | |
203 | |
204 /** | |
205 * Draws the shape | |
206 */ | |
207 Shape.prototype.draw = function(drawlist) { | |
208 for (var i = 0; i< this.points.length; i++) { | |
209 space.flatten(this.points[i]); | |
210 } | |
211 | |
212 for (var i = 0; i< this.polygons.length; i++) { | |
213 var poly = this.polygons[i]; // convenience | |
214 | |
215 space.flatten(poly.origin); | |
216 | |
217 // lazy backface culling | |
218 if (poly.normal && this.backface) { | |
219 space.flatten(poly.normal); | |
220 | |
221 var originDist = Math.pow(poly.origin.tx, 2) | |
222 + Math.pow(poly.origin.ty, 2) | |
223 + Math.pow(poly.origin.tz, 2); | |
224 | |
225 var normalDist = Math.pow(poly.normal.tx, 2) | |
226 + Math.pow(poly.normal.ty, 2) | |
227 + Math.pow(poly.normal.tz, 2); | |
228 | |
229 if(originDist > normalDist) { | |
230 drawlist.push(poly); | |
231 } | |
232 } else { | |
233 drawlist.push(poly); | |
234 } | |
235 } | |
236 } | |
237 | |
238 /** | |
239 * A polygon is a connection of points in the shape object. You | |
240 * should probably try to make them coplanar. | |
241 */ | |
242 function Polygon(points, normal, backface, type, color) { | |
243 this.points = points; | |
244 | |
245 this.origin = new Point(0, 0, 0); | |
246 for(var i = 0; i < this.points.length; i++) { | |
247 this.origin.x += this.points[i].x; | |
248 this.origin.y += this.points[i].y; | |
249 this.origin.z += this.points[i].z; | |
250 } | |
251 | |
252 this.origin.x /= this.points.length; | |
253 this.origin.y /= this.points.length; | |
254 this.origin.z /= this.points.length; | |
255 | |
256 if (normal) { | |
257 this.normal = new Point(this.origin.x + normal.x, | |
258 this.origin.y + normal.y, | |
259 this.origin.z + normal.z); | |
260 } else { | |
261 this.normal = null; | |
262 } | |
263 | |
264 this.backface = backface; | |
265 this.type = type; | |
266 this.color = color; | |
267 } | |
268 | |
269 Polygon.SOLID = 0; | |
270 Polygon.WIRE = 1; | |
271 | |
272 /** | |
273 * Draws the polygon. Assumes that the points have already been | |
274 * flattened. | |
275 */ | |
276 Polygon.prototype.draw = function() { | |
277 ctx.beginPath(); | |
278 ctx.moveTo(this.points[0].fx, this.points[0].fy); | |
279 | |
280 for(var i = 0; i < this.points.length; i++) { | |
281 ctx.lineTo(this.points[i].fx, this.points[i].fy); | |
282 } | |
283 | |
284 ctx.closePath(); | |
285 | |
286 var color = this.color; | |
287 | |
288 /* | |
289 // Do lighting here | |
290 lightvector = Math.abs(this.normal.x + this.normal.y); | |
291 if(lightvector > 1) { | |
292 lightvector = 1; | |
293 } | |
294 | |
295 color[0] = (color[0] * lightvector).toString(); | |
296 color[1] = (color[1] * lightvector).toString(); | |
297 color[2] = (color[2] * lightvector).toString(); | |
298 */ | |
299 | |
300 if (color.length > 3) { | |
301 var style = ["rgba(", | |
302 color[0], ",", | |
303 color[1], ",", | |
304 color[2], ",", | |
305 color[3], ")"].join(""); | |
306 } else { | |
307 var style = ["rgb(", | |
308 color[0], ",", | |
309 color[1], ",", | |
310 color[2], ")"].join(""); | |
311 } | |
312 | |
313 if (this.type == Polygon.SOLID) { | |
314 ctx.fillStyle = style; | |
315 ctx.fill(); | |
316 } else if (this.type == Polygon.WIRE) { | |
317 ctx.strokeStyle = style; | |
318 ctx.stroke(); | |
319 } | |
320 } | |
321 | |
322 /* -------------------------------------------------------------------- */ | |
323 | |
324 /** | |
325 * Scene describes the 3D environment | |
326 */ | |
327 function Scene() { | |
328 this.shapes = {}; | |
329 this.camera = new Point(0, 0, 0); | |
330 this.cameraTarget = new Point(0, 0, 0); | |
331 this.cameraRotation = 0; | |
332 | |
333 this.drawlist = []; | |
334 } | |
335 | |
336 /** | |
337 * Draw the world | |
338 */ | |
339 Scene.prototype.draw = function() { | |
340 space.push(); | |
341 | |
342 // Camera transformation | |
343 space.translate( | |
344 -this.camera.x, | |
345 -this.camera.y, | |
346 -this.camera.z | |
347 ); | |
348 | |
349 // Camera rotation | |
350 var xdiff = this.cameraTarget.x - this.camera.x; | |
351 var ydiff = this.cameraTarget.y - this.camera.y; | |
352 var zdiff = this.cameraTarget.z - this.camera.z; | |
353 | |
354 var xzdist = Math.sqrt(Math.pow(xdiff, 2) + Math.pow(zdiff, 2)); | |
355 | |
356 var xrot = -Math.atan2(ydiff, xzdist); // up/down rotation | |
357 var yrot = Math.atan2(xdiff, zdiff); // left/right rotation | |
358 | |
359 space.rotate(xrot, yrot, this.cameraRotation); | |
360 | |
361 // Drawing | |
362 this.drawlist = []; | |
363 | |
364 for(var i in this.shapes) { | |
365 this.shapes[i].draw(this.drawlist); | |
366 } | |
367 | |
368 // Depth sorting (warning: this is only enough to drive this demo - feel | |
369 // free to contribute a better system). | |
370 this.drawlist.sort(function (poly1, poly2) { | |
371 return poly2.origin.tz - poly1.origin.tz; | |
372 }); | |
373 | |
374 for (var i = 0; i < this.drawlist.length; i++) { | |
375 this.drawlist[i].draw(); | |
376 } | |
377 | |
378 space.pop(); | |
379 } | |
380 | |
381 /* -------------------------------------------------------------------- */ | |
382 | |
383 var count = 0; | |
384 | |
385 function loop() { | |
386 ctx.clearRect(0, 0, canvasWidth, canvasHeight); | |
387 | |
388 scene.camera.x = 70*Math.sin(count); | |
389 scene.camera.y = 70; | |
390 scene.camera.z = 70*Math.cos(count); | |
391 scene.cameraRotation = count / 10; | |
392 | |
393 count += 0.01; | |
394 scene.draw(); | |
395 } | |
396 | |
397 function load() { | |
398 // Init drawing system | |
399 canvas = document.getElementById("cv"); | |
400 ctx = canvas.getContext("2d"); | |
401 | |
402 canvasWidth = canvas.width; | |
403 canvasHeight = canvas.height; | |
404 halfCanvasWidth = canvasWidth * 0.5; | |
405 halfCanvasHeight = canvasHeight * 0.5; | |
406 | |
407 // Init 3D components | |
408 space = new Space(); | |
409 scene = new Scene(); | |
410 | |
411 // Create a box shape and add it to the scene | |
412 scene.shapes['box'] = new Shape(); | |
413 var p = scene.shapes['box'].points; // for convenience | |
414 | |
415 p[0] = new Point(-10, -10, -10); // left bottom front | |
416 p[1] = new Point(10, -10, -10); // right bottom front | |
417 p[2] = new Point(10, 10, -10); // right top front | |
418 p[3] = new Point(-10, 10, -10); // left top front | |
419 | |
420 p[4] = new Point(-10, -10, 10); // left bottom back | |
421 p[5] = new Point(10, -10, 10); // right bottom back | |
422 p[6] = new Point(10, 10, 10); // right top back | |
423 p[7] = new Point(-10, 10, 10); // left top back | |
424 | |
425 // Back | |
426 scene.shapes['box'].polygons.push(new Polygon( | |
427 [ p[0], p[1], p[2], p[3] ], | |
428 new Point(0, 0, -1), | |
429 true /* double-sided */, | |
430 Polygon.SOLID, | |
431 [255, 0, 0] | |
432 )); | |
433 | |
434 // Front | |
435 scene.shapes['box'].polygons.push(new Polygon( | |
436 [ p[4], p[5], p[6], p[7] ], | |
437 new Point(0, 0, 1), | |
438 true /* double-sided */, | |
439 Polygon.SOLID, | |
440 [0, 0, 255] | |
441 )); | |
442 | |
443 // Top | |
444 scene.shapes['box'].polygons.push(new Polygon( | |
445 [ p[2], p[3], p[7], p[6] ], | |
446 new Point(0, 1, 0), | |
447 false /* single-sided */, | |
448 Polygon.WIRE, | |
449 [0, 255, 0] | |
450 )); | |
451 | |
452 // Transparent Top | |
453 scene.shapes['box'].polygons.push(new Polygon( | |
454 [ p[2], p[3], p[7], p[6] ], | |
455 new Point(0, 1, 0), | |
456 false /* single-sided */, | |
457 Polygon.SOLID, | |
458 [0, 255, 0, 0.4] | |
459 )); | |
460 | |
461 // Left | |
462 scene.shapes['box'].polygons.push(new Polygon( | |
463 [ p[0], p[4], p[7], p[3] ], | |
464 new Point(-1, 0, 0), | |
465 true /* double-sided */, | |
466 Polygon.SOLID, | |
467 [255, 255, 0] | |
468 )); | |
469 | |
470 // Right | |
471 scene.shapes['box'].polygons.push(new Polygon( | |
472 [ p[1], p[5], p[6], p[2] ], | |
473 new Point(1, 0, 0), | |
474 true /* double-sided */, | |
475 Polygon.SOLID, | |
476 [0, 255, 255] | |
477 )); | |
478 | |
479 // Create a floor shape and add it to the scene | |
480 scene.shapes['floor'] = new Shape(); | |
481 var p = scene.shapes['floor'].points; // for convenience | |
482 | |
483 p[0] = new Point(-40, -10, -40); | |
484 p[1] = new Point(-40, -10, 40); | |
485 p[2] = new Point( 40, -10, 40); | |
486 p[3] = new Point( 40, -10, -40); | |
487 | |
488 // Floor | |
489 scene.shapes['floor'].polygons.push(new Polygon( | |
490 [ p[0], p[1], p[2], p[3] ], | |
491 new Point(0, 1, 0), | |
492 false /* single-sided */, | |
493 Polygon.SOLID, | |
494 [45, 45, 45] | |
495 )); | |
496 | |
497 setInterval('loop()', 20); | |
498 } | |
499 | |
500 /* -------------------------------------------------------------------- */ | |
501 </script> | |
502 <style> | |
503 body { | |
504 background-color:black; | |
505 margin:50px; | |
506 text-align:center; | |
507 } | |
508 </style> | |
509 </head> | |
510 <body onload="load();"> | |
511 <canvas id="cv" width="400" height="300"></canvas> | |
512 </body> | |
513 </html> |