Tim Bray wrote:

> I have neat-looking haystack-y objects which use LineArray geometry.

        I hesitate to post this because it's such a hack, but it
        does demonstrate lighting lines.

        Attached is source for a class, HaystackBG, that uses lit
        line segments (LineArray) to simulate (vaguely) a haystack.
        The line segments are arranged such that one end is "on the
        ground" on a circular perimeter and the other is at the apex
        of the "haystack".  Normals are assigned to each endpoint of
        the line segments that generally point perpendicular to the
        shape of the haystack (roughly a cone).  I also had to insert
        a white cone inside the haystack (of slightly smaller size)
        so that the "back facing" lines are obscured--they can't be
        culled (or have their normals flipped) because that is done
        using PolygonAttributes.  Besides, a line segment can't have
        a CCW winding order with just two vertices.

        Also attached is a small GIF image of the haystack (using a
        lousy Material) lit with white ambient and directional lights.

        Feedback (+ or -) welcome.

--
Allen L. McPherson               Member Holstein Aerobatic Club
Los Alamos National Laboratory   Scientific Viz / Advanced Computing Lab
Box 1663 Group:CIC-ACL MS:B287   [EMAIL PROTECTED]
Los Alamos, NM   87545           Voice: (505) 665-6548  Fax: (505) 665-4939
[Personal mail to:               [EMAIL PROTECTED]]

GIF image

//  Copyright (c) 1999 by Allen Lynn McPherson.  All rights reserved.
//  This example is provided WITHOUT ANY WARRANTY either expressed or implied.

import java.util.Random;
import javax.media.j3d.*;
import javax.vecmath.*;


//  Fake (i.e. hack) "haystack" using lit lines.
public class  HaystackBG  extends BranchGroup {

  public  HaystackBG(float radius, float height) {
    //  This is the haystack created using lit lines.
    this.addChild(new Haystack(radius, height, 500));
    //  Here we insert a white, unlit cone into the middle of the
    //  haystack because "backfacing" lines can't be culled
    //  and must be obscured.
    this.addChild(new InsertCone(radius-0.1f, height-0.1f, 30));
  }

  //  The haystack itself.
  private class  Haystack  extends Shape3D {
    public  Haystack(float radius, float height, int nLines) {
      Point3f   coords[] = new Point3f[2*nLines];
      Vector3f  norms[]  = new Vector3f[2*nLines];
      double    range    = 2 * Math.PI;
      double    rIncr    = range / nLines;
      double    start    = 0;
      float     fScale   = 0.3f;                //  Fudge scale
      double    aTop     = Math.PI/2 - Math.atan(height/radius);

      double  theta = start;
      Random  rand  = new Random();
      for (int i=0; i<nLines; i++) {
        //  True point (before fudge)
        Point3f  pt   = new Point3f((float)(radius*Math.cos(theta)), 0,
                                    (float)(radius*Math.sin(theta)));
        //  Fudge the true point for noise
        float  xFudged = (rand.nextFloat() - 0.5f) * fScale;
        float  yFudged = (rand.nextFloat() - 0.5f) * fScale;
        float  zFudged = (rand.nextFloat() - 0.5f) * fScale;
        coords[2*i]   = new Point3f(pt.x+xFudged, pt.y+yFudged, pt.z+zFudged);
        coords[2*i+1] = new Point3f(xFudged, height+yFudged, zFudged);
        //  True vector (before fudge)
        Vector3f  vec = new Vector3f(coords[2*i].x,
                                     (float)(radius * Math.tan(aTop)),
                                     coords[2*i].z);
        //  Fudge the true vector for noise.
        xFudged = vec.x + (rand.nextFloat() - 0.5f) * fScale;
        yFudged = vec.y + (rand.nextFloat() - 0.5f) * fScale;
        zFudged = vec.z + (rand.nextFloat() - 0.5f) * fScale;
        norms[2*i]    = new Vector3f(xFudged, yFudged, zFudged);
        norms[2*i].normalize();
        norms[2*i+1]  = new Vector3f(norms[2*i]);
        theta += rIncr;
      }

      LineArray  lines = new LineArray(2*nLines, GeometryArray.COORDINATES |
                                       GeometryArray.NORMALS);
      lines.setCoordinates(0, coords);
      lines.setNormals(0, norms);

      Appearance  app = new Appearance();
      app.setMaterial(new Material(
        new Color3f(0.44f, 0.16f, 0.16f),              //  ambient
        new Color3f(0.0f, 0.0f, 0.0f),                 //  emisive
        new Color3f(0.44f, 0.16f, 0.16f),              //  diffuse
        new Color3f(0.6f, 0.6f, 0.6f),                 //  specular
        128.0f * 0.3f));                               //  shininess
      app.setLineAttributes(
        new LineAttributes(3.0f, LineAttributes.PATTERN_SOLID, true));

      this.setGeometry(lines);
      this.setAppearance(app);
    }
  }

  //  Cone that is inserted into the center of the haystack to obscure
  //  the "backfacing" lines (since they can't be culled).
  private class  InsertCone  extends Shape3D {
    Point3d     coords[];
    Vector3f    norms[];

    public  InsertCone(float radius, float height, int sides) {
      coords = new Point3d[sides+2];    //  Includes center point

      //  Load coordinate array.
      coords[0] = new Point3d(0.0, height, 0.0);        //  Top center point
      for (int i=1; i<sides+2; i++) {
        //  Make sure to build fan using CCW winding order for culling.
        double  angle = (sides+2-i) * (2*Math.PI) / sides;
        coords[i] = new Point3d(radius * Math.cos(angle), 0.0,
                                radius * Math.sin(angle));
      }

      //  Create traingle fan for geometry
      int  counts[] = {coords.length};
      TriangleFanArray  fan =
        new TriangleFanArray(coords.length, GeometryArray.COORDINATES, counts);
      fan.setCoordinates(0, coords);

      Appearance  app = new Appearance();
      ColoringAttributes  ca =
        new ColoringAttributes(1.0f, 1.0f, 1.0f, ColoringAttributes.FASTEST);
      app.setColoringAttributes(ca);

      this.setGeometry(fan);
      this.setAppearance(app);
    }
  }

}

Reply via email to