Commit 6fbf4c7a authored by Will Schroeder's avatar Will Schroeder
Browse files

Added two-sided lighting; backface culling.

parent 7e92088b
......@@ -3,8 +3,8 @@
Program: Visualization Toolkit
Module: vtkConeSource.cc
Language: C++
Date: $Date$
Version: $Revision$
Date: 09 Oct 1995
Version: 1.22
Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.
......@@ -157,7 +157,7 @@ void vtkConeSource::Execute()
//
if ( this->Capping )
{
for (i=0; i<this->Resolution; i++) pts[i] = i+1;
for (i=0; i<this->Resolution; i++) pts[this->Resolution - i - 1] = i+1;
newPolys->InsertNextCell(this->Resolution,pts);
}
} //switch
......
......@@ -83,15 +83,15 @@ static int NumberOfDuplicatePoints;
// arbitrary tetrahedron (tetra) and "walks" towards it. Influenced by
// some of Guibas and Stolfi's work. Returns id of enclosing tetra, or -1
// if no tetrahedron found.
static int FindTetra(float x[3], int ptIds[4], int tetra,
vtkUnstructuredGrid *Mesh,
static int FindTetra(float x[3], int ptIds[4], float p[4][3],
int tetra, vtkUnstructuredGrid *Mesh,
vtkFloatPoints *points, float tol)
{
int i, j, npts, inside, i2, i3, i4;
vtkIdList pts(4), facePts(3);
static vtkMath math;
vtkIdList neighbors(2);
float p[4][3], v12[3], vp[3], vx[3], v32[3], n[3], valx, valp;
float v12[3], vp[3], vx[3], v32[3], n[3], valx, valp;
// get local tetrahedron info
Mesh->GetCellPoints(tetra,pts);
......@@ -139,13 +139,13 @@ static int FindTetra(float x[3], int ptIds[4], int tetra,
Mesh->GetCellNeighbors(tetra, facePts, neighbors);
if ( neighbors.GetNumberOfIds() > 0 ) //not boundary
{
return FindTetra(x,ptIds,neighbors.GetId(0),Mesh,points,tol);
return FindTetra(x,ptIds,p,neighbors.GetId(0),Mesh,points,tol);
}
}//outside this edge
}//for each edge
//must be in this tetraangle if all edges test inside
//must be in this tetra if all faces test inside
if ( !inside ) return -1;
else return tetra;
}
......@@ -153,7 +153,7 @@ static int FindTetra(float x[3], int ptIds[4], int tetra,
// Recursive method checks whether face is Delaunay, and if not, swaps face.
// Continues until all faces are Delaunay. Points p1,p2,p3 form the face in
// question; x is the coordinates of the inserted point; tetra is the current
// triangle id; Mesh is a pointer to cell structure.
// tetrahedron id; Mesh is a pointer to cell structure.
static void CheckFace(int ptId, float x[3], int p1, int p2, int p3, int tetra,
vtkUnstructuredGrid *Mesh, vtkFloatPoints *points)
{
......@@ -215,6 +215,148 @@ static void CheckFace(int ptId, float x[3], int p1, int p2, int p3, int tetra,
}//interior edge
}
// Find all faces that enclose a point. Usually, a single tetra (and therefore
// four faces) enclose a point. But, if the point is on a face or edge rwo or
// more tetra "enclose" the point; thus six or more face enclose it. Enclosing
// tetras are returned in the tetras list; the enclosing faces are returned in
// the faces list.
static int FindEnclosingFaces(float x[3], int tetra, vtkUnstructuredGrid *Mesh,
vtkFloatPoints *points, float tol,
vtkIdList &tetras, vtkIdList &faces)
{
static vtkTetra cell;
int ptIds[4];
float p[4][3], bcoords[4];
int tetraId, verts[4], onCount, i, j;
static vtkIdList boundaryPts(3);
int v1, v2, v3, v4, p1, p2, p3;
int npts, *tetraPts;
tetras.Reset();
faces.Reset();
onCount = verts[0] = verts[1] = verts[2] = verts[3] = 0;
if ( (tetraId = FindTetra(x,ptIds,p,tetra,Mesh,points,tol)) >= 0 )
{
if ( cell.BarycentricCoords(x, p[0], p[1], p[2], p[3], bcoords) )
{
//check edges / faces for point being "on" them. Coincident points
//should have been caught already.
for (i=0; i < 4; i++ )
{
if ( bcoords[i] <= tol )
{
verts[i] = 1;
onCount++;
}
}
if ( onCount == 0 ) //inside tetra
{
tetras.InsertNextId(tetraId);
for (i=0; i < 4; i++)
{
faces.InsertNextId(ptIds[i]);
faces.InsertNextId(ptIds[(i+1)%4]);
faces.InsertNextId(ptIds[(i+2)%4]);
}
}
else if ( onCount == 1 ) //on face
{
for (i=0; i < 4; i++)
if ( !verts[i] )
boundaryPts.InsertNextId(ptIds[i]);
Mesh->GetCellNeighbors(tetraId, boundaryPts, tetras);
tetras.InsertNextId(tetraId);
//now for the tricky part...find boundary faces. For a face neighbor,
//boundary face is a face that uses just two of three points defining
//face
v1 = boundaryPts.GetId(0);
v2 = boundaryPts.GetId(1);
v3 = boundaryPts.GetId(2);
for (i=0; i < tetras.GetNumberOfIds(); i++)
{
Mesh->GetCellPoints(tetras.GetId(i),npts,tetraPts);
for (j=0; j<4; j++)
{
p1 = tetraPts[j];
p2 = tetraPts[(j+1)%4];
p3 = tetraPts[(j+2)%4];
if ( ! ((p1 == v1 || p2 == v1 || p3 == v1) &&
(p1 == v2 || p2 == v2 || p3 == v2) &&
(p1 == v3 || p2 == v3 || p3 == v3)) )
{
faces.InsertNextId(p1);
faces.InsertNextId(p2);
faces.InsertNextId(p3);
}
}//for each face
}//for each tetra
}//if on edge
else if ( onCount == 2 ) //on edge
{
for (i=0; i < 4; i++)
if ( !verts[i] )
boundaryPts.InsertNextId(ptIds[i]);
Mesh->GetCellNeighbors(tetraId, boundaryPts, tetras);
tetras.InsertNextId(tetraId);
//now for the tricky part...find boundary faces. For an edge neighbor,
//boundary face is a face that uses just one of two points defining
//edge.
v1 = boundaryPts.GetId(0);
v2 = boundaryPts.GetId(1);
for (i=0; i < tetras.GetNumberOfIds(); i++)
{
Mesh->GetCellPoints(tetras.GetId(i),npts,tetraPts);
for (j=0; j<4; j++)
{
p1 = tetraPts[j];
p2 = tetraPts[(j+1)%4];
p3 = tetraPts[(j+2)%4];
if ( ! ((p1 == v1 || p2 == v1 || p3 == v1) &&
(p1 == v2 || p2 == v2 || p3 == v2)) )
{
faces.InsertNextId(p1);
faces.InsertNextId(p2);
faces.InsertNextId(p3);
}
}//for each facce
}//for each tetra
}//if on edge
else //on vertex - shouldn't happen, but hey, you never know!
{
NumberOfDuplicatePoints++;
return 0;
}
}//if non-degenerate tetra
}//inside tetra
// Okay, let's delete the cell and prepare the data structure
for (i=0; i < tetras.GetNumberOfIds(); i++)
{
tetraId = tetras.GetId(i);
Mesh->GetCellPoints(tetraId, npts, tetraPts);
for (j=0; j<4; j++)
{
Mesh->RemoveReferenceToCell(tetraPts[j],tetraId);
}
}
return (faces.GetNumberOfIds() / 3);
}
// 3D Delaunay triangulation. Steps are as follows:
// 1. For each point
// 2. Find triangle point is in
......@@ -225,6 +367,7 @@ static void CheckFace(int ptId, float x[3], int p1, int p2, int p3, int tetra,
void vtkDelaunay3D::Execute()
{
int numPoints, numTetras, i;
int tetraNum, numFaces, tetraId;
int ptId, tetra[4];
vtkPoints *inPoints;
vtkFloatPoints *points;
......@@ -232,8 +375,8 @@ void vtkDelaunay3D::Execute()
vtkPointSet *input=(vtkPointSet *)this->Input;
vtkUnstructuredGrid *output=(vtkUnstructuredGrid *)this->Output;
float x[3];
int nodes[4][4], pts[4], npts, *tetraPts;
vtkIdList neighbors(2), cells(64);
int nodes[4], pts[4], npts, *tetraPts;
vtkIdList neighbors(2), cells(64), tetras(5), faces(15);
float center[3], length, tol;
vtkMath math;
char *tetraUse;
......@@ -318,46 +461,49 @@ void vtkDelaunay3D::Execute()
Mesh->SetPoints(points);
Mesh->BuildLinks();
//
// For each point; find tetra containing point. Then evaluate four
// neighboring tetras for Delaunay criterion. Tetras that do not
// satisfy criterion have their faces swapped. This continues recursively
// until all tetras have been shown to be Delaunay.
// For each point; find faces containing point. (Faces are found by deleting
// one or more tetrahedra "containing" point. More than one tetra may contain
// a point if the point is on an edge or face.) For each face, create a
// tetrahedron, and then check for "face swapping" to satisfy Delaunay
// criterion.
//
for (ptId=0; ptId < numPoints; ptId++)
// for (ptId=0; ptId < numPoints; ptId++)
for (ptId=0; ptId < 1; ptId++)
{
points->GetPoint(ptId,x);
if ( (tetra[0] = FindTetra(x,pts,tetra[1],Mesh,points,tol)) >= 0 )
if ( (numFaces=FindEnclosingFaces(x,tetra[1],Mesh,
points,this->Tolerance,tetras,faces)) > 0 )
{
//delete this tetra; create four new tetras
//first tetra is replaced with one of the new ones
nodes[0][0] = ptId; nodes[0][1] = pts[0];
nodes[0][2] = pts[1]; nodes[0][3] = pts[2];
Mesh->RemoveReferenceToCell(pts[3], tetra[0]);
Mesh->ReplaceCell(tetra[0], 4, nodes[0]);
Mesh->ResizeCellList(ptId,1);
Mesh->AddReferenceToCell(ptId,tetra[0]);
//create three new tetras
nodes[1][0] = ptId; nodes[1][1] = pts[1];
nodes[1][2] = pts[2]; nodes[1][3] = pts[3];
tetra[1] = Mesh->InsertNextLinkedCell(VTK_TETRA, 4, nodes[1]);
nodes[2][0] = ptId; nodes[2][1] = pts[2];
nodes[2][2] = pts[3]; nodes[2][3] = pts[0];
tetra[2] = Mesh->InsertNextLinkedCell(VTK_TETRA, 4, nodes[2]);
nodes[3][0] = ptId; nodes[3][1] = pts[3];
nodes[3][2] = pts[0]; nodes[3][3] = pts[1];
tetra[3] = Mesh->InsertNextLinkedCell(VTK_TETRA, 4, nodes[3]);
// Check face neighbors for Delaunay criterion. If not satisfied,
// "swap" face. (This is done recursively.)
CheckFace(ptId, x, pts[0], pts[1], pts[2], tetra[0], Mesh, points);
CheckFace(ptId, x, pts[1], pts[2], pts[3], tetra[1], Mesh, points);
CheckFace(ptId, x, pts[2], pts[3], pts[0], tetra[2], Mesh, points);
CheckFace(ptId, x, pts[3], pts[0], pts[1], tetra[3], Mesh, points);
}//if triangle found
for (tetraNum=0; tetraNum < numFaces; tetraNum++)
{
//create tetrahedron
nodes[0] = ptId;
nodes[1] = faces.GetId(3*tetraNum);
nodes[2] = faces.GetId(3*tetraNum+1);
nodes[3] = faces.GetId(3*tetraNum+2);
//either replace previously deleted tetra or create new one
if ( tetraNum < tetras.GetNumberOfIds() )
{
tetraId = tetras.GetId(tetraNum);
Mesh->ReplaceCell(tetraId, 4, nodes);
for (i=0; i < 4; i++)
{
Mesh->ResizeCellList(nodes[i],1);
Mesh->AddReferenceToCell(nodes[i],tetraId);
}
}
else
{
tetraId = Mesh->InsertNextLinkedCell(VTK_TETRA, 4, nodes);
}
// Check face neighbors for Delaunay criterion. If not satisfied,
// "swap" face. (This is done recursively.)
// CheckFace(ptId, x, nodes[1], nodes[2], nodes[3], tetraId, Mesh,points);
}//for each face
}//if enclosing faces found
}//for all points
vtkDebugMacro(<<"Triangulated " << numPoints <<" points, "
......
......@@ -71,6 +71,10 @@ void vtkGlrProperty::Render(vtkProperty *prop, vtkGlrRenderer *ren)
// unbind any textures for starters
texbind(TX_TEXTURE_0,0);
// turn on/off culling of surface primitives
backface(prop->GetBackfaceCulling() ? TRUE : FALSE);
frontface(prop->GetFrontfaceCulling() ? TRUE : FALSE);
lmcolor (LMC_NULL);
mat[1] = prop->GetOpacity();
mat[15] = prop->GetSpecularPower();
......
......@@ -53,11 +53,6 @@ MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#define MAX_LIGHTS 8
static float amb_light_info[] = {
AMBIENT, 0.2, 0.2, 0.2,
LMNULL
};
vtkGlrRenderer::vtkGlrRenderer()
{
}
......@@ -101,24 +96,34 @@ int vtkGlrRenderer::UpdateCameras ()
// into graphics pipeline.
void vtkGlrRenderer::ClearLights (void)
{
short cur_light;
short curLight;
static float lightInfo[] = {AMBIENT, 0.2, 0.2, 0.2, LMNULL};
static float twoSidedLightInfo[] = {AMBIENT, 0.2, 0.2, 0.2,
TWOSIDE, 1.0, LMNULL};
// define a lighting model and set up the ambient light.
// use index 11 for the heck of it. Doesn't matter except for 0.
// update the ambient light
amb_light_info[1] = this->Ambient[0];
amb_light_info[2] = this->Ambient[1];
amb_light_info[3] = this->Ambient[2];
lmdef(DEFLMODEL, 11, 0, amb_light_info);
if ( this->TwoSidedLighting )
{
twoSidedLightInfo[1] = this->Ambient[0];
twoSidedLightInfo[2] = this->Ambient[1];
twoSidedLightInfo[3] = this->Ambient[2];
lmdef(DEFLMODEL, 11, 0, twoSidedLightInfo);
}
else
{
lightInfo[1] = this->Ambient[0];
lightInfo[2] = this->Ambient[1];
lightInfo[3] = this->Ambient[2];
lmdef(DEFLMODEL, 11, 0, lightInfo);
}
lmbind(LMODEL, 11);
// now delete all the old lights
for (cur_light = LIGHT0;
cur_light < LIGHT0 + MAX_LIGHTS; cur_light++)
for (curLight = LIGHT0; curLight < LIGHT0 + MAX_LIGHTS; curLight++)
{
lmbind(cur_light,0);
lmbind(curLight,0);
}
this->NumberOfLightsBound = 0;
......@@ -129,11 +134,11 @@ void vtkGlrRenderer::ClearLights (void)
int vtkGlrRenderer::UpdateLights ()
{
vtkLight *light;
short cur_light;
short curLight;
float status;
int count = 0;
cur_light= this->NumberOfLightsBound + LIGHT0;
curLight= this->NumberOfLightsBound + LIGHT0;
// set the matrix mode for lighting. ident matrix on viewing stack
mmode(MVIEWING);
......@@ -146,17 +151,17 @@ int vtkGlrRenderer::UpdateLights ()
// if the light is on then define it and bind it.
// also make sure we still have room.
if ((status > 0.0)&& (cur_light < (LIGHT0+MAX_LIGHTS)))
if ((status > 0.0)&& (curLight < (LIGHT0+MAX_LIGHTS)))
{
light->Render((vtkRenderer *)this,cur_light);
lmbind(cur_light, cur_light);
light->Render((vtkRenderer *)this,curLight);
lmbind(curLight, curLight);
// increment the current light by one
cur_light++;
curLight++;
count++;
}
}
this->NumberOfLightsBound = cur_light - LIGHT0;
this->NumberOfLightsBound = curLight - LIGHT0;
popmatrix();
return count;
......
......@@ -3,8 +3,8 @@
Program: Visualization Library
Module: vtkHyperStreamline.cc
Language: C++
Date: $Date$
Version: $Revision$
Date: 06 Nov 1995
Version: 1.16
Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.
......@@ -643,7 +643,9 @@ void vtkHyperStreamline::BuildTube()
newStrips->InsertNextCell(npts*2);
for (i=0; i < npts; i++)
{
i2 = i*this->NumberOfSides;
//make sure strip definition consistent with normals
if (this->Streamers[ptId].Direction > 0.0) i2 = i*this->NumberOfSides;
else i2 = (npts - i - 1) * this->NumberOfSides;
newStrips->InsertCellPoint(ptOffset+i2+k);
newStrips->InsertCellPoint(ptOffset+i2+i1);
}
......
......@@ -65,14 +65,30 @@ void vtkOglrProperty::Render(vtkProperty *prop, vtkOglrRenderer *ren)
glDisable(GL_TEXTURE_2D);
glDisable(GL_COLOR_MATERIAL);
Face = GL_FRONT_AND_BACK;
// turn on/off backface culling
if ( ! prop->GetBackfaceCulling() && ! prop->GetFrontfaceCulling() )
{
glDisable (GL_CULL_FACE);
}
else if ( prop->GetBackfaceCulling() )
{
glCullFace (GL_BACK);
glEnable (GL_CULL_FACE);
}
else //if both front & back culling on, will fall into backface culling
{ //if you really want both front and back, use the Actor's visibility flag
glCullFace (GL_FRONT);
glEnable (GL_CULL_FACE);
}
Info[3] = prop->GetOpacity();
// deal with blending if necc
if (Info[3] < 1.0)
{
glEnable( GL_BLEND);
glEnable(GL_BLEND);
}
else
{
......
......@@ -482,7 +482,6 @@ void vtkOglrRenderWindow::WindowInitialize (void)
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glEnable( GL_NORMALIZE );
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
glAlphaFunc(GL_GREATER,0);
this->Mapped = 1;
......
......@@ -101,7 +101,7 @@ int vtkOglrRenderer::UpdateCameras ()
// into graphics pipeline.
void vtkOglrRenderer::ClearLights (void)
{
short cur_light;
short curLight;
float Info[4];
// define a lighting model and set up the ambient light.
......@@ -112,15 +112,22 @@ void vtkOglrRenderer::ClearLights (void)
Info[1] = this->Ambient[1];
Info[2] = this->Ambient[2];
Info[3] = 1.0;
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, Info);
// now delete all the old lights
for (cur_light = GL_LIGHT0;
cur_light < GL_LIGHT0 + MAX_LIGHTS; cur_light++)
if ( this->TwoSidedLighting )
{
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
}
else
{
glDisable((GLenum)cur_light);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
}
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, Info);
// now delete all the old lights
for (curLight = GL_LIGHT0; curLight < GL_LIGHT0 + MAX_LIGHTS; curLight++)
{
glDisable((GLenum)curLight);
}
this->NumberOfLightsBound = 0;
}
......@@ -130,11 +137,11 @@ void vtkOglrRenderer::ClearLights (void)
int vtkOglrRenderer::UpdateLights ()
{
vtkLight *light;
short cur_light;
short curLight;
float status;
int count = 0;
cur_light= this->NumberOfLightsBound + GL_LIGHT0;
curLight= this->NumberOfLightsBound + GL_LIGHT0;
// set the matrix mode for lighting. ident matrix on viewing stack
glMatrixMode(GL_MODELVIEW);
......@@ -148,17 +155,17 @@ int vtkOglrRenderer::UpdateLights ()
// if the light is on then define it and bind it.
// also make sure we still have room.
if ((status > 0.0)&& (cur_light < (GL_LIGHT0+MAX_LIGHTS)))
if ((status > 0.0)&& (curLight < (GL_LIGHT0+MAX_LIGHTS)))
{
light->Render((vtkRenderer *)this,cur_light);
glEnable((GLenum)cur_light);
light->Render((vtkRenderer *)this,curLight);
glEnable((GLenum)curLight);
// increment the current light by one
cur_light++;
curLight++;
count++;
}
}
this->NumberOfLightsBound = cur_light - GL_LIGHT0;
this->NumberOfLightsBound = curLight - GL_LIGHT0;
glPopMatrix();
glEnable(GL_LIGHTING);
......
......@@ -3,8 +3,8 @@
Program: Visualization Toolkit
Module: vtkPolygon.cc
Language: C++
Date: $Date$
Version: $Revision$
Date: 11/01/95
Version: 1.31
Copyright (c) 1993-1995 Ken Martin, Will Schroeder, Bill Lorensen.
......@@ -74,23 +74,25 @@ vtkPolygon::vtkPolygon(const vtkPolygon& p)
// that index into the points list.
void vtkPolygon::ComputeNormal(vtkPoints *p, int numPts, int *pts, float *n)
{
int i;
float *v1, *v2, *v3;
float length;
float ax, ay, az;
float bx, by, bz;
int i;
float v1[3], v2[3], v3[3];
float length;
float ax, ay, az;
float bx, by, bz;
//
// Because some polygon vertices are colinear, need to make sure
// first non-zero normal is found.
//
v1 = p->GetPoint(pts[0]);
v2 = p->GetPoint(pts[1]);
v3 = p->GetPoint(pts[2]);