Commit 23949554 authored by hybrid's avatar hybrid

Added angleweighted and smoothed generation of tangent space, by ryanclark.

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@1391 dfc29bdd-3216-0410-991c-e03cc46cb475
parent 9646ed09
...@@ -93,11 +93,13 @@ namespace scene ...@@ -93,11 +93,13 @@ namespace scene
mapped geometry because it calculates the tangent and binormal mapped geometry because it calculates the tangent and binormal
data which is needed there. data which is needed there.
\param mesh Input mesh \param mesh Input mesh
\param smooth The normals are smoothed across the meshbuffer's faces if this flag is set.
\param angleWeighted Improved smoothing calculation used
\return Mesh consisting only of S3DVertexTangents vertices. If \return Mesh consisting only of S3DVertexTangents vertices. If
you no longer need the cloned mesh, you should call you no longer need the cloned mesh, you should call
IMesh::drop(). See IReferenceCounted::drop() for more IMesh::drop(). See IReferenceCounted::drop() for more
information. */ information. */
virtual IMesh* createMeshWithTangents(IMesh* mesh) const = 0; virtual IMesh* createMeshWithTangents(IMesh* mesh, bool smooth=false, bool angleWeighted=false) const = 0;
//! Creates a copy of the mesh, which will only consist of S3DVertex2TCoord vertices. //! Creates a copy of the mesh, which will only consist of S3DVertex2TCoord vertices.
/** \param mesh Input mesh /** \param mesh Input mesh
......
...@@ -57,6 +57,27 @@ inline void makePlanarMappingT(VERTEXTYPE *v, ...@@ -57,6 +57,27 @@ inline void makePlanarMappingT(VERTEXTYPE *v,
} }
static inline core::vector3df getAngleWeight(const core::vector3df& v1,
const core::vector3df& v2,
const core::vector3df& v3)
{
// Calculate this triangle's weight for each of its three vertices
// start by calculating the lengths of its sides
const f32 a = v2.getDistanceFromSQ(v3);
const f32 asqrt = sqrtf(a);
const f32 b = v1.getDistanceFromSQ(v3);
const f32 bsqrt = sqrtf(b);
const f32 c = v1.getDistanceFromSQ(v2);
const f32 csqrt = sqrtf(c);
// use them to find the angle at each vertex
return core::vector3df(
acosf((b + c - a) / (2.f * bsqrt * csqrt)),
acosf((-b + c + a) / (2.f * asqrt * csqrt)),
acosf((b - c + a) / (2.f * bsqrt * asqrt)));
}
//! Flips the direction of surfaces. Changes backfacing triangles to frontfacing //! Flips the direction of surfaces. Changes backfacing triangles to frontfacing
//! triangles and vice versa. //! triangles and vice versa.
//! \param mesh: Mesh on which the operation is performed. //! \param mesh: Mesh on which the operation is performed.
...@@ -203,24 +224,10 @@ void CMeshManipulator::recalculateNormals(IMeshBuffer* buffer, bool smooth, bool ...@@ -203,24 +224,10 @@ void CMeshManipulator::recalculateNormals(IMeshBuffer* buffer, bool smooth, bool
const core::vector3df& v2 = buffer->getPosition(idx[i+1]); const core::vector3df& v2 = buffer->getPosition(idx[i+1]);
const core::vector3df& v3 = buffer->getPosition(idx[i+2]); const core::vector3df& v3 = buffer->getPosition(idx[i+2]);
core::vector3df normal = core::plane3d<f32>(v1, v2, v3).Normal; core::vector3df normal = core::plane3d<f32>(v1, v2, v3).Normal;
if (angleWeighted) if (angleWeighted)
{ normal *= getAngleWeight(v1,v2,v3);
// Calculate this triangle's weight for each of its three vertices
// start by calculating the lengths of its sides
const f32 a = v2.getDistanceFromSQ(v3);
const f32 asqrt = sqrtf(a);
const f32 b = v1.getDistanceFromSQ(v3);
const f32 bsqrt = sqrtf(b);
const f32 c = v1.getDistanceFromSQ(v2);
const f32 csqrt = sqrtf(c);
// use them to find the angle at each vertex
const core::vector3df weight(
acosf((b + c - a) / (2.f * bsqrt * csqrt)),
acosf((-b + c + a) / (2.f * asqrt * csqrt)),
acosf((b - c + a) / (2.f * bsqrt * asqrt)));
normal *= weight;
}
buffer->getNormal(idx[i+0]) += normal; buffer->getNormal(idx[i+0]) += normal;
buffer->getNormal(idx[i+1]) += normal; buffer->getNormal(idx[i+1]) += normal;
buffer->getNormal(idx[i+2]) += normal; buffer->getNormal(idx[i+2]) += normal;
...@@ -744,7 +751,7 @@ IMesh* CMeshManipulator::createMeshWelded(IMesh *mesh, f32 tolerance) const ...@@ -744,7 +751,7 @@ IMesh* CMeshManipulator::createMeshWelded(IMesh *mesh, f32 tolerance) const
//! Creates a copy of the mesh, which will only consist of S3DVertexTangents vertices. //! Creates a copy of the mesh, which will only consist of S3DVertexTangents vertices.
IMesh* CMeshManipulator::createMeshWithTangents(IMesh* mesh) const IMesh* CMeshManipulator::createMeshWithTangents(IMesh* mesh, bool smooth, bool angleWeighted) const
{ {
if (!mesh) if (!mesh)
return 0; return 0;
...@@ -817,13 +824,103 @@ IMesh* CMeshManipulator::createMeshWithTangents(IMesh* mesh) const ...@@ -817,13 +824,103 @@ IMesh* CMeshManipulator::createMeshWithTangents(IMesh* mesh) const
// now calculate tangents // now calculate tangents
for (b=0; b<meshBufferCount; ++b) for (b=0; b<meshBufferCount; ++b)
{ {
const s32 idxCnt = clone->getMeshBuffer(b)->getIndexCount(); const u32 vtxCnt = mesh->getMeshBuffer(b)->getVertexCount();
const u32 idxCnt = clone->getMeshBuffer(b)->getIndexCount();
u16* idx = clone->getMeshBuffer(b)->getIndices(); u16* idx = clone->getMeshBuffer(b)->getIndices();
video::S3DVertexTangents* v = video::S3DVertexTangents* v =
(video::S3DVertexTangents*)clone->getMeshBuffer(b)->getVertices(); (video::S3DVertexTangents*)clone->getMeshBuffer(b)->getVertices();
for (s32 i=0; i<idxCnt; i+=3) if (smooth)
{
u32 i;
for ( i = 0; i!= vtxCnt; ++i )
{
v[i].Normal.set( 0.f, 0.f, 0.f );
v[i].Tangent.set( 0.f, 0.f, 0.f );
v[i].Binormal.set( 0.f, 0.f, 0.f );
}
//Each vertex gets the sum of the tangents and binormals from the faces around it
for ( i=0; i<idxCnt; i+=3)
{
// if this triangle is degenerate, skip it!
if (v[idx[i+0]].Pos == v[idx[i+1]].Pos ||
v[idx[i+0]].Pos == v[idx[i+2]].Pos ||
v[idx[i+1]].Pos == v[idx[i+2]].Pos
/*||
v[idx[i+0]].TCoords == v[idx[i+1]].TCoords ||
v[idx[i+0]].TCoords == v[idx[i+2]].TCoords ||
v[idx[i+1]].TCoords == v[idx[i+2]].TCoords */
)
continue;
//Angle-weighted normals look better, but are slightly more CPU intensive to calculate
core::vector3df weight(1.f,1.f,1.f);
if (angleWeighted)
weight = getAngleWeight(v[i+0].Pos,v[i+1].Pos,v[i+2].Pos);
core::vector3df localNormal;
core::vector3df localTangent;
core::vector3df localBinormal;
calculateTangents(
localNormal,
localTangent,
localBinormal,
v[idx[i+0]].Pos,
v[idx[i+1]].Pos,
v[idx[i+2]].Pos,
v[idx[i+0]].TCoords,
v[idx[i+1]].TCoords,
v[idx[i+2]].TCoords);
v[idx[i+0]].Tangent += localTangent * weight.X;
v[idx[i+0]].Binormal += localBinormal * weight.X;
v[idx[i+0]].Normal += localNormal * weight.X;
calculateTangents(
localNormal,
localTangent,
localBinormal,
v[idx[i+1]].Pos,
v[idx[i+2]].Pos,
v[idx[i+0]].Pos,
v[idx[i+1]].TCoords,
v[idx[i+2]].TCoords,
v[idx[i+0]].TCoords);
v[idx[i+1]].Tangent += localTangent * weight.Y;
v[idx[i+1]].Binormal += localBinormal * weight.Y;
v[idx[i+1]].Normal += localNormal * weight.Y;
calculateTangents(
localNormal,
localTangent,
localBinormal,
v[idx[i+2]].Pos,
v[idx[i+0]].Pos,
v[idx[i+1]].Pos,
v[idx[i+2]].TCoords,
v[idx[i+0]].TCoords,
v[idx[i+1]].TCoords);
v[idx[i+2]].Tangent += localTangent * weight.Z;
v[idx[i+2]].Binormal += localBinormal * weight.Z;
v[idx[i+2]].Normal += localNormal * weight.Z;
}
// Normalize the tangents and binormals
for ( i = 0; i!= vtxCnt; ++i )
{
v[i].Tangent.normalize();
v[i].Binormal.normalize();
v[i].Normal.normalize();
}
}
else
{
for (u32 i=0; i<idxCnt; i+=3)
{ {
calculateTangents( calculateTangents(
v[idx[i+0]].Normal, v[idx[i+0]].Normal,
...@@ -859,12 +956,12 @@ IMesh* CMeshManipulator::createMeshWithTangents(IMesh* mesh) const ...@@ -859,12 +956,12 @@ IMesh* CMeshManipulator::createMeshWithTangents(IMesh* mesh) const
v[idx[i+1]].TCoords); v[idx[i+1]].TCoords);
} }
} }
}
return clone; return clone;
} }
//! Creates a copy of the mesh, which will only consist of S3DVertex2TCoords vertices. //! Creates a copy of the mesh, which will only consist of S3DVertex2TCoords vertices.
IMesh* CMeshManipulator::createMeshWith2TCoords(IMesh* mesh) const IMesh* CMeshManipulator::createMeshWith2TCoords(IMesh* mesh) const
{ {
...@@ -879,7 +976,7 @@ IMesh* CMeshManipulator::createMeshWith2TCoords(IMesh* mesh) const ...@@ -879,7 +976,7 @@ IMesh* CMeshManipulator::createMeshWith2TCoords(IMesh* mesh) const
for (b=0; b<meshBufferCount; ++b) for (b=0; b<meshBufferCount; ++b)
{ {
const s32 idxCnt = mesh->getMeshBuffer(b)->getIndexCount(); const u32 idxCnt = mesh->getMeshBuffer(b)->getIndexCount();
const u16* idx = mesh->getMeshBuffer(b)->getIndices(); const u16* idx = mesh->getMeshBuffer(b)->getIndices();
SMeshBufferLightMap* buffer = new SMeshBufferLightMap(); SMeshBufferLightMap* buffer = new SMeshBufferLightMap();
...@@ -895,7 +992,7 @@ IMesh* CMeshManipulator::createMeshWith2TCoords(IMesh* mesh) const ...@@ -895,7 +992,7 @@ IMesh* CMeshManipulator::createMeshWith2TCoords(IMesh* mesh) const
video::S3DVertex* v = video::S3DVertex* v =
(video::S3DVertex*)mesh->getMeshBuffer(b)->getVertices(); (video::S3DVertex*)mesh->getMeshBuffer(b)->getVertices();
for (s32 i=0; i<idxCnt; ++i) for (u32 i=0; i<idxCnt; ++i)
buffer->Vertices.push_back( buffer->Vertices.push_back(
video::S3DVertex2TCoords( video::S3DVertex2TCoords(
v[idx[i]].Pos, v[idx[i]].Color, v[idx[i]].TCoords, v[idx[i]].TCoords)); v[idx[i]].Pos, v[idx[i]].Color, v[idx[i]].TCoords, v[idx[i]].TCoords));
...@@ -906,7 +1003,7 @@ IMesh* CMeshManipulator::createMeshWith2TCoords(IMesh* mesh) const ...@@ -906,7 +1003,7 @@ IMesh* CMeshManipulator::createMeshWith2TCoords(IMesh* mesh) const
video::S3DVertex2TCoords* v = video::S3DVertex2TCoords* v =
(video::S3DVertex2TCoords*)mesh->getMeshBuffer(b)->getVertices(); (video::S3DVertex2TCoords*)mesh->getMeshBuffer(b)->getVertices();
for (s32 i=0; i<idxCnt; ++i) for (u32 i=0; i<idxCnt; ++i)
buffer->Vertices.push_back(v[idx[i]]); buffer->Vertices.push_back(v[idx[i]]);
} }
break; break;
...@@ -915,7 +1012,7 @@ IMesh* CMeshManipulator::createMeshWith2TCoords(IMesh* mesh) const ...@@ -915,7 +1012,7 @@ IMesh* CMeshManipulator::createMeshWith2TCoords(IMesh* mesh) const
video::S3DVertexTangents* v = video::S3DVertexTangents* v =
(video::S3DVertexTangents*)mesh->getMeshBuffer(b)->getVertices(); (video::S3DVertexTangents*)mesh->getMeshBuffer(b)->getVertices();
for (s32 i=0; i<idxCnt; ++i) for (u32 i=0; i<idxCnt; ++i)
buffer->Vertices.push_back(video::S3DVertex2TCoords( buffer->Vertices.push_back(video::S3DVertex2TCoords(
v[idx[i]].Pos, v[idx[i]].Color, v[idx[i]].TCoords, v[idx[i]].TCoords)); v[idx[i]].Pos, v[idx[i]].Color, v[idx[i]].TCoords, v[idx[i]].TCoords));
} }
...@@ -925,7 +1022,7 @@ IMesh* CMeshManipulator::createMeshWith2TCoords(IMesh* mesh) const ...@@ -925,7 +1022,7 @@ IMesh* CMeshManipulator::createMeshWith2TCoords(IMesh* mesh) const
// create new indices // create new indices
buffer->Indices.set_used(idxCnt); buffer->Indices.set_used(idxCnt);
for (s32 i=0; i<idxCnt; ++i) for (u32 i=0; i<idxCnt; ++i)
buffer->Indices[i] = i; buffer->Indices[i] = i;
buffer->setBoundingBox(mesh->getMeshBuffer(b)->getBoundingBox()); buffer->setBoundingBox(mesh->getMeshBuffer(b)->getBoundingBox());
......
...@@ -68,17 +68,15 @@ public: ...@@ -68,17 +68,15 @@ public:
virtual void makePlanarTextureMapping(scene::IMesh* mesh, f32 resolution) const; virtual void makePlanarTextureMapping(scene::IMesh* mesh, f32 resolution) const;
//! Creates a copy of the mesh, which will only consist of S3DVertexTangents vertices. //! Creates a copy of the mesh, which will only consist of S3DVertexTangents vertices.
//! This is useful if you want to draw tangent space normal mapped geometry because virtual IMesh* createMeshWithTangents(IMesh* mesh, bool smooth=false, bool angleWeighted=false) const;
//! it calculates the tangent and binormal data which is needed there.
//! \param mesh: Input mesh //! Creates a copy of the mesh, which will only consist of S3D2TCoords vertices.
//! \return Mesh consiting only of S3DVertexNormalMapped vertices.
//! If you no longer need the cloned mesh, you should call IMesh::drop().
//! See IReferenceCounted::drop() for more information.
virtual IMesh* createMeshWithTangents(IMesh* mesh) const;
virtual IMesh* createMeshWith2TCoords(IMesh* mesh) const; virtual IMesh* createMeshWith2TCoords(IMesh* mesh) const;
//! Creates a copy of the mesh, which will only consist of unique triangles, i.e. no vertices are shared.
virtual IMesh* createMeshUniquePrimitives(IMesh* mesh) const; virtual IMesh* createMeshUniquePrimitives(IMesh* mesh) const;
//! Creates a copy of the mesh, which will have all duplicated vertices removed, i.e. maximal amount of vertices are shared via indexing.
virtual IMesh* createMeshWelded(IMesh *mesh, f32 tolerance=core::ROUNDING_ERROR_32) const; virtual IMesh* createMeshWelded(IMesh *mesh, f32 tolerance=core::ROUNDING_ERROR_32) const;
//! Returns amount of polygons in mesh. //! Returns amount of polygons in mesh.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment