From 48b3f1a4d3e843e72de46495b10de7eb699fd3db Mon Sep 17 00:00:00 2001 From: jmekaelthas Date: Tue, 15 Mar 2016 17:18:16 +0100 Subject: [PATCH 1/4] Bugfix: fixes to face triangulation and some edges computations. --- .../jme3/scene/plugins/blender/meshes/Edge.java | 15 ++++++++++----- .../jme3/scene/plugins/blender/meshes/Face.java | 10 ---------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/Edge.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/Edge.java index 1d76fc02f..12aff2f4f 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/Edge.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/Edge.java @@ -215,8 +215,8 @@ public class Edge { /** * The method computes the crossing pint of this edge and another edge. If - * there is no crossing then null is returned. This method also allows to - * get the crossing point of the straight lines that contain these edges if + * there is no crossing then null is returned. Also null is returned if the edges are parallel. + * This method also allows to get the crossing point of the straight lines that contain these edges if * you set the 'extend' parameter to true. * * @param edge @@ -227,7 +227,7 @@ public class Edge { * @param extendSecondEdge * set to true to find a crossing point along the whole * straight that contains the given edge - * @return cross point on null if none exist + * @return cross point on null if none exist or the edges are parallel */ public Vector3f getCrossPoint(Edge edge, boolean extendThisEdge, boolean extendSecondEdge) { Vector3d P1 = new Vector3d(this.getFirstVertex()); @@ -235,6 +235,11 @@ public class Edge { Vector3d u = new Vector3d(this.getSecondVertex()).subtract(P1).normalizeLocal(); Vector3d v = new Vector3d(edge.getSecondVertex()).subtract(P2).normalizeLocal(); + if(Math.abs(u.dot(v)) >= 1 - FastMath.DBL_EPSILON) { + // the edges are parallel; do not care about the crossing point + return null; + } + double t1 = 0, t2 = 0; if(u.x == 0 && v.x == 0) { t2 = (u.z * (P2.y - P1.y) - u.y * (P2.z - P1.z)) / (u.y * v.z - u.z * v.y); @@ -262,11 +267,11 @@ public class Edge { // the lines cross, check if p1 and p2 are within the edges Vector3d p = p1.subtract(P1); double cos = p.dot(u) / p.length(); - if (extendThisEdge || p.length()<= FastMath.FLT_EPSILON || cos >= 1 - FastMath.FLT_EPSILON && p.length() <= this.getLength()) { + if (extendThisEdge || p.length()<= FastMath.FLT_EPSILON || cos >= 1 - FastMath.FLT_EPSILON && p.length() - this.getLength() <= FastMath.FLT_EPSILON) { // p1 is inside the first edge, lets check the other edge now p = p2.subtract(P2); cos = p.dot(v) / p.length(); - if(extendSecondEdge || p.length()<= FastMath.FLT_EPSILON || cos >= 1 - FastMath.FLT_EPSILON && p.length() <= edge.getLength()) { + if(extendSecondEdge || p.length()<= FastMath.FLT_EPSILON || cos >= 1 - FastMath.FLT_EPSILON && p.length() - edge.getLength() <= FastMath.FLT_EPSILON) { return p1.toVector3f(); } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/Face.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/Face.java index a41d58ff0..a746df180 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/Face.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/Face.java @@ -279,16 +279,6 @@ public class Face implements Comparator { // two special cases will improve the computations speed if(face.getIndexes().size() == 3) { triangulatedFaces.add(face.getIndexes().clone()); - } else if(face.getIndexes().size() == 4) { - // in case face has 4 verts we use the plain triangulation - indexes[0] = face.getIndex(0); - indexes[1] = face.getIndex(1); - indexes[2] = face.getIndex(2); - triangulatedFaces.add(new IndexesLoop(indexes)); - - indexes[1] = face.getIndex(2); - indexes[2] = face.getIndex(3); - triangulatedFaces.add(new IndexesLoop(indexes)); } else { int previousIndex1 = -1, previousIndex2 = -1, previousIndex3 = -1; while (face.vertexCount() > 0) { From 008768f18c7133c0ae977035e939b5f5a626d46b Mon Sep 17 00:00:00 2001 From: jmekaelthas Date: Mon, 4 Apr 2016 18:57:56 +0200 Subject: [PATCH 2/4] Feature: appending user defined UV sets to the mesh even if they are not directly used by the model. --- .../blender/materials/MaterialContext.java | 21 ++++++++--- .../blender/textures/CombinedTexture.java | 37 +++++++++++-------- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/materials/MaterialContext.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/materials/MaterialContext.java index 3b5a8eefb..c8dedcd40 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/materials/MaterialContext.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/materials/MaterialContext.java @@ -1,6 +1,7 @@ package com.jme3.scene.plugins.blender.materials; import java.io.IOException; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -157,14 +158,14 @@ public final class MaterialContext implements Savable { } // applying textures + int textureIndex = 0; if (loadedTextures != null && loadedTextures.size() > 0) { - int textureIndex = 0; if (loadedTextures.size() > TextureHelper.TEXCOORD_TYPES.length) { LOGGER.log(Level.WARNING, "The blender file has defined more than {0} different textures. JME supports only {0} UV mappings.", TextureHelper.TEXCOORD_TYPES.length); } for (CombinedTexture combinedTexture : loadedTextures) { if (textureIndex < TextureHelper.TEXCOORD_TYPES.length) { - combinedTexture.flatten(geometry, geometriesOMA, userDefinedUVCoordinates, blenderContext); + String usedUserUVSet = combinedTexture.flatten(geometry, geometriesOMA, userDefinedUVCoordinates, blenderContext); this.setTexture(material, combinedTexture.getMappingType(), combinedTexture.getResultTexture()); List uvs = combinedTexture.getResultUVS(); @@ -173,13 +174,19 @@ public final class MaterialContext implements Savable { uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float, BufferUtils.createFloatBuffer(uvs.toArray(new Vector2f[uvs.size()]))); geometry.getMesh().setBuffer(uvCoordsBuffer); }//uvs might be null if the user assigned non existing UV coordinates group name to the mesh (this should be fixed in blender file) + + if(usedUserUVSet != null) { + userDefinedUVCoordinates = new HashMap<>(userDefinedUVCoordinates); + userDefinedUVCoordinates.remove(usedUserUVSet); + } } else { LOGGER.log(Level.WARNING, "The texture could not be applied because JME only supports up to {0} different UV's.", TextureHelper.TEXCOORD_TYPES.length); } } - } else if (userDefinedUVCoordinates != null && userDefinedUVCoordinates.size() > 0) { - LOGGER.fine("No textures found for the mesh, but UV coordinates are applied."); - int textureIndex = 0; + } + + if (userDefinedUVCoordinates != null && userDefinedUVCoordinates.size() > 0) { + LOGGER.fine("Storing unused, user defined UV coordinates sets."); if (userDefinedUVCoordinates.size() > TextureHelper.TEXCOORD_TYPES.length) { LOGGER.log(Level.WARNING, "The blender file has defined more than {0} different UV coordinates for the mesh. JME supports only {0} UV coordinates buffers.", TextureHelper.TEXCOORD_TYPES.length); } @@ -190,7 +197,9 @@ public final class MaterialContext implements Savable { uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float, BufferUtils.createFloatBuffer(uvs.toArray(new Vector2f[uvs.size()]))); geometry.getMesh().setBuffer(uvCoordsBuffer); } else { - LOGGER.log(Level.WARNING, "The texture could not be applied because JME only supports up to {0} different UV's.", TextureHelper.TEXCOORD_TYPES.length); + LOGGER.log(Level.WARNING, "The user's UV set named: '{0}' could not be stored because JME only supports up to {1} different UV's.", new Object[] { + entry.getKey(), TextureHelper.TEXCOORD_TYPES.length + }); } } } diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/CombinedTexture.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/CombinedTexture.java index e406447eb..6c40542e2 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/CombinedTexture.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/textures/CombinedTexture.java @@ -119,22 +119,24 @@ public class CombinedTexture { } } - /** - * This method flattens the texture and creates a single result of Texture2D - * type. - * - * @param geometry - * the geometry the texture is created for - * @param geometriesOMA - * the old memory address of the geometries list that the given - * geometry belongs to (needed for bounding box creation) - * @param userDefinedUVCoordinates - * the UV's defined by user (null or zero length table if none - * were defined) - * @param blenderContext - * the blender context - */ - public void flatten(Geometry geometry, Long geometriesOMA, Map> userDefinedUVCoordinates, BlenderContext blenderContext) { + /** + * This method flattens the texture and creates a single result of Texture2D + * type. + * + * @param geometry + * the geometry the texture is created for + * @param geometriesOMA + * the old memory address of the geometries list that the given + * geometry belongs to (needed for bounding box creation) + * @param userDefinedUVCoordinates + * the UV's defined by user (null or zero length table if none + * were defined) + * @param blenderContext + * the blender context + * @return the name of the user UV coordinates used (null if the UV's were + * generated) + */ + public String flatten(Geometry geometry, Long geometriesOMA, Map> userDefinedUVCoordinates, BlenderContext blenderContext) { Mesh mesh = geometry.getMesh(); Texture previousTexture = null; UVCoordinatesType masterUVCoordinatesType = null; @@ -226,6 +228,7 @@ public class CombinedTexture { } resultUVS = ((TriangulatedTexture) resultTexture).getResultUVS(); resultTexture = ((TriangulatedTexture) resultTexture).getResultTexture(); + masterUserUVSetName = null; } // setting additional data @@ -234,6 +237,8 @@ public class CombinedTexture { // otherwise ugly lines appear between the mesh faces resultTexture.setMagFilter(MagFilter.Nearest); resultTexture.setMinFilter(MinFilter.NearestNoMipMaps); + + return masterUserUVSetName; } /** From 271f6492dd852830ab5d1ff20694ea1f4583b201 Mon Sep 17 00:00:00 2001 From: Paul Speed Date: Tue, 5 Apr 2016 09:12:45 -0400 Subject: [PATCH 3/4] Fixed a bug in cloning that prevented a null from being usable as a 'precloned' value. This made Spatial attempt to clone its parent. --- jme3-core/src/main/java/com/jme3/util/clone/Cloner.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/util/clone/Cloner.java b/jme3-core/src/main/java/com/jme3/util/clone/Cloner.java index 4b812006f..3cc2b5576 100644 --- a/jme3-core/src/main/java/com/jme3/util/clone/Cloner.java +++ b/jme3-core/src/main/java/com/jme3/util/clone/Cloner.java @@ -207,10 +207,10 @@ public class Cloner { // Check the index to see if we already have it Object clone = index.get(object); - if( clone != null ) { + if( clone != null || index.containsKey(object) ) { if( log.isLoggable(Level.FINER) ) { log.finer("cloned:" + object.getClass() + "@" + System.identityHashCode(object) - + " as cached:" + clone.getClass() + "@" + System.identityHashCode(clone)); + + " as cached:" + (clone == null ? "null" : (clone.getClass() + "@" + System.identityHashCode(clone)))); } return type.cast(clone); } From 80f4e0493528d7689ea306d95b72b1de6f0ba576 Mon Sep 17 00:00:00 2001 From: Paul Speed Date: Tue, 5 Apr 2016 11:01:27 -0400 Subject: [PATCH 4/4] Fixed cloning to not confuse the hardware skinning safety check that attempts to protect users from shared materials. --- .../com/jme3/animation/SkeletonControl.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/jme3-core/src/main/java/com/jme3/animation/SkeletonControl.java b/jme3-core/src/main/java/com/jme3/animation/SkeletonControl.java index 4a69c2d7c..b753ad2cb 100644 --- a/jme3-core/src/main/java/com/jme3/animation/SkeletonControl.java +++ b/jme3-core/src/main/java/com/jme3/animation/SkeletonControl.java @@ -409,7 +409,23 @@ public class SkeletonControl extends AbstractControl implements Cloneable, JmeCl // Not automatic set cloning yet Set newMaterials = new HashSet(); for( Material m : this.materials ) { - newMaterials.add(cloner.clone(m)); + Material mClone = cloner.clone(m); + newMaterials.add(mClone); + if( mClone != m ) { + // Material was really cloned so clear the bone matrices in case + // this is hardware skinned. This allows a local version to be + // used and will be reset on the material. Really this just avoids + // the 'safety' check in controlRenderHardware(). Right now material + // doesn't clone itself with the cloner (and doesn't clone its parameters) + // else this would be unnecessary. + MatParam boneMatrices = mClone.getParam("BoneMatrices"); + + // ...because for some strange reason you can't clear a non-existant + // parameter. + if( boneMatrices != null ) { + mClone.clearParam("BoneMatrices"); + } + } } this.materials = newMaterials; }