123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547 |
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Contains a handy indexed triangle class.
- * \file IceIndexedTriangle.cpp
- * \author Pierre Terdiman
- * \date January, 17, 2000
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- #include "../Opcode.h"
- using namespace IceMaths;
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Contains an indexed triangle class.
- *
- * \class Triangle
- * \author Pierre Terdiman
- * \version 1.0
- * \date 08.15.98
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Flips the winding order.
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void IndexedTriangle::Flip()
- {
- Swap(mVRef[1], mVRef[2]);
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Computes the triangle area.
- * \param verts [in] the list of indexed vertices
- * \return the area
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- float IndexedTriangle::Area(const Point* verts) const
- {
- if(!verts) return 0.0f;
- const Point& p0 = verts[0];
- const Point& p1 = verts[1];
- const Point& p2 = verts[2];
- return ((p0-p1)^(p0-p2)).Magnitude() * 0.5f;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Computes the triangle perimeter.
- * \param verts [in] the list of indexed vertices
- * \return the perimeter
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- float IndexedTriangle::Perimeter(const Point* verts) const
- {
- if(!verts) return 0.0f;
- const Point& p0 = verts[0];
- const Point& p1 = verts[1];
- const Point& p2 = verts[2];
- return p0.Distance(p1)
- + p0.Distance(p2)
- + p1.Distance(p2);
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Computes the triangle compacity.
- * \param verts [in] the list of indexed vertices
- * \return the compacity
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- float IndexedTriangle::Compacity(const Point* verts) const
- {
- if(!verts) return 0.0f;
- float P = Perimeter(verts);
- if(P==0.0f) return 0.0f;
- return (4.0f*PI*Area(verts)/(P*P));
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Computes the triangle normal.
- * \param verts [in] the list of indexed vertices
- * \param normal [out] the computed normal
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void IndexedTriangle::Normal(const Point* verts, Point& normal) const
- {
- if(!verts) return;
- const Point& p0 = verts[mVRef[0]];
- const Point& p1 = verts[mVRef[1]];
- const Point& p2 = verts[mVRef[2]];
- normal = ((p2-p1)^(p0-p1)).Normalize();
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Computes the triangle denormalized normal.
- * \param verts [in] the list of indexed vertices
- * \param normal [out] the computed normal
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void IndexedTriangle::DenormalizedNormal(const Point* verts, Point& normal) const
- {
- if(!verts) return;
- const Point& p0 = verts[mVRef[0]];
- const Point& p1 = verts[mVRef[1]];
- const Point& p2 = verts[mVRef[2]];
- normal = ((p2-p1)^(p0-p1));
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Computes the triangle center.
- * \param verts [in] the list of indexed vertices
- * \param center [out] the computed center
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void IndexedTriangle::Center(const Point* verts, Point& center) const
- {
- if(!verts) return;
- const Point& p0 = verts[mVRef[0]];
- const Point& p1 = verts[mVRef[1]];
- const Point& p2 = verts[mVRef[2]];
- center = (p0+p1+p2)*INV3;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Computes the centered normal
- * \param verts [in] the list of indexed vertices
- * \param normal [out] the computed centered normal
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void IndexedTriangle::CenteredNormal(const Point* verts, Point& normal) const
- {
- if(!verts) return;
- const Point& p0 = verts[mVRef[0]];
- const Point& p1 = verts[mVRef[1]];
- const Point& p2 = verts[mVRef[2]];
- Point Center = (p0+p1+p2)*INV3;
- normal = Center + ((p2-p1)^(p0-p1)).Normalize();
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Computes a random point within the triangle.
- * \param verts [in] the list of indexed vertices
- * \param normal [out] the computed centered normal
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void IndexedTriangle::RandomPoint(const Point* verts, Point& random) const
- {
- if(!verts) return;
- // Random barycentric coords
- float Alpha = UnitRandomFloat();
- float Beta = UnitRandomFloat();
- float Gamma = UnitRandomFloat();
- float OneOverTotal = 1.0f / (Alpha + Beta + Gamma);
- Alpha *= OneOverTotal;
- Beta *= OneOverTotal;
- Gamma *= OneOverTotal;
- const Point& p0 = verts[mVRef[0]];
- const Point& p1 = verts[mVRef[1]];
- const Point& p2 = verts[mVRef[2]];
- random = Alpha*p0 + Beta*p1 + Gamma*p2;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Computes backface culling.
- * \param verts [in] the list of indexed vertices
- * \param source [in] source point (in local space) from which culling must be computed
- * \return true if the triangle is visible from the source point
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- bool IndexedTriangle::IsVisible(const Point* verts, const Point& source) const
- {
- // Checkings
- if(!verts) return false;
- const Point& p0 = verts[mVRef[0]];
- const Point& p1 = verts[mVRef[1]];
- const Point& p2 = verts[mVRef[2]];
- // Compute denormalized normal
- Point Normal = (p2 - p1)^(p0 - p1);
- // Backface culling
- return (Normal | source) >= 0.0f;
- // Same as:
- // Plane PL(verts[mVRef[0]], verts[mVRef[1]], verts[mVRef[2]]);
- // return PL.Distance(source) > PL.d;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Computes backface culling.
- * \param verts [in] the list of indexed vertices
- * \param source [in] source point (in local space) from which culling must be computed
- * \return true if the triangle is visible from the source point
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- bool IndexedTriangle::BackfaceCulling(const Point* verts, const Point& source) const
- {
- // Checkings
- if(!verts) return false;
- const Point& p0 = verts[mVRef[0]];
- const Point& p1 = verts[mVRef[1]];
- const Point& p2 = verts[mVRef[2]];
- // Compute base
- // Point Base = (p0 + p1 + p2)*INV3;
- // Compute denormalized normal
- Point Normal = (p2 - p1)^(p0 - p1);
- // Backface culling
- // return (Normal | (source - Base)) >= 0.0f;
- return (Normal | (source - p0)) >= 0.0f;
- // Same as: (but a bit faster)
- // Plane PL(verts[mVRef[0]], verts[mVRef[1]], verts[mVRef[2]]);
- // return PL.Distance(source)>0.0f;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Computes the occlusion potential of the triangle.
- * \param verts [in] the list of indexed vertices
- * \param source [in] source point (in local space) from which occlusion potential must be computed
- * \return the occlusion potential
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- float IndexedTriangle::ComputeOcclusionPotential(const Point* verts, const Point& view) const
- {
- if(!verts) return 0.0f;
- // Occlusion potential: -(A * (N|V) / d^2)
- // A = polygon area
- // N = polygon normal
- // V = view vector
- // d = distance viewpoint-center of polygon
- float A = Area(verts);
- Point N; Normal(verts, N);
- Point C; Center(verts, C);
- float d = view.Distance(C);
- return -(A*(N|view))/(d*d);
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Replaces a vertex reference with another one.
- * \param oldref [in] the vertex reference to replace
- * \param newref [in] the new vertex reference
- * \return true if success, else false if the input vertex reference doesn't belong to the triangle
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- bool IndexedTriangle::ReplaceVertex(udword oldref, udword newref)
- {
- if(mVRef[0]==oldref) { mVRef[0] = newref; return true; }
- else if(mVRef[1]==oldref) { mVRef[1] = newref; return true; }
- else if(mVRef[2]==oldref) { mVRef[2] = newref; return true; }
- return false;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Checks whether the triangle is degenerate or not. A degenerate triangle has two common vertex references. This is a zero-area triangle.
- * \return true if the triangle is degenerate
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- bool IndexedTriangle::IsDegenerate() const
- {
- if(mVRef[0]==mVRef[1]) return true;
- if(mVRef[1]==mVRef[2]) return true;
- if(mVRef[2]==mVRef[0]) return true;
- return false;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Checks whether the input vertex reference belongs to the triangle or not.
- * \param ref [in] the vertex reference to look for
- * \return true if the triangle contains the vertex reference
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- bool IndexedTriangle::HasVertex(udword ref) const
- {
- if(mVRef[0]==ref) return true;
- if(mVRef[1]==ref) return true;
- if(mVRef[2]==ref) return true;
- return false;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Checks whether the input vertex reference belongs to the triangle or not.
- * \param ref [in] the vertex reference to look for
- * \param index [out] the corresponding index in the triangle
- * \return true if the triangle contains the vertex reference
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- bool IndexedTriangle::HasVertex(udword ref, udword* index) const
- {
- if(mVRef[0]==ref) { *index = 0; return true; }
- if(mVRef[1]==ref) { *index = 1; return true; }
- if(mVRef[2]==ref) { *index = 2; return true; }
- return false;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Finds an edge in a tri, given two vertex references.
- * \param vref0 [in] the edge's first vertex reference
- * \param vref1 [in] the edge's second vertex reference
- * \return the edge number between 0 and 2, or 0xff if input refs are wrong.
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ubyte IndexedTriangle::FindEdge(udword vref0, udword vref1) const
- {
- if(mVRef[0]==vref0 && mVRef[1]==vref1) return 0;
- else if(mVRef[0]==vref1 && mVRef[1]==vref0) return 0;
- else if(mVRef[0]==vref0 && mVRef[2]==vref1) return 1;
- else if(mVRef[0]==vref1 && mVRef[2]==vref0) return 1;
- else if(mVRef[1]==vref0 && mVRef[2]==vref1) return 2;
- else if(mVRef[1]==vref1 && mVRef[2]==vref0) return 2;
- return 0xff;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Gets the last reference given the first two.
- * \param vref0 [in] the first vertex reference
- * \param vref1 [in] the second vertex reference
- * \return the last reference, or INVALID_ID_OPC if input refs are wrong.
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- udword IndexedTriangle::OppositeVertex(udword vref0, udword vref1) const
- {
- if(mVRef[0]==vref0 && mVRef[1]==vref1) return mVRef[2];
- else if(mVRef[0]==vref1 && mVRef[1]==vref0) return mVRef[2];
- else if(mVRef[0]==vref0 && mVRef[2]==vref1) return mVRef[1];
- else if(mVRef[0]==vref1 && mVRef[2]==vref0) return mVRef[1];
- else if(mVRef[1]==vref0 && mVRef[2]==vref1) return mVRef[0];
- else if(mVRef[1]==vref1 && mVRef[2]==vref0) return mVRef[0];
- return INVALID_ID_OPC;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Gets the three sorted vertex references according to an edge number.
- * edgenb = 0 => edge 0-1, returns references 0, 1, 2
- * edgenb = 1 => edge 0-2, returns references 0, 2, 1
- * edgenb = 2 => edge 1-2, returns references 1, 2, 0
- *
- * \param edgenb [in] the edge number, 0, 1 or 2
- * \param vref0 [out] the returned first vertex reference
- * \param vref1 [out] the returned second vertex reference
- * \param vref2 [out] the returned third vertex reference
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void IndexedTriangle::GetVRefs(ubyte edgenb, udword& vref0, udword& vref1, udword& vref2) const
- {
- if(edgenb==0)
- {
- vref0 = mVRef[0];
- vref1 = mVRef[1];
- vref2 = mVRef[2];
- }
- else if(edgenb==1)
- {
- vref0 = mVRef[0];
- vref1 = mVRef[2];
- vref2 = mVRef[1];
- }
- else if(edgenb==2)
- {
- vref0 = mVRef[1];
- vref1 = mVRef[2];
- vref2 = mVRef[0];
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Computes the triangle's smallest edge length.
- * \param verts [in] the list of indexed vertices
- * \return the smallest edge length
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- float IndexedTriangle::MinEdgeLength(const Point* verts) const
- {
- if(!verts) return 0.0f;
- float Min = MAX_FLOAT;
- float Length01 = verts[0].Distance(verts[1]);
- float Length02 = verts[0].Distance(verts[2]);
- float Length12 = verts[1].Distance(verts[2]);
- if(Length01 < Min) Min = Length01;
- if(Length02 < Min) Min = Length02;
- if(Length12 < Min) Min = Length12;
- return Min;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Computes the triangle's largest edge length.
- * \param verts [in] the list of indexed vertices
- * \return the largest edge length
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- float IndexedTriangle::MaxEdgeLength(const Point* verts) const
- {
- if(!verts) return 0.0f;
- float Max = MIN_FLOAT;
- float Length01 = verts[0].Distance(verts[1]);
- float Length02 = verts[0].Distance(verts[2]);
- float Length12 = verts[1].Distance(verts[2]);
- if(Length01 > Max) Max = Length01;
- if(Length02 > Max) Max = Length02;
- if(Length12 > Max) Max = Length12;
- return Max;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Computes a point on the triangle according to the stabbing information.
- * \param verts [in] the list of indexed vertices
- * \param u,v [in] point's barycentric coordinates
- * \param pt [out] point on triangle
- * \param nearvtx [out] index of nearest vertex
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void IndexedTriangle::ComputePoint(const Point* verts, float u, float v, Point& pt, udword* nearvtx) const
- {
- // Checkings
- if(!verts) return;
- // Get face in local or global space
- const Point& p0 = verts[mVRef[0]];
- const Point& p1 = verts[mVRef[1]];
- const Point& p2 = verts[mVRef[2]];
- // Compute point coordinates
- pt = (1.0f - u - v)*p0 + u*p1 + v*p2;
- // Compute nearest vertex if needed
- if(nearvtx)
- {
- // Compute distance vector
- Point d(p0.SquareDistance(pt), // Distance^2 from vertex 0 to point on the face
- p1.SquareDistance(pt), // Distance^2 from vertex 1 to point on the face
- p2.SquareDistance(pt)); // Distance^2 from vertex 2 to point on the face
- // Get smallest distance
- *nearvtx = mVRef[d.SmallestAxis()];
- }
- }
- //**************************************
- // Angle between two vectors (in radians)
- // we use this formula
- // uv = |u||v| cos(u,v)
- // u ^ v = w
- // |w| = |u||v| |sin(u,v)|
- //**************************************
- float Angle(const Point& u, const Point& v)
- {
- float NormU = u.Magnitude(); // |u|
- float NormV = v.Magnitude(); // |v|
- float Product = NormU*NormV; // |u||v|
- if(Product==0.0f) return 0.0f;
- float OneOverProduct = 1.0f / Product;
- // Cosinus
- float Cosinus = (u|v) * OneOverProduct;
- // Sinus
- Point w = u^v;
- float NormW = w.Magnitude();
- float AbsSinus = NormW * OneOverProduct;
- // Remove degeneracy
- if(AbsSinus > 1.0f) AbsSinus = 1.0f;
- if(AbsSinus < -1.0f) AbsSinus = -1.0f;
- if(Cosinus>=0.0f) return asinf(AbsSinus);
- else return (PI-asinf(AbsSinus));
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Computes the angle between two triangles.
- * \param tri [in] the other triangle
- * \param verts [in] the list of indexed vertices
- * \return the angle in radians
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- float IndexedTriangle::Angle(const IndexedTriangle& tri, const Point* verts) const
- {
- // Checkings
- if(!verts) return 0.0f;
- // Compute face normals
- Point n0, n1;
- Normal(verts, n0);
- tri.Normal(verts, n1);
- // Compute angle
- float dp = n0|n1;
- if(dp>1.0f) return 0.0f;
- if(dp<-1.0f) return PI;
- return acosf(dp);
- // return ::Angle(n0,n1);
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Checks a triangle is the same as another one.
- * \param tri [in] the other triangle
- * \return true if same triangle
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- bool IndexedTriangle::Equal(const IndexedTriangle& tri) const
- {
- // Test all vertex references
- return (HasVertex(tri.mVRef[0]) &&
- HasVertex(tri.mVRef[1]) &&
- HasVertex(tri.mVRef[2]));
- }
|