[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Graphing 3D surfaces



On Mon, 24 Jan 2005, Steve Bellenot wrote:

> I haven't found much in the documentation about drawing general
> 3D surfaces. There is the Hidden object removal in the advanced
> topics, of course. I'm trying to do 3D graphs. The goal is to do
> at least as good as maple.
>
> One of the common color/3D tricks is to make the color of a surface
> depend on its height. Say low values are blue, high values are
> red and the color blends for the points in between. Maple calls this
> shading=Z, and seems to set the color for every quad
> once in the postscript output file.
>
> Are these types of things that have been done already?
>
Dear Steve,

The short answer is "no". :)

The grayscale shading in the ad hoc examples is easily modified to depend
on position rather than orientation of the face relative to the camera. To
my knowledge, there's no reason the effects you describe couldn't be
implemented (in color) using (say) pstricks. The current "procedural"
design of ePiX may not facilitate the task, unfortunately. In particular,
ePiX isn't subtle about grouping elements of the same color, or actually
removing hidden objects, so the LaTeX color stack will tend to fill
prematurely.

A couple of ugly torus mesh hacks are attached, representing roughly the
limit of what I know how to do with the existing code. Only the edges are
colored; the faces are white-filled. I'll fiddle with solid colored
surface elements in pstricks, but please post if you make progress.

Best, Andy


Andrew D. Hwang			ahwang@mathcs.holycross.edu
Department of Math and CS	http://math.holycross.edu/~ahwang
College of the Holy Cross	(508) 793-2458 (Office: 320 Swords)
Worcester, MA, 01610-2395	(508) 793-3530 (fax)

/* -*-ePiX-*- */
#include "epix.h"
using namespace ePiX;

int N1=24;
int N2=48;

double du=2.0/N1, dv=2.0/N2;
P VIEWPT=P(8, 3, 4);

double r_0=1.5;

double EPS=0.0025;

class mesh_quad
{
private:
  P pt1;
  P pt2;
  P pt3;
  P pt4;
  
  double distance;

public:
  mesh_quad() 
  {
    pt1=P();
    pt2=P();
    pt3=P();
    pt4=P();
    distance=camera.get_range();
  }

  mesh_quad(P f(double u, double v), double u0, double v0)
  {
    pt1=f(u0+EPS,v0+EPS);
    pt2=f(u0+du-EPS,v0+EPS);
    pt3=f(u0+du-EPS,v0+dv-EPS);
    pt4=f(u0+EPS,v0+dv-EPS);
    
    P center = 0.25*(pt1 + (pt2 + (pt3 + pt4)));
    P temp = camera.get_viewpt();

    distance = norm(center-temp);
  }

  double how_far() const { return distance; }

  void draw() 
  { 
    P normal = (pt2 - pt1)*(pt4 - pt1);
    normal *= 1/norm(normal);

    double dens = (2+r_0-pt1.x3())/(2*(2+r_0)); // in [0,1]

    // white-filled quad
    fill();
    gray(0);
    quad(pt1, pt2, pt3, pt4); 
    fill(false);

    rgb(dens, 0, 1-dens);
    quad(pt1, pt2, pt3, pt4); 
  }

};

class by_distance {
public:
  bool operator() (const mesh_quad& arg1, const mesh_quad& arg2)
  {
    return arg1.how_far() > arg2.how_far(); 
  }
};

P f2(double u, double v)
{
  return P(r_0*Sin(M_PI*u), 
	   (2+r_0*Cos(M_PI*u))*Cos(M_PI*v),
	   (2+r_0*Cos(M_PI*u))*Sin(M_PI*v));
}

int main() {
  bounding_box(P(-4,-4),P(4,4));
  unitlength("1in");
  picture(P(5,5));

  begin();

  viewpoint(VIEWPT);

  crop();
  camera.range(20);

  std::vector<mesh_quad> mesh(0);

  for (int i=0; i<N1; ++i)
    for (int j=0; j<N2; ++j)
      mesh.push_back(mesh_quad(f2, -1+du*i, -1+dv*j));

  sort(mesh.begin(), mesh.end(), by_distance());

  bold();
  for (unsigned int i=0; i<mesh.size(); ++i)
    mesh.at(i).draw();

  end();
}
/* -*-ePiX-*- */
#include "epix.h"
using namespace ePiX;

int N1=24;
int N2=48;

double du=2.0/N1, dv=2.0/N2;
P VIEWPT(4, 3, 4);

// locations of "lights"
P LIGHT_R(4,3,2);
P LIGHT_G(4,-6,2);
P LIGHT_B(-2,-2,6);
/*
P LIGHT_R(1,0,0);
P LIGHT_G(0,1,0);
P LIGHT_B(0,0,1);
*/

double r_0=1.0;

double EPS=0.00125;

class mesh_quad
{
private:
  P pt1;
  P pt2;
  P pt3;
  P pt4;
  
  double distance;

public:
  mesh_quad() 
  {
    pt1=P();
    pt2=P();
    pt3=P();
    pt4=P();
    distance=camera.get_range();
  }

  mesh_quad(P f(double u, double v), double u0, double v0)
  {
    pt1=f(u0+EPS,v0+EPS);
    pt2=f(u0+du-EPS,v0+EPS);
    pt3=f(u0+du-EPS,v0+dv-EPS);
    pt4=f(u0+EPS,v0+dv-EPS);
    
    P center = 0.25*(pt1 + (pt2 + (pt3 + pt4)));
    P temp = camera.get_viewpt();

    distance = norm(center-temp);
  }

  double how_far() const { return distance; }

  void draw() 
  { 
    P normal = (pt2 - pt1)*(pt4 - pt1);
    normal *= 1/norm(normal);

    double dens_r  = 0.75*(1-pow(normal|LIGHT_R, 2)/(LIGHT_R|LIGHT_R));
    double dens_g  = 0.75*(1-pow(normal|LIGHT_G, 2)/(LIGHT_G|LIGHT_G));
    double dens_b  = 0.75*(1-pow(normal|LIGHT_B, 2)/(LIGHT_B|LIGHT_B));

    // white-filled quad
    fill();
    gray(0);
    quad(pt1, pt2, pt3, pt4); 
    fill(false);

    rgb(dens_r, dens_g, dens_b);
    quad(pt1, pt2, pt3, pt4); 
  }

};

class by_distance {
public:
  bool operator() (const mesh_quad& arg1, const mesh_quad& arg2)
  {
    return arg1.how_far() > arg2.how_far(); 
  }
};

P f2(double u, double v)
{
  return P(r_0*Sin(M_PI*u), 
	   (2+r_0*Cos(M_PI*u))*Cos(M_PI*v),
	   (2+r_0*Cos(M_PI*u))*Sin(M_PI*v));
}

int main() {
  bounding_box(P(-3,-3),P(3,3));
  unitlength("1in");
  picture(P(5,5));

  begin();

  viewpoint(VIEWPT);

  crop();
  camera.range(20);

  std::vector<mesh_quad> mesh(0);

  for (int i=0; i<N1; ++i)
    for (int j=0; j<N2; ++j)
      mesh.push_back(mesh_quad(f2, -1+du*i, -1+dv*j));

  sort(mesh.begin(), mesh.end(), by_distance());

  pen(2);
  for (unsigned int i=0; i<mesh.size(); ++i)
    mesh.at(i).draw();

  end();
}