Menu

3D drawings -- are there better ways?

Help
Danie Els
2008-03-26
2013-05-30
  • Danie Els

    Danie Els - 2008-03-26

    I am new to Asymptote, and is very imressed so far. The program that follows is a first attempt at rendering a 3D figure and the code was pillaged from various examples. It works more or less, but I am sure there are much better ways to do this. I would appreciated it a lot if you can point me to better routines or examples.

    I there a way to implement light for better shading?

    Thank you very much

    Danie

    //////////////////////////////////////////////////////////
    import three;

    //currentprojection=orthographic(1600,800,400);
    currentprojection=perspective((1600,800,400)); //Far away!

    typedef path3[] Shape;

    Shape operator *(transform3 T, Shape p){
      Shape pt;
      for(int i=0;i<p.length;++i) pt[i]=T*p[i];
      return pt;
    }

    path3 buildpath(triple[] T){
        path3 P;
        P = T[0];
        for(int i=1; i<T.length; ++i){P = P -- T[i];}
        return P;
    }

    face[] drawshapes(face[] F, Shape[] Shp, pen fcol=white, pen dcol=black+0.3bp, real op=1){
        face[] faces;
        faces.append(F);
        for(int i=0; i<Shp.length; ++i){
            for(int j=0; j<Shp[i].length; ++j) {
                picture pic=faces.push(Shp[i][j]);
                filldraw(pic,Shp[i][j], fcol+opacity(op), dcol);
            }
        }
        return faces;
    }

    Shape BuildCylinder(real R=1.0, real H=1.0, int n=18, transform3 T=scale3(1)){
        Shape Cyl;
        triple[] CTop;
        triple[] CBot;

        void Vertex(real x,real y, real z){ CBot.push((x,y,0)); }
        for(int i=0;i<n+1;++i){Vertex(R*cos(2pi*i/n), R*sin(2pi*i/n),0);}
        CTop = CBot+(0,0,H);

        for(int i=0;i<n;++i){Cyl.push(CBot[i]--CBot[i+1]--CTop[i+1]--CTop[i]--cycle3);} 
       
        path3 P = buildpath(CBot)--cycle3;
        Cyl.push(P);
        Cyl.push(shift(H*Z)*P);
       
        return T*Cyl;
    }

    Shape BuildSlab(real x=1.0, real y=1.0, real z=1.0, transform3 T=scale3(1)){
        Shape Slab;
       
        Slab[0] = (0,0,0)--(1,0,0)--(1,1,0)--(0,1,0)--cycle3;
        Slab[1] = (0,0,0)--(1,0,0)--(1,0,1)--(0,0,1)--cycle3;
        Slab[2] = (1,0,0)--(1,1,0)--(1,1,1)--(1,0,1)--cycle3;
        Slab[3] = (1,1,0)--(0,1,0)--(0,1,1)--(1,1,1)--cycle3;
        Slab[4] = (0,1,0)--(0,0,0)--(0,0,1)--(0,1,1)--cycle3;
        Slab[5] = (0,0,1)--(1,0,1)--(1,1,1)--(0,1,1)--cycle3;
       
        return T*scale(x,y,z)*Slab;
    }

    size(10cm,0);

    real Blen = 360;
    real Bwdt =  30;
    real Bhgt =   3;
    real Clen = 130;
    real Cwdt = 100;
    real Chgt = 100;
    real cylr =   7.5;
    real cylh =  37.0 ;

    Shape slab1 = BuildSlab(Blen,Bwdt,Bhgt, shift(-Bwdt/2*Y - Bhgt/2*Z + Clen/2*X));
    Shape slab2 = BuildSlab(Clen,Cwdt,Chgt, shift(-Cwdt/2*Y - Chgt/2*Z - Clen/2*X));
    Shape cyl1  = BuildCylinder(R=cylr, H=cylh, shift(400*X - (cylh/2)*Z));

    Shape[] Sarr1={slab1,slab2};
    Shape[] Sarr2={cyl1};

    face[] faces;
    faces = drawshapes(faces, Sarr1, fcol=gray(0.8),    dcol=black+0.25bp, op=0.8 );
    faces = drawshapes(faces, Sarr2, fcol=yellow+white, dcol=black+0.25bp, op=0.8 );
    add(faces);
    shipout(bbox(3mm,white));
    //////////////////////////////////////////////////////////

     
    • John Bowman

      John Bowman - 2008-06-05

      Yes, it is easy to add lighting. Just change your drawshapes routine to:

      import light;
      face[] drawshapes(face[] F, Shape[] Shp, pen fcol=white, pen dcol=black+0.3bp, real op=1){
        face[] faces;
        faces.append(F);
        for(int i=0; i<Shp.length; ++i){
          for(int j=0; j<Shp[i].length; ++j) {
            path3 g=Shp[i][j]; 
            picture pic=faces.push(g);
            filldraw(pic,g,currentlight.intensity(faces[faces.length-1].point)*fcol+opacity(op), dcol);
          }
        }
        return faces;
      }

       

Log in to post a comment.