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>