Fixes to vertex color buffer applying. This functionality is also moved from MEshHelper to MeshBuilder.

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9518 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
Kae..pl 13 years ago
parent 53dd4c2941
commit 691ebcb53d
  1. 48
      engine/src/blender/com/jme3/scene/plugins/blender/AbstractBlenderHelper.java
  2. 69
      engine/src/blender/com/jme3/scene/plugins/blender/meshes/MeshBuilder.java
  3. 35
      engine/src/blender/com/jme3/scene/plugins/blender/meshes/MeshHelper.java

@ -37,10 +37,6 @@ import com.jme3.scene.plugins.blender.exceptions.BlenderFileException;
import com.jme3.scene.plugins.blender.file.Pointer; import com.jme3.scene.plugins.blender.file.Pointer;
import com.jme3.scene.plugins.blender.file.Structure; import com.jme3.scene.plugins.blender.file.Structure;
import com.jme3.scene.plugins.blender.objects.Properties; import com.jme3.scene.plugins.blender.objects.Properties;
import com.jme3.util.BufferUtils;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.util.List;
/** /**
* A purpose of the helper class is to split calculation code into several classes. Each helper after use should be cleared because it can * A purpose of the helper class is to split calculation code into several classes. Each helper after use should be cleared because it can
@ -95,50 +91,6 @@ public abstract class AbstractBlenderHelper {
return true; return true;
} }
/**
* Generate a new ByteBuffer using the given array of byte[4] objects. The ByteBuffer will be 4 * data.length
* long and contain the vector data as data[0][0], data[0][1], data[0][2], data[0][3], data[1][0]... etc.
* @param data
* list of byte[4] objects to place into a new ByteBuffer
*/
protected ByteBuffer createByteBuffer(List<byte[]> data) {
if (data == null) {
return null;
}
ByteBuffer buff = BufferUtils.createByteBuffer(4 * data.size());
for (byte[] v : data) {
if (v != null) {
buff.put(v[0]).put(v[1]).put(v[2]).put(v[3]);
} else {
buff.put((byte)0).put((byte)0).put((byte)0).put((byte)0);
}
}
buff.flip();
return buff;
}
/**
* Generate a new FloatBuffer using the given array of float[4] objects. The FloatBuffer will be 4 * data.length
* long and contain the vector data as data[0][0], data[0][1], data[0][2], data[0][3], data[1][0]... etc.
* @param data
* list of float[4] objects to place into a new FloatBuffer
*/
protected FloatBuffer createFloatBuffer(List<float[]> data) {
if (data == null) {
return null;
}
FloatBuffer buff = BufferUtils.createFloatBuffer(4 * data.size());
for (float[] v : data) {
if (v != null) {
buff.put(v[0]).put(v[1]).put(v[2]).put(v[3]);
} else {
buff.put(0).put(0).put(0).put(0);
}
}
buff.flip();
return buff;
}
/** /**
* This method loads the properties if they are available and defined for the structure. * This method loads the properties if they are available and defined for the structure.
* @param structure * @param structure

@ -1,5 +1,6 @@
package com.jme3.scene.plugins.blender.meshes; package com.jme3.scene.plugins.blender.meshes;
import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -8,10 +9,13 @@ import java.util.Map;
import com.jme3.math.FastMath; import com.jme3.math.FastMath;
import com.jme3.math.Vector2f; import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.util.BufferUtils;
/*package*/ class MeshBuilder { /*package*/ class MeshBuilder {
/** An array of reference vertices. */ /** An array of reference vertices. */
private Vector3f[] vertices; private Vector3f[] vertices;
/** An list of vertices colors. */
private List<byte[]> verticesColors;
/** A variable that indicates if the model uses generated textures. */ /** A variable that indicates if the model uses generated textures. */
private boolean usesGeneratedTextures; private boolean usesGeneratedTextures;
@ -27,6 +31,8 @@ import com.jme3.math.Vector3f;
private Map<Integer, List<Vector3f>> normalMap = new HashMap<Integer, List<Vector3f>>(); private Map<Integer, List<Vector3f>> normalMap = new HashMap<Integer, List<Vector3f>>();
/** The following map sorts vertices by material number (because in jme Mesh can have only one material). */ /** The following map sorts vertices by material number (because in jme Mesh can have only one material). */
private Map<Integer, List<Vector3f>> vertexMap = new HashMap<Integer, List<Vector3f>>(); private Map<Integer, List<Vector3f>> vertexMap = new HashMap<Integer, List<Vector3f>>();
/** The following map sorts vertices colors by material number (because in jme Mesh can have only one material). */
private Map<Integer, List<byte[]>> vertexColorsMap = new HashMap<Integer, List<byte[]>>();
/** The following map sorts indexes by material number (because in jme Mesh can have only one material). */ /** The following map sorts indexes by material number (because in jme Mesh can have only one material). */
private Map<Integer, List<Integer>> indexMap = new HashMap<Integer, List<Integer>>(); private Map<Integer, List<Integer>> indexMap = new HashMap<Integer, List<Integer>>();
/** A map between material number and UV coordinates of mesh that has this material applied. */ /** A map between material number and UV coordinates of mesh that has this material applied. */
@ -39,11 +45,12 @@ import com.jme3.math.Vector3f;
* @param vertices the reference vertices array * @param vertices the reference vertices array
* @param usesGeneratedTextures a variable that indicates if the model uses generated textures or not * @param usesGeneratedTextures a variable that indicates if the model uses generated textures or not
*/ */
public MeshBuilder(Vector3f[] vertices, boolean usesGeneratedTextures) { public MeshBuilder(Vector3f[] vertices, List<byte[]> verticesColors, boolean usesGeneratedTextures) {
if(vertices == null || vertices.length == 0) { if(vertices == null || vertices.length == 0) {
throw new IllegalArgumentException("No vertices loaded to build mesh."); throw new IllegalArgumentException("No vertices loaded to build mesh.");
} }
this.vertices = vertices; this.vertices = vertices;
this.verticesColors = verticesColors;
this.usesGeneratedTextures = usesGeneratedTextures; this.usesGeneratedTextures = usesGeneratedTextures;
globalVertexReferenceMap = new HashMap<Integer, Map<Integer, List<Integer>>>(vertices.length); globalVertexReferenceMap = new HashMap<Integer, Map<Integer, List<Integer>>>(vertices.length);
} }
@ -56,11 +63,15 @@ import com.jme3.math.Vector3f;
* @param smooth indicates if this face should have smooth shading or flat shading * @param smooth indicates if this face should have smooth shading or flat shading
* @param materialNumber the material number for this face * @param materialNumber the material number for this face
* @param uvs a 3-element array of vertices UV coordinates * @param uvs a 3-element array of vertices UV coordinates
* @param quad indicates if the appended face is a part of a quad face (used for creating vertex colors buffer)
* @param faceIndex the face index (used for creating vertex colors buffer)
*/ */
public void appendFace(int v1, int v2, int v3, boolean smooth, int materialNumber, Vector2f[] uvs) { public void appendFace(int v1, int v2, int v3, boolean smooth, int materialNumber, Vector2f[] uvs, boolean quad, int faceIndex) {
if(uvs != null && uvs.length != 3) { if(uvs != null && uvs.length != 3) {
throw new IllegalArgumentException("UV coordinates must be a 3-element array!"); throw new IllegalArgumentException("UV coordinates must be a 3-element array!");
} }
//getting the required lists
List<Integer> indexList = indexMap.get(materialNumber); List<Integer> indexList = indexMap.get(materialNumber);
if (indexList == null) { if (indexList == null) {
indexList = new ArrayList<Integer>(); indexList = new ArrayList<Integer>();
@ -71,6 +82,12 @@ import com.jme3.math.Vector3f;
vertexList = new ArrayList<Vector3f>(); vertexList = new ArrayList<Vector3f>();
vertexMap.put(materialNumber, vertexList); vertexMap.put(materialNumber, vertexList);
} }
List<byte[]> vertexColorsList = vertexColorsMap != null ? vertexColorsMap.get(materialNumber) : null;
int[] vertexColorIndex = new int[] { 0, 1, 2 };
if(vertexColorsList == null && vertexColorsMap != null) {
vertexColorsList = new ArrayList<byte[]>();
vertexColorsMap.put(materialNumber, vertexColorsList);
}
List<Vector3f> normalList = normalMap.get(materialNumber); List<Vector3f> normalList = normalMap.get(materialNumber);
if (normalList == null) { if (normalList == null) {
normalList = new ArrayList<Vector3f>(); normalList = new ArrayList<Vector3f>();
@ -81,7 +98,6 @@ import com.jme3.math.Vector3f;
vertexReferenceMap = new HashMap<Integer, List<Integer>>(); vertexReferenceMap = new HashMap<Integer, List<Integer>>();
globalVertexReferenceMap.put(materialNumber, vertexReferenceMap); globalVertexReferenceMap.put(materialNumber, vertexReferenceMap);
} }
List<Vector2f> uvCoordinatesList = null; List<Vector2f> uvCoordinatesList = null;
if(uvs != null) { if(uvs != null) {
uvCoordinatesList = uvCoordinates.get(Integer.valueOf(materialNumber)); uvCoordinatesList = uvCoordinates.get(Integer.valueOf(materialNumber));
@ -91,6 +107,13 @@ import com.jme3.math.Vector3f;
} }
} }
faceIndex *= 4;
if(quad) {
vertexColorIndex[1] = 2;
vertexColorIndex[2] = 3;
}
//creating faces
Integer[] index = new Integer[] {v1, v2, v3}; Integer[] index = new Integer[] {v1, v2, v3};
Vector3f n = FastMath.computeNormal(vertices[v1], vertices[v2], vertices[v3]); Vector3f n = FastMath.computeNormal(vertices[v1], vertices[v2], vertices[v3]);
this.addNormal(n, globalNormalMap, smooth, vertices[v1], vertices[v2], vertices[v3]); this.addNormal(n, globalNormalMap, smooth, vertices[v1], vertices[v2], vertices[v3]);
@ -99,6 +122,9 @@ import com.jme3.math.Vector3f;
if(!vertexReferenceMap.containsKey(index[i])) { if(!vertexReferenceMap.containsKey(index[i])) {
this.appendVertexReference(index[i], vertexList.size(), vertexReferenceMap); this.appendVertexReference(index[i], vertexList.size(), vertexReferenceMap);
vertexList.add(vertices[index[i]]); vertexList.add(vertices[index[i]]);
if(verticesColors != null) {
vertexColorsList.add(verticesColors.get(faceIndex + vertexColorIndex[i]));
}
normalList.add(globalNormalMap.get(vertices[index[i]])); normalList.add(globalNormalMap.get(vertices[index[i]]));
if(uvCoordinatesList != null) { if(uvCoordinatesList != null) {
uvsMap.put(vertexList.size(), uvs[i]); uvsMap.put(vertexList.size(), uvs[i]);
@ -118,6 +144,9 @@ import com.jme3.math.Vector3f;
this.appendVertexReference(index[i], vertexList.size(), vertexReferenceMap); this.appendVertexReference(index[i], vertexList.size(), vertexReferenceMap);
uvsMap.put(vertexList.size(), uvs[i]); uvsMap.put(vertexList.size(), uvs[i]);
vertexList.add(vertices[index[i]]); vertexList.add(vertices[index[i]]);
if(verticesColors != null) {
vertexColorsList.add(verticesColors.get(faceIndex + vertexColorIndex[i]));
}
normalList.add(globalNormalMap.get(vertices[index[i]])); normalList.add(globalNormalMap.get(vertices[index[i]]));
uvCoordinatesList.add(uvs[i]); uvCoordinatesList.add(uvs[i]);
index[i] = vertexList.size() - 1; index[i] = vertexList.size() - 1;
@ -136,6 +165,9 @@ import com.jme3.math.Vector3f;
uvsMap.put(vertexList.size(), uvs[i]); uvsMap.put(vertexList.size(), uvs[i]);
} }
vertexList.add(vertices[index[i]]); vertexList.add(vertices[index[i]]);
if(verticesColors != null) {
vertexColorsList.add(verticesColors.get(faceIndex + vertexColorIndex[i]));
}
normalList.add(globalNormalMap.get(vertices[index[i]])); normalList.add(globalNormalMap.get(vertices[index[i]]));
} }
} }
@ -149,6 +181,8 @@ import com.jme3.math.Vector3f;
} }
/** /**
* @param materialNumber
* the material index
* @return result vertices array * @return result vertices array
*/ */
public Vector3f[] getVertices(int materialNumber) { public Vector3f[] getVertices(int materialNumber) {
@ -156,6 +190,8 @@ import com.jme3.math.Vector3f;
} }
/** /**
* @param materialNumber
* the material index
* @return the amount of result vertices * @return the amount of result vertices
*/ */
public int getVerticesAmount(int materialNumber) { public int getVerticesAmount(int materialNumber) {
@ -163,12 +199,36 @@ import com.jme3.math.Vector3f;
} }
/** /**
* @param materialNumber
* the material index
* @return normals result array * @return normals result array
*/ */
public Vector3f[] getNormals(int materialNumber) { public Vector3f[] getNormals(int materialNumber) {
return normalMap.get(materialNumber).toArray(new Vector3f[normalMap.get(materialNumber).size()]); return normalMap.get(materialNumber).toArray(new Vector3f[normalMap.get(materialNumber).size()]);
} }
/**
* @param materialNumber
* the material index
* @return the vertices colors buffer or null if no vertex colors is set
*/
public ByteBuffer getVertexColorsBuffer(int materialNumber) {
ByteBuffer result = null;
if (verticesColors != null && vertexColorsMap.get(materialNumber) != null) {
List<byte[]> data = vertexColorsMap.get(materialNumber);
result = BufferUtils.createByteBuffer(4 * data.size());
for (byte[] v : data) {
if (v != null) {
result.put(v[0]).put(v[1]).put(v[2]).put(v[3]);
} else {
result.put((byte)0).put((byte)0).put((byte)0).put((byte)0);
}
}
result.flip();
}
return result;
}
/** /**
* @return a map between material number and the mesh part vertices indices * @return a map between material number and the mesh part vertices indices
*/ */
@ -184,7 +244,8 @@ import com.jme3.math.Vector3f;
} }
/** /**
* @param materialNumber the material number that is appied to the mesh * @param materialNumber
* the material number that is appied to the mesh
* @return UV coordinates of vertices that belong to the required mesh part * @return UV coordinates of vertices that belong to the required mesh part
*/ */
public List<Vector2f> getUVCoordinates(int materialNumber) { public List<Vector2f> getUVCoordinates(int materialNumber) {

@ -31,9 +31,7 @@
*/ */
package com.jme3.scene.plugins.blender.meshes; package com.jme3.scene.plugins.blender.meshes;
import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
@ -87,8 +85,7 @@ public class MeshHelper extends AbstractBlenderHelper {
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public List<Geometry> toMesh(Structure structure, BlenderContext blenderContext) throws BlenderFileException { public List<Geometry> toMesh(Structure structure, BlenderContext blenderContext) throws BlenderFileException {
List<Geometry> geometries = (List<Geometry>) blenderContext.getLoadedFeature(structure.getOldMemoryAddress(), List<Geometry> geometries = (List<Geometry>) blenderContext.getLoadedFeature(structure.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);
LoadedFeatureDataType.LOADED_FEATURE);
if (geometries != null) { if (geometries != null) {
List<Geometry> copiedGeometries = new ArrayList<Geometry>(geometries.size()); List<Geometry> copiedGeometries = new ArrayList<Geometry>(geometries.size());
for (Geometry geometry : geometries) { for (Geometry geometry : geometries) {
@ -108,12 +105,11 @@ public class MeshHelper extends AbstractBlenderHelper {
materials = materialHelper.getMaterials(structure, blenderContext); materials = materialHelper.getMaterials(structure, blenderContext);
} }
// reading vertices // reading vertices and their colors
Vector3f[] vertices = this.getVertices(structure, blenderContext); Vector3f[] vertices = this.getVertices(structure, blenderContext);
MeshBuilder meshBuilder = new MeshBuilder(vertices, this.areGeneratedTexturesPresent(materials));
// vertices Colors
List<byte[]> verticesColors = this.getVerticesColors(structure, blenderContext); List<byte[]> verticesColors = this.getVerticesColors(structure, blenderContext);
MeshBuilder meshBuilder = new MeshBuilder(vertices, verticesColors, this.areGeneratedTexturesPresent(materials));
Pointer pMFace = (Pointer) structure.getFieldValue("mface"); Pointer pMFace = (Pointer) structure.getFieldValue("mface");
List<Structure> mFaces = null; List<Structure> mFaces = null;
@ -138,7 +134,6 @@ public class MeshHelper extends AbstractBlenderHelper {
} }
// indicates if the material with the specified number should have a texture attached // indicates if the material with the specified number should have a texture attached
int vertexColorIndex = 0;
Vector2f[] uvCoordinatesForFace = new Vector2f[3]; Vector2f[] uvCoordinatesForFace = new Vector2f[3];
for (int i = 0; i < mFaces.size(); ++i) { for (int i = 0; i < mFaces.size(); ++i) {
Structure mFace = mFaces.get(i); Structure mFace = mFaces.get(i);
@ -160,25 +155,14 @@ public class MeshHelper extends AbstractBlenderHelper {
int v3 = ((Number) mFace.getFieldValue("v3")).intValue(); int v3 = ((Number) mFace.getFieldValue("v3")).intValue();
int v4 = ((Number) mFace.getFieldValue("v4")).intValue(); int v4 = ((Number) mFace.getFieldValue("v4")).intValue();
meshBuilder.appendFace(v1, v2, v3, smooth, materialNumber, uvs == null ? null : uvCoordinatesForFace); meshBuilder.appendFace(v1, v2, v3, smooth, materialNumber, uvs == null ? null : uvCoordinatesForFace, false, i);
if (v4 > 0) { if (v4 > 0) {
if (uvs != null) { if (uvs != null) {
uvCoordinatesForFace[0] = new Vector2f(uvs.get(0, 0).floatValue(), uvs.get(0, 1).floatValue()); uvCoordinatesForFace[0] = new Vector2f(uvs.get(0, 0).floatValue(), uvs.get(0, 1).floatValue());
uvCoordinatesForFace[1] = new Vector2f(uvs.get(2, 0).floatValue(), uvs.get(2, 1).floatValue()); uvCoordinatesForFace[1] = new Vector2f(uvs.get(2, 0).floatValue(), uvs.get(2, 1).floatValue());
uvCoordinatesForFace[2] = new Vector2f(uvs.get(3, 0).floatValue(), uvs.get(3, 1).floatValue()); uvCoordinatesForFace[2] = new Vector2f(uvs.get(3, 0).floatValue(), uvs.get(3, 1).floatValue());
} }
meshBuilder.appendFace(v1, v3, v4, smooth, materialNumber, uvs == null ? null : uvCoordinatesForFace); meshBuilder.appendFace(v1, v3, v4, smooth, materialNumber, uvs == null ? null : uvCoordinatesForFace, true, i);
if (verticesColors != null) {
verticesColors.add(vertexColorIndex + 3, verticesColors.get(vertexColorIndex));
verticesColors.add(vertexColorIndex + 4, verticesColors.get(vertexColorIndex + 2));
}
vertexColorIndex += 6;
} else {
if (verticesColors != null) {
verticesColors.remove(vertexColorIndex + 3);
vertexColorIndex += 3;
}
} }
} }
meshContext.setVertexReferenceMap(meshBuilder.getVertexReferenceMap()); meshContext.setVertexReferenceMap(meshBuilder.getVertexReferenceMap());
@ -200,7 +184,6 @@ public class MeshHelper extends AbstractBlenderHelper {
Properties properties = this.loadProperties(structure, blenderContext); Properties properties = this.loadProperties(structure, blenderContext);
// generating meshes // generating meshes
ByteBuffer verticesColorsBuffer = this.createByteBuffer(verticesColors);
for (Entry<Integer, List<Integer>> meshEntry : meshBuilder.getMeshesMap().entrySet()) { for (Entry<Integer, List<Integer>> meshEntry : meshBuilder.getMeshesMap().entrySet()) {
int materialIndex = meshEntry.getKey(); int materialIndex = meshEntry.getKey();
//key is the material index (or -1 if the material has no texture) //key is the material index (or -1 if the material has no texture)
@ -241,8 +224,8 @@ public class MeshHelper extends AbstractBlenderHelper {
meshContext.setBindPoseBuffer(verticesBind);//this is stored in the context and applied when needed (when animation is applied to the mesh) meshContext.setBindPoseBuffer(verticesBind);//this is stored in the context and applied when needed (when animation is applied to the mesh)
// setting vertices colors // setting vertices colors
if (verticesColorsBuffer != null) { if (verticesColors != null) {
mesh.setBuffer(Type.Color, 4, verticesColorsBuffer); mesh.setBuffer(Type.Color, 4, meshBuilder.getVertexColorsBuffer(materialIndex));
mesh.getBuffer(Type.Color).setNormalized(true); mesh.getBuffer(Type.Color).setNormalized(true);
} }
@ -323,7 +306,7 @@ public class MeshHelper extends AbstractBlenderHelper {
List<byte[]> verticesColors = null; List<byte[]> verticesColors = null;
List<Structure> mCol = null; List<Structure> mCol = null;
if (pMCol.isNotNull()) { if (pMCol.isNotNull()) {
verticesColors = new LinkedList<byte[]>(); verticesColors = new ArrayList<byte[]>();
mCol = pMCol.fetchData(blenderContext.getInputStream()); mCol = pMCol.fetchData(blenderContext.getInputStream());
for (Structure color : mCol) { for (Structure color : mCol) {
byte r = ((Number)color.getFieldValue("r")).byteValue(); byte r = ((Number)color.getFieldValue("r")).byteValue();

Loading…
Cancel
Save