Manta Interactive Ray Tracer Development Mailing List

Text archives Help


[MANTA] r327 - trunk/Model/Primitives


Chronological Thread 
  • From: vpegorar@sci.utah.edu
  • To: manta@sci.utah.edu
  • Subject: [MANTA] r327 - trunk/Model/Primitives
  • Date: Mon, 16 May 2005 15:57:51 -0600 (MDT)

Author: vpegorar
Date: Mon May 16 15:57:51 2005
New Revision: 327

Added:
   trunk/Model/Primitives/Heightfield.cc
   trunk/Model/Primitives/Heightfield.h
Log:
Heightfield implemented. Should modify the scene to allow dynamic data 
specification. Fixed small bug in PointVector class.


Added: trunk/Model/Primitives/Heightfield.cc
==============================================================================
--- (empty file)
+++ trunk/Model/Primitives/Heightfield.cc       Mon May 16 15:57:51 2005
@@ -0,0 +1,308 @@
+
+#include <Model/Primitives/Heightfield.h>
+#include <Interface/RayPacket.h>
+#include <Core/Geometry/BBox.h>
+#include <Core/Math/MiscMath.h>
+#include <Core/Math/MinMax.h>
+#include <Core/Malloc/ArrayAllocation.h>
+#include <Core/Geometry/PointVector.h>
+#include <fstream>
+#include <iostream>
+
+using namespace Manta;
+using namespace std;
+
+
+// 
--------------------------------------------------------------------------------------
+// --- Constructor
+// 
--------------------------------------------------------------------------------------
+Heightfield::Heightfield(Material * material, char * fileName, const Point & 
minBound, const Point & maxBound, double scale)
+  : PrimitiveCommon(material), m_Box(minBound, maxBound)
+{
+  readHeightfieldFile(fileName, &m_Nx, &m_Ny, &m_Data);
+  rescaleDataHeight(scale);
+}
+
+
+// 
--------------------------------------------------------------------------------------
+// --- Destructor
+// 
--------------------------------------------------------------------------------------
+Heightfield::~Heightfield()
+{
+  DELETE2DARRAY(m_Data, m_Nx+1);
+}
+
+
+// 
--------------------------------------------------------------------------------------
+// --- Get the Bounding Box
+// 
--------------------------------------------------------------------------------------
+void Heightfield::computeBounds(const PreprocessContext & context, BBox & 
bbox) const
+{
+  bbox.extendByPoint(m_Box.getMin());
+  bbox.extendByPoint(m_Box.getMax());
+}
+
+
+// 
--------------------------------------------------------------------------------------
+// --- Test whether the ray intersects the Heightfield or not
+// 
--------------------------------------------------------------------------------------
+void Heightfield::intersect(const RenderContext & context, RayPacket & rays) 
const
+{
+  Vector diagonal;
+  Point hitPoint;
+  int hitLattice[2], stop[2], di[2], ind;
+  double tnext[2], dtd[2], far[2], zm[2], datam[2], cellSize[2];
+  double tnear, tfar, zenter, texit, zexit;
+  bool validtcells[2];
+
+  if (!(rays.getFlags() & RayPacket::NormalizedDirections))
+  {
+    rays.normalizeDirections();
+    rays.setFlag(RayPacket::NormalizedDirections);
+  }
+
+  for(int i=0; i<rays.getSize(); i++)
+  {
+    RayPacket::Element & e = rays.get(i);
+    Ray & ray = e.ray;
+
+    using Manta::Min;
+    using Manta::Max;
+    rays.computeInverseDirections();
+    Vector t1 = (m_Box.getMin() - ray.origin()) * e.inverseDirection;
+    Vector t2 = (m_Box.getMax() - ray.origin()) * e.inverseDirection;
+    Vector tn = Min(t1, t2);
+    Vector tf = Max(t1, t2);
+    tnear = tn.maxComponent();
+    tfar  = tf.minComponent();
+    if (tnear > tfar)
+      continue;
+
+    using SCIRun::Min;
+    using SCIRun::Max;
+
+    if (m_Box.getMin().x() < ray.origin().x() && m_Box.getMin().y() < 
ray.origin().y() && m_Box.getMin().z() < ray.origin().z() && 
+        m_Box.getMax().x() > ray.origin().x() && m_Box.getMax().y() > 
ray.origin().y() && m_Box.getMax().z() < ray.origin().z() )
+      tnear = 0.0;
+
+    diagonal = m_Box.diagonal();
+    cellSize[0] = diagonal.x() / (double)m_Nx;
+    cellSize[1] = diagonal.y() / (double)m_Ny;
+
+    hitPoint = ray.origin() + (ray.direction() * tnear);
+    hitLattice[0] = (int)((hitPoint.x() - m_Box.getMin().x()) / cellSize[0]);
+    hitLattice[1] = (int)((hitPoint.y() - m_Box.getMin().y()) / cellSize[1]);
+
+    if      (hitLattice[0] < 0)          hitLattice[0] = 0;
+    else if (hitLattice[0] >= (int)m_Nx) hitLattice[0] = (int)(m_Nx-1);
+    if      (hitLattice[1] < 0)          hitLattice[1] = 0;
+    else if (hitLattice[1] >= (int)m_Ny) hitLattice[1] = (int)(m_Ny-1);
+
+    di[0] = (diagonal.x() * ray.direction().x() > 0.0) ? 1 : -1;
+    stop[0] = (di[0] == 1) ? m_Nx : -1;
+    di[1] = (diagonal.y() * ray.direction().y() > 0.0) ? 1 : -1;
+    stop[1] = (di[1] == 1) ? m_Ny : -1;
+
+    dtd[0] = fabs(cellSize[0] / ray.direction().x());
+    dtd[1] = fabs(cellSize[1] / ray.direction().y());
+
+    if (di[0] == 1) far[0] = m_Box.getMin().x() + cellSize[0] * 
(double)(hitLattice[0] + 1);
+    else            far[0] = m_Box.getMin().x() + cellSize[0] * 
(double)(hitLattice[0]    );
+    if (di[1] == 1) far[1] = m_Box.getMin().y() + cellSize[1] * 
(double)(hitLattice[1] + 1);
+    else            far[1] = m_Box.getMin().y() + cellSize[1] * 
(double)(hitLattice[1]    );
+
+    tnext[0] = (far[0] - ray.origin().x()) / ray.direction().x();
+    tnext[1] = (far[1] - ray.origin().y()) / ray.direction().y();
+
+    while(true)
+    {
+      zenter = ray.origin().z() + (tnear * ray.direction().z());
+      texit  = Min(tnext[0], tnext[1]);
+      zexit  = ray.origin().z() + (texit * ray.direction().z());
+
+      datam[0] = Min(Min(m_Data[hitLattice[0]][hitLattice[1]  ], 
m_Data[hitLattice[0]+1][hitLattice[1]  ]) ,
+                     Min(m_Data[hitLattice[0]][hitLattice[1]+1], 
m_Data[hitLattice[0]+1][hitLattice[1]+1]) );
+      zm[0] = Min(zenter, zexit);
+      datam[1] = Max(Max(m_Data[hitLattice[0]][hitLattice[1]  ], 
m_Data[hitLattice[0]+1][hitLattice[1]  ]) ,
+                     Max(m_Data[hitLattice[0]][hitLattice[1]+1], 
m_Data[hitLattice[0]+1][hitLattice[1]+1]) );
+      zm[1] = Max(zenter, zexit);
+
+      if (!(zm[0] > datam[1] || zm[1] < datam[0]))
+      {
+        double a, b, c;
+        double sx, dx, sy, dy;
+        Point pe;
+        double ce[2], z[4];
+
+        pe = ray.origin() + ray.direction() * tnear;
+        ce[0] = pe.x() - (m_Box.getMin().x() + cellSize[0] * 
(double)(hitLattice[0]));
+        ce[1] = pe.y() - (m_Box.getMin().y() + cellSize[1] * 
(double)(hitLattice[1]));
+
+        sx = ce[0] / cellSize[0];
+        sy = ce[1] / cellSize[1];
+        dx = ray.direction().x() / cellSize[0];
+        dy = ray.direction().y() / cellSize[1];
+
+        z[0] = m_Data[hitLattice[0]  ][hitLattice[1]  ];
+        z[1] = m_Data[hitLattice[0]+1][hitLattice[1]  ] - z[0];
+        z[2] = m_Data[hitLattice[0]  ][hitLattice[1]+1] - z[0];
+        z[3] = m_Data[hitLattice[0]+1][hitLattice[1]+1] - 
m_Data[hitLattice[0]+1][hitLattice[1]] - z[2];
+
+        a = dx * dy * z[3];
+        b = (sx * dy + sy * dx)*z[3] + dx*z[1] + dy*z[2] - 
ray.direction().z();
+        c = sx*sy*z[3] + sx*z[1] + sy*z[2] + z[0] - pe.z();
+
+        if (a == 0.0)
+        {
+          double tcell, u, v;
+
+          tcell = -c / b;
+          u = sx + tcell * dx;
+          v = sy + tcell * dy;
+
+          if (tcell > T_EPSILON && tcell < texit && u > 0.0 && u < 1.0 && v 
> 0.0 && v < 1.0)
+          {
+            if (e.hitInfo.hit(tnear + tcell, material, this, tex))
+              e.hitInfo.scratchpad<Vector>() = Vector(- (z[1] + v*z[3]) / 
cellSize[0], - (z[2] + u*z[3]) / cellSize[1], 1.0);
+            break;
+          }
+        }
+        else
+        {
+          double delta = b*b - 4.0*a*c;
+          if (delta >= 0.0)
+          {
+            double tcells[2], a2, u, v, tcell;
+
+            delta = sqrt(delta);
+            a2 = 2.0 * a;
+
+            tcells[0] = (-b - delta) / a2;
+            tcells[1] = (-b + delta) / a2;
+
+            validtcells[0] = (tcells[0] > 0.0 && tcells[0] < texit);
+            validtcells[1] = (tcells[1] > 0.0 && tcells[1] < texit);
+
+            tcell = -1.0;
+            if (validtcells[0] && validtcells[1]) tcell = Min(tcells[0], 
tcells[1]);
+            else if (validtcells[0])              tcell = tcells[0];
+            else if (validtcells[1])              tcell = tcells[1];
+
+            if (tcell > T_EPSILON)
+            {
+              u = sx + tcell * dx;
+              v = sy + tcell * dy;
+              if (u > 0.0 && u < 1.0 && v > 0.0 && v < 1.0)
+              {
+                if (e.hitInfo.hit(tnear + tcell, material, this, tex))
+                  e.hitInfo.scratchpad<Vector>() = Vector( - (z[1] + v*z[3]) 
/ cellSize[0], - (z[2] + u*z[3]) / cellSize[1], 1.0);
+                break;
+              }
+            }
+          }
+       }
+      }
+
+      ind = (tnext[0] < tnext[1]) ? 0 : 1;
+      tnear = tnext[ind];
+      tnext[ind] += dtd[ind];
+      hitLattice[ind] += di[ind];
+
+      if (hitLattice[0] == stop[0] || hitLattice[1] == stop[1] || tnear > 
tfar)
+        break;
+    }
+  }
+}
+
+
+// 
--------------------------------------------------------------------------------------
+// --- Set the normals
+// 
--------------------------------------------------------------------------------------
+void Heightfield::computeNormal(const RenderContext & context, RayPacket & 
rays) const
+{
+  int i, numRays(rays.getSize());
+  
+  for (i=0; i<numRays; i++)
+  {
+    RayPacket::Element & e(rays.get(i));
+    e.normal = e.hitInfo.scratchpad<Vector>();
+    e.normal.normalize();
+  }
+
+  // set flags to indicate packet now has unit normals
+  rays.setFlag(RayPacket::HaveNormals | RayPacket::HaveUnitNormals);
+}
+
+
+// 
--------------------------------------------------------------------------------------
+// --- Rescale the height of the data to fit the Box
+// --- according to the given percentage of the size of the box to which the 
data should be rescaled
+// 
--------------------------------------------------------------------------------------
+void Heightfield::rescaleDataHeight(double scale)
+{
+  using SCIRun::Min;
+  using SCIRun::Max;
+
+  unsigned int i, j;
+  double min, max, factor, margin;
+
+  min = m_Data[0][0];
+  max = min;
+  for(i=0; i<=m_Nx; i++)
+    for(j=0; j<=m_Ny; j++)
+    {
+      min = Min(min, m_Data[i][j]);
+      max = Max(max, m_Data[i][j]);
+    }
+
+  factor = m_Box.getMax().z() - m_Box.getMin().z();
+  margin = factor * (1.0 - scale) * 0.5;
+  factor *= scale / (max - min);
+
+  for(i=0; i<=m_Nx; i++)
+    for(j=0; j<=m_Ny; j++)
+      m_Data[i][j] = ((m_Data[i][j] - min) * factor) + (m_Box.getMin().z() + 
margin);
+}
+
+
+// 
--------------------------------------------------------------------------------------
+// --- Read the given file and returns nx, ny and the data
+// 
--------------------------------------------------------------------------------------
+void Heightfield::readHeightfieldFile(char * fileName, unsigned int * pnx, 
unsigned int * pny, double *** pdata)
+{
+  double minz, maxz;
+  int nx, ny, i, j;
+  float ** data;
+
+  ifstream in(fileName, std::ios::in | std::ios::binary);
+  if (!in)
+  {
+    cerr << "Error : unable to open " << fileName << "\n";
+    exit(1);
+  }
+
+  in >> nx >> ny >> minz >> maxz;
+  if (!in)
+  {
+    cerr << "Error : unable to read header from " << fileName << "\n";
+    exit(1);
+  }
+  in.get();
+
+  ALLOCATE2DARRAY(data, nx+1, ny+1, float);
+  in.read((char *)data[0], sizeof(float)*(nx+1)*(ny+1));
+  if (!in)
+  {
+    cerr << "Error : unable to read data from " << fileName << "\n";
+    exit(1);
+  }
+
+  *pnx = nx;
+  *pny = ny;
+  ALLOCATE2DARRAY(*pdata, nx+1, ny+1, double);
+  for(i=0; i<=nx; i++)
+    for(j=0; j<=ny; j++)
+      (*pdata)[i][j] = (double)data[i][j];
+
+  //  DELETE2DARRAY(data, nx+1);
+}

Added: trunk/Model/Primitives/Heightfield.h
==============================================================================
--- (empty file)
+++ trunk/Model/Primitives/Heightfield.h        Mon May 16 15:57:51 2005
@@ -0,0 +1,35 @@
+
+#ifndef Manta_Model_Heightfield_h
+#define Manta_Model_Heightfield_h
+
+#include <Model/Primitives/PrimitiveCommon.h>
+#include <Core/Geometry/PointVector.h>
+#include <Core/Geometry/BBox.h>
+
+namespace Manta {
+
+  //  using namespace SCIRun;
+  class Heightfield : public PrimitiveCommon
+  {
+
+    public:
+
+                   Heightfield(Material * material, char * fileName, const 
Point & minBound, const Point & maxBound, double scale = 0.95);
+      virtual      ~Heightfield();
+
+      virtual void computeBounds(const PreprocessContext & context, BBox & 
bbox) const;
+      virtual void intersect(const RenderContext & context, RayPacket & 
rays) const;
+      virtual void computeNormal(const RenderContext & context, RayPacket & 
rays) const;
+      virtual void rescaleDataHeight(double scale);
+      virtual void readHeightfieldFile(char * fileName, unsigned int * pnx, 
unsigned int * pny, double *** pdata);
+
+    private:
+
+      BBox         m_Box;
+      unsigned int m_Nx;
+      unsigned int m_Ny;
+      double **    m_Data;
+  };
+}
+
+#endif





Archive powered by MHonArc 2.6.16.

Top of page