OBJ loader: fixed another whitespace-related issue; removed unused "modifyUVs" property for now; added the "flip-v" property to switch between OpenGL-style and DirextX-style model UVs; fixed normals - they are now correct in-world, still a bit strange for the items; fixed normals a little bit for B3D models too.
This commit is contained in:
parent
c3b15e3f6c
commit
12e6fe9db7
3 changed files with 255 additions and 286 deletions
|
@ -582,11 +582,11 @@ public class B3DLoader implements ICustomModelLoader
|
||||||
case NORMAL:
|
case NORMAL:
|
||||||
if(v.getNormal() != null)
|
if(v.getNormal() != null)
|
||||||
{
|
{
|
||||||
builder.put(e, v.getNormal().x, v.getNormal().y, v.getNormal().z, 1);
|
builder.put(e, v.getNormal().x, v.getNormal().y, v.getNormal().z, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
builder.put(e, faceNormal.x, faceNormal.y, faceNormal.z, 1);
|
builder.put(e, faceNormal.x, faceNormal.y, faceNormal.z, 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -17,6 +17,7 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.vecmath.Matrix3f;
|
||||||
import javax.vecmath.Matrix4f;
|
import javax.vecmath.Matrix4f;
|
||||||
import javax.vecmath.Quat4f;
|
import javax.vecmath.Quat4f;
|
||||||
import javax.vecmath.Vector2f;
|
import javax.vecmath.Vector2f;
|
||||||
|
@ -625,7 +626,8 @@ public class B3DModel
|
||||||
bm.mul(bone.getLeft());
|
bm.mul(bone.getLeft());
|
||||||
t.add(bm);
|
t.add(bm);
|
||||||
}
|
}
|
||||||
if(totalWeight != 0) t.mul(1f / totalWeight);
|
if(Math.abs(totalWeight) > 1e-4) t.mul(1f / totalWeight);
|
||||||
|
else t.setIdentity();
|
||||||
}
|
}
|
||||||
|
|
||||||
// pos
|
// pos
|
||||||
|
@ -635,12 +637,12 @@ public class B3DModel
|
||||||
Vector3f rPos = new Vector3f(newPos.x / newPos.w, newPos.y / newPos.w, newPos.z / newPos.w);
|
Vector3f rPos = new Vector3f(newPos.x / newPos.w, newPos.y / newPos.w, newPos.z / newPos.w);
|
||||||
|
|
||||||
// normal
|
// normal
|
||||||
t.invert();
|
Matrix3f tm = new Matrix3f();
|
||||||
t.transpose();
|
t.getRotationScale(tm);
|
||||||
Vector4f normal = new Vector4f(this.normal), newNormal = new Vector4f();
|
tm.invert();
|
||||||
normal.w = 1;
|
tm.transpose();
|
||||||
t.transform(normal, newNormal);
|
Vector3f normal = new Vector3f(this.normal), rNormal = new Vector3f();
|
||||||
Vector3f rNormal = new Vector3f(newNormal.x / newNormal.w, newNormal.y / newNormal.w, newNormal.z / newNormal.w);
|
tm.transform(normal, rNormal);
|
||||||
rNormal.normalize();
|
rNormal.normalize();
|
||||||
|
|
||||||
// texCoords TODO
|
// texCoords TODO
|
||||||
|
|
|
@ -14,6 +14,7 @@ import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import javax.vecmath.Matrix3f;
|
||||||
import javax.vecmath.Matrix4f;
|
import javax.vecmath.Matrix4f;
|
||||||
import javax.vecmath.Vector2f;
|
import javax.vecmath.Vector2f;
|
||||||
import javax.vecmath.Vector3f;
|
import javax.vecmath.Vector3f;
|
||||||
|
@ -69,7 +70,7 @@ public class OBJModel implements IRetexturableModel, IModelCustomData
|
||||||
|
|
||||||
public OBJModel(MaterialLibrary matLib, ResourceLocation modelLocation)
|
public OBJModel(MaterialLibrary matLib, ResourceLocation modelLocation)
|
||||||
{
|
{
|
||||||
this(matLib, modelLocation, null);
|
this(matLib, modelLocation, new CustomData());
|
||||||
}
|
}
|
||||||
|
|
||||||
public OBJModel(MaterialLibrary matLib, ResourceLocation modelLocation, CustomData customData)
|
public OBJModel(MaterialLibrary matLib, ResourceLocation modelLocation, CustomData customData)
|
||||||
|
@ -132,15 +133,10 @@ public class OBJModel implements IRetexturableModel, IModelCustomData
|
||||||
return this.matLib;
|
return this.matLib;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasCustomData()
|
|
||||||
{
|
|
||||||
return this.customData != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IModel process(ImmutableMap<String, String> customData)
|
public IModel process(ImmutableMap<String, String> customData)
|
||||||
{
|
{
|
||||||
OBJModel ret = new OBJModel(this.matLib, this.modelLocation, new CustomData(customData));
|
OBJModel ret = new OBJModel(this.matLib, this.modelLocation, new CustomData(this.customData, customData));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,17 +147,24 @@ public class OBJModel implements IRetexturableModel, IModelCustomData
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class CustomData
|
static class CustomData
|
||||||
{
|
{
|
||||||
public boolean ambientOcclusion = true;
|
public boolean ambientOcclusion = true;
|
||||||
public boolean gui3d = true;
|
public boolean gui3d = true;
|
||||||
public boolean modifyUVs = false;
|
// should be an enum, TODO
|
||||||
|
//public boolean modifyUVs = false;
|
||||||
|
public boolean flipV = false;
|
||||||
|
|
||||||
public CustomData(ImmutableMap<String, String> customData)
|
public CustomData(CustomData parent, ImmutableMap<String, String> customData)
|
||||||
{
|
{
|
||||||
|
this.ambientOcclusion = parent.ambientOcclusion;
|
||||||
|
this.gui3d = parent.gui3d;
|
||||||
|
this.flipV = parent.flipV;
|
||||||
this.process(customData);
|
this.process(customData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CustomData() {}
|
||||||
|
|
||||||
public void process(ImmutableMap<String, String> customData)
|
public void process(ImmutableMap<String, String> customData)
|
||||||
{
|
{
|
||||||
for (Map.Entry<String, String> e : customData.entrySet())
|
for (Map.Entry<String, String> e : customData.entrySet())
|
||||||
|
@ -170,8 +173,10 @@ public class OBJModel implements IRetexturableModel, IModelCustomData
|
||||||
this.ambientOcclusion = Boolean.valueOf(e.getValue());
|
this.ambientOcclusion = Boolean.valueOf(e.getValue());
|
||||||
else if (e.getKey().equals("gui3d"))
|
else if (e.getKey().equals("gui3d"))
|
||||||
this.gui3d = Boolean.valueOf(e.getValue());
|
this.gui3d = Boolean.valueOf(e.getValue());
|
||||||
else if (e.getKey().equals("modifyUVs"))
|
/*else if (e.getKey().equals("modifyUVs"))
|
||||||
this.modifyUVs = Boolean.valueOf(e.getValue());
|
this.modifyUVs = Boolean.valueOf(e.getValue());*/
|
||||||
|
else if (e.getKey().equals("flip-v"))
|
||||||
|
this.flipV = Boolean.valueOf(e.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -217,6 +222,7 @@ public class OBJModel implements IRetexturableModel, IModelCustomData
|
||||||
{
|
{
|
||||||
currentLine = objReader.readLine();
|
currentLine = objReader.readLine();
|
||||||
if (currentLine == null) break;
|
if (currentLine == null) break;
|
||||||
|
currentLine.trim();
|
||||||
if (currentLine.isEmpty() || currentLine.startsWith("#")) continue;
|
if (currentLine.isEmpty() || currentLine.startsWith("#")) continue;
|
||||||
|
|
||||||
String[] fields = WHITE_SPACE.split(currentLine, 2);
|
String[] fields = WHITE_SPACE.split(currentLine, 2);
|
||||||
|
@ -402,7 +408,7 @@ public class OBJModel implements IRetexturableModel, IModelCustomData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OBJModel model = new OBJModel(this.materialLibrary, this.objFrom, null);
|
OBJModel model = new OBJModel(this.materialLibrary, this.objFrom);
|
||||||
// model.getMatLib().setUVBounds(minUVBounds[0], maxUVBounds[0], minUVBounds[1], maxUVBounds[1]);
|
// model.getMatLib().setUVBounds(minUVBounds[0], maxUVBounds[0], minUVBounds[1], maxUVBounds[1]);
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
@ -528,6 +534,7 @@ public class OBJModel implements IRetexturableModel, IModelCustomData
|
||||||
{
|
{
|
||||||
currentLine = mtlReader.readLine();
|
currentLine = mtlReader.readLine();
|
||||||
if (currentLine == null) break;
|
if (currentLine == null) break;
|
||||||
|
currentLine.trim();
|
||||||
if (currentLine.isEmpty() || currentLine.startsWith("#")) continue;
|
if (currentLine.isEmpty() || currentLine.startsWith("#")) continue;
|
||||||
|
|
||||||
String[] fields = WHITE_SPACE.split(currentLine, 2);
|
String[] fields = WHITE_SPACE.split(currentLine, 2);
|
||||||
|
@ -849,13 +856,13 @@ public class OBJModel implements IRetexturableModel, IModelCustomData
|
||||||
public Face bake(TRSRTransformation transform)
|
public Face bake(TRSRTransformation transform)
|
||||||
{
|
{
|
||||||
Matrix4f m = transform.getMatrix();
|
Matrix4f m = transform.getMatrix();
|
||||||
|
Matrix3f mn = null;
|
||||||
Vertex[] vertices = new Vertex[verts.length];
|
Vertex[] vertices = new Vertex[verts.length];
|
||||||
// Normal[] normals = norms != null ? new Normal[norms.length] : null;
|
// Normal[] normals = norms != null ? new Normal[norms.length] : null;
|
||||||
// TextureCoordinate[] textureCoords = texCoords != null ? new TextureCoordinate[texCoords.length] : null;
|
// TextureCoordinate[] textureCoords = texCoords != null ? new TextureCoordinate[texCoords.length] : null;
|
||||||
|
|
||||||
for (int i = 0; i < verts.length; i++)
|
for (int i = 0; i < verts.length; i++)
|
||||||
{
|
{
|
||||||
m = transform.getMatrix();
|
|
||||||
Vertex v = verts[i];
|
Vertex v = verts[i];
|
||||||
// Normal n = norms != null ? norms[i] : null;
|
// Normal n = norms != null ? norms[i] : null;
|
||||||
// TextureCoordinate t = texCoords != null ? texCoords[i] : null;
|
// TextureCoordinate t = texCoords != null ? texCoords[i] : null;
|
||||||
|
@ -867,31 +874,22 @@ public class OBJModel implements IRetexturableModel, IModelCustomData
|
||||||
|
|
||||||
if (v.hasNormal())
|
if (v.hasNormal())
|
||||||
{
|
{
|
||||||
m.invert();
|
if(mn == null)
|
||||||
Vector4f normal = new Vector4f(v.getNormal().getData()), newNormal = new Vector4f();
|
{
|
||||||
normal.w = 1.0f;
|
mn = new Matrix3f();
|
||||||
m.transform(normal, newNormal);
|
m.getRotationScale(mn);
|
||||||
Vector3f rNormal = new Vector3f(newNormal.x / newNormal.w, newNormal.y / newNormal.w, newNormal.z / newNormal.w);
|
mn.invert();
|
||||||
rNormal.normalize();
|
mn.transpose();
|
||||||
vertices[i].setNormal(new Normal(rNormal));
|
}
|
||||||
|
Vector3f normal = new Vector3f(v.getNormal().getData()), newNormal = new Vector3f();
|
||||||
|
mn.transform(normal, newNormal);
|
||||||
|
newNormal.normalize();
|
||||||
|
vertices[i].setNormal(new Normal(newNormal));
|
||||||
}
|
}
|
||||||
else v.setNormal(new Normal(0.0f, 1.0f, 0.0f));
|
|
||||||
|
|
||||||
if (v.hasTextureCoordinate()) vertices[i].setTextureCoordinate(v.getTextureCoordinate());
|
if (v.hasTextureCoordinate()) vertices[i].setTextureCoordinate(v.getTextureCoordinate());
|
||||||
else v.setTextureCoordinate(TextureCoordinate.getDefaultUVs()[i]);
|
else v.setTextureCoordinate(TextureCoordinate.getDefaultUVs()[i]);
|
||||||
|
|
||||||
// if (n != null)
|
|
||||||
// {
|
|
||||||
// m.invert();
|
|
||||||
// m.transpose();
|
|
||||||
// Vector4f normal = new Vector4f(n.getData()), newNormal = new Vector4f();
|
|
||||||
// normal.w = 1;
|
|
||||||
// m.transform(normal, newNormal);
|
|
||||||
// Vector3f rNormal = new Vector3f(newNormal.x / newNormal.w, newNormal.y / newNormal.w, newNormal.z / newNormal.w);
|
|
||||||
// rNormal.normalize();
|
|
||||||
// normals[i] = new Normal(rNormal);
|
|
||||||
// }
|
|
||||||
|
|
||||||
//texCoords TODO
|
//texCoords TODO
|
||||||
// if (t != null) textureCoords[i] = t;
|
// if (t != null) textureCoords[i] = t;
|
||||||
}
|
}
|
||||||
|
@ -900,40 +898,13 @@ public class OBJModel implements IRetexturableModel, IModelCustomData
|
||||||
|
|
||||||
public Normal getNormal()
|
public Normal getNormal()
|
||||||
{
|
{
|
||||||
for (Vertex v : this.verts)
|
Vector3f a = this.verts[2].getPos3();
|
||||||
{
|
a.sub(this.verts[0].getPos3());
|
||||||
if (!v.hasNormal())
|
Vector3f b = this.verts[3].getPos3();
|
||||||
{
|
b.sub(this.verts[1].getPos3());
|
||||||
Vector3f vPos = v.getPos3();
|
a.cross(a, b);
|
||||||
vPos.normalize();
|
a.normalize();
|
||||||
v.setNormal(new Normal(vPos));
|
return new Normal(a);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector3f a = this.verts[1].getNormal().getData();
|
|
||||||
a.sub(this.verts[0].getNormal().getData());
|
|
||||||
Vector3f b = this.verts[2].getNormal().getData();
|
|
||||||
b.sub(this.verts[0].getNormal().getData());
|
|
||||||
Vector3f c = new Vector3f();
|
|
||||||
c.cross(a, b);
|
|
||||||
c.normalize();
|
|
||||||
|
|
||||||
if (this.isTri) return new Normal(c);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
a = this.verts[1].getNormal().getData();
|
|
||||||
a.sub(this.verts[3].getNormal().getData());
|
|
||||||
b = this.verts[2].getNormal().getData();
|
|
||||||
b.sub(this.verts[3].getNormal().getData());
|
|
||||||
Vector3f c1 = new Vector3f();
|
|
||||||
c1.cross(a, b);
|
|
||||||
c1.normalize();
|
|
||||||
Vector3f normal = new Vector3f();
|
|
||||||
normal.add(c, c1);
|
|
||||||
normal.scale(0.5f);
|
|
||||||
normal.normalize();
|
|
||||||
return new Normal(normal);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1340,9 +1311,9 @@ public class OBJModel implements IRetexturableModel, IModelCustomData
|
||||||
if (this.state instanceof OBJState)
|
if (this.state instanceof OBJState)
|
||||||
{
|
{
|
||||||
OBJState state = (OBJState) this.state;
|
OBJState state = (OBJState) this.state;
|
||||||
if (state.parent != null && state.parent instanceof TRSRTransformation)
|
if (state.parent != null)
|
||||||
{
|
{
|
||||||
transform = (TRSRTransformation) state.parent;
|
transform = state.parent.apply(model);
|
||||||
}
|
}
|
||||||
//TODO: can this be replaced by updateStateVisibilityMap(OBJState)?
|
//TODO: can this be replaced by updateStateVisibilityMap(OBJState)?
|
||||||
if (state.getGroupNamesFromMap().contains(Group.ALL))
|
if (state.getGroupNamesFromMap().contains(Group.ALL))
|
||||||
|
@ -1377,14 +1348,9 @@ public class OBJModel implements IRetexturableModel, IModelCustomData
|
||||||
faces.addAll(g.applyTransform(transform));
|
faces.addAll(g.applyTransform(transform));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (this.state instanceof TRSRTransformation)
|
|
||||||
{
|
|
||||||
transform = (TRSRTransformation) this.state;
|
|
||||||
faces.addAll(g.applyTransform(transform));
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
transform = TRSRTransformation.identity();
|
transform = state.apply(model);
|
||||||
faces.addAll(g.applyTransform(transform));
|
faces.addAll(g.applyTransform(transform));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1404,10 +1370,11 @@ public class OBJModel implements IRetexturableModel, IModelCustomData
|
||||||
UnpackedBakedQuad.Builder builder = new UnpackedBakedQuad.Builder(format);
|
UnpackedBakedQuad.Builder builder = new UnpackedBakedQuad.Builder(format);
|
||||||
builder.setQuadOrientation(EnumFacing.getFacingFromVector(f.getNormal().x, f.getNormal().y, f.getNormal().z));
|
builder.setQuadOrientation(EnumFacing.getFacingFromVector(f.getNormal().x, f.getNormal().y, f.getNormal().z));
|
||||||
builder.setQuadColored();
|
builder.setQuadColored();
|
||||||
putVertexData(builder, f.verts[0], f.getNormal(), TextureCoordinate.getDefaultUVs()[0], sprite);
|
Normal faceNormal = f.getNormal();
|
||||||
putVertexData(builder, f.verts[1], f.getNormal(), TextureCoordinate.getDefaultUVs()[1], sprite);
|
putVertexData(builder, f.verts[0], faceNormal, TextureCoordinate.getDefaultUVs()[0], sprite);
|
||||||
putVertexData(builder, f.verts[2], f.getNormal(), TextureCoordinate.getDefaultUVs()[2], sprite);
|
putVertexData(builder, f.verts[1], faceNormal, TextureCoordinate.getDefaultUVs()[1], sprite);
|
||||||
putVertexData(builder, f.verts[3], f.getNormal(), TextureCoordinate.getDefaultUVs()[3], sprite);
|
putVertexData(builder, f.verts[2], faceNormal, TextureCoordinate.getDefaultUVs()[2], sprite);
|
||||||
|
putVertexData(builder, f.verts[3], faceNormal, TextureCoordinate.getDefaultUVs()[3], sprite);
|
||||||
quads.add(builder.build());
|
quads.add(builder.build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1444,19 +1411,19 @@ public class OBJModel implements IRetexturableModel, IModelCustomData
|
||||||
if (!v.hasTextureCoordinate())
|
if (!v.hasTextureCoordinate())
|
||||||
builder.put(e,
|
builder.put(e,
|
||||||
sprite.getInterpolatedU(defUV.u * 16),
|
sprite.getInterpolatedU(defUV.u * 16),
|
||||||
sprite.getInterpolatedV(defUV.v * 16),
|
sprite.getInterpolatedV((model.customData.flipV ? 1 - defUV.v: defUV.v) * 16),
|
||||||
0, 1);
|
0, 1);
|
||||||
else
|
else
|
||||||
builder.put(e,
|
builder.put(e,
|
||||||
sprite.getInterpolatedU(v.getTextureCoordinate().u * 16),
|
sprite.getInterpolatedU(v.getTextureCoordinate().u * 16),
|
||||||
sprite.getInterpolatedV(v.getTextureCoordinate().v * 16),
|
sprite.getInterpolatedV((model.customData.flipV ? 1 - v.getTextureCoordinate().v : v.getTextureCoordinate().v) * 16),
|
||||||
0, 1);
|
0, 1);
|
||||||
break;
|
break;
|
||||||
case NORMAL:
|
case NORMAL:
|
||||||
if (!v.hasNormal())
|
if (!v.hasNormal())
|
||||||
builder.put(e, faceNormal.x, faceNormal.y, faceNormal.z, 1);
|
builder.put(e, faceNormal.x, faceNormal.y, faceNormal.z, 0);
|
||||||
else
|
else
|
||||||
builder.put(e, v.getNormal().x, v.getNormal().y, v.getNormal().z, 1);
|
builder.put(e, v.getNormal().x, v.getNormal().y, v.getNormal().z, 0);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
builder.put(e);
|
builder.put(e);
|
||||||
|
@ -1467,13 +1434,13 @@ public class OBJModel implements IRetexturableModel, IModelCustomData
|
||||||
@Override
|
@Override
|
||||||
public boolean isAmbientOcclusion()
|
public boolean isAmbientOcclusion()
|
||||||
{
|
{
|
||||||
return model != null && model.hasCustomData() ? model.customData.ambientOcclusion : true;
|
return model != null ? model.customData.ambientOcclusion : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isGui3d()
|
public boolean isGui3d()
|
||||||
{
|
{
|
||||||
return model != null && model.hasCustomData() ? model.customData.gui3d : true;
|
return model != null ? model.customData.gui3d : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in a new issue