3d-thingy.html (13077B)
1 <html> 2 <head> 3 <title>3d thingy</title> 4 <style type="text/css"> 5 div.z2 { position:absolute; z-index:2; } 6 div.z1 { position:absolute; z-index:1; } 7 </style> 8 <script type="text/javascript"> 9 /************************************************************************** 10 JavaScript Graphics Library 0.0.1, Updated Source Code at Scriptersoft.com 11 Copyright (C) 2005 Kurt L. Whicher 12 November,13,2005 13 14 This library is free software; you can redistribute it and/or 15 modify it under the terms of the GNU Lesser General Public 16 License as published by the Free Software Foundation; either 17 version 2.1 of the License, or (at your option) any later version. 18 19 This library is distributed in the hope that it will be useful, 20 but WITHOUT ANY WARRANTY; without even the implied warranty of 21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 Lesser General Public License for more details. 23 24 You should have received a copy of the GNU Lesser General Public 25 License along with this library; if not, write to the Free Software 26 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 27 **************************************************************************/ 28 29 //________________________________________ global variables 30 31 var S_piDoubled=Math.PI*2; 32 var S_deg2Rad=Math.PI/180; 33 34 //_______________________________________________ functions 35 36 function S_matrix() { 37 return [1,0,0,0, 38 0,1,0,0, 39 0,0,1,0, 40 0,0,0,1]; 41 } 42 function S_vec2D(x,y) { this.x=x; this.y=y; } 43 function S_vec3D(x,y,z) { this.x=x; this.y=y; this.z=z; } 44 function S_subVec2D(a,b) { 45 return new S_vec2D(a.x-b.x, a.y-b.y); 46 } 47 function S_subVec3D(a,b) { 48 return new S_vec3D(a.x-b.x, a.y-b.y, a.z-b.z); 49 } 50 function S_dotVec3D(a, b) { return a.x*b.x+a.y*b.y+a.z*b.z; } 51 function S_cross(a,b) { 52 return new S_vec3D( a.y*b.z-a.z*b.y, a.z*b.x-a.x*b.z, a.x*b.y-a.y*b.x); 53 } 54 function S_lengthSquaredVec3D(v) { return S_dotVec3D(v,v); } 55 function S_lengthVec3D(v) { return Math.sqrt(S_lengthSquaredVec3D(v)); } 56 function S_normalizeVec3D(v) { 57 var l=S_lengthVec3D(v), nv=new S_vec3D(0,0,0); 58 if(l!=0) { nv.x=v.x/l; nv.y=v.y/l; nv.z=v.z/l; } 59 return nv; 60 } 61 function S_rotate(m,ax,a) { // transformation matrix, axis, angle 62 var i,j,ij=new Array(),v=new Array(),c=Math.cos(a),s=Math.sin(a); 63 if (ax=="x") ij=[1,2,5,6,9,10,13,14]; 64 else if (ax=="y") ij=[2,0,6,4,10,8,14,12]; 65 else if (ax=="z") ij=[0,1,4,5,8,9,12,13]; 66 for (i=0;i<8;i++) v[i]=m[ij[i]]; 67 for (i=0,j=1;i<8;i+=2,j+=2) { 68 m[ij[i]]=v[i]*c-v[j]*s; 69 m[ij[j]]=v[i]*s+v[j]*c 70 } 71 } 72 function S_checkBrowser() { 73 if (document.getElementById) return true; else return false; 74 } 75 function S_zIndex(e,z) { document.getElementById(e).style.zIndex=z; } 76 function S_rgbColor(r,g,b) { 77 var i, c=[r,g,b]; 78 for(i=0; i<3; i++) { 79 c[i]=Math.floor(c[i]); 80 if(c[i]<0) c[i]=0; else if(c[i]>255) c[i]=255; 81 } 82 return c; 83 } 84 function S_rgbColorString(c) { 85 return "rgb("+c[0]+","+c[1]+","+c[2]+")"; 86 } 87 function S_vertice(x,y,z) { 88 this.x=x; this.y=y; this.z=z; this.w=1; 89 this.t=new S_vec3D(x,y,z); // transformed 3d 90 this.p=new S_vec2D(0,0); // projected 2d 91 } 92 function S_face(v0,v1,v2,c) { // 3 vertice faces 93 this.v=[v0,v1,v2]; this.c=c; this.b=0; // b:brightness 94 this.d=true; // display: true or false 95 } 96 // x coordinate, number of vertices, distance 97 function S_verticeRing(x,nv,d) { 98 var i,a,v=new Array(); 99 for(i=0;i<nv;i++) { 100 a=S_piDoubled*i/nv; 101 v[i]=new S_vertice(x,d*Math.sin(a),d*Math.cos(a)); 102 } 103 return v; 104 } 105 function S_triangleRing(r1,r2,c,clr) { // rows 1 & 2, cols, color 106 var i,j,tr=new Array(); 107 for(i=0,j=1;i<c;i++,j=++j%c) { 108 tr.push(new S_face(r1+i,r2+i,r2+j,clr)); 109 tr.push(new S_face(r1+i,r2+j,r1+j,clr)); 110 } 111 return tr; 112 } 113 function S_model(v,f) { 114 // vertice & face arrays, transformation matrix, display boolean 115 this.v=v; this.f=f, this.tm=S_matrix(), this.d=true; 116 } 117 S_model.prototype.S_rotateX=function(a) { 118 S_rotate(this.tm,"x",a*=S_deg2Rad); 119 } 120 S_model.prototype.S_rotateY=function(a) { 121 S_rotate(this.tm,"y",a*=S_deg2Rad); 122 } 123 S_model.prototype.S_rotateZ=function(a) { 124 S_rotate(this.tm,"z",a*=S_deg2Rad); 125 } 126 S_model.prototype.S_show=function() { this.d=true; } 127 S_model.prototype.S_hide=function() { this.d=false; } 128 function S_cube(d,c) { //distance & color 129 return new S_cone(d,d,Math.cos(Math.PI/4)*d*2,1,4,c); 130 } 131 function S_cylinder(w,h,r,c,clr,e) { 132 return new S_cone(w,w,h,r,c,clr,e); 133 } 134 // width, height, "rows", "columns", color, ends 135 function S_cone(w1,w2,h,r,c,clr,e) { 136 var i,r1=0,r2=c,v=new Array(),t=new Array(),rxc=r*c; 137 for(i=0;i<=r;i++) 138 v=v.concat(S_verticeRing(h*(0.5-i/r),c,w1*i/r+w2*(r-i)/r)); 139 for(i=0;i<r;i++,r1+=c,r2+=c) 140 t=t.concat(S_triangleRing(r1,r2,c,clr)); 141 if (e!="hideEnds") 142 for(i=1;i<(c-1);i++) { 143 t.push(new S_face(0,i,i+1,clr)); 144 t.push(new S_face(rxc,rxc+i+1,rxc+i,clr)); 145 } 146 return new S_model(v,t); 147 } 148 function S_sphere(d,r,c,clr) { 149 // distance, "rows">=2, "columns">=3, color paramaters 150 var v=new Array(),t=new Array(),r_1xc=(r-1)*c,r_2xc=(r-2)*c; 151 var i,j,tmp,r1=0,r2=c; 152 for(i=1;i<r;i++) { 153 tmp=Math.PI*i/r; 154 v=v.concat(S_verticeRing(d*Math.cos(tmp),c,Math.sin(tmp)*d)); 155 } 156 v.push(new S_vertice( d,0,0)); 157 v.push(new S_vertice(-d,0,0)); 158 for(i=0;i<(r-2);i++,r1+=c,r2+=c) 159 t=t.concat(S_triangleRing(r1,r2,c,clr)); 160 for(i=0,j=1;i<c;i++,j=++j%c) { 161 t.push(new S_face(r_1xc,i,j,clr)); 162 t.push(new S_face(r_1xc+1,r_2xc+j,r_2xc+i,clr)); 163 } 164 return new S_model(v,t); 165 } 166 S_model.prototype.S_scale=function(x) { 167 this.tm[0]*=x; this.tm[5]*=x; this.tm[10]*=x; 168 } 169 S_model.prototype.S_faceColor=function(i,c) { this.f[i].c=c; } 170 S_model.prototype.S_scaleX=function(s) { this.tm[0]*=s; } 171 S_model.prototype.S_scaleY=function(s) { this.tm[5]*=s; } 172 S_model.prototype.S_scaleZ=function(s) { this.tm[10]*=s; } 173 function S_scene(dv,l,t,w,h,cmra) { // left, top, width, height 174 this.dv=dv; 175 this.ps=1; // pixel size 176 this.l=l; this.t=t; this.w=w; this.h=h; 177 this.cx=l+w/2; this.cy=t+h/2; // center x, center y 178 this.dt="paint"; // output type 179 this.m=new Array(); // model array 180 this.lght=new S_light(); 181 this.lc=S_rgbColor(255,255,255); // light color 182 this.cmra=-cmra; // camera on z axis 183 this.bfr=S_buffer(h,w); 184 } 185 function S_buffer(h,w) { 186 var i, j, b=new Array(); 187 for(i=0;i<h;i++) { 188 b[i]=new Array(); 189 for(j=0;j<w;j++) b[i][j]=new S_pixel(); 190 } 191 return b; 192 } 193 function S_pixel() { // display boolean, color 194 this.d=true; this.c=0; 195 } 196 S_pixel.prototype.S_setColor=function(c) { 197 this.d=true; this.c=c; 198 } 199 S_pixel.prototype.S_hide=function() { this.d=false; } 200 S_scene.prototype.S_pixelSize=function(ps){ this.ps=ps; } 201 S_scene.prototype.S_widthAndHeight=function(w,h){ this.w=w; this.h=h; } 202 S_scene.prototype.S_center=function(cx,cy){ this.cx=cx; this.cy=cy; } 203 S_scene.prototype.S_paint=function(){ this.dt="paint"; } 204 S_scene.prototype.S_models=function() { 205 var i; this.m=new Array(); 206 for(i=0;i<arguments.length;i++) this.m.push(arguments[i]); 207 } 208 S_scene.prototype.S_lightColor=function(c){ this.lc=c; } 209 S_scene.prototype.S_project=function() { 210 var i, j, v, tm, d, m; 211 for(i=0;i<this.m.length;i++) { 212 m=this.m[i]; tm=this.m[i].tm; 213 for(j=0;j<m.v.length;j++) { 214 v=m.v[j]; 215 v.t.x=v.x*tm[0]+v.y*tm[4]+v.z*tm[8]+v.w*tm[12]; 216 v.t.y=v.x*tm[1]+v.y*tm[5]+v.z*tm[9]+v.w*tm[13]; 217 v.t.z=v.x*tm[2]+v.y*tm[6]+v.z*tm[10]+v.w*tm[14]; 218 d=(this.cmra-v.t.z/2); 219 if (d<0) { 220 v.p.x=(this.cmra*v.t.x/d)+this.cx; 221 v.p.y=-(this.cmra*v.t.y/d)+this.cy; 222 } 223 } 224 } 225 } 226 S_scene.prototype.S_display=function(disp){ 227 var i, j, k, s="", ds, c, cnt=0; // ds:div start 228 this.tr=new Array(); // triangles ready to draw 229 this.S_project(); 230 this.S_adjustLight(); 231 this.S_clearBuffer(); 232 for(i=0;i<this.m.length;i++) { 233 this.m[i].S_setupFaces(this.tr,this.lght.t); 234 for(j=0;j<this.tr.length;j++) { // loop through triangles 235 c=S_divColor(this.tr[j].c,this.lc,this.tr[j].b); 236 S_setupBuffer(this,this.tr[j].p,c); 237 } 238 } 239 for(i=0;i<this.h;i++) { 240 ds=-1; 241 for(j=0,k=1;j<this.w;j++,k++) { 242 if((this.bfr[i][j].d==true)&&(ds==-1)) ds=j; 243 if( (this.bfr[i][j].d==true)&& 244 ( (k==this.w)|| 245 (this.bfr[i][k].d==false)|| 246 (!S_sameColor(this.bfr[i][j].c, this.bfr[i][k].c)) ) ) { 247 s+=S_divString(S_rgbColorString(this.bfr[i][j].c),this.t+i*this.ps,this.l+ds*this.ps,this.ps,(k-ds)*this.ps); 248 ds=-1; 249 cnt++; 250 } 251 } 252 } 253 S_writeInnerHTML(this.dv,s); 254 if(disp=="ShowCount") alert(cnt); 255 } 256 S_scene.prototype.S_displayAndShowCount=function(){ 257 this.S_display("ShowCount"); 258 } 259 S_model.prototype.S_setupFaces=function(tr,lght) { 260 var i, j, fn, v, p=new Array(); // vertice & projection arrays 261 var z=new Array(); 262 for(i=0;i<this.f.length;i++) { // loop through faces 263 v=this.f[i].v; 264 for(j=0;j<3;j++) { p[j]=this.v[v[j]].p; } 265 for(j=0;j<3;j++) { z[j]=this.v[v[j]].t.z; } 266 if (((p[1].x-p[0].x)*(p[2].y-p[0].y))<((p[2].x-p[0].x)*(p[1].y-p[0].y))) { 267 this.f[i].d=true; 268 fn=S_faceNormal(this.v[v[0]].t, this.v[v[1]].t, this.v[v[2]].t); 269 this.f[i].b=S_faceIntensity(fn,lght); 270 tr.push(new S_triangle(fn,this.f[i].b,p.slice(),this.f[i].c,z)); 271 } else { this.f[i].d=false; } 272 } 273 } 274 // normal, brightness, array of 2D projection coordinates, and z depth 275 function S_triangle(fn,b,p,c,z) { 276 this.fn=fn; this.b=b; this.p=p; this.z=z; this.c=c; 277 } 278 function S_faceNormal(a,b,c){ 279 var cr=S_cross(S_subVec3D(b,a), S_subVec3D(b,c)); 280 return S_normalizeVec3D(cr); 281 } 282 function S_faceIntensity(fn,lght) { 283 var i=S_dotVec3D(fn,lght); return (i>0)?i:0; 284 } 285 function S_divColor(c,lc,b) { // c:array of colors 286 var i, clr=new Array(); 287 for(i=0;i<3;i++) clr[i]=Math.floor(c[i]+(lc[i]-c[i]+1)*b); 288 for(i=0;i<3;i++) if (clr[i]>lc[i]) { clr[i]=lc[i]; } 289 return S_rgbColor(clr[0],clr[1],clr[2]); 290 } 291 function S_sameColor(a,b) { 292 for(var i=0;i<3;i++) { if(a[i]!=b[i]) return false; } 293 return true; 294 } 295 function S_setupBuffer(scn,p,c) { 296 // temp, counters, min, max, scanline, vertice & slope arrays 297 var t,i,j,xmin=new Array(),xmax=new Array(),sl; 298 var v=new Array(), m=new Array(); 299 p.sort(function(a,b) { return a.y-b.y; } ); 300 for(i=0;i<3;i++) p[i].y=Math.floor(p[i].y); 301 v[0]=S_subVec2D(p[1],p[0]); 302 v[1]=S_subVec2D(p[2],p[0]); 303 v[2]=S_subVec2D(p[2],p[1]); 304 for(i=0;i<3;i++) { m[i]=(v[i].y!=0)?v[i].x/v[i].y:0; } 305 for(i=0,sl=scn.t;i<scn.h;i++,sl++) { 306 xmin[i]=1000;xmax[i]=0; 307 if((sl>=p[0].y)&&(sl<=p[2].y)) { 308 xmin[i]=xmax[i]=Math.floor(p[0].x+m[1]*(sl-p[0].y)); 309 } 310 if((sl>=p[0].y)&&(sl<=p[1].y)) { 311 t=Math.floor(p[0].x+m[0]*(sl-p[0].y)); 312 if(t<xmin[i]) xmin[i]=Math.floor(t); 313 else if(t>xmax[i]) xmax[i]=Math.floor(t); 314 } 315 if((sl>=p[1].y)&&(sl<=p[2].y)) { 316 t=Math.floor(p[1].x+m[2]*(sl-p[1].y)); 317 if(t<xmin[i]) xmin[i]=Math.floor(t); 318 else if(t>xmax[i]) xmax[i]=Math.floor(t); 319 } 320 for(j=0;j<scn.w;j++) 321 if((j>=(xmin[i]-scn.l))&&(j<=(xmax[i]-scn.l))) { 322 scn.bfr[i][j].d=true; scn.bfr[i][j].c=c; 323 } 324 } 325 } 326 function S_light() { 327 this.x=0; this.y=1; this.z=0; this.w=1; // original coordinates 328 this.t=new S_vec3D(0,1,0); // transformed coordinates 329 this.tm=new S_matrix(); 330 } 331 S_scene.prototype.S_adjustLight=function() { 332 var m=this.lght.tm, l=this.lght; 333 l.t.x=l.x*m[0]+l.y*m[4]+ l.z*m[8]+l.w*m[12]; 334 l.t.y=l.x*m[1]+l.y*m[5]+ l.z*m[9]+l.w*m[13]; 335 l.t.z=l.x*m[2]+l.y*m[6]+ l.z*m[10]+l.w*m[14]; 336 l.t=S_normalizeVec3D(l.t); 337 } 338 S_scene.prototype.S_lightRotateX=function(a) { 339 S_rotate(this.lght.tm,"x",a*=S_deg2Rad); 340 } 341 S_scene.prototype.S_lightRotateY=function(a) { 342 S_rotate(this.lght.tm,"y",a*=S_deg2Rad); 343 } 344 S_scene.prototype.S_lightRotateZ=function(a) { 345 S_rotate(this.lght.tm,"z",a*=S_deg2Rad); 346 } 347 S_scene.prototype.S_clearBuffer=function() { 348 for(var i=0;i<this.h;i++) 349 for(var j=0;j<this.w;j++) this.bfr[i][j].d=false; 350 } 351 function S_divString(b,t,l,h,w) { 352 var s='<div style="background-color:'+b+';position:absolute;'; 353 s+='top:'+t+'px;left:'+l+'px;height:'+h+'px;width:'+w; 354 return s+'px;font-size:0;visibility:visible"></div>'; 355 } 356 function S_writeInnerHTML(id,text) { 357 document.getElementById(id).innerHTML = text; 358 } 359 </script> 360 </head> 361 <body> 362 <div class="z1" id="graphicsDiv">Text to be replaced with graphics.</div> 363 <script type="text/javascript"> 364 if(S_checkBrowser()) { 365 var intrvl; 366 // Create a new scene with parameters for 367 // div id, left, top, width, height, and camera distance 368 var scn=new S_scene("graphicsDiv",75,25,100,100,300); 369 scn.S_pixelSize(3); // set scene pixel size 370 var c=S_rgbColor(0,0,127); // color 371 var c2=S_rgbColor(0,127,127); // color 372 var m=new S_cube(18,c); // model 373 m.S_faceColor(4,c2); 374 m.S_faceColor(5,c2); 375 m.S_scaleX(2.5); // scale model along x axis 376 scn.S_models(m); // add model(s) to scene 377 scn.S_lightRotateX(-25); // adjust light 378 function r(){ // rotation function 379 m.S_rotateX(11); // rotate model around y axis 380 m.S_rotateY(5); // rotate model around y axis 381 m.S_rotateZ(7); // rotate model around z axis 382 scn.S_display(); // display scene 383 } // end rotation function 384 intrvl=setInterval('r();',75); 385 } 386 </script> 387 388 </body> 389 </html>