@ -29,9 +29,11 @@
* NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
* /
package com.jme3.util ;
import com.jme3.scene.VertexBuffer ;
import com.jme3.scene.VertexBuffer.Format ;
import com.jme3.scene.VertexBuffer.Usage ;
import java.util.logging.Level ;
import com.jme3.scene.mesh.IndexBuffer ;
import com.jme3.scene.Geometry ;
@ -58,8 +60,7 @@ public class TangentBinormalGenerator {
private static final float ZERO_TOLERANCE = 0 . 0000001f ;
private static final Logger log = Logger . getLogger (
TangentBinormalGenerator . class . getName ( ) ) ;
TangentBinormalGenerator . class . getName ( ) ) ;
private static float toleranceAngle ;
private static float toleranceDot ;
@ -68,17 +69,18 @@ public class TangentBinormalGenerator {
}
private static class VertexData {
public final Vector3f tangent = new Vector3f ( ) ;
public final Vector3f binormal = new Vector3f ( ) ;
public final List < TriangleData > triangles =
new ArrayList < TriangleData > ( ) ;
new ArrayList < TriangleData > ( ) ;
public VertexData ( ) {
}
}
public static class TriangleData {
public final Vector3f tangent ;
public final Vector3f binormal ;
public final Vector3f normal ;
@ -87,9 +89,8 @@ public class TangentBinormalGenerator {
public int index2 ;
public TriangleData ( Vector3f tangent , Vector3f binormal ,
Vector3f normal ,
int index0 , int index1 , int index2 )
{
Vector3f normal ,
int index0 , int index1 , int index2 ) {
this . tangent = tangent ;
this . binormal = binormal ;
this . normal = normal ;
@ -112,13 +113,13 @@ public class TangentBinormalGenerator {
generate ( mesh , true ) ;
}
public static void generate ( Spatial scene ) {
if ( scene instanceof Node ) {
public static void generate ( Spatial scene ) {
if ( scene instanceof Node ) {
Node node = ( Node ) scene ;
for ( Spatial child : node . getChildren ( ) ) {
for ( Spatial child : node . getChildren ( ) ) {
generate ( child ) ;
}
} else {
} else {
Geometry geom = ( Geometry ) scene ;
generate ( geom . getMesh ( ) ) ;
}
@ -133,33 +134,56 @@ public class TangentBinormalGenerator {
t [ i ] = new Vector2f ( ) ;
}
if ( mesh . getBuffer ( Type . Normal ) = = null ) {
if ( mesh . getBuffer ( Type . Normal ) = = null ) {
throw new IllegalArgumentException ( "The given mesh has no normal data!" ) ;
}
VertexData [ ] vertices ;
switch ( mesh . getMode ( ) ) {
case Triangles :
vertices = processTriangles ( mesh , index , v , t ) ; break ;
vertices = processTriangles ( mesh , index , v , t ) ;
break ;
case TriangleStrip :
vertices = processTriangleStrip ( mesh , index , v , t ) ; break ;
vertices = processTriangleStrip ( mesh , index , v , t ) ;
break ;
case TriangleFan :
vertices = processTriangleFan ( mesh , index , v , t ) ; break ;
default : throw new UnsupportedOperationException (
mesh . getMode ( ) + " is not supported." ) ;
vertices = processTriangleFan ( mesh , index , v , t ) ;
break ;
default :
throw new UnsupportedOperationException (
mesh . getMode ( ) + " is not supported." ) ;
}
processTriangleData ( mesh , vertices , approxTangents ) ;
//if the mesh has a bind pose, we need to generate the bind pose for the tangent buffer
if ( mesh . getBuffer ( Type . BindPosePosition ) ! = null ) {
VertexBuffer tangents = mesh . getBuffer ( Type . Tangent ) ;
if ( tangents ! = null ) {
VertexBuffer bindTangents = new VertexBuffer ( Type . BindPoseTangent ) ;
bindTangents . setupData ( Usage . CpuOnly ,
4 ,
Format . Float ,
BufferUtils . clone ( tangents . getData ( ) ) ) ;
if ( mesh . getBuffer ( Type . BindPoseTangent ) ! = null ) {
mesh . clearBuffer ( Type . BindPoseTangent ) ;
}
mesh . setBuffer ( bindTangents ) ;
tangents . setUsage ( Usage . Stream ) ;
}
}
}
private static VertexData [ ] processTriangles ( Mesh mesh ,
int [ ] index , Vector3f [ ] v , Vector2f [ ] t )
{
IndexBuffer indexBuffer = mesh . getIndexBuffer ( ) ;
int [ ] index , Vector3f [ ] v , Vector2f [ ] t ) {
IndexBuffer indexBuffer = mesh . getIndexBuffer ( ) ;
FloatBuffer vertexBuffer = ( FloatBuffer ) mesh . getBuffer ( Type . Position ) . getData ( ) ;
if ( mesh . getBuffer ( Type . TexCoord ) = = null )
if ( mesh . getBuffer ( Type . TexCoord ) = = null ) {
throw new IllegalArgumentException ( "Can only generate tangents for "
+ "meshes with texture coordinates" ) ;
+ "meshes with texture coordinates" ) ;
}
FloatBuffer textureBuffer = ( FloatBuffer ) mesh . getBuffer ( Type . TexCoord ) . getData ( ) ;
@ -167,7 +191,7 @@ public class TangentBinormalGenerator {
for ( int i = 0 ; i < indexBuffer . size ( ) / 3 ; i + + ) {
for ( int j = 0 ; j < 3 ; j + + ) {
index [ j ] = indexBuffer . get ( i * 3 + j ) ;
index [ j ] = indexBuffer . get ( i * 3 + j ) ;
populateFromBuffer ( v [ j ] , vertexBuffer , index [ j ] ) ;
populateFromBuffer ( t [ j ] , textureBuffer , index [ j ] ) ;
}
@ -182,10 +206,10 @@ public class TangentBinormalGenerator {
return vertices ;
}
private static VertexData [ ] processTriangleStrip ( Mesh mesh ,
int [ ] index , Vector3f [ ] v , Vector2f [ ] t )
{
IndexBuffer indexBuffer = mesh . getIndexBuffer ( ) ;
int [ ] index , Vector3f [ ] v , Vector2f [ ] t ) {
IndexBuffer indexBuffer = mesh . getIndexBuffer ( ) ;
FloatBuffer vertexBuffer = ( FloatBuffer ) mesh . getBuffer ( Type . Position ) . getData ( ) ;
FloatBuffer textureBuffer = ( FloatBuffer ) mesh . getBuffer ( Type . TexCoord ) . getData ( ) ;
@ -230,10 +254,10 @@ public class TangentBinormalGenerator {
return vertices ;
}
private static VertexData [ ] processTriangleFan ( Mesh mesh ,
int [ ] index , Vector3f [ ] v , Vector2f [ ] t )
{
IndexBuffer indexBuffer = mesh . getIndexBuffer ( ) ;
int [ ] index , Vector3f [ ] v , Vector2f [ ] t ) {
IndexBuffer indexBuffer = mesh . getIndexBuffer ( ) ;
FloatBuffer vertexBuffer = ( FloatBuffer ) mesh . getBuffer ( Type . Position ) . getData ( ) ;
FloatBuffer textureBuffer = ( FloatBuffer ) mesh . getBuffer ( Type . TexCoord ) . getData ( ) ;
@ -279,10 +303,8 @@ public class TangentBinormalGenerator {
return ( a . subtract ( b ) . cross ( c . subtract ( b ) ) ) . lengthSquared ( ) = = 0 ;
}
public static TriangleData processTriangle ( int [ ] index ,
Vector3f [ ] v , Vector2f [ ] t )
{
Vector3f [ ] v , Vector2f [ ] t ) {
Vector3f edge1 = new Vector3f ( ) ;
Vector3f edge2 = new Vector3f ( ) ;
Vector2f edge1uv = new Vector2f ( ) ;
@ -294,15 +316,15 @@ public class TangentBinormalGenerator {
t [ 1 ] . subtract ( t [ 0 ] , edge1uv ) ;
t [ 2 ] . subtract ( t [ 0 ] , edge2uv ) ;
float det = edge1uv . x * edge2uv . y - edge1uv . y * edge2uv . x ;
float det = edge1uv . x * edge2uv . y - edge1uv . y * edge2uv . x ;
boolean normalize = false ;
if ( Math . abs ( det ) < ZERO_TOLERANCE ) {
log . log ( Level . WARNING , "Colinear uv coordinates for triangle " +
"[{0}, {1}, {2}]; tex0 = [{3}, {4}], " +
"tex1 = [{5}, {6}], tex2 = [{7}, {8}]" ,
new Object [ ] { index [ 0 ] , index [ 1 ] , index [ 2 ] ,
t [ 0 ] . x , t [ 0 ] . y , t [ 1 ] . x , t [ 1 ] . y , t [ 2 ] . x , t [ 2 ] . y } ) ;
log . log ( Level . WARNING , "Colinear uv coordinates for triangle "
+ "[{0}, {1}, {2}]; tex0 = [{3}, {4}], "
+ "tex1 = [{5}, {6}], tex2 = [{7}, {8}]" ,
new Object [ ] { index [ 0 ] , index [ 1 ] , index [ 2 ] ,
t [ 0 ] . x , t [ 0 ] . y , t [ 1 ] . x , t [ 1 ] . y , t [ 2 ] . x , t [ 2 ] . y } ) ;
det = 1 ;
normalize = true ;
}
@ -316,47 +338,48 @@ public class TangentBinormalGenerator {
binormal . normalizeLocal ( ) ;
if ( Math . abs ( Math . abs ( tangent . dot ( binormal ) ) - 1 )
< ZERO_TOLERANCE )
{
log . log ( Level . WARNING , "Vertices are on the same line " +
"for triangle [{0}, {1}, {2}]." ,
new Object [ ] { index [ 0 ] , index [ 1 ] , index [ 2 ] } ) ;
< ZERO_TOLERANCE ) {
log . log ( Level . WARNING , "Vertices are on the same line "
+ "for triangle [{0}, {1}, {2}]." ,
new Object [ ] { index [ 0 ] , index [ 1 ] , index [ 2 ] } ) ;
}
float factor = 1 / det ;
tangent . x = ( edge2uv . y * edge1 . x - edge1uv . y * edge2 . x ) * factor ;
tangent . y = ( edge2uv . y * edge1 . y - edge1uv . y * edge2 . y ) * factor ;
tangent . z = ( edge2uv . y * edge1 . z - edge1uv . y * edge2 . z ) * factor ;
if ( normalize ) tangent . normalizeLocal ( ) ;
float factor = 1 / det ;
tangent . x = ( edge2uv . y * edge1 . x - edge1uv . y * edge2 . x ) * factor ;
tangent . y = ( edge2uv . y * edge1 . y - edge1uv . y * edge2 . y ) * factor ;
tangent . z = ( edge2uv . y * edge1 . z - edge1uv . y * edge2 . z ) * factor ;
if ( normalize ) {
tangent . normalizeLocal ( ) ;
}
binormal . x = ( edge1uv . x * edge2 . x - edge2uv . x * edge1 . x ) * factor ;
binormal . y = ( edge1uv . x * edge2 . y - edge2uv . x * edge1 . y ) * factor ;
binormal . z = ( edge1uv . x * edge2 . z - edge2uv . x * edge1 . z ) * factor ;
if ( normalize ) binormal . normalizeLocal ( ) ;
binormal . x = ( edge1uv . x * edge2 . x - edge2uv . x * edge1 . x ) * factor ;
binormal . y = ( edge1uv . x * edge2 . y - edge2uv . x * edge1 . y ) * factor ;
binormal . z = ( edge1uv . x * edge2 . z - edge2uv . x * edge1 . z ) * factor ;
if ( normalize ) {
binormal . normalizeLocal ( ) ;
}
tangent . cross ( binormal , normal ) ;
normal . normalizeLocal ( ) ;
return new TriangleData (
tangent ,
binormal ,
normal ,
index [ 0 ] , index [ 1 ] , index [ 2 ]
) ;
tangent ,
binormal ,
normal ,
index [ 0 ] , index [ 1 ] , index [ 2 ] ) ;
}
public static void setToleranceAngle ( float angle ) {
if ( angle < 0 | | angle > 179 ) {
throw new IllegalArgumentException (
"The angle must be between 0 and 179 degrees." ) ;
"The angle must be between 0 and 179 degrees." ) ;
}
toleranceDot = FastMath . cos ( angle * FastMath . DEG_TO_RAD ) ;
toleranceDot = FastMath . cos ( angle * FastMath . DEG_TO_RAD ) ;
toleranceAngle = angle ;
}
private static void processTriangleData ( Mesh mesh , VertexData [ ] vertices ,
boolean approxTangent )
{
boolean approxTangent ) {
FloatBuffer normalBuffer = ( FloatBuffer ) mesh . getBuffer ( Type . Normal ) . getData ( ) ;
FloatBuffer tangents = BufferUtils . createFloatBuffer ( vertices . length * 4 ) ;
@ -392,8 +415,8 @@ public class TangentBinormalGenerator {
tangentUnit . normalizeLocal ( ) ;
if ( tangent . dot ( tangentUnit ) < toleranceDot ) {
log . log ( Level . WARNING ,
"Angle between tangents exceeds tolerance " +
"for vertex {0}." , i ) ;
"Angle between tangents exceeds tolerance "
+ "for vertex {0}." , i ) ;
break ;
}
@ -402,8 +425,8 @@ public class TangentBinormalGenerator {
binormalUnit . normalizeLocal ( ) ;
if ( binormal . dot ( binormalUnit ) < toleranceDot ) {
log . log ( Level . WARNING ,
"Angle between binormals exceeds tolerance " +
"for vertex {0}." , i ) ;
"Angle between binormals exceeds tolerance "
+ "for vertex {0}." , i ) ;
break ;
}
}
@ -439,21 +462,18 @@ public class TangentBinormalGenerator {
if ( binormal . length ( ) > = ZERO_TOLERANCE ) {
binormal . cross ( givenNormal , tangent ) ;
tangent . normalizeLocal ( ) ;
}
// if all fails use the tangent from the first triangle
} // if all fails use the tangent from the first triangle
else {
tangent . set ( triangles . get ( 0 ) . tangent ) ;
}
}
else {
} else {
tangent . divideLocal ( triangles . size ( ) ) ;
}
tangentUnit . set ( tangent ) ;
tangentUnit . normalizeLocal ( ) ;
if ( Math . abs ( Math . abs ( tangentUnit . dot ( givenNormal ) ) - 1 )
< ZERO_TOLERANCE )
{
< ZERO_TOLERANCE ) {
log . log ( Level . WARNING ,
"Normal and tangent are parallel for vertex {0}." , i ) ;
}
@ -467,28 +487,24 @@ public class TangentBinormalGenerator {
if ( tangent . length ( ) > = ZERO_TOLERANCE ) {
givenNormal . cross ( tangent , binormal ) ;
binormal . normalizeLocal ( ) ;
}
// if all fails use the binormal from the first triangle
} // if all fails use the binormal from the first triangle
else {
binormal . set ( triangles . get ( 0 ) . binormal ) ;
}
}
else {
} else {
binormal . divideLocal ( triangles . size ( ) ) ;
}
binormalUnit . set ( binormal ) ;
binormalUnit . normalizeLocal ( ) ;
if ( Math . abs ( Math . abs ( binormalUnit . dot ( givenNormal ) ) - 1 )
< ZERO_TOLERANCE )
{
< ZERO_TOLERANCE ) {
log . log ( Level . WARNING ,
"Normal and binormal are parallel for vertex {0}." , i ) ;
}
if ( Math . abs ( Math . abs ( binormalUnit . dot ( tangentUnit ) ) - 1 )
< ZERO_TOLERANCE )
{
< ZERO_TOLERANCE ) {
log . log ( Level . WARNING ,
"Tangent and binormal are parallel for vertex {0}." , i ) ;
}
@ -503,8 +519,7 @@ public class TangentBinormalGenerator {
tangents . put ( ( i * 4 ) + 1 , tangent . y ) ;
tangents . put ( ( i * 4 ) + 2 , tangent . z ) ;
tangents . put ( ( i * 4 ) + 3 , wCoord ) ;
}
else {
} else {
tangents . put ( ( i * 4 ) , tangent . x ) ;
tangents . put ( ( i * 4 ) + 1 , tangent . y ) ;
tangents . put ( ( i * 4 ) + 2 , tangent . z ) ;
@ -514,15 +529,16 @@ public class TangentBinormalGenerator {
}
}
mesh . setBuffer ( Type . Tangent , 4 , tangents ) ;
mesh . setBuffer ( Type . Tangent , 4 , tangents ) ;
// if (!approxTangent) mesh.setBuffer(Type.Binormal, 3, binormals);
}
public static Mesh genTbnLines ( Mesh mesh , float scale ) {
if ( mesh . getBuffer ( Type . Tangent ) = = null )
if ( mesh . getBuffer ( Type . Tangent ) = = null ) {
return genNormalLines ( mesh , scale ) ;
else
} else {
return genTangentLines ( mesh , scale ) ;
}
}
public static Mesh genNormalLines ( Mesh mesh , float scale ) {
@ -598,12 +614,12 @@ public class TangentBinormalGenerator {
populateFromBuffer ( origin , vertexBuffer , i ) ;
populateFromBuffer ( normal , normalBuffer , i ) ;
if ( hasParity ) {
if ( hasParity ) {
tangent . x = tangentBuffer . get ( i * 4 ) ;
tangent . y = tangentBuffer . get ( i * 4 + 1 ) ;
tangent . z = tangentBuffer . get ( i * 4 + 2 ) ;
tangentW = tangentBuffer . get ( i * 4 + 3 ) ;
} else {
tangentW = tangentBuffer . get ( i * 4 + 3 ) ;
} else {
populateFromBuffer ( tangent , tangentBuffer , i ) ;
}