- Added tangent transforms support for skinning (normal mapped models with bone animation had incorrect tangents during animation)
- added a BindPoseTangent buffer type - made generateBindPose generate a BindPoseTangent buffer if Tangent buffer is set in Mesh - added a temp float array in TempVars to compute tangent skinning - Generated bind pose for tangents after tangent generation in TangentBinormalGenerator git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@8563 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
40e32790d6
commit
a5ff915fc1
@ -182,6 +182,19 @@ public class SkeletonControl extends AbstractControl implements Cloneable {
|
|||||||
nb.clear();
|
nb.clear();
|
||||||
bpb.clear();
|
bpb.clear();
|
||||||
bnb.clear();
|
bnb.clear();
|
||||||
|
|
||||||
|
//reseting bind tangents if there is a bind tangent buffer
|
||||||
|
VertexBuffer bindTangents = mesh.getBuffer(Type.BindPoseTangent);
|
||||||
|
if (bindTangents != null) {
|
||||||
|
VertexBuffer tangents = mesh.getBuffer(Type.Tangent);
|
||||||
|
FloatBuffer tb = (FloatBuffer) tangents.getData();
|
||||||
|
FloatBuffer btb = (FloatBuffer) bindTangents.getData();
|
||||||
|
tb.clear();
|
||||||
|
btb.clear();
|
||||||
|
tb.put(btb).clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pb.put(bpb).clear();
|
pb.put(bpb).clear();
|
||||||
nb.put(bnb).clear();
|
nb.put(bnb).clear();
|
||||||
}
|
}
|
||||||
@ -251,7 +264,6 @@ public class SkeletonControl extends AbstractControl implements Cloneable {
|
|||||||
// public void setSkeleton(Skeleton skeleton) {
|
// public void setSkeleton(Skeleton skeleton) {
|
||||||
// this.skeleton = skeleton;
|
// this.skeleton = skeleton;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns the targets meshes of this control
|
* returns the targets meshes of this control
|
||||||
* @return
|
* @return
|
||||||
@ -267,8 +279,31 @@ public class SkeletonControl extends AbstractControl implements Cloneable {
|
|||||||
// public void setTargets(Mesh[] targets) {
|
// public void setTargets(Mesh[] targets) {
|
||||||
// this.targets = targets;
|
// this.targets = targets;
|
||||||
// }
|
// }
|
||||||
|
/**
|
||||||
|
* Update the mesh according to the given transformation matrices
|
||||||
|
* @param mesh then mesh
|
||||||
|
* @param offsetMatrices the transformation matrices to apply
|
||||||
|
*/
|
||||||
private void softwareSkinUpdate(Mesh mesh, Matrix4f[] offsetMatrices) {
|
private void softwareSkinUpdate(Mesh mesh, Matrix4f[] offsetMatrices) {
|
||||||
|
|
||||||
|
VertexBuffer tb = mesh.getBuffer(Type.Tangent);
|
||||||
|
if (tb == null) {
|
||||||
|
//if there are no tangents use the classic skinning
|
||||||
|
applySkinning(mesh, offsetMatrices);
|
||||||
|
} else {
|
||||||
|
//if there are tangents use the skinning with tangents
|
||||||
|
applySkinningTangents(mesh, offsetMatrices, tb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to apply skinning transforms to a mesh's buffers
|
||||||
|
* @param mesh the mesh
|
||||||
|
* @param offsetMatrices the offset matices to apply
|
||||||
|
*/
|
||||||
|
private void applySkinning(Mesh mesh, Matrix4f[] offsetMatrices) {
|
||||||
int maxWeightsPerVert = mesh.getMaxNumWeights();
|
int maxWeightsPerVert = mesh.getMaxNumWeights();
|
||||||
if (maxWeightsPerVert <= 0) {
|
if (maxWeightsPerVert <= 0) {
|
||||||
throw new IllegalStateException("Max weights per vert is incorrectly set!");
|
throw new IllegalStateException("Max weights per vert is incorrectly set!");
|
||||||
@ -304,7 +339,7 @@ public class SkeletonControl extends AbstractControl implements Cloneable {
|
|||||||
float[] normBuf = vars.skinNormals;
|
float[] normBuf = vars.skinNormals;
|
||||||
|
|
||||||
int iterations = (int) FastMath.ceil(fvb.capacity() / ((float) posBuf.length));
|
int iterations = (int) FastMath.ceil(fvb.capacity() / ((float) posBuf.length));
|
||||||
int bufLength = posBuf.length * 3;
|
int bufLength = posBuf.length;
|
||||||
for (int i = iterations - 1; i >= 0; i--) {
|
for (int i = iterations - 1; i >= 0; i--) {
|
||||||
// read next set of positions and normals from native buffer
|
// read next set of positions and normals from native buffer
|
||||||
bufLength = Math.min(posBuf.length, fvb.remaining());
|
bufLength = Math.min(posBuf.length, fvb.remaining());
|
||||||
@ -359,7 +394,146 @@ public class SkeletonControl extends AbstractControl implements Cloneable {
|
|||||||
vb.updateData(fvb);
|
vb.updateData(fvb);
|
||||||
nb.updateData(fnb);
|
nb.updateData(fnb);
|
||||||
|
|
||||||
// mesh.updateBound();
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specific method for skinning with tangents to avoid cluttering the classic skinning calculation with
|
||||||
|
* null checks that would slow down the process even if tangents don't have to be computed.
|
||||||
|
* Also the iteration has additional indexes since tangent has 4 components instead of 3 for pos and norm
|
||||||
|
* @param maxWeightsPerVert maximum number of weights per vertex
|
||||||
|
* @param mesh the mesh
|
||||||
|
* @param offsetMatrices the offsetMaytrices to apply
|
||||||
|
* @param tb the tangent vertexBuffer
|
||||||
|
*/
|
||||||
|
private void applySkinningTangents(Mesh mesh, Matrix4f[] offsetMatrices, VertexBuffer tb) {
|
||||||
|
int maxWeightsPerVert = mesh.getMaxNumWeights();
|
||||||
|
|
||||||
|
if (maxWeightsPerVert <= 0) {
|
||||||
|
throw new IllegalStateException("Max weights per vert is incorrectly set!");
|
||||||
|
}
|
||||||
|
|
||||||
|
int fourMinusMaxWeights = 4 - maxWeightsPerVert;
|
||||||
|
|
||||||
|
// NOTE: This code assumes the vertex buffer is in bind pose
|
||||||
|
// resetToBind() has been called this frame
|
||||||
|
VertexBuffer vb = mesh.getBuffer(Type.Position);
|
||||||
|
FloatBuffer fvb = (FloatBuffer) vb.getData();
|
||||||
|
fvb.rewind();
|
||||||
|
|
||||||
|
VertexBuffer nb = mesh.getBuffer(Type.Normal);
|
||||||
|
|
||||||
|
FloatBuffer fnb = (FloatBuffer) nb.getData();
|
||||||
|
fnb.rewind();
|
||||||
|
|
||||||
|
|
||||||
|
FloatBuffer ftb = (FloatBuffer) tb.getData();
|
||||||
|
ftb.rewind();
|
||||||
|
|
||||||
|
|
||||||
|
// get boneIndexes and weights for mesh
|
||||||
|
ByteBuffer ib = (ByteBuffer) mesh.getBuffer(Type.BoneIndex).getData();
|
||||||
|
FloatBuffer wb = (FloatBuffer) mesh.getBuffer(Type.BoneWeight).getData();
|
||||||
|
|
||||||
|
ib.rewind();
|
||||||
|
wb.rewind();
|
||||||
|
|
||||||
|
float[] weights = wb.array();
|
||||||
|
byte[] indices = ib.array();
|
||||||
|
int idxWeights = 0;
|
||||||
|
|
||||||
|
TempVars vars = TempVars.get();
|
||||||
|
|
||||||
|
|
||||||
|
float[] posBuf = vars.skinPositions;
|
||||||
|
float[] normBuf = vars.skinNormals;
|
||||||
|
float[] tanBuf = vars.skinTangents;
|
||||||
|
|
||||||
|
int iterations = (int) FastMath.ceil(fvb.capacity() / ((float) posBuf.length));
|
||||||
|
int bufLength = 0;
|
||||||
|
int tanLength = 0;
|
||||||
|
for (int i = iterations - 1; i >= 0; i--) {
|
||||||
|
// read next set of positions and normals from native buffer
|
||||||
|
bufLength = Math.min(posBuf.length, fvb.remaining());
|
||||||
|
tanLength = Math.min(tanBuf.length, ftb.remaining());
|
||||||
|
fvb.get(posBuf, 0, bufLength);
|
||||||
|
fnb.get(normBuf, 0, bufLength);
|
||||||
|
ftb.get(tanBuf, 0, tanLength);
|
||||||
|
int verts = bufLength / 3;
|
||||||
|
int idxPositions = 0;
|
||||||
|
//tangents has their own index because of the 4 components
|
||||||
|
int idxTangents = 0;
|
||||||
|
|
||||||
|
// iterate vertices and apply skinning transform for each effecting bone
|
||||||
|
for (int vert = verts - 1; vert >= 0; vert--) {
|
||||||
|
float nmx = normBuf[idxPositions];
|
||||||
|
float vtx = posBuf[idxPositions++];
|
||||||
|
float nmy = normBuf[idxPositions];
|
||||||
|
float vty = posBuf[idxPositions++];
|
||||||
|
float nmz = normBuf[idxPositions];
|
||||||
|
float vtz = posBuf[idxPositions++];
|
||||||
|
|
||||||
|
float tnx = tanBuf[idxTangents++];
|
||||||
|
float tny = tanBuf[idxTangents++];
|
||||||
|
float tnz = tanBuf[idxTangents++];
|
||||||
|
|
||||||
|
//skipping the 4th component of the tangent since it doesn't have to be transformed
|
||||||
|
idxTangents++;
|
||||||
|
|
||||||
|
float rx = 0, ry = 0, rz = 0, rnx = 0, rny = 0, rnz = 0, rtx = 0, rty = 0, rtz = 0;
|
||||||
|
|
||||||
|
for (int w = maxWeightsPerVert - 1; w >= 0; w--) {
|
||||||
|
float weight = weights[idxWeights];
|
||||||
|
Matrix4f mat = offsetMatrices[indices[idxWeights++]];
|
||||||
|
|
||||||
|
rx += (mat.m00 * vtx + mat.m01 * vty + mat.m02 * vtz + mat.m03) * weight;
|
||||||
|
ry += (mat.m10 * vtx + mat.m11 * vty + mat.m12 * vtz + mat.m13) * weight;
|
||||||
|
rz += (mat.m20 * vtx + mat.m21 * vty + mat.m22 * vtz + mat.m23) * weight;
|
||||||
|
|
||||||
|
rnx += (nmx * mat.m00 + nmy * mat.m01 + nmz * mat.m02) * weight;
|
||||||
|
rny += (nmx * mat.m10 + nmy * mat.m11 + nmz * mat.m12) * weight;
|
||||||
|
rnz += (nmx * mat.m20 + nmy * mat.m21 + nmz * mat.m22) * weight;
|
||||||
|
|
||||||
|
rtx += (tnx * mat.m00 + tny * mat.m01 + tnz * mat.m02) * weight;
|
||||||
|
rty += (tnx * mat.m10 + tny * mat.m11 + tnz * mat.m12) * weight;
|
||||||
|
rtz += (tnx * mat.m20 + tny * mat.m21 + tnz * mat.m22) * weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
idxWeights += fourMinusMaxWeights;
|
||||||
|
|
||||||
|
idxPositions -= 3;
|
||||||
|
|
||||||
|
normBuf[idxPositions] = rnx;
|
||||||
|
posBuf[idxPositions++] = rx;
|
||||||
|
normBuf[idxPositions] = rny;
|
||||||
|
posBuf[idxPositions++] = ry;
|
||||||
|
normBuf[idxPositions] = rnz;
|
||||||
|
posBuf[idxPositions++] = rz;
|
||||||
|
|
||||||
|
idxTangents -= 4;
|
||||||
|
|
||||||
|
tanBuf[idxTangents++] = rtx;
|
||||||
|
tanBuf[idxTangents++] = rty;
|
||||||
|
tanBuf[idxTangents++] = rtz;
|
||||||
|
|
||||||
|
//once again skipping the 4th component of the tangent
|
||||||
|
idxTangents++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fvb.position(fvb.position() - bufLength);
|
||||||
|
fvb.put(posBuf, 0, bufLength);
|
||||||
|
fnb.position(fnb.position() - bufLength);
|
||||||
|
fnb.put(normBuf, 0, bufLength);
|
||||||
|
ftb.position(ftb.position() - tanLength);
|
||||||
|
ftb.put(tanBuf, 0, tanLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
vars.release();
|
||||||
|
|
||||||
|
vb.updateData(fvb);
|
||||||
|
nb.updateData(fnb);
|
||||||
|
tb.updateData(ftb);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -334,6 +334,17 @@ public class Mesh implements Savable, Cloneable {
|
|||||||
setBuffer(bindNorm);
|
setBuffer(bindNorm);
|
||||||
norm.setUsage(Usage.Stream);
|
norm.setUsage(Usage.Stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VertexBuffer tangents = getBuffer(Type.Tangent);
|
||||||
|
if (tangents != null) {
|
||||||
|
VertexBuffer bindTangents = new VertexBuffer(Type.BindPoseTangent);
|
||||||
|
bindTangents.setupData(Usage.CpuOnly,
|
||||||
|
4,
|
||||||
|
Format.Float,
|
||||||
|
BufferUtils.clone(tangents.getData()));
|
||||||
|
setBuffer(bindTangents);
|
||||||
|
tangents.setUsage(Usage.Stream);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +94,9 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
|
|||||||
Color,
|
Color,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tangent vector, normalized (3 floats)
|
* Tangent vector, normalized (4 floats) (x,y,z,w)
|
||||||
|
* the w component is called the binormal parity, is not normalized and is either 1f or -1f
|
||||||
|
* It's used to compuste the direction on the binormal verctor on the GPU at render time.
|
||||||
*/
|
*/
|
||||||
Tangent,
|
Tangent,
|
||||||
|
|
||||||
@ -140,6 +142,15 @@ public class VertexBuffer extends NativeObject implements Savable, Cloneable {
|
|||||||
*/
|
*/
|
||||||
BindPoseNormal,
|
BindPoseNormal,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initial vertex tangents, used with animation.
|
||||||
|
* Should have the same format and size as {@link Type#Tangent}.
|
||||||
|
* If used with software skinning, the usage should be
|
||||||
|
* {@link Usage#CpuOnly}, and the buffer should be allocated
|
||||||
|
* on the heap.
|
||||||
|
*/
|
||||||
|
BindPoseTangent,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bone weights, used with animation (4 floats).
|
* Bone weights, used with animation (4 floats).
|
||||||
* If used with software skinning, the usage should be
|
* If used with software skinning, the usage should be
|
||||||
|
@ -29,9 +29,11 @@
|
|||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.jme3.util;
|
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 java.util.logging.Level;
|
||||||
import com.jme3.scene.mesh.IndexBuffer;
|
import com.jme3.scene.mesh.IndexBuffer;
|
||||||
import com.jme3.scene.Geometry;
|
import com.jme3.scene.Geometry;
|
||||||
@ -59,7 +61,6 @@ public class TangentBinormalGenerator {
|
|||||||
private static final float ZERO_TOLERANCE = 0.0000001f;
|
private static final float ZERO_TOLERANCE = 0.0000001f;
|
||||||
private static final Logger log = Logger.getLogger(
|
private static final Logger log = Logger.getLogger(
|
||||||
TangentBinormalGenerator.class.getName());
|
TangentBinormalGenerator.class.getName());
|
||||||
|
|
||||||
private static float toleranceAngle;
|
private static float toleranceAngle;
|
||||||
private static float toleranceDot;
|
private static float toleranceDot;
|
||||||
|
|
||||||
@ -68,17 +69,18 @@ public class TangentBinormalGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static class VertexData {
|
private static class VertexData {
|
||||||
|
|
||||||
public final Vector3f tangent = new Vector3f();
|
public final Vector3f tangent = new Vector3f();
|
||||||
public final Vector3f binormal = new Vector3f();
|
public final Vector3f binormal = new Vector3f();
|
||||||
public final List<TriangleData> triangles =
|
public final List<TriangleData> triangles =
|
||||||
new ArrayList<TriangleData>();
|
new ArrayList<TriangleData>();
|
||||||
|
|
||||||
public VertexData() {
|
public VertexData() {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TriangleData {
|
public static class TriangleData {
|
||||||
|
|
||||||
public final Vector3f tangent;
|
public final Vector3f tangent;
|
||||||
public final Vector3f binormal;
|
public final Vector3f binormal;
|
||||||
public final Vector3f normal;
|
public final Vector3f normal;
|
||||||
@ -88,8 +90,7 @@ public class TangentBinormalGenerator {
|
|||||||
|
|
||||||
public TriangleData(Vector3f tangent, Vector3f binormal,
|
public TriangleData(Vector3f tangent, Vector3f binormal,
|
||||||
Vector3f normal,
|
Vector3f normal,
|
||||||
int index0, int index1, int index2)
|
int index0, int index1, int index2) {
|
||||||
{
|
|
||||||
this.tangent = tangent;
|
this.tangent = tangent;
|
||||||
this.binormal = binormal;
|
this.binormal = binormal;
|
||||||
this.normal = normal;
|
this.normal = normal;
|
||||||
@ -140,26 +141,49 @@ public class TangentBinormalGenerator {
|
|||||||
VertexData[] vertices;
|
VertexData[] vertices;
|
||||||
switch (mesh.getMode()) {
|
switch (mesh.getMode()) {
|
||||||
case Triangles:
|
case Triangles:
|
||||||
vertices = processTriangles(mesh, index, v, t); break;
|
vertices = processTriangles(mesh, index, v, t);
|
||||||
|
break;
|
||||||
case TriangleStrip:
|
case TriangleStrip:
|
||||||
vertices = processTriangleStrip(mesh, index, v, t); break;
|
vertices = processTriangleStrip(mesh, index, v, t);
|
||||||
|
break;
|
||||||
case TriangleFan:
|
case TriangleFan:
|
||||||
vertices = processTriangleFan(mesh, index, v, t); break;
|
vertices = processTriangleFan(mesh, index, v, t);
|
||||||
default: throw new UnsupportedOperationException(
|
break;
|
||||||
|
default:
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
mesh.getMode() + " is not supported.");
|
mesh.getMode() + " is not supported.");
|
||||||
}
|
}
|
||||||
|
|
||||||
processTriangleData(mesh, vertices, approxTangents);
|
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,
|
private static VertexData[] processTriangles(Mesh mesh,
|
||||||
int[] index, Vector3f[] v, Vector2f[] t)
|
int[] index, Vector3f[] v, Vector2f[] t) {
|
||||||
{
|
|
||||||
IndexBuffer indexBuffer = mesh.getIndexBuffer();
|
IndexBuffer indexBuffer = mesh.getIndexBuffer();
|
||||||
FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData();
|
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 "
|
throw new IllegalArgumentException("Can only generate tangents for "
|
||||||
+ "meshes with texture coordinates");
|
+ "meshes with texture coordinates");
|
||||||
|
}
|
||||||
|
|
||||||
FloatBuffer textureBuffer = (FloatBuffer) mesh.getBuffer(Type.TexCoord).getData();
|
FloatBuffer textureBuffer = (FloatBuffer) mesh.getBuffer(Type.TexCoord).getData();
|
||||||
|
|
||||||
@ -182,9 +206,9 @@ public class TangentBinormalGenerator {
|
|||||||
|
|
||||||
return vertices;
|
return vertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static VertexData[] processTriangleStrip(Mesh mesh,
|
private static VertexData[] processTriangleStrip(Mesh mesh,
|
||||||
int[] index, Vector3f[] v, Vector2f[] t)
|
int[] index, Vector3f[] v, Vector2f[] t) {
|
||||||
{
|
|
||||||
IndexBuffer indexBuffer = mesh.getIndexBuffer();
|
IndexBuffer indexBuffer = mesh.getIndexBuffer();
|
||||||
FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData();
|
FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData();
|
||||||
FloatBuffer textureBuffer = (FloatBuffer) mesh.getBuffer(Type.TexCoord).getData();
|
FloatBuffer textureBuffer = (FloatBuffer) mesh.getBuffer(Type.TexCoord).getData();
|
||||||
@ -230,9 +254,9 @@ public class TangentBinormalGenerator {
|
|||||||
|
|
||||||
return vertices;
|
return vertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static VertexData[] processTriangleFan(Mesh mesh,
|
private static VertexData[] processTriangleFan(Mesh mesh,
|
||||||
int[] index, Vector3f[] v, Vector2f[] t)
|
int[] index, Vector3f[] v, Vector2f[] t) {
|
||||||
{
|
|
||||||
IndexBuffer indexBuffer = mesh.getIndexBuffer();
|
IndexBuffer indexBuffer = mesh.getIndexBuffer();
|
||||||
FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData();
|
FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData();
|
||||||
FloatBuffer textureBuffer = (FloatBuffer) mesh.getBuffer(Type.TexCoord).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;
|
return (a.subtract(b).cross(c.subtract(b))).lengthSquared() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static TriangleData processTriangle(int[] index,
|
public static TriangleData processTriangle(int[] index,
|
||||||
Vector3f[] v, Vector2f[] t)
|
Vector3f[] v, Vector2f[] t) {
|
||||||
{
|
|
||||||
Vector3f edge1 = new Vector3f();
|
Vector3f edge1 = new Vector3f();
|
||||||
Vector3f edge2 = new Vector3f();
|
Vector3f edge2 = new Vector3f();
|
||||||
Vector2f edge1uv = new Vector2f();
|
Vector2f edge1uv = new Vector2f();
|
||||||
@ -298,9 +320,9 @@ public class TangentBinormalGenerator {
|
|||||||
|
|
||||||
boolean normalize = false;
|
boolean normalize = false;
|
||||||
if (Math.abs(det) < ZERO_TOLERANCE) {
|
if (Math.abs(det) < ZERO_TOLERANCE) {
|
||||||
log.log(Level.WARNING, "Colinear uv coordinates for triangle " +
|
log.log(Level.WARNING, "Colinear uv coordinates for triangle "
|
||||||
"[{0}, {1}, {2}]; tex0 = [{3}, {4}], " +
|
+ "[{0}, {1}, {2}]; tex0 = [{3}, {4}], "
|
||||||
"tex1 = [{5}, {6}], tex2 = [{7}, {8}]",
|
+ "tex1 = [{5}, {6}], tex2 = [{7}, {8}]",
|
||||||
new Object[]{index[0], index[1], index[2],
|
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});
|
t[0].x, t[0].y, t[1].x, t[1].y, t[2].x, t[2].y});
|
||||||
det = 1;
|
det = 1;
|
||||||
@ -316,10 +338,9 @@ public class TangentBinormalGenerator {
|
|||||||
binormal.normalizeLocal();
|
binormal.normalizeLocal();
|
||||||
|
|
||||||
if (Math.abs(Math.abs(tangent.dot(binormal)) - 1)
|
if (Math.abs(Math.abs(tangent.dot(binormal)) - 1)
|
||||||
< ZERO_TOLERANCE)
|
< ZERO_TOLERANCE) {
|
||||||
{
|
log.log(Level.WARNING, "Vertices are on the same line "
|
||||||
log.log(Level.WARNING, "Vertices are on the same line " +
|
+ "for triangle [{0}, {1}, {2}].",
|
||||||
"for triangle [{0}, {1}, {2}].",
|
|
||||||
new Object[]{index[0], index[1], index[2]});
|
new Object[]{index[0], index[1], index[2]});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,12 +348,16 @@ public class TangentBinormalGenerator {
|
|||||||
tangent.x = (edge2uv.y * edge1.x - edge1uv.y * edge2.x) * factor;
|
tangent.x = (edge2uv.y * edge1.x - edge1uv.y * edge2.x) * factor;
|
||||||
tangent.y = (edge2uv.y * edge1.y - edge1uv.y * edge2.y) * factor;
|
tangent.y = (edge2uv.y * edge1.y - edge1uv.y * edge2.y) * factor;
|
||||||
tangent.z = (edge2uv.y * edge1.z - edge1uv.y * edge2.z) * factor;
|
tangent.z = (edge2uv.y * edge1.z - edge1uv.y * edge2.z) * factor;
|
||||||
if (normalize) tangent.normalizeLocal();
|
if (normalize) {
|
||||||
|
tangent.normalizeLocal();
|
||||||
|
}
|
||||||
|
|
||||||
binormal.x = (edge1uv.x * edge2.x - edge2uv.x * edge1.x) * factor;
|
binormal.x = (edge1uv.x * edge2.x - edge2uv.x * edge1.x) * factor;
|
||||||
binormal.y = (edge1uv.x * edge2.y - edge2uv.x * edge1.y) * factor;
|
binormal.y = (edge1uv.x * edge2.y - edge2uv.x * edge1.y) * factor;
|
||||||
binormal.z = (edge1uv.x * edge2.z - edge2uv.x * edge1.z) * factor;
|
binormal.z = (edge1uv.x * edge2.z - edge2uv.x * edge1.z) * factor;
|
||||||
if (normalize) binormal.normalizeLocal();
|
if (normalize) {
|
||||||
|
binormal.normalizeLocal();
|
||||||
|
}
|
||||||
|
|
||||||
tangent.cross(binormal, normal);
|
tangent.cross(binormal, normal);
|
||||||
normal.normalizeLocal();
|
normal.normalizeLocal();
|
||||||
@ -341,8 +366,7 @@ public class TangentBinormalGenerator {
|
|||||||
tangent,
|
tangent,
|
||||||
binormal,
|
binormal,
|
||||||
normal,
|
normal,
|
||||||
index[0], index[1], index[2]
|
index[0], index[1], index[2]);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setToleranceAngle(float angle) {
|
public static void setToleranceAngle(float angle) {
|
||||||
@ -355,8 +379,7 @@ public class TangentBinormalGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void processTriangleData(Mesh mesh, VertexData[] vertices,
|
private static void processTriangleData(Mesh mesh, VertexData[] vertices,
|
||||||
boolean approxTangent)
|
boolean approxTangent) {
|
||||||
{
|
|
||||||
FloatBuffer normalBuffer = (FloatBuffer) mesh.getBuffer(Type.Normal).getData();
|
FloatBuffer normalBuffer = (FloatBuffer) mesh.getBuffer(Type.Normal).getData();
|
||||||
|
|
||||||
FloatBuffer tangents = BufferUtils.createFloatBuffer(vertices.length * 4);
|
FloatBuffer tangents = BufferUtils.createFloatBuffer(vertices.length * 4);
|
||||||
@ -392,8 +415,8 @@ public class TangentBinormalGenerator {
|
|||||||
tangentUnit.normalizeLocal();
|
tangentUnit.normalizeLocal();
|
||||||
if (tangent.dot(tangentUnit) < toleranceDot) {
|
if (tangent.dot(tangentUnit) < toleranceDot) {
|
||||||
log.log(Level.WARNING,
|
log.log(Level.WARNING,
|
||||||
"Angle between tangents exceeds tolerance " +
|
"Angle between tangents exceeds tolerance "
|
||||||
"for vertex {0}.", i);
|
+ "for vertex {0}.", i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -402,8 +425,8 @@ public class TangentBinormalGenerator {
|
|||||||
binormalUnit.normalizeLocal();
|
binormalUnit.normalizeLocal();
|
||||||
if (binormal.dot(binormalUnit) < toleranceDot) {
|
if (binormal.dot(binormalUnit) < toleranceDot) {
|
||||||
log.log(Level.WARNING,
|
log.log(Level.WARNING,
|
||||||
"Angle between binormals exceeds tolerance " +
|
"Angle between binormals exceeds tolerance "
|
||||||
"for vertex {0}.", i);
|
+ "for vertex {0}.", i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -439,21 +462,18 @@ public class TangentBinormalGenerator {
|
|||||||
if (binormal.length() >= ZERO_TOLERANCE) {
|
if (binormal.length() >= ZERO_TOLERANCE) {
|
||||||
binormal.cross(givenNormal, tangent);
|
binormal.cross(givenNormal, tangent);
|
||||||
tangent.normalizeLocal();
|
tangent.normalizeLocal();
|
||||||
}
|
} // if all fails use the tangent from the first triangle
|
||||||
// if all fails use the tangent from the first triangle
|
|
||||||
else {
|
else {
|
||||||
tangent.set(triangles.get(0).tangent);
|
tangent.set(triangles.get(0).tangent);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
tangent.divideLocal(triangles.size());
|
tangent.divideLocal(triangles.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
tangentUnit.set(tangent);
|
tangentUnit.set(tangent);
|
||||||
tangentUnit.normalizeLocal();
|
tangentUnit.normalizeLocal();
|
||||||
if (Math.abs(Math.abs(tangentUnit.dot(givenNormal)) - 1)
|
if (Math.abs(Math.abs(tangentUnit.dot(givenNormal)) - 1)
|
||||||
< ZERO_TOLERANCE)
|
< ZERO_TOLERANCE) {
|
||||||
{
|
|
||||||
log.log(Level.WARNING,
|
log.log(Level.WARNING,
|
||||||
"Normal and tangent are parallel for vertex {0}.", i);
|
"Normal and tangent are parallel for vertex {0}.", i);
|
||||||
}
|
}
|
||||||
@ -467,28 +487,24 @@ public class TangentBinormalGenerator {
|
|||||||
if (tangent.length() >= ZERO_TOLERANCE) {
|
if (tangent.length() >= ZERO_TOLERANCE) {
|
||||||
givenNormal.cross(tangent, binormal);
|
givenNormal.cross(tangent, binormal);
|
||||||
binormal.normalizeLocal();
|
binormal.normalizeLocal();
|
||||||
}
|
} // if all fails use the binormal from the first triangle
|
||||||
// if all fails use the binormal from the first triangle
|
|
||||||
else {
|
else {
|
||||||
binormal.set(triangles.get(0).binormal);
|
binormal.set(triangles.get(0).binormal);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
binormal.divideLocal(triangles.size());
|
binormal.divideLocal(triangles.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
binormalUnit.set(binormal);
|
binormalUnit.set(binormal);
|
||||||
binormalUnit.normalizeLocal();
|
binormalUnit.normalizeLocal();
|
||||||
if (Math.abs(Math.abs(binormalUnit.dot(givenNormal)) - 1)
|
if (Math.abs(Math.abs(binormalUnit.dot(givenNormal)) - 1)
|
||||||
< ZERO_TOLERANCE)
|
< ZERO_TOLERANCE) {
|
||||||
{
|
|
||||||
log.log(Level.WARNING,
|
log.log(Level.WARNING,
|
||||||
"Normal and binormal are parallel for vertex {0}.", i);
|
"Normal and binormal are parallel for vertex {0}.", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Math.abs(Math.abs(binormalUnit.dot(tangentUnit)) - 1)
|
if (Math.abs(Math.abs(binormalUnit.dot(tangentUnit)) - 1)
|
||||||
< ZERO_TOLERANCE)
|
< ZERO_TOLERANCE) {
|
||||||
{
|
|
||||||
log.log(Level.WARNING,
|
log.log(Level.WARNING,
|
||||||
"Tangent and binormal are parallel for vertex {0}.", i);
|
"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) + 1, tangent.y);
|
||||||
tangents.put((i * 4) + 2, tangent.z);
|
tangents.put((i * 4) + 2, tangent.z);
|
||||||
tangents.put((i * 4) + 3, wCoord);
|
tangents.put((i * 4) + 3, wCoord);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
tangents.put((i * 4), tangent.x);
|
tangents.put((i * 4), tangent.x);
|
||||||
tangents.put((i * 4) + 1, tangent.y);
|
tangents.put((i * 4) + 1, tangent.y);
|
||||||
tangents.put((i * 4) + 2, tangent.z);
|
tangents.put((i * 4) + 2, tangent.z);
|
||||||
@ -519,11 +534,12 @@ public class TangentBinormalGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Mesh genTbnLines(Mesh mesh, float scale) {
|
public static Mesh genTbnLines(Mesh mesh, float scale) {
|
||||||
if (mesh.getBuffer(Type.Tangent) == null)
|
if (mesh.getBuffer(Type.Tangent) == null) {
|
||||||
return genNormalLines(mesh, scale);
|
return genNormalLines(mesh, scale);
|
||||||
else
|
} else {
|
||||||
return genTangentLines(mesh, scale);
|
return genTangentLines(mesh, scale);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static Mesh genNormalLines(Mesh mesh, float scale) {
|
public static Mesh genNormalLines(Mesh mesh, float scale) {
|
||||||
FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData();
|
FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData();
|
||||||
|
@ -157,6 +157,8 @@ public class TempVars {
|
|||||||
*/
|
*/
|
||||||
public final float[] skinPositions = new float[512 * 3];
|
public final float[] skinPositions = new float[512 * 3];
|
||||||
public final float[] skinNormals = new float[512 * 3];
|
public final float[] skinNormals = new float[512 * 3];
|
||||||
|
//tangent buffer as 4 components by elements
|
||||||
|
public final float[] skinTangents = new float[512 * 4];
|
||||||
/**
|
/**
|
||||||
* Fetching triangle from mesh
|
* Fetching triangle from mesh
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user