Feature: loading separate UV sets defined by user and loading LightMap.
git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10737 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
d2d86d649b
commit
bf4447bc46
@ -2,9 +2,11 @@ package com.jme3.scene.plugins.blender.materials;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.jme3.material.Material;
|
||||
@ -44,6 +46,7 @@ public final class MaterialContext {
|
||||
public static final int MTEX_SPEC = 0x04;
|
||||
public static final int MTEX_EMIT = 0x40;
|
||||
public static final int MTEX_ALPHA = 0x80;
|
||||
public static final int MTEX_AMB = 0x800;
|
||||
|
||||
/* package */final String name;
|
||||
/* package */final Map<Number, CombinedTexture> loadedTextures;
|
||||
@ -109,7 +112,11 @@ public final class MaterialContext {
|
||||
textureData.mtex = p.fetchData(blenderContext.getInputStream()).get(0);
|
||||
textureData.uvCoordinatesType = ((Number) textureData.mtex.getFieldValue("texco")).intValue();
|
||||
textureData.projectionType = ((Number) textureData.mtex.getFieldValue("mapping")).intValue();
|
||||
|
||||
textureData.uvCoordinatesName = textureData.mtex.getFieldValue("uvName").toString();
|
||||
if(textureData.uvCoordinatesName != null && textureData.uvCoordinatesName.trim().length() == 0) {
|
||||
textureData.uvCoordinatesName = null;
|
||||
}
|
||||
|
||||
Pointer pTex = (Pointer) textureData.mtex.getFieldValue("tex");
|
||||
if (pTex.isNotNull()) {
|
||||
Structure tex = pTex.fetchData(blenderContext.getInputStream()).get(0);
|
||||
@ -136,7 +143,8 @@ public final class MaterialContext {
|
||||
float[] color = new float[] { ((Number) textureData.mtex.getFieldValue("r")).floatValue(), ((Number) textureData.mtex.getFieldValue("g")).floatValue(), ((Number) textureData.mtex.getFieldValue("b")).floatValue() };
|
||||
float colfac = ((Number) textureData.mtex.getFieldValue("colfac")).floatValue();
|
||||
TextureBlender textureBlender = TextureBlenderFactory.createTextureBlender(texture.getImage().getFormat(), texflag, negateTexture, blendType, diffuseColorArray, color, colfac);
|
||||
combinedTexture.add(texture, textureBlender, textureData.uvCoordinatesType, textureData.projectionType, textureData.textureStructure, blenderContext);
|
||||
combinedTexture.add(texture, textureBlender, textureData.uvCoordinatesType, textureData.projectionType,
|
||||
textureData.textureStructure, textureData.uvCoordinatesName, blenderContext);
|
||||
}
|
||||
}
|
||||
if (combinedTexture.getTexturesCount() > 0) {
|
||||
@ -176,7 +184,7 @@ public final class MaterialContext {
|
||||
* @param blenderContext
|
||||
* the blender context
|
||||
*/
|
||||
public void applyMaterial(Geometry geometry, Long geometriesOMA, List<Vector2f> userDefinedUVCoordinates, BlenderContext blenderContext) {
|
||||
public void applyMaterial(Geometry geometry, Long geometriesOMA, LinkedHashMap<String, List<Vector2f>> userDefinedUVCoordinates, BlenderContext blenderContext) {
|
||||
Material material = null;
|
||||
if (shadeless) {
|
||||
material = new Material(blenderContext.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
|
||||
@ -206,30 +214,24 @@ public final class MaterialContext {
|
||||
|
||||
// applying textures
|
||||
if (loadedTextures != null && loadedTextures.size() > 0) {
|
||||
Entry<Number, CombinedTexture> basicUVSOwner = null;
|
||||
int textureIndex = 0;
|
||||
if(loadedTextures.size() > 8) {
|
||||
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 (Entry<Number, CombinedTexture> entry : loadedTextures.entrySet()) {
|
||||
CombinedTexture combinedTexture = entry.getValue();
|
||||
combinedTexture.flatten(geometry, geometriesOMA, userDefinedUVCoordinates, blenderContext);
|
||||
if(textureIndex < TextureHelper.TEXCOORD_TYPES.length) {
|
||||
CombinedTexture combinedTexture = entry.getValue();
|
||||
combinedTexture.flatten(geometry, geometriesOMA, userDefinedUVCoordinates, blenderContext);
|
||||
|
||||
if (basicUVSOwner == null) {
|
||||
basicUVSOwner = entry;
|
||||
} else {
|
||||
combinedTexture.castToUVS(basicUVSOwner.getValue(), blenderContext);
|
||||
this.setTexture(material, entry.getKey().intValue(), combinedTexture.getResultTexture());
|
||||
List<Vector2f> uvs = entry.getValue().getResultUVS();
|
||||
VertexBuffer uvCoordsBuffer = new VertexBuffer(TextureHelper.TEXCOORD_TYPES[textureIndex++]);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if (basicUVSOwner != null) {
|
||||
this.setTexture(material, basicUVSOwner.getKey().intValue(), basicUVSOwner.getValue().getResultTexture());
|
||||
List<Vector2f> basicUVS = basicUVSOwner.getValue().getResultUVS();
|
||||
VertexBuffer uvCoordsBuffer = new VertexBuffer(VertexBuffer.Type.TexCoord);
|
||||
uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float, BufferUtils.createFloatBuffer(basicUVS.toArray(new Vector2f[basicUVS.size()])));
|
||||
geometry.getMesh().setBuffer(uvCoordsBuffer);
|
||||
}
|
||||
} else if (userDefinedUVCoordinates != null && userDefinedUVCoordinates.size() > 0) {
|
||||
VertexBuffer uvCoordsBuffer = new VertexBuffer(VertexBuffer.Type.TexCoord);
|
||||
uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float, BufferUtils.createFloatBuffer(userDefinedUVCoordinates.toArray(new Vector2f[userDefinedUVCoordinates.size()])));
|
||||
geometry.getMesh().setBuffer(uvCoordsBuffer);
|
||||
}
|
||||
|
||||
// applying additional data
|
||||
@ -237,11 +239,7 @@ public final class MaterialContext {
|
||||
if (vertexColor) {
|
||||
material.setBoolean(shadeless ? "VertexColor" : "UseVertexColor", true);
|
||||
}
|
||||
if (this.faceCullMode != null) {
|
||||
material.getAdditionalRenderState().setFaceCullMode(faceCullMode);
|
||||
} else {
|
||||
material.getAdditionalRenderState().setFaceCullMode(blenderContext.getBlenderKey().getFaceCullMode());
|
||||
}
|
||||
material.getAdditionalRenderState().setFaceCullMode(faceCullMode != null ? faceCullMode : blenderContext.getBlenderKey().getFaceCullMode());
|
||||
if (transparent) {
|
||||
material.setTransparent(true);
|
||||
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
|
||||
@ -282,6 +280,9 @@ public final class MaterialContext {
|
||||
LOGGER.warning("JME does not support alpha map on unshaded material. Material name is " + name);
|
||||
}
|
||||
break;
|
||||
case MTEX_AMB:
|
||||
material.setTexture(MaterialHelper.TEXTURE_TYPE_LIGHTMAP, texture);
|
||||
break;
|
||||
default:
|
||||
LOGGER.severe("Unknown mapping type: " + mapTo);
|
||||
}
|
||||
@ -311,7 +312,7 @@ public final class MaterialContext {
|
||||
* @return a map with sorted and filtered textures
|
||||
*/
|
||||
private Map<Number, List<TextureData>> sortAndFilterTextures(List<TextureData> textures) {
|
||||
int[] mappings = new int[] { MTEX_COL, MTEX_NOR, MTEX_EMIT, MTEX_SPEC, MTEX_ALPHA };
|
||||
int[] mappings = new int[] { MTEX_COL, MTEX_NOR, MTEX_EMIT, MTEX_SPEC, MTEX_ALPHA, MTEX_AMB };
|
||||
Map<Number, List<TextureData>> result = new HashMap<Number, List<TextureData>>();
|
||||
for (TextureData data : textures) {
|
||||
Number mapto = (Number) data.mtex.getFieldValue("mapto");
|
||||
@ -413,5 +414,7 @@ public final class MaterialContext {
|
||||
Structure textureStructure;
|
||||
int uvCoordinatesType;
|
||||
int projectionType;
|
||||
/** The name of the user's UV coordinates that are used for this texture. */
|
||||
String uvCoordinatesName;
|
||||
}
|
||||
}
|
||||
|
@ -65,6 +65,7 @@ public class MaterialHelper extends AbstractBlenderHelper {
|
||||
public static final String TEXTURE_TYPE_SPECULAR = "SpecularMap";
|
||||
public static final String TEXTURE_TYPE_GLOW = "GlowMap";
|
||||
public static final String TEXTURE_TYPE_ALPHA = "AlphaMap";
|
||||
public static final String TEXTURE_TYPE_LIGHTMAP = "LightMap";
|
||||
|
||||
public static final Integer ALPHA_MASK_NONE = Integer.valueOf(0);
|
||||
public static final Integer ALPHA_MASK_CIRCLE = Integer.valueOf(1);
|
||||
|
@ -3,13 +3,16 @@ package com.jme3.scene.plugins.blender.meshes;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.jme3.math.FastMath;
|
||||
import com.jme3.math.Vector2f;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.scene.plugins.blender.textures.UserUVCollection;
|
||||
import com.jme3.util.BufferUtils;
|
||||
|
||||
/**
|
||||
@ -17,8 +20,8 @@ import com.jme3.util.BufferUtils;
|
||||
*
|
||||
* @author Marcin Roguski (Kaelthas)
|
||||
*/
|
||||
/*package*/class MeshBuilder {
|
||||
private static final Logger LOGGER = Logger.getLogger(MeshBuilder.class.getName());
|
||||
/* package */class MeshBuilder {
|
||||
private static final Logger LOGGER = Logger.getLogger(MeshBuilder.class.getName());
|
||||
|
||||
/** An array of reference vertices. */
|
||||
private Vector3f[][] verticesAndNormals;
|
||||
@ -26,25 +29,21 @@ import com.jme3.util.BufferUtils;
|
||||
private List<byte[]> verticesColors;
|
||||
/** A variable that indicates if the model uses generated textures. */
|
||||
private boolean usesGeneratedTextures;
|
||||
|
||||
/**
|
||||
* This map's key is the vertex index from 'vertices 'table and the value are indices from 'vertexList'
|
||||
* positions (it simply tells which vertex is referenced where in the result list).
|
||||
*/
|
||||
private Map<Integer, Map<Integer, List<Integer>>> globalVertexReferenceMap;
|
||||
|
||||
/** A map between vertex index and its UV coordinates. */
|
||||
private Map<Integer, Vector2f> uvsMap = new HashMap<Integer, Vector2f>();
|
||||
/** The following map sorts vertices by material number (because in jme Mesh can have only one material). */
|
||||
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). */
|
||||
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[]>>();
|
||||
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). */
|
||||
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. */
|
||||
private Map<Integer, List<Vector2f>> uvCoordinates = new HashMap<Integer, List<Vector2f>>(); // <material_number; list of uv coordinates for mesh's vertices>
|
||||
private Map<Integer, List<Integer>> indexMap = new HashMap<Integer, List<Integer>>();
|
||||
/** A collection of user defined UV coordinates (one mesh can have more than one such mappings). */
|
||||
private UserUVCollection userUVCollection = new UserUVCollection();
|
||||
|
||||
/**
|
||||
* Constructor. Stores the given array (not copying it).
|
||||
@ -100,16 +99,20 @@ import com.jme3.util.BufferUtils;
|
||||
* indicates if this face should have smooth shading or flat shading
|
||||
* @param materialNumber
|
||||
* the material number for this face
|
||||
* @param uvs
|
||||
* a 3-element array of vertices UV coordinates
|
||||
* @param uvsForFace
|
||||
* a 3-element array of vertices UV coordinates mapped to the UV's set name
|
||||
* @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, boolean quad, int faceIndex) {
|
||||
if (uvs != null && uvs.length != 3) {
|
||||
throw new IllegalArgumentException("UV coordinates must be a 3-element array!");
|
||||
public void appendFace(int v1, int v2, int v3, boolean smooth, int materialNumber, Map<String, Vector2f[]> uvsForFace, boolean quad, int faceIndex) {
|
||||
if (uvsForFace != null && uvsForFace.size() > 0) {
|
||||
for (Entry<String, Vector2f[]> entry : uvsForFace.entrySet()) {
|
||||
if (entry.getValue().length != 3) {
|
||||
throw new IllegalArgumentException("UV coordinates must be a 3-element array!" + (entry.getKey() != null ? " (UV set name: " + entry.getKey() + ')' : ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// getting the required lists
|
||||
@ -139,14 +142,6 @@ import com.jme3.util.BufferUtils;
|
||||
vertexReferenceMap = new HashMap<Integer, List<Integer>>();
|
||||
globalVertexReferenceMap.put(materialNumber, vertexReferenceMap);
|
||||
}
|
||||
List<Vector2f> uvCoordinatesList = null;
|
||||
if (uvs != null) {
|
||||
uvCoordinatesList = uvCoordinates.get(Integer.valueOf(materialNumber));
|
||||
if (uvCoordinatesList == null) {
|
||||
uvCoordinatesList = new ArrayList<Vector2f>();
|
||||
uvCoordinates.put(Integer.valueOf(materialNumber), uvCoordinatesList);
|
||||
}
|
||||
}
|
||||
|
||||
faceIndex *= 4;
|
||||
if (quad) {
|
||||
@ -159,38 +154,55 @@ import com.jme3.util.BufferUtils;
|
||||
if (smooth && !usesGeneratedTextures) {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (!vertexReferenceMap.containsKey(index[i])) {
|
||||
//if this index is not yet used then create another face
|
||||
this.appendVertexReference(index[i], vertexList.size(), vertexReferenceMap);
|
||||
if (uvsForFace != null) {
|
||||
for (Entry<String, Vector2f[]> entry : uvsForFace.entrySet()) {
|
||||
userUVCollection.addUV(materialNumber, entry.getKey(), entry.getValue()[i], vertexList.size());
|
||||
}
|
||||
}
|
||||
|
||||
vertexList.add(verticesAndNormals[index[i]][0]);
|
||||
if (verticesColors != null) {
|
||||
vertexColorsList.add(verticesColors.get(faceIndex + vertexColorIndex[i]));
|
||||
}
|
||||
normalList.add(verticesAndNormals[index[i]][1]);
|
||||
if (uvCoordinatesList != null) {
|
||||
uvsMap.put(vertexList.size(), uvs[i]);
|
||||
uvCoordinatesList.add(uvs[i]);
|
||||
}
|
||||
|
||||
index[i] = vertexList.size() - 1;
|
||||
} else if (uvCoordinatesList != null) {
|
||||
} else if (uvsForFace != null) {
|
||||
//if the index is used then check if the vertexe's UV coordinates match, if yes then the vertex doesn't have separate UV's
|
||||
//in different faces so we can use it here as well, if UV's are different in separate faces the we need to add this vert
|
||||
//because in jme one vertex can have only on UV coordinate
|
||||
boolean vertexAlreadyUsed = false;
|
||||
for (Integer vertexIndex : vertexReferenceMap.get(index[i])) {
|
||||
if (uvs[i].equals(uvsMap.get(vertexIndex))) {
|
||||
int vertexUseCounter = 0;
|
||||
for (Entry<String, Vector2f[]> entry : uvsForFace.entrySet()) {
|
||||
if (entry.getValue()[i].equals(userUVCollection.getUVForVertex(entry.getKey(), vertexIndex))) {
|
||||
++vertexUseCounter;
|
||||
}
|
||||
}
|
||||
if (vertexUseCounter == uvsForFace.size()) {
|
||||
vertexAlreadyUsed = true;
|
||||
index[i] = vertexIndex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!vertexAlreadyUsed) {
|
||||
// treat this face as a new one because its vertices have separate UV's
|
||||
this.appendVertexReference(index[i], vertexList.size(), vertexReferenceMap);
|
||||
uvsMap.put(vertexList.size(), uvs[i]);
|
||||
for (Entry<String, Vector2f[]> entry : uvsForFace.entrySet()) {
|
||||
userUVCollection.addUV(materialNumber, entry.getKey(), entry.getValue()[i], vertexList.size());
|
||||
}
|
||||
vertexList.add(verticesAndNormals[index[i]][0]);
|
||||
if (verticesColors != null) {
|
||||
vertexColorsList.add(verticesColors.get(faceIndex + vertexColorIndex[i]));
|
||||
}
|
||||
normalList.add(verticesAndNormals[index[i]][1]);
|
||||
uvCoordinatesList.add(uvs[i]);
|
||||
index[i] = vertexList.size() - 1;
|
||||
}
|
||||
} else {
|
||||
//use this index again
|
||||
index[i] = vertexList.indexOf(verticesAndNormals[index[i]][0]);
|
||||
}
|
||||
indexList.add(index[i]);
|
||||
@ -200,9 +212,10 @@ import com.jme3.util.BufferUtils;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
indexList.add(vertexList.size());
|
||||
this.appendVertexReference(index[i], vertexList.size(), vertexReferenceMap);
|
||||
if (uvCoordinatesList != null) {
|
||||
uvCoordinatesList.add(uvs[i]);
|
||||
uvsMap.put(vertexList.size(), uvs[i]);
|
||||
if (uvsForFace != null) {
|
||||
for (Entry<String, Vector2f[]> entry : uvsForFace.entrySet()) {
|
||||
userUVCollection.addUV(materialNumber, entry.getKey(), entry.getValue()[i], vertexList.size());
|
||||
}
|
||||
}
|
||||
vertexList.add(verticesAndNormals[index[i]][0]);
|
||||
if (verticesColors != null) {
|
||||
@ -288,15 +301,15 @@ import com.jme3.util.BufferUtils;
|
||||
* the material number that is appied to the mesh
|
||||
* @return UV coordinates of vertices that belong to the required mesh part
|
||||
*/
|
||||
public List<Vector2f> getUVCoordinates(int materialNumber) {
|
||||
return uvCoordinates.get(materialNumber);
|
||||
public LinkedHashMap<String, List<Vector2f>> getUVCoordinates(int materialNumber) {
|
||||
return userUVCollection.getUVCoordinates(materialNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return indicates if the mesh has UV coordinates
|
||||
*/
|
||||
public boolean hasUVCoordinates() {
|
||||
return uvCoordinates.size() > 0;
|
||||
return userUVCollection.hasUVCoordinates();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -32,7 +32,10 @@
|
||||
package com.jme3.scene.plugins.blender.meshes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@ -55,6 +58,7 @@ import com.jme3.scene.plugins.blender.file.Structure;
|
||||
import com.jme3.scene.plugins.blender.materials.MaterialContext;
|
||||
import com.jme3.scene.plugins.blender.materials.MaterialHelper;
|
||||
import com.jme3.scene.plugins.blender.objects.Properties;
|
||||
import com.jme3.scene.plugins.blender.textures.TextureHelper;
|
||||
import com.jme3.util.BufferUtils;
|
||||
|
||||
/**
|
||||
@ -63,7 +67,12 @@ import com.jme3.util.BufferUtils;
|
||||
* @author Marcin Roguski (Kaelthas)
|
||||
*/
|
||||
public class MeshHelper extends AbstractBlenderHelper {
|
||||
private static final Logger LOGGER = Logger.getLogger(MeshHelper.class.getName());
|
||||
private static final Logger LOGGER = Logger.getLogger(MeshHelper.class.getName());
|
||||
|
||||
/** A type of UV data layer in traditional faced mesh (triangles or quads). */
|
||||
private static final int UV_DATA_LAYER_TYPE_FMESH = 5;
|
||||
/** A type of UV data layer in bmesh type. */
|
||||
private static final int UV_DATA_LAYER_TYPE_BMESH = 16;
|
||||
|
||||
/**
|
||||
* This constructor parses the given blender version and stores the result. Some functionalities may differ in different blender
|
||||
@ -213,7 +222,7 @@ public class MeshHelper extends AbstractBlenderHelper {
|
||||
for (Geometry geometry : geometries) {
|
||||
int materialNumber = meshContext.getMaterialIndex(geometry);
|
||||
if (materials[materialNumber] != null) {
|
||||
List<Vector2f> uvCoordinates = meshBuilder.getUVCoordinates(materialNumber);
|
||||
LinkedHashMap<String, List<Vector2f>> uvCoordinates = meshBuilder.getUVCoordinates(materialNumber);
|
||||
MaterialContext materialContext = materials[materialNumber];
|
||||
materialContext.applyMaterial(geometry, structure.getOldMemoryAddress(), uvCoordinates, blenderContext);
|
||||
} else {
|
||||
@ -223,17 +232,26 @@ public class MeshHelper extends AbstractBlenderHelper {
|
||||
}
|
||||
} else {
|
||||
// add UV coordinates if they are defined even if the material is not applied to the model
|
||||
VertexBuffer uvCoordsBuffer = null;
|
||||
List<VertexBuffer> uvCoordsBuffer = null;
|
||||
if (meshBuilder.hasUVCoordinates()) {
|
||||
List<Vector2f> uvs = meshBuilder.getUVCoordinates(0);
|
||||
uvCoordsBuffer = new VertexBuffer(Type.TexCoord);
|
||||
uvCoordsBuffer.setupData(Usage.Static, 2, Format.Float, BufferUtils.createFloatBuffer(uvs.toArray(new Vector2f[uvs.size()])));
|
||||
Map<String, List<Vector2f>> uvs = meshBuilder.getUVCoordinates(0);
|
||||
if (uvs != null && uvs.size() > 0) {
|
||||
uvCoordsBuffer = new ArrayList<VertexBuffer>(uvs.size());
|
||||
int uvIndex = 0;
|
||||
for (Entry<String, List<Vector2f>> entry : uvs.entrySet()) {
|
||||
VertexBuffer buffer = new VertexBuffer(TextureHelper.TEXCOORD_TYPES[uvIndex++]);
|
||||
buffer.setupData(Usage.Static, 2, Format.Float, BufferUtils.createFloatBuffer(entry.getValue().toArray(new Vector2f[uvs.size()])));
|
||||
uvCoordsBuffer.add(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Geometry geometry : geometries) {
|
||||
geometry.setMaterial(blenderContext.getDefaultMaterial());
|
||||
if (uvCoordsBuffer != null) {
|
||||
geometry.getMesh().setBuffer(uvCoordsBuffer);
|
||||
for (VertexBuffer buffer : uvCoordsBuffer) {
|
||||
geometry.getMesh().setBuffer(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -254,6 +272,67 @@ public class MeshHelper extends AbstractBlenderHelper {
|
||||
return pMLoop != null && pMPoly != null && pMLoop.isNotNull() && pMPoly.isNotNull();
|
||||
}
|
||||
|
||||
/**
|
||||
* The method loads the UV coordinates. The result is a map where the key is the user's UV set name and the values are UV coordinates.
|
||||
* But depending on the mesh type (triangle/quads or bmesh) the lists in the map have different meaning.
|
||||
* For bmesh they are enlisted just like they are stored in the blend file (in loops).
|
||||
* For traditional faces every 4 UV's should be assigned for a single face.
|
||||
* @param meshStructure
|
||||
* the mesh structure
|
||||
* @param useBMesh
|
||||
* tells if we should load the coordinates from loops of from faces
|
||||
* @param blenderContext
|
||||
* the blender context
|
||||
* @return a map that sorts UV coordinates between different UV sets
|
||||
* @throws BlenderFileException
|
||||
* an exception is thrown when problems with blend file occur
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<String, List<Vector2f>> loadUVCoordinates(Structure meshStructure, boolean useBMesh, BlenderContext blenderContext) throws BlenderFileException {
|
||||
Map<String, List<Vector2f>> result = new HashMap<String, List<Vector2f>>();
|
||||
if (useBMesh) {
|
||||
// in this case the UV's are assigned to vertices (an array is the same length as the vertex array)
|
||||
Structure loopData = (Structure) meshStructure.getFieldValue("ldata");
|
||||
Pointer pLoopDataLayers = (Pointer) loopData.getFieldValue("layers");
|
||||
List<Structure> loopDataLayers = pLoopDataLayers.fetchData(blenderContext.getInputStream());
|
||||
for (Structure structure : loopDataLayers) {
|
||||
Pointer p = (Pointer) structure.getFieldValue("data");
|
||||
if (p.isNotNull() && ((Number) structure.getFieldValue("type")).intValue() == UV_DATA_LAYER_TYPE_BMESH) {
|
||||
String uvSetName = structure.getFieldValue("name").toString();
|
||||
List<Structure> uvsStructures = p.fetchData(blenderContext.getInputStream());
|
||||
List<Vector2f> uvs = new ArrayList<Vector2f>(uvsStructures.size());
|
||||
for (Structure uvStructure : uvsStructures) {
|
||||
DynamicArray<Number> loopUVS = (DynamicArray<Number>) uvStructure.getFieldValue("uv");
|
||||
uvs.add(new Vector2f(loopUVS.get(0).floatValue(), loopUVS.get(1).floatValue()));
|
||||
}
|
||||
result.put(uvSetName, uvs);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// in this case UV's are assigned to faces (the array has the same legnth as the faces count)
|
||||
Structure facesData = (Structure) meshStructure.getFieldValue("fdata");
|
||||
Pointer pFacesDataLayers = (Pointer) facesData.getFieldValue("layers");
|
||||
List<Structure> facesDataLayers = pFacesDataLayers.fetchData(blenderContext.getInputStream());
|
||||
for (Structure structure : facesDataLayers) {
|
||||
Pointer p = (Pointer) structure.getFieldValue("data");
|
||||
if (p.isNotNull() && ((Number) structure.getFieldValue("type")).intValue() == UV_DATA_LAYER_TYPE_FMESH) {
|
||||
String uvSetName = structure.getFieldValue("name").toString();
|
||||
List<Structure> uvsStructures = p.fetchData(blenderContext.getInputStream());
|
||||
List<Vector2f> uvs = new ArrayList<Vector2f>(uvsStructures.size());
|
||||
for (Structure uvStructure : uvsStructures) {
|
||||
DynamicArray<Number> mFaceUVs = (DynamicArray<Number>) uvStructure.getFieldValue("uv");
|
||||
uvs.add(new Vector2f(mFaceUVs.get(0).floatValue(), mFaceUVs.get(1).floatValue()));
|
||||
uvs.add(new Vector2f(mFaceUVs.get(2).floatValue(), mFaceUVs.get(3).floatValue()));
|
||||
uvs.add(new Vector2f(mFaceUVs.get(4).floatValue(), mFaceUVs.get(5).floatValue()));
|
||||
uvs.add(new Vector2f(mFaceUVs.get(6).floatValue(), mFaceUVs.get(7).floatValue()));
|
||||
}
|
||||
result.put(uvSetName, uvs);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method reads the mesh from the new BMesh system.
|
||||
*
|
||||
@ -267,33 +346,26 @@ public class MeshHelper extends AbstractBlenderHelper {
|
||||
* an exception is thrown when there are problems with the
|
||||
* blender file
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void readBMesh(MeshBuilder meshBuilder, Structure meshStructure, BlenderContext blenderContext) throws BlenderFileException {
|
||||
Pointer pMLoop = (Pointer) meshStructure.getFieldValue("mloop");
|
||||
Pointer pMPoly = (Pointer) meshStructure.getFieldValue("mpoly");
|
||||
Pointer pMEdge = (Pointer) meshStructure.getFieldValue("medge");
|
||||
Pointer pMLoopUV = (Pointer) meshStructure.getFieldValue("mloopuv");
|
||||
Vector2f[] uvCoordinatesForFace = new Vector2f[3];
|
||||
Map<String, Vector2f[]> uvCoordinatesForFace = new HashMap<String, Vector2f[]>();
|
||||
|
||||
if (pMPoly.isNotNull() && pMLoop.isNotNull() && pMEdge.isNotNull()) {
|
||||
Map<String, List<Vector2f>> uvs = this.loadUVCoordinates(meshStructure, true, blenderContext);
|
||||
int faceIndex = 0;
|
||||
List<Structure> polys = pMPoly.fetchData(blenderContext.getInputStream());
|
||||
List<Structure> loops = pMLoop.fetchData(blenderContext.getInputStream());
|
||||
List<Structure> loopuvs = pMLoopUV.isNotNull() ? pMLoopUV.fetchData(blenderContext.getInputStream()) : null;
|
||||
for (Structure poly : polys) {
|
||||
int materialNumber = ((Number) poly.getFieldValue("mat_nr")).intValue();
|
||||
int loopStart = ((Number) poly.getFieldValue("loopstart")).intValue();
|
||||
int totLoop = ((Number) poly.getFieldValue("totloop")).intValue();
|
||||
boolean smooth = (((Number) poly.getFieldValue("flag")).byteValue() & 0x01) != 0x00;
|
||||
int[] vertexIndexes = new int[totLoop];
|
||||
Vector2f[] uvs = loopuvs != null ? new Vector2f[totLoop] : null;
|
||||
|
||||
for (int i = loopStart; i < loopStart + totLoop; ++i) {
|
||||
vertexIndexes[i - loopStart] = ((Number) loops.get(i).getFieldValue("v")).intValue();
|
||||
if (uvs != null) {
|
||||
DynamicArray<Number> loopUVS = (DynamicArray<Number>) loopuvs.get(i).getFieldValue("uv");
|
||||
uvs[i - loopStart] = new Vector2f(loopUVS.get(0).floatValue(), loopUVS.get(1).floatValue());
|
||||
}
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
@ -302,15 +374,19 @@ public class MeshHelper extends AbstractBlenderHelper {
|
||||
int v2 = vertexIndexes[i + 1];
|
||||
int v3 = vertexIndexes[i + 2];
|
||||
|
||||
if (uvs != null) {// uvs always must be added wheater we
|
||||
// have texture or not
|
||||
uvCoordinatesForFace[0] = uvs[0];
|
||||
uvCoordinatesForFace[1] = uvs[i + 1];
|
||||
uvCoordinatesForFace[2] = uvs[i + 2];
|
||||
if (uvs != null) {
|
||||
// uvs always must be added wheater we have texture or not
|
||||
for (Entry<String, List<Vector2f>> entry : uvs.entrySet()) {
|
||||
Vector2f[] uvCoordsForASingleFace = new Vector2f[3];
|
||||
uvCoordsForASingleFace[0] = entry.getValue().get(loopStart);
|
||||
uvCoordsForASingleFace[1] = entry.getValue().get(loopStart + i + 1);
|
||||
uvCoordsForASingleFace[2] = entry.getValue().get(loopStart + i + 2);
|
||||
uvCoordinatesForFace.put(entry.getKey(), uvCoordsForASingleFace);
|
||||
}
|
||||
}
|
||||
|
||||
meshBuilder.appendFace(v1, v2, v3, smooth, materialNumber, uvs == null ? null : uvCoordinatesForFace, false, faceIndex);
|
||||
|
||||
uvCoordinatesForFace.clear();
|
||||
++i;
|
||||
}
|
||||
++faceIndex;
|
||||
@ -332,38 +408,26 @@ public class MeshHelper extends AbstractBlenderHelper {
|
||||
* an exception is thrown when there are problems with the
|
||||
* blender file
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void readTraditionalFaces(MeshBuilder meshBuilder, Structure meshStructure, BlenderContext blenderContext) throws BlenderFileException {
|
||||
Pointer pMFace = (Pointer) meshStructure.getFieldValue("mface");
|
||||
List<Structure> mFaces = pMFace.isNotNull() ? pMFace.fetchData(blenderContext.getInputStream()) : null;
|
||||
if (mFaces != null && mFaces.size() > 0) {
|
||||
Pointer pMTFace = (Pointer) meshStructure.getFieldValue("mtface");
|
||||
List<Structure> mtFaces = null;
|
||||
|
||||
if (pMTFace.isNotNull()) {
|
||||
mtFaces = pMTFace.fetchData(blenderContext.getInputStream());
|
||||
int facesAmount = ((Number) meshStructure.getFieldValue("totface")).intValue();
|
||||
if (mtFaces.size() != facesAmount) {
|
||||
throw new BlenderFileException("The amount of faces uv coordinates is not equal to faces amount!");
|
||||
}
|
||||
}
|
||||
|
||||
// indicates if the material with the specified number should have a
|
||||
// texture attached
|
||||
Vector2f[] uvCoordinatesForFace = new Vector2f[3];
|
||||
// indicates if the material with the specified number should have a texture attached
|
||||
Map<String, List<Vector2f>> uvs = this.loadUVCoordinates(meshStructure, false, blenderContext);
|
||||
Map<String, Vector2f[]> uvCoordinatesForFace = new HashMap<String, Vector2f[]>();
|
||||
for (int i = 0; i < mFaces.size(); ++i) {
|
||||
Structure mFace = mFaces.get(i);
|
||||
int materialNumber = ((Number) mFace.getFieldValue("mat_nr")).intValue();
|
||||
boolean smooth = (((Number) mFace.getFieldValue("flag")).byteValue() & 0x01) != 0x00;
|
||||
DynamicArray<Number> uvs = null;
|
||||
|
||||
if (mtFaces != null) {
|
||||
Structure mtFace = mtFaces.get(i);
|
||||
if (uvs != null) {
|
||||
// uvs always must be added wheater we have texture or not
|
||||
uvs = (DynamicArray<Number>) mtFace.getFieldValue("uv");
|
||||
uvCoordinatesForFace[0] = new Vector2f(uvs.get(0, 0).floatValue(), uvs.get(0, 1).floatValue());
|
||||
uvCoordinatesForFace[1] = new Vector2f(uvs.get(1, 0).floatValue(), uvs.get(1, 1).floatValue());
|
||||
uvCoordinatesForFace[2] = new Vector2f(uvs.get(2, 0).floatValue(), uvs.get(2, 1).floatValue());
|
||||
for (Entry<String, List<Vector2f>> entry : uvs.entrySet()) {
|
||||
Vector2f[] uvCoordsForASingleFace = new Vector2f[3];
|
||||
uvCoordsForASingleFace[0] = entry.getValue().get(i * 4);
|
||||
uvCoordsForASingleFace[1] = entry.getValue().get(i * 4 + 1);
|
||||
uvCoordsForASingleFace[2] = entry.getValue().get(i * 4 + 2);
|
||||
uvCoordinatesForFace.put(entry.getKey(), uvCoordsForASingleFace);
|
||||
}
|
||||
}
|
||||
|
||||
int v1 = ((Number) mFace.getFieldValue("v1")).intValue();
|
||||
@ -372,13 +436,20 @@ public class MeshHelper extends AbstractBlenderHelper {
|
||||
int v4 = ((Number) mFace.getFieldValue("v4")).intValue();
|
||||
|
||||
meshBuilder.appendFace(v1, v2, v3, smooth, materialNumber, uvs == null ? null : uvCoordinatesForFace, false, i);
|
||||
uvCoordinatesForFace.clear();
|
||||
if (v4 > 0) {
|
||||
if (uvs != null) {
|
||||
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[2] = new Vector2f(uvs.get(3, 0).floatValue(), uvs.get(3, 1).floatValue());
|
||||
// uvs always must be added wheater we have texture or not
|
||||
for (Entry<String, List<Vector2f>> entry : uvs.entrySet()) {
|
||||
Vector2f[] uvCoordsForASingleFace = new Vector2f[3];
|
||||
uvCoordsForASingleFace[0] = entry.getValue().get(i * 4);
|
||||
uvCoordsForASingleFace[1] = entry.getValue().get(i * 4 + 2);
|
||||
uvCoordsForASingleFace[2] = entry.getValue().get(i * 4 + 3);
|
||||
uvCoordinatesForFace.put(entry.getKey(), uvCoordsForASingleFace);
|
||||
}
|
||||
}
|
||||
meshBuilder.appendFace(v1, v3, v4, smooth, materialNumber, uvs == null ? null : uvCoordinatesForFace, true, i);
|
||||
uvCoordinatesForFace.clear();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -2,10 +2,9 @@ package com.jme3.scene.plugins.blender.textures;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@ -46,8 +45,6 @@ public class CombinedTexture {
|
||||
private final int mappingType;
|
||||
/** The data for each of the textures. */
|
||||
private List<TextureData> textureDatas = new ArrayList<TextureData>();
|
||||
/** The variable indicates if the texture was already triangulated or not. */
|
||||
private boolean wasTriangulated;
|
||||
/** The result texture. */
|
||||
private Texture resultTexture;
|
||||
/** The UV values for the result texture. */
|
||||
@ -77,10 +74,12 @@ public class CombinedTexture {
|
||||
* the type of UV coordinates projection (for flat textures)
|
||||
* @param textureStructure
|
||||
* the texture sructure
|
||||
* @param uvCoordinatesName
|
||||
* the name of the used user's UV coordinates for this texture
|
||||
* @param blenderContext
|
||||
* the blender context
|
||||
*/
|
||||
public void add(Texture texture, TextureBlender textureBlender, int uvCoordinatesType, int projectionType, Structure textureStructure, BlenderContext blenderContext) {
|
||||
public void add(Texture texture, TextureBlender textureBlender, int uvCoordinatesType, int projectionType, Structure textureStructure, String uvCoordinatesName, BlenderContext blenderContext) {
|
||||
if (!(texture instanceof GeneratedTexture) && !(texture instanceof Texture2D)) {
|
||||
throw new IllegalArgumentException("Unsupported texture type: " + (texture == null ? "null" : texture.getClass()));
|
||||
}
|
||||
@ -92,6 +91,7 @@ public class CombinedTexture {
|
||||
textureData.uvCoordinatesType = UVCoordinatesType.valueOf(uvCoordinatesType);
|
||||
textureData.projectionType = UVProjectionType.valueOf(projectionType);
|
||||
textureData.textureStructure = textureStructure;
|
||||
textureData.uvCoordinatesName = uvCoordinatesName;
|
||||
|
||||
if (textureDatas.size() > 0 && this.isWithoutAlpha(textureData, blenderContext)) {
|
||||
textureDatas.clear();// clear previous textures, they will be covered anyway
|
||||
@ -119,11 +119,12 @@ public class CombinedTexture {
|
||||
* the blender context
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void flatten(Geometry geometry, Long geometriesOMA, List<Vector2f> userDefinedUVCoordinates, BlenderContext blenderContext) {
|
||||
public void flatten(Geometry geometry, Long geometriesOMA, LinkedHashMap<String, List<Vector2f>> userDefinedUVCoordinates, BlenderContext blenderContext) {
|
||||
TextureHelper textureHelper = blenderContext.getHelper(TextureHelper.class);
|
||||
Mesh mesh = geometry.getMesh();
|
||||
Texture previousTexture = null;
|
||||
UVCoordinatesType masterUVCoordinatesType = null;
|
||||
String masterUserUVSetName = null;
|
||||
for (TextureData textureData : textureDatas) {
|
||||
// decompress compressed textures (all will be merged into one texture anyway)
|
||||
if (textureDatas.size() > 1 && textureData.texture.getImage().getFormat().isCompressed()) {
|
||||
@ -138,7 +139,12 @@ public class CombinedTexture {
|
||||
resultTexture = textureData.texture;
|
||||
|
||||
if (textureData.uvCoordinatesType == UVCoordinatesType.TEXCO_UV && userDefinedUVCoordinates != null && userDefinedUVCoordinates.size() > 0) {
|
||||
resultUVS = userDefinedUVCoordinates;
|
||||
if(textureData.uvCoordinatesName == null) {
|
||||
resultUVS = userDefinedUVCoordinates.values().iterator().next();//get the first UV available
|
||||
} else {
|
||||
resultUVS = userDefinedUVCoordinates.get(textureData.uvCoordinatesName);
|
||||
}
|
||||
masterUserUVSetName = textureData.uvCoordinatesName;
|
||||
} else {
|
||||
List<Geometry> geometries = (List<Geometry>) blenderContext.getLoadedFeature(geometriesOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
||||
resultUVS = UVCoordinatesGenerator.generateUVCoordinatesFor2DTexture(mesh, textureData.uvCoordinatesType, textureData.projectionType, geometries);
|
||||
@ -161,7 +167,9 @@ public class CombinedTexture {
|
||||
triangulatedTexture.blend(textureData.textureBlender, (TriangulatedTexture) resultTexture, blenderContext);
|
||||
resultTexture = previousTexture = triangulatedTexture;
|
||||
} else if (textureData.texture instanceof Texture2D) {
|
||||
if (masterUVCoordinatesType == textureData.uvCoordinatesType && resultTexture instanceof Texture2D) {
|
||||
if (this.isUVTypesMatch(masterUVCoordinatesType, masterUserUVSetName,
|
||||
textureData.uvCoordinatesType, textureData.uvCoordinatesName) &&
|
||||
resultTexture instanceof Texture2D) {
|
||||
this.scale((Texture2D) textureData.texture, resultTexture.getImage().getWidth(), resultTexture.getImage().getHeight());
|
||||
this.merge((Texture2D) resultTexture, (Texture2D) textureData.texture);
|
||||
previousTexture = resultTexture;
|
||||
@ -173,7 +181,11 @@ public class CombinedTexture {
|
||||
// first triangulate the current texture
|
||||
List<Vector2f> textureUVS = null;
|
||||
if (textureData.uvCoordinatesType == UVCoordinatesType.TEXCO_UV && userDefinedUVCoordinates != null && userDefinedUVCoordinates.size() > 0) {
|
||||
textureUVS = userDefinedUVCoordinates;
|
||||
if(textureData.uvCoordinatesName == null) {
|
||||
textureUVS = userDefinedUVCoordinates.values().iterator().next();//get the first UV available
|
||||
} else {
|
||||
textureUVS = userDefinedUVCoordinates.get(textureData.uvCoordinatesName);
|
||||
}
|
||||
} else {
|
||||
List<Geometry> geometries = (List<Geometry>) blenderContext.getLoadedFeature(geometriesOMA, LoadedFeatureDataType.LOADED_FEATURE);
|
||||
textureUVS = UVCoordinatesGenerator.generateUVCoordinatesFor2DTexture(mesh, textureData.uvCoordinatesType, textureData.projectionType, geometries);
|
||||
@ -196,7 +208,6 @@ public class CombinedTexture {
|
||||
}
|
||||
resultUVS = ((TriangulatedTexture) resultTexture).getResultUVS();
|
||||
resultTexture = ((TriangulatedTexture) resultTexture).getResultTexture();
|
||||
wasTriangulated = true;
|
||||
}
|
||||
|
||||
// setting additional data
|
||||
@ -207,6 +218,31 @@ public class CombinedTexture {
|
||||
resultTexture.setMinFilter(MinFilter.NearestNoMipMaps);
|
||||
}
|
||||
|
||||
/**
|
||||
* The method checks if the texture UV coordinates match.
|
||||
* It the types are equal and different then UVCoordinatesType.TEXCO_UV then we consider them a match.
|
||||
* If they are both UVCoordinatesType.TEXCO_UV then they match only when their UV sets names are equal.
|
||||
* In other cases they are considered NOT a match.
|
||||
* @param type1 the UV coord type
|
||||
* @param uvSetName1 the user's UV coords set name (considered only for UVCoordinatesType.TEXCO_UV)
|
||||
* @param type2 the UV coord type
|
||||
* @param uvSetName2 the user's UV coords set name (considered only for UVCoordinatesType.TEXCO_UV)
|
||||
* @return <b>true</b> if the types match and <b>false</b> otherwise
|
||||
*/
|
||||
private boolean isUVTypesMatch(UVCoordinatesType type1, String uvSetName1,
|
||||
UVCoordinatesType type2, String uvSetName2) {
|
||||
if(type1 == type2) {
|
||||
if(type1 == UVCoordinatesType.TEXCO_UV) {
|
||||
if(uvSetName1 != null && uvSetName2 != null && uvSetName1.equals(uvSetName2)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method blends the texture.
|
||||
*
|
||||
@ -228,129 +264,6 @@ public class CombinedTexture {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method casts the current image to the basic UV's owner UV's
|
||||
* coordinates.
|
||||
*
|
||||
* @param basicUVSOwner
|
||||
* the owner of the UV's we cast to
|
||||
* @param blenderContext
|
||||
* the blender context
|
||||
*/
|
||||
public void castToUVS(CombinedTexture basicUVSOwner, BlenderContext blenderContext) {
|
||||
if (resultUVS.size() != basicUVSOwner.resultUVS.size()) {
|
||||
throw new IllegalStateException("The amount of UV coordinates must be equal in order to cast one UV's onto another!");
|
||||
}
|
||||
if (!resultUVS.equals(basicUVSOwner.resultUVS)) {
|
||||
if (!basicUVSOwner.wasTriangulated) {
|
||||
throw new IllegalStateException("The given texture must be triangulated!");
|
||||
}
|
||||
if (!this.wasTriangulated) {
|
||||
resultTexture = new TriangulatedTexture((Texture2D) resultTexture, resultUVS, blenderContext);
|
||||
resultUVS = ((TriangulatedTexture) resultTexture).getResultUVS();
|
||||
resultTexture = ((TriangulatedTexture) resultTexture).getResultTexture();
|
||||
}
|
||||
// casting algorithm
|
||||
TextureHelper textureHelper = blenderContext.getHelper(TextureHelper.class);
|
||||
ImageLoader imageLoader = new ImageLoader();
|
||||
List<TriangleTextureElement> faceTextures = new ArrayList<TriangleTextureElement>();
|
||||
List<Vector2f> basicUVS = basicUVSOwner.getResultUVS();
|
||||
int[] imageRectangle = new int[4];// minX, minY, maxX, maxY
|
||||
int[] sourceSize = new int[2], targetSize = new int[2];// width,
|
||||
// height
|
||||
Vector2f[] destinationUVS = new Vector2f[3];
|
||||
Vector2f[] sourceUVS = new Vector2f[3];
|
||||
List<Vector2f> partImageUVS = Arrays.asList(new Vector2f(), new Vector2f(), new Vector2f());
|
||||
int faceIndex = 0;
|
||||
|
||||
for (int i = 0; i < basicUVS.size(); i += 3) {
|
||||
// destination size nad UVS
|
||||
destinationUVS[0] = basicUVS.get(i);
|
||||
destinationUVS[1] = basicUVS.get(i + 1);
|
||||
destinationUVS[2] = basicUVS.get(i + 2);
|
||||
this.computeImageRectangle(destinationUVS, imageRectangle, basicUVSOwner.resultTexture.getImage().getWidth(), basicUVSOwner.resultTexture.getImage().getHeight(), blenderContext);
|
||||
targetSize[0] = imageRectangle[2] - imageRectangle[0];
|
||||
targetSize[1] = imageRectangle[3] - imageRectangle[1];
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
partImageUVS.get(j).set((basicUVSOwner.resultTexture.getImage().getWidth() * destinationUVS[j].x - imageRectangle[0]) / targetSize[0], (basicUVSOwner.resultTexture.getImage().getHeight() * destinationUVS[j].y - imageRectangle[1]) / targetSize[1]);
|
||||
}
|
||||
|
||||
// source size and UVS (translate UVS to (0,0) and stretch it to
|
||||
// the borders of the image)
|
||||
sourceUVS[0] = resultUVS.get(i);
|
||||
sourceUVS[1] = resultUVS.get(i + 1);
|
||||
sourceUVS[2] = resultUVS.get(i + 2);
|
||||
this.computeImageRectangle(sourceUVS, imageRectangle, resultTexture.getImage().getWidth(), resultTexture.getImage().getHeight(), blenderContext);
|
||||
sourceSize[0] = imageRectangle[2] - imageRectangle[0];
|
||||
sourceSize[1] = imageRectangle[3] - imageRectangle[1];
|
||||
float xTranslateFactor = imageRectangle[0] / (float) resultTexture.getImage().getWidth();
|
||||
float xStreachFactor = resultTexture.getImage().getWidth() / (float) sourceSize[0];
|
||||
float yTranslateFactor = imageRectangle[1] / (float) resultTexture.getImage().getHeight();
|
||||
float yStreachFactor = resultTexture.getImage().getHeight() / (float) sourceSize[1];
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
sourceUVS[j].x = (sourceUVS[j].x - xTranslateFactor) * xStreachFactor;
|
||||
sourceUVS[j].y = (sourceUVS[j].y - yTranslateFactor) * yStreachFactor;
|
||||
}
|
||||
|
||||
AffineTransform affineTransform = textureHelper.createAffineTransform(sourceUVS, partImageUVS.toArray(new Vector2f[3]), sourceSize, targetSize);
|
||||
|
||||
Image image = textureHelper.getSubimage(resultTexture.getImage(), imageRectangle[0], imageRectangle[1], imageRectangle[2], imageRectangle[3]);
|
||||
|
||||
// compute the result texture
|
||||
BufferedImage sourceImage = ImageToAwt.convert(image, false, true, 0);
|
||||
|
||||
BufferedImage targetImage = new BufferedImage(targetSize[0], targetSize[1], sourceImage.getType());
|
||||
Graphics2D g = targetImage.createGraphics();
|
||||
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
g.drawImage(sourceImage, affineTransform, null);
|
||||
g.dispose();
|
||||
|
||||
Image output = imageLoader.load(targetImage, false);
|
||||
faceTextures.add(new TriangleTextureElement(faceIndex++, output, partImageUVS, false, blenderContext));
|
||||
}
|
||||
TriangulatedTexture triangulatedTexture = new TriangulatedTexture(faceTextures, blenderContext);
|
||||
triangulatedTexture.setKeepIdenticalTextures(false);
|
||||
resultTexture = triangulatedTexture.getResultTexture();
|
||||
resultUVS = basicUVS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method computes the rectangle of an image constrained by the
|
||||
* triangle UV coordinates.
|
||||
*
|
||||
* @param triangleVertices
|
||||
* the triangle UV coordinates
|
||||
* @param result
|
||||
* the array where the result is stored
|
||||
* @param totalImageWidth
|
||||
* the total image width
|
||||
* @param totalImageHeight
|
||||
* the total image height
|
||||
* @param blenderContext
|
||||
* the blender context
|
||||
*/
|
||||
private void computeImageRectangle(Vector2f[] triangleVertices, int[] result, int totalImageWidth, int totalImageHeight, BlenderContext blenderContext) {
|
||||
TextureHelper textureHelper = blenderContext.getHelper(TextureHelper.class);
|
||||
|
||||
float minX = Math.min(triangleVertices[0].x, triangleVertices[1].x);
|
||||
minX = Math.min(minX, triangleVertices[2].x);
|
||||
|
||||
float maxX = Math.max(triangleVertices[0].x, triangleVertices[1].x);
|
||||
maxX = Math.max(maxX, triangleVertices[2].x);
|
||||
|
||||
float minY = Math.min(triangleVertices[0].y, triangleVertices[1].y);
|
||||
minY = Math.min(minY, triangleVertices[2].y);
|
||||
|
||||
float maxY = Math.max(triangleVertices[0].y, triangleVertices[1].y);
|
||||
maxY = Math.max(maxY, triangleVertices[2].y);
|
||||
|
||||
result[0] = textureHelper.getPixelPosition(minX, totalImageWidth);
|
||||
result[1] = textureHelper.getPixelPosition(minY, totalImageHeight);
|
||||
result[2] = textureHelper.getPixelPosition(maxX, totalImageWidth);
|
||||
result[3] = textureHelper.getPixelPosition(maxY, totalImageHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the result texture
|
||||
*/
|
||||
@ -546,5 +459,7 @@ public class CombinedTexture {
|
||||
public UVProjectionType projectionType;
|
||||
/** The texture sructure. */
|
||||
public Structure textureStructure;
|
||||
/** The name of the user's UV coordinates that are used for this texture. */
|
||||
public String uvCoordinatesName;
|
||||
}
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ import com.jme3.asset.GeneratedTextureKey;
|
||||
import com.jme3.asset.TextureKey;
|
||||
import com.jme3.math.Vector2f;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.scene.VertexBuffer.Type;
|
||||
import com.jme3.scene.plugins.blender.AbstractBlenderHelper;
|
||||
import com.jme3.scene.plugins.blender.BlenderContext;
|
||||
import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType;
|
||||
@ -94,11 +95,11 @@ public class TextureHelper extends AbstractBlenderHelper {
|
||||
public static final int TEX_MUSGRAVE = 11;
|
||||
public static final int TEX_VORONOI = 12;
|
||||
public static final int TEX_DISTNOISE = 13;
|
||||
public static final int TEX_POINTDENSITY = 14; // v.
|
||||
// 25+
|
||||
public static final int TEX_VOXELDATA = 15; // v.
|
||||
// 25+
|
||||
public static final int TEX_POINTDENSITY = 14; // v. 25+
|
||||
public static final int TEX_VOXELDATA = 15; // v. 25+
|
||||
|
||||
public static final Type[] TEXCOORD_TYPES = new Type[] { Type.TexCoord, Type.TexCoord2, Type.TexCoord3, Type.TexCoord4, Type.TexCoord5, Type.TexCoord6, Type.TexCoord7, Type.TexCoord8 };
|
||||
|
||||
private TextureGeneratorFactory textureGeneratorFactory = new TextureGeneratorFactory();
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,86 @@
|
||||
package com.jme3.scene.plugins.blender.textures;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.jme3.math.Vector2f;
|
||||
|
||||
/**
|
||||
* A collection of UV coordinates. The coords are stored in groups defined by the material index and their UV set name.
|
||||
*
|
||||
* @author Kaelthas (Marcin Roguski)
|
||||
*/
|
||||
public class UserUVCollection {
|
||||
/** A map between material number and UV coordinates of mesh that has this material applied. */
|
||||
private Map<Integer, LinkedHashMap<String, List<Vector2f>>> uvCoordinates = new HashMap<Integer, LinkedHashMap<String, List<Vector2f>>>();
|
||||
/** A map between vertex index and its UV coordinates. */
|
||||
private Map<String, Map<Integer, Vector2f>> uvsMap = new HashMap<String, Map<Integer, Vector2f>>();
|
||||
|
||||
/**
|
||||
* Adds a single UV coordinates for a specified vertex index.
|
||||
* @param materialIndex
|
||||
* the material index
|
||||
* @param uvSetName
|
||||
* the UV set name
|
||||
* @param uv
|
||||
* the added UV coordinates
|
||||
* @param jmeVertexIndex
|
||||
* the index of the vertex in result jme mesh
|
||||
*/
|
||||
public void addUV(int materialIndex, String uvSetName, Vector2f uv, int jmeVertexIndex) {
|
||||
// first get all UV sets for the specified material ...
|
||||
LinkedHashMap<String, List<Vector2f>> uvsForMaterial = uvCoordinates.get(materialIndex);
|
||||
if (uvsForMaterial == null) {
|
||||
uvsForMaterial = new LinkedHashMap<String, List<Vector2f>>();
|
||||
uvCoordinates.put(materialIndex, uvsForMaterial);
|
||||
}
|
||||
|
||||
// ... then fetch the UVS for the specified UV set name ...
|
||||
List<Vector2f> uvsForName = uvsForMaterial.get(uvSetName);
|
||||
if (uvsForName == null) {
|
||||
uvsForName = new ArrayList<Vector2f>();
|
||||
uvsForMaterial.put(uvSetName, uvsForName);
|
||||
}
|
||||
|
||||
// ... add the UV coordinates to the proper list ...
|
||||
uvsForName.add(uv);
|
||||
|
||||
// ... and add the mapping of the UV coordinates to a vertex index for the specified UV set
|
||||
Map<Integer, Vector2f> uvToVertexIndexMapping = uvsMap.get(uvSetName);
|
||||
if (uvToVertexIndexMapping == null) {
|
||||
uvToVertexIndexMapping = new HashMap<Integer, Vector2f>();
|
||||
uvsMap.put(uvSetName, uvToVertexIndexMapping);
|
||||
}
|
||||
uvToVertexIndexMapping.put(jmeVertexIndex, uv);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uvSetName
|
||||
* the name of the UV set
|
||||
* @param vertexIndex
|
||||
* the vertex index corresponds to the index in jme mesh and not the original one in blender
|
||||
* @return
|
||||
*/
|
||||
public Vector2f getUVForVertex(String uvSetName, int vertexIndex) {
|
||||
return uvsMap.get(uvSetName).get(vertexIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param materialNumber
|
||||
* the material number that is appied to the mesh
|
||||
* @return UV coordinates of vertices that belong to the required mesh part
|
||||
*/
|
||||
public LinkedHashMap<String, List<Vector2f>> getUVCoordinates(int materialNumber) {
|
||||
return uvCoordinates.get(materialNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return indicates if the mesh has UV coordinates
|
||||
*/
|
||||
public boolean hasUVCoordinates() {
|
||||
return uvCoordinates.size() > 0;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user