Instead of computing model bounds after loading, compute them at compile
time and store them with the model. For skinned meshes, run through every frame of every animation as they're compiled in order to find the bounding volume that encloses every deformation. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4080 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -175,6 +175,13 @@ public class Model extends ModelNode
|
|||||||
_scale = scale;
|
_scale = scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void apply (Spatial target)
|
||||||
|
{
|
||||||
|
target.getLocalTranslation().set(_translation);
|
||||||
|
target.getLocalRotation().set(_rotation);
|
||||||
|
target.getLocalScale().set(_scale);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blends between this transform and the next, applying the result to
|
* Blends between this transform and the next, applying the result to
|
||||||
* the given target.
|
* the given target.
|
||||||
@@ -297,6 +304,31 @@ public class Model extends ModelNode
|
|||||||
_anims = new HashMap<String, Animation>();
|
_anims = new HashMap<String, Animation>();
|
||||||
}
|
}
|
||||||
_anims.put(name, anim);
|
_anims.put(name, anim);
|
||||||
|
|
||||||
|
// store the original transforms
|
||||||
|
Transform[] oxforms = new Transform[anim.transformTargets.length];
|
||||||
|
for (int ii = 0; ii < anim.transformTargets.length; ii++) {
|
||||||
|
Spatial target = anim.transformTargets[ii];
|
||||||
|
oxforms[ii] = new Transform(
|
||||||
|
new Vector3f(target.getLocalTranslation()),
|
||||||
|
new Quaternion(target.getLocalRotation()),
|
||||||
|
new Vector3f(target.getLocalScale()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// run through every frame of the animation, expanding the bounding
|
||||||
|
// volumes of any deformable meshes
|
||||||
|
for (int ii = 0; ii < anim.transforms.length; ii++) {
|
||||||
|
for (int jj = 0; jj < anim.transforms[ii].length; jj++) {
|
||||||
|
anim.transforms[ii][jj].apply(anim.transformTargets[jj]);
|
||||||
|
}
|
||||||
|
updateWorldData(0f);
|
||||||
|
expandModelBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
// restore the original transforms
|
||||||
|
for (int ii = 0; ii < anim.transformTargets.length; ii++) {
|
||||||
|
oxforms[ii].apply(anim.transformTargets[ii]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -447,7 +479,15 @@ public class Model extends ModelNode
|
|||||||
public void writeExternal (ObjectOutput out)
|
public void writeExternal (ObjectOutput out)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
|
// don't serialize the emission node; it contains transient geometry
|
||||||
|
// created by controllers
|
||||||
|
if (_emissionNode != null) {
|
||||||
|
detachChild(_emissionNode);
|
||||||
|
}
|
||||||
super.writeExternal(out);
|
super.writeExternal(out);
|
||||||
|
if (_emissionNode != null) {
|
||||||
|
attachChild(_emissionNode);
|
||||||
|
}
|
||||||
out.writeObject(_props);
|
out.writeObject(_props);
|
||||||
out.writeObject(_anims);
|
out.writeObject(_anims);
|
||||||
out.writeObject(getControllers());
|
out.writeObject(getControllers());
|
||||||
|
|||||||
@@ -35,8 +35,7 @@ import java.nio.channels.FileChannel;
|
|||||||
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import com.jme.bounding.BoundingBox;
|
import com.jme.bounding.BoundingVolume;
|
||||||
import com.jme.bounding.BoundingSphere;
|
|
||||||
import com.jme.math.Quaternion;
|
import com.jme.math.Quaternion;
|
||||||
import com.jme.math.Vector3f;
|
import com.jme.math.Vector3f;
|
||||||
import com.jme.renderer.CloneCreator;
|
import com.jme.renderer.CloneCreator;
|
||||||
@@ -89,8 +88,7 @@ public class ModelMesh extends TriMesh
|
|||||||
public void configure (
|
public void configure (
|
||||||
boolean solid, String texture, boolean transparent, Properties props)
|
boolean solid, String texture, boolean transparent, Properties props)
|
||||||
{
|
{
|
||||||
_boundingType = "sphere".equals(props.getProperty("bound")) ?
|
|
||||||
SPHERE_BOUND : BOX_BOUND;
|
|
||||||
_textures = (texture == null) ? null : StringUtil.parseStringArray(
|
_textures = (texture == null) ? null : StringUtil.parseStringArray(
|
||||||
props.getProperty(texture, texture));
|
props.getProperty(texture, texture));
|
||||||
_solid = solid;
|
_solid = solid;
|
||||||
@@ -118,13 +116,6 @@ public class ModelMesh extends TriMesh
|
|||||||
_textureByteBuffer = textures;
|
_textureByteBuffer = textures;
|
||||||
_indexByteBuffer = indices;
|
_indexByteBuffer = indices;
|
||||||
|
|
||||||
if (_boundingType == BOX_BOUND) {
|
|
||||||
setModelBound(new BoundingBox());
|
|
||||||
} else { // _boundingType == SPHERE_BOUND
|
|
||||||
setModelBound(new BoundingSphere());
|
|
||||||
}
|
|
||||||
updateModelBound();
|
|
||||||
|
|
||||||
// initialize the model if we're displaying
|
// initialize the model if we're displaying
|
||||||
if (DisplaySystem.getDisplaySystem() == null) {
|
if (DisplaySystem.getDisplaySystem() == null) {
|
||||||
return;
|
return;
|
||||||
@@ -231,12 +222,12 @@ public class ModelMesh extends TriMesh
|
|||||||
out.writeObject(getLocalTranslation());
|
out.writeObject(getLocalTranslation());
|
||||||
out.writeObject(getLocalRotation());
|
out.writeObject(getLocalRotation());
|
||||||
out.writeObject(getLocalScale());
|
out.writeObject(getLocalScale());
|
||||||
|
out.writeObject(getModelBound());
|
||||||
out.writeInt(_vertexBufferSize);
|
out.writeInt(_vertexBufferSize);
|
||||||
out.writeInt(_normalBufferSize);
|
out.writeInt(_normalBufferSize);
|
||||||
out.writeInt(_colorBufferSize);
|
out.writeInt(_colorBufferSize);
|
||||||
out.writeInt(_textureBufferSize);
|
out.writeInt(_textureBufferSize);
|
||||||
out.writeInt(_indexBufferSize);
|
out.writeInt(_indexBufferSize);
|
||||||
out.writeInt(_boundingType);
|
|
||||||
out.writeObject(_textures);
|
out.writeObject(_textures);
|
||||||
out.writeBoolean(_solid);
|
out.writeBoolean(_solid);
|
||||||
out.writeBoolean(_transparent);
|
out.writeBoolean(_transparent);
|
||||||
@@ -250,17 +241,23 @@ public class ModelMesh extends TriMesh
|
|||||||
setLocalTranslation((Vector3f)in.readObject());
|
setLocalTranslation((Vector3f)in.readObject());
|
||||||
setLocalRotation((Quaternion)in.readObject());
|
setLocalRotation((Quaternion)in.readObject());
|
||||||
setLocalScale((Vector3f)in.readObject());
|
setLocalScale((Vector3f)in.readObject());
|
||||||
|
setModelBound((BoundingVolume)in.readObject());
|
||||||
_vertexBufferSize = in.readInt();
|
_vertexBufferSize = in.readInt();
|
||||||
_normalBufferSize = in.readInt();
|
_normalBufferSize = in.readInt();
|
||||||
_colorBufferSize = in.readInt();
|
_colorBufferSize = in.readInt();
|
||||||
_textureBufferSize = in.readInt();
|
_textureBufferSize = in.readInt();
|
||||||
_indexBufferSize = in.readInt();
|
_indexBufferSize = in.readInt();
|
||||||
_boundingType = in.readInt();
|
|
||||||
_textures = (String[])in.readObject();
|
_textures = (String[])in.readObject();
|
||||||
_solid = in.readBoolean();
|
_solid = in.readBoolean();
|
||||||
_transparent = in.readBoolean();
|
_transparent = in.readBoolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// documentation inherited from interface ModelSpatial
|
||||||
|
public void expandModelBounds ()
|
||||||
|
{
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
// documentation inherited from interface ModelSpatial
|
// documentation inherited from interface ModelSpatial
|
||||||
public void setReferenceTransforms ()
|
public void setReferenceTransforms ()
|
||||||
{
|
{
|
||||||
@@ -489,11 +486,5 @@ public class ModelMesh extends TriMesh
|
|||||||
/** The shared state for checking, but not writing to, the z buffer. */
|
/** The shared state for checking, but not writing to, the z buffer. */
|
||||||
protected static ZBufferState _overlayZBuffer;
|
protected static ZBufferState _overlayZBuffer;
|
||||||
|
|
||||||
/** Indicates that this mesh should use a bounding box. */
|
|
||||||
protected static final int BOX_BOUND = 0;
|
|
||||||
|
|
||||||
/** Indicates that this mesh should use a bounding sphere. */
|
|
||||||
protected static final int SPHERE_BOUND = 1;
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1;
|
private static final long serialVersionUID = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,6 +103,16 @@ public class ModelNode extends Node
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override // documentation inherited
|
||||||
|
public void updateWorldBound ()
|
||||||
|
{
|
||||||
|
// if the node is culled, there are no mesh descendants and thus no
|
||||||
|
// bounds
|
||||||
|
if (cullMode != CULL_ALWAYS) {
|
||||||
|
super.updateWorldBound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override // documentation inherited
|
@Override // documentation inherited
|
||||||
public void updateWorldVectors ()
|
public void updateWorldVectors ()
|
||||||
{
|
{
|
||||||
@@ -159,6 +169,16 @@ public class ModelNode extends Node
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// documentation inherited from interface ModelSpatial
|
||||||
|
public void expandModelBounds ()
|
||||||
|
{
|
||||||
|
for (Object child : getChildren()) {
|
||||||
|
if (child instanceof ModelSpatial) {
|
||||||
|
((ModelSpatial)child).expandModelBounds();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// documentation inherited from interface ModelSpatial
|
// documentation inherited from interface ModelSpatial
|
||||||
public void setReferenceTransforms ()
|
public void setReferenceTransforms ()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -36,6 +36,12 @@ import com.jme.scene.Spatial;
|
|||||||
*/
|
*/
|
||||||
public interface ModelSpatial
|
public interface ModelSpatial
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Recursively expands the model bounds of any deformable meshes so that
|
||||||
|
* they include the current vertex positions.
|
||||||
|
*/
|
||||||
|
public void expandModelBounds ();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively sets the reference transforms for any bones in the model.
|
* Recursively sets the reference transforms for any bones in the model.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import java.nio.IntBuffer;
|
|||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import com.jme.bounding.BoundingVolume;
|
||||||
import com.jme.math.Matrix4f;
|
import com.jme.math.Matrix4f;
|
||||||
import com.jme.math.Vector3f;
|
import com.jme.math.Vector3f;
|
||||||
import com.jme.renderer.CloneCreator;
|
import com.jme.renderer.CloneCreator;
|
||||||
@@ -184,6 +185,14 @@ public class SkinMesh extends ModelMesh
|
|||||||
_weightGroups = (WeightGroup[])in.readObject();
|
_weightGroups = (WeightGroup[])in.readObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override // documentation inherited
|
||||||
|
public void expandModelBounds ()
|
||||||
|
{
|
||||||
|
BoundingVolume obound = (BoundingVolume)getModelBound().clone(null);
|
||||||
|
updateModelBound();
|
||||||
|
getModelBound().mergeLocal(obound);
|
||||||
|
}
|
||||||
|
|
||||||
@Override // documentation inherited
|
@Override // documentation inherited
|
||||||
public void setReferenceTransforms ()
|
public void setReferenceTransforms ()
|
||||||
{
|
{
|
||||||
@@ -280,7 +289,6 @@ public class SkinMesh extends ModelMesh
|
|||||||
BufferUtils.setInBuffer(_normal, nbuf, idx);
|
BufferUtils.setInBuffer(_normal, nbuf, idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateModelBound();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import org.apache.tools.ant.types.FileSet;
|
|||||||
|
|
||||||
import com.jme.scene.Spatial;
|
import com.jme.scene.Spatial;
|
||||||
import com.jme.util.LoggingSystem;
|
import com.jme.util.LoggingSystem;
|
||||||
|
import com.jmex.model.XMLparser.Converters.DummyDisplaySystem;
|
||||||
|
|
||||||
import com.samskivert.util.PropertiesUtil;
|
import com.samskivert.util.PropertiesUtil;
|
||||||
import com.samskivert.util.StringUtil;
|
import com.samskivert.util.StringUtil;
|
||||||
@@ -103,6 +104,7 @@ public class CompileModelTask extends Task
|
|||||||
ModelDef mdef = _mparser.parseModel(content.toString());
|
ModelDef mdef = _mparser.parseModel(content.toString());
|
||||||
HashMap<String, Spatial> nodes = new HashMap<String, Spatial>();
|
HashMap<String, Spatial> nodes = new HashMap<String, Spatial>();
|
||||||
Model model = mdef.createModel(props, nodes);
|
Model model = mdef.createModel(props, nodes);
|
||||||
|
model.initPrototype();
|
||||||
|
|
||||||
// load the animations, if any
|
// load the animations, if any
|
||||||
for (int ii = 0; ii < anims.length; ii++) {
|
for (int ii = 0; ii < anims.length; ii++) {
|
||||||
@@ -122,11 +124,16 @@ public class CompileModelTask extends Task
|
|||||||
_filesets.add(set);
|
_filesets.add(set);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void init () throws BuildException
|
||||||
|
{
|
||||||
|
// create a dummy display system
|
||||||
|
new DummyDisplaySystem();
|
||||||
|
LoggingSystem.getLogger().setLevel(Level.WARNING);
|
||||||
|
}
|
||||||
|
|
||||||
public void execute ()
|
public void execute ()
|
||||||
throws BuildException
|
throws BuildException
|
||||||
{
|
{
|
||||||
LoggingSystem.getLoggingSystem().setLevel(Level.WARNING);
|
|
||||||
|
|
||||||
for (int ii = 0, nn = _filesets.size(); ii < nn; ii++) {
|
for (int ii = 0, nn = _filesets.size(); ii < nn; ii++) {
|
||||||
FileSet fs = _filesets.get(ii);
|
FileSet fs = _filesets.get(ii);
|
||||||
DirectoryScanner ds = fs.getDirectoryScanner(getProject());
|
DirectoryScanner ds = fs.getDirectoryScanner(getProject());
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ import java.util.Iterator;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import com.jme.bounding.BoundingBox;
|
||||||
|
import com.jme.bounding.BoundingSphere;
|
||||||
import com.jme.math.FastMath;
|
import com.jme.math.FastMath;
|
||||||
import com.jme.scene.Spatial;
|
import com.jme.scene.Spatial;
|
||||||
import com.jme.util.geom.BufferUtils;
|
import com.jme.util.geom.BufferUtils;
|
||||||
@@ -49,7 +51,8 @@ import com.threerings.jme.model.ModelNode;
|
|||||||
import com.threerings.jme.model.SkinMesh;
|
import com.threerings.jme.model.SkinMesh;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An intermediate representation for model nodes using in XML parsing.
|
* An intermediate representation for models used to store data parsed from
|
||||||
|
* XML and convert it into JME nodes.
|
||||||
*/
|
*/
|
||||||
public class ModelDef
|
public class ModelDef
|
||||||
{
|
{
|
||||||
@@ -211,6 +214,10 @@ public class ModelDef
|
|||||||
}
|
}
|
||||||
_mesh.reconstruct(vbbuf, nbbuf, null, tbbuf, ibbuf);
|
_mesh.reconstruct(vbbuf, nbbuf, null, tbbuf, ibbuf);
|
||||||
|
|
||||||
|
_mesh.setModelBound("sphere".equals(props.getProperty("bound")) ?
|
||||||
|
new BoundingSphere() : new BoundingBox());
|
||||||
|
_mesh.updateModelBound();
|
||||||
|
|
||||||
// set the mesh's origin to the center of its bounding box
|
// set the mesh's origin to the center of its bounding box
|
||||||
_mesh.centerVertices();
|
_mesh.centerVertices();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -423,7 +423,6 @@ public class ModelViewer extends JmeCanvasApp
|
|||||||
_status.setText(_msg.get("m.compiling_model", file));
|
_status.setText(_msg.get("m.compiling_model", file));
|
||||||
Model model = CompileModelTask.compileModel(file);
|
Model model = CompileModelTask.compileModel(file);
|
||||||
if (model != null) {
|
if (model != null) {
|
||||||
model.initPrototype();
|
|
||||||
setModel(model, file);
|
setModel(model, file);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -456,7 +455,6 @@ public class ModelViewer extends JmeCanvasApp
|
|||||||
}
|
}
|
||||||
_ctx.getGeometry().attachChild(_model = model);
|
_ctx.getGeometry().attachChild(_model = model);
|
||||||
_model.lockStaticMeshes(_ctx.getRenderer(), true, true);
|
_model.lockStaticMeshes(_ctx.getRenderer(), true, true);
|
||||||
_model.getLocalTranslation().set(-20f, 0f, 0f);
|
|
||||||
|
|
||||||
// resolve the textures from the file's directory
|
// resolve the textures from the file's directory
|
||||||
final File dir = file.getParentFile();
|
final File dir = file.getParentFile();
|
||||||
|
|||||||
Reference in New Issue
Block a user