3d-thingy.html 13 KB

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