Model global pretransforms + physics work

This commit is contained in:
austin 2023-12-02 18:24:05 -05:00
parent f248bf4e2d
commit dc0a61c0dc
32 changed files with 470 additions and 110 deletions

View File

@ -103,6 +103,10 @@
"dimension1" : 0.1,
"dimension2" : 0.2,
"dimension3" : 0.1,
"rotX": 0,
"rotY": 0,
"rotZ": 0,
"rotW": 1,
"offsetX" : 0,
"offsetY" : 0.2,
"offsetZ" : 0
@ -159,6 +163,10 @@
"dimension1" : 0.1,
"dimension2" : 0.45,
"dimension3" : 0.1,
"rotX": 0,
"rotY": 0,
"rotZ": 0,
"rotW": 1,
"offsetX" : 0,
"offsetY" : 0.45,
"offsetZ" : 0
@ -208,6 +216,10 @@
"dimension1" : 0.1,
"dimension2" : 0.2,
"dimension3" : 0.1,
"rotX": 0,
"rotY": 0,
"rotZ": 0,
"rotW": 1,
"offsetX" : 0,
"offsetY" : 0.2,
"offsetZ" : 0

View File

@ -269,6 +269,10 @@
"dimension1" : 0.1,
"dimension2" : 0.45,
"dimension3" : 0.1,
"rotX": 0,
"rotY": 0,
"rotZ": 0,
"rotW": 1,
"offsetX" : 0,
"offsetY" : 0.45,
"offsetZ" : 0

View File

@ -269,6 +269,10 @@
"dimension1" : 0.1,
"dimension2" : 0.9,
"dimension3" : 0.1,
"rotX": 0,
"rotY": 0,
"rotZ": 0,
"rotW": 1,
"offsetX" : 0,
"offsetY" : 0.45,
"offsetZ" : 0

View File

@ -75,6 +75,10 @@
"dimension1" : 0.1,
"dimension2" : 0.45,
"dimension3" : 0.1,
"rotX": 0,
"rotY": 0,
"rotZ": 0,
"rotW": 1,
"offsetX" : 0,
"offsetY" : 0.45,
"offsetZ" : 0

View File

@ -76,6 +76,10 @@
"dimension1" : 0.5,
"dimension2" : 3,
"dimension3" : 0.5,
"rotX": 0,
"rotY": 0,
"rotZ": 0,
"rotW": 1,
"offsetX" : 0,
"offsetY" : 1.5,
"offsetZ" : 0

View File

@ -41,6 +41,10 @@
"dimension1" : 0.03,
"dimension2" : 0.03,
"dimension3" : 0.2,
"rotX": 0,
"rotY": 0,
"rotZ": 0,
"rotW": 1,
"offsetX" : 0.0,
"offsetY" : 0.05,
"offsetZ" : 0.0
@ -67,6 +71,10 @@
"dimension1" : 0.1,
"dimension2" : 0.1,
"dimension3" : 0.35,
"rotX": 0,
"rotY": 0,
"rotZ": 0,
"rotW": 1,
"offsetX" : 0,
"offsetY" : 0.05,
"offsetZ" : 0
@ -87,6 +95,10 @@
"dimension1" : 0.1,
"dimension2" : 0.1,
"dimension3" : 0.35,
"rotX": 0,
"rotY": 0,
"rotZ": 0,
"rotW": 1,
"offsetX" : 0,
"offsetY" : 0.05,
"offsetZ" : 0
@ -120,6 +132,10 @@
"dimension1" : 0.1,
"dimension2" : 0.1,
"dimension3" : 0.35,
"rotX": 0,
"rotY": 0,
"rotZ": 0,
"rotW": 1,
"offsetX" : 0,
"offsetY" : 0.05,
"offsetZ" : 0
@ -151,6 +167,10 @@
"dimension1" : 0.1,
"dimension2" : 0.1,
"dimension3" : 0.35,
"rotX": 0,
"rotY": 0,
"rotZ": 0,
"rotW": 1,
"offsetX" : 0,
"offsetY" : 0.05,
"offsetZ" : 0
@ -188,6 +208,10 @@
"dimension1" : 0.1,
"dimension2" : 0.1,
"dimension3" : 0.35,
"rotX": 0,
"rotY": 0,
"rotZ": 0,
"rotW": 1,
"offsetX" : 0,
"offsetY" : 0.05,
"offsetZ" : 0

View File

@ -13,6 +13,10 @@
"dimension1" : 0.1,
"dimension2" : 0.1,
"dimension3" : 0.35,
"rotX": 0,
"rotY": 0,
"rotZ": 0,
"rotW": 1,
"offsetX" : 0,
"offsetY" : 0.05,
"offsetZ" : 0

View File

@ -13,6 +13,10 @@
"dimension1" : 1.7,
"dimension2" : 1.7,
"dimension3" : 1.7,
"rotX": 0,
"rotY": 0,
"rotZ": 0,
"rotW": 1,
"offsetX" : 0,
"offsetY" : -1.7,
"offsetZ" : 0

View File

@ -54,6 +54,16 @@
"scale" : [1.0, 1.0, 1.0]
}
]
},
{
"path" : "Models/baseman5.fbx",
"globalTransform": {
"rotation" : [0,0,0,1],
"offset" : [0.0, 0.0, 0.0],
"scale" : [0.005, 0.005, 0.005]
},
"meshes" : [
]
}
]
}

View File

@ -25,6 +25,7 @@ The big case for this engine is the main physics system. The goal is to provide
## Major Usage Notes
- All geometries are aligned along z by default in the library (ie your cylinders will be on their sides)
- All functions that transform the scale of a DBody only transform the first shape within the rigid body. This should likely eventually be updated to support multiple shapes in a body.

View File

@ -0,0 +1,79 @@
# Model Loading
TODO
## High Level Overview
## Major Usage Notes
## Main Classes
[CollisionEngine.java](@ref #electrosphere.collision.CollisionEngine) - Represents a specific collision system. It may be helpful to think of it as viewing the world through a specific lens. Keeps track of all entities that do its type of collisions and fires callbacks on collision. Should be updated each tick.
## Library Explanation
## Code Organization and Best Practices
#### Startup
#### Usage
## Terminology
## Future Goals

View File

@ -16,9 +16,12 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.Semaphore;
import org.joml.Matrix4d;
import org.joml.Matrix4f;
import org.joml.Quaterniond;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector4d;
import org.ode4j.math.DMatrix3;
import org.ode4j.math.DVector3;
import org.ode4j.math.DVector4;
@ -356,15 +359,19 @@ public class CollisionEngine {
*/
public void updateDynamicObjectTransforms(){
for(Collidable collidable : collidableList){
if(collidable.getParentTracksCollidable()){
Entity physicsEntity = collidable.getParent();
DBody rigidBody = (DBody)physicsEntity.getData(EntityDataStrings.PHYSICS_COLLISION_BODY);
Vector3d offset = (Vector3d)physicsEntity.getData(EntityDataStrings.PHYSICS_COLLISION_BODY_OFFSET);
Vector3d newPosition = PhysicsUtils.getRigidBodyPosition(rigidBody).sub(offset);
Matrix4d transform = PhysicsEntityUtils.getEntityCollidableTransform(physicsEntity);
Matrix4d inverseTransform = transform.invert();
Vector4d rawPos = inverseTransform.transform(new Vector4d(PhysicsUtils.getRigidBodyPosition(rigidBody),1));
Vector3d newPosition = new Vector3d(rawPos.x,rawPos.y,rawPos.z);
Quaterniond newRotation = PhysicsUtils.getRigidBodyRotation(rigidBody);
EntityUtils.getPosition(physicsEntity).set(newPosition);
EntityUtils.getRotation(physicsEntity).set(newRotation);
}
}
}
public void registerCollisionObject(DBody body, Collidable collidable){
registerPhysicsObject(body);
@ -633,6 +640,28 @@ public class CollisionEngine {
spaceLock.release();
}
/**
* Sets the transform on a body
* @param body The body
* @param position The position
* @param rotation The rotation
* @param scale The scale
*/
protected void setBodyTransform(DBody body, Vector3d position, Quaterniond rotation, Vector3d scale){
spaceLock.acquireUninterruptibly();
body.setPosition(position.x, position.y, position.z);
body.setQuaternion(PhysicsUtils.jomlQuatToOdeQuat(rotation));
DGeom firstGeom = body.getFirstGeom();
if(firstGeom instanceof DCylinder){
((DCylinder)firstGeom).setParams(scale.x,scale.y);
} else if(firstGeom instanceof DBox){
((DBox)firstGeom).setLengths(scale.x,scale.y,scale.z);
} else if(firstGeom instanceof DCapsule){
((DCapsule)firstGeom).setParams(scale.x,scale.y);
}
spaceLock.release();
}
/**
* Gets the position of the body in a thread-safe way
* @param body The body to get the position of

View File

@ -1,5 +1,6 @@
package electrosphere.collision;
import org.joml.Matrix4d;
import org.joml.Matrix4f;
import org.joml.Vector3d;
import org.joml.Vector3f;
@ -45,7 +46,13 @@ public class PhysicsEntityUtils {
collidable = new Collidable(rVal, Collidable.TYPE_CREATURE);
ClientCollidableTree tree = new ClientCollidableTree(rVal,collidable,rigidBody);
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY, rigidBody);
Matrix4d offsetTransform = new Matrix4d().translationRotateScale(
physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ(), //translate
physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW(), //rotate
1, 1, 1 //scale
);
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_OFFSET, new Vector3f(physicsTemplate.getOffsetX(),physicsTemplate.getOffsetY(),physicsTemplate.getOffsetZ()));
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform);
rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate);
rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
rVal.putData(EntityDataStrings.CLIENT_COLLIDABLE_TREE, tree);
@ -71,7 +78,13 @@ public class PhysicsEntityUtils {
collidable = new Collidable(rVal, Collidable.TYPE_CREATURE);
ClientCollidableTree tree = new ClientCollidableTree(rVal,collidable,rigidBody);
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY, rigidBody);
Matrix4d offsetTransform = new Matrix4d().translationRotateScale(
physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ(), //translate
physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW(), //rotate
1, 1, 1 //scale
);
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_OFFSET, new Vector3f(physicsTemplate.getOffsetX(),physicsTemplate.getOffsetY(),physicsTemplate.getOffsetZ()));
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform);
rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate);
rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
rVal.putData(EntityDataStrings.CLIENT_COLLIDABLE_TREE, tree);
@ -267,4 +280,13 @@ public class PhysicsEntityUtils {
return terrainBody;
}
/**
* Gets the transform from parent entity position to rigid body
* @param entity The entity
* @return The transform
*/
public static Matrix4d getEntityCollidableTransform(Entity entity){
return (Matrix4d) entity.getData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM);
}
}

View File

@ -68,6 +68,18 @@ public class PhysicsUtils {
collisionEngine.setBodyTransform(body, position, rotation);
}
/**
* Sets the position + rotation + scale of a body
* @param position The position
* @param rotation The rotation
* @param scale The scale
* @param body The body
*/
public static void setRigidBodyTransform(CollisionEngine collisionEngine, Vector3d position, Quaterniond rotation, Vector3d scale, DBody body){
collisionEngine.setBodyTransform(body, position, rotation, scale);
}
/**
* Creates a mass in the physics space from the body and mass value input
* @param collisionEngine The collision engine to create the mass in

View File

@ -15,9 +15,15 @@ import org.joml.Vector3f;
*/
public class Collidable {
//The entity this collidable is attached to
Entity parent;
//The type of collidable
String type;
//If true, once impulses are applied to the collidable, have the parent entity resynchronize its position with the collidable
boolean parentTracksCollidable = true;
//The impulses to be applied to this collidable
List<Impulse> impulses = new CopyOnWriteArrayList<Impulse>();
public static final String TYPE_TERRAIN = "terrain";
@ -49,6 +55,14 @@ public class Collidable {
return type;
}
/**
* Gets whether the parent tracks the collidable's position
* @return True if the parent tracks the collidable's position, false otherwise
*/
public boolean getParentTracksCollidable(){
return parentTracksCollidable;
}
public void overrideType(String type){
this.type = type;
}

View File

@ -242,10 +242,10 @@ public class ClientLoading {
});
Random rand = new Random(0);
{
Entity tree = ProceduralTree.clientGenerateProceduralTree("oak", rand.nextLong());
EntityUtils.getPosition(tree).set(5,0,5);
}
// {
// Entity tree = ProceduralTree.clientGenerateProceduralTree("oak", rand.nextLong());
// EntityUtils.getPosition(tree).set(5,0,5);
// }
// for(int i = 0; i < 6; i++){
// Entity tree = ProceduralTree.clientGenerateProceduralTree("oak", rand.nextLong());
// // EntityUtils.getPosition(tree).set(5,0,5);
@ -258,6 +258,7 @@ public class ClientLoading {
for(int z = 0; z < 5; z++){
Entity tree = ProceduralTree.clientGenerateProceduralTree("oak", rand.nextLong());
ClientEntityUtils.initiallyPositionEntity(tree, new Vector3d(5 + x * 5,0,5 + z * 5));
EntityUtils.getScale(tree).set(0.5f);
}
}

View File

@ -118,6 +118,7 @@ public class EntityDataStrings {
*/
public static final String PHYSICS_COLLISION_BODY = "physicsRigidBody";
public static final String PHYSICS_COLLISION_BODY_OFFSET = "physicsRigidBodyOffset";
public static final String PHYSICS_COLLISION_BODY_TRANSFORM = "physicsRigidBodyTransform"; // the transform matrix from origin of entity to origin of physics body
public static final String PHYSICS_COLLIDABLE = "physicsCollidable";
public static final String PHYSICS_MODEL_TEMPLATE = "physicsModelTemplate";
public static final String PHYSICS_MASS = "physicsMass";

View File

@ -1,11 +1,14 @@
package electrosphere.entity.state.collidable;
import org.joml.Matrix4d;
import org.joml.Matrix4f;
import org.joml.Quaterniond;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector4d;
import org.ode4j.ode.DBody;
import electrosphere.collision.PhysicsEntityUtils;
import electrosphere.collision.PhysicsUtils;
import electrosphere.collision.collidable.Collidable;
import electrosphere.engine.Globals;
@ -201,10 +204,26 @@ public class ClientCollidableTree implements BehaviorTree {
//update collision engine of this thing's position
CollidableTemplate template = (CollidableTemplate)parent.getData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE);
Matrix4d physicsBodyTransform = PhysicsEntityUtils.getEntityCollidableTransform(parent);
Vector3f parentScale = EntityUtils.getScale(parent);
Matrix4d parentTransform = new Matrix4d();
// calculate new transform for current entity
parentTransform.identity()
.translate(position)
.rotate(rotation)
.scale(parentScale.x,parentScale.y,parentScale.z)
.mul(physicsBodyTransform);
//transform bone space
Vector4d rigidBodyPositionRaw = parentTransform.transform(new Vector4d(0,0,0,1));
Vector3d rigidBodyPosition = new Vector3d(rigidBodyPositionRaw.x,rigidBodyPositionRaw.y,rigidBodyPositionRaw.z);
Quaterniond rigidBodyRotation = parentTransform.getUnnormalizedRotation(new Quaterniond()).normalize();
Vector3d rigidBodyScaleRaw = parentTransform.getScale(new Vector3d());
Vector3d rigidBodyScale = new Vector3d(rigidBodyScaleRaw.x,rigidBodyScaleRaw.y,rigidBodyScaleRaw.z);
PhysicsUtils.setRigidBodyTransform(
Globals.clientSceneWrapper.getCollisionEngine(),
new Vector3d(position.x + template.getOffsetX(),position.y + template.getOffsetY(),position.z + template.getOffsetZ()),
rotation,
rigidBodyPosition,
rigidBodyRotation,
rigidBodyScale,
body
);
}

View File

@ -11,6 +11,11 @@ public class CollidableTemplate {
float dimension2;
float dimension3;
float rotX;
float rotY;
float rotZ;
float rotW;
float offsetX;
float offsetY;
float offsetZ;
@ -31,6 +36,22 @@ public class CollidableTemplate {
return dimension3;
}
public float getRotX(){
return rotX;
}
public float getRotY(){
return rotY;
}
public float getRotZ(){
return rotZ;
}
public float getRotW(){
return rotW;
}
public float getOffsetX() {
return offsetX;
}

View File

@ -44,7 +44,6 @@ public class EntityProtocol {
LoggerInterface.loggerNetworking.DEBUG("Spawn Creature " + message.getentityID() + " at " + message.getpositionX() + " " + message.getpositionY() + " " + message.getpositionZ());
CreatureTemplate template = Utilities.deserialize(message.getcreatureTemplate(), CreatureTemplate.class);
newlySpawnedEntity = CreatureUtils.clientSpawnBasicCreature(template.getCreatureType(),template);
EntityUtils.getScale(newlySpawnedEntity).set(0.005f);
EntityUtils.getPosition(newlySpawnedEntity).set(message.getpositionX(),message.getpositionY(),message.getpositionZ());
Globals.clientSceneWrapper.mapIdToId(newlySpawnedEntity.getId(), message.getentityID());
break;

View File

@ -7,6 +7,8 @@ import org.joml.Matrix4d;
import org.joml.Matrix4f;
import org.lwjgl.assimp.AIBone;
import electrosphere.renderer.loading.ModelPretransforms;
/**
*
* @author satellite
@ -15,22 +17,22 @@ public class Bone {
public String boneID;
int numWeights;
HashMap<Integer,Float> weights;
public Matrix4f inverseBindPoseMatrix;
public Matrix4d inverseBindPoseMatrix;
public Matrix4d deform;
public Matrix4f transform;
public Matrix4f final_transform;
public Matrix4d transform;
public Matrix4d final_transform;
public AIBone raw_data;
public Bone(){
transform = new Matrix4f();
transform = new Matrix4d();
deform = new Matrix4d();
final_transform = new Matrix4f();
final_transform = new Matrix4d();
}
public Bone(AIBone raw_data){
transform = new Matrix4f();
transform = new Matrix4d();
deform = new Matrix4d();
final_transform = new Matrix4f();
final_transform = new Matrix4d();
boneID = raw_data.mName().dataString();
inverseBindPoseMatrix = electrosphere.util.Utilities.convertAIMatrix(raw_data.mOffsetMatrix());
inverseBindPoseMatrix = electrosphere.util.Utilities.convertAIMatrixd(raw_data.mOffsetMatrix());
this.raw_data = raw_data;
}
}

View File

@ -25,6 +25,7 @@ import java.util.Map;
import org.joml.Matrix4d;
import org.joml.Matrix4f;
import org.joml.Quaternionf;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector4d;
import org.lwjgl.BufferUtils;
@ -161,8 +162,6 @@ public class Mesh {
Matrix4d vertexPretransform = new Matrix4d().identity();
if(metadata != null){
System.out.println("Pretransforming");
@ -199,6 +198,7 @@ public class Mesh {
minZ = maxZ = z;
}
Vector4d transformedVertex = vertexPretransform.transform(new Vector4d(x,y,z,1.0));
transformedVertex.w = 1.0;
temp[0] = (float)transformedVertex.x;
temp[1] = (float)transformedVertex.y;
temp[2] = (float)transformedVertex.z;
@ -313,7 +313,7 @@ public class Mesh {
// System.out.println("Num weights: " + currentBoneData.mNumWeights());
Bone currentBone = new Bone();
currentBone.boneID = currentBoneData.mName().dataString();
currentBone.inverseBindPoseMatrix = electrosphere.util.Utilities.convertAIMatrix(currentBoneData.mOffsetMatrix());
currentBone.inverseBindPoseMatrix = electrosphere.util.Utilities.convertAIMatrixd(currentBoneData.mOffsetMatrix());
currentBone.numWeights = currentBoneData.mNumWeights();
currentBone.weights = new HashMap<Integer,Float>();
Iterator<AIVertexWeight> weightIterator = currentBoneData.mWeights().iterator();

View File

@ -65,7 +65,7 @@ public class Model {
public ArrayList<Material> materials;
public Matrix4d modelMatrix = new Matrix4d();
ShaderProgram program;
Matrix4f globalInverseTransform;
Matrix4d globalInverseTransform;
AnimNode root_anim_node;
ActorMeshMask meshMask;
@ -80,6 +80,10 @@ public class Model {
rVal.scene = s;
ModelPretransforms.ModelMetadata modelMetadata = Globals.modelPretransforms.getModel(path);
ModelPretransforms.GlobalTransform globalTransform = null;
if(modelMetadata != null){
globalTransform = modelMetadata.getGlobalTransform();
}
//
//load meshes
@ -146,7 +150,10 @@ public class Model {
//parse animation nodes and form hierarchy
//
AINode rootNode = s.mRootNode();
rVal.globalInverseTransform = electrosphere.util.Utilities.convertAIMatrix(rootNode.mTransformation());
rVal.globalInverseTransform = electrosphere.util.Utilities.convertAIMatrixd(rootNode.mTransformation());
if(globalTransform != null){
rVal.globalInverseTransform.scale(globalTransform.getScale());
}
// System.out.println("Global inverse transform");
// System.out.println(globalInverseTransform);
rVal.root_anim_node = rVal.build_anim_node_map(s.mRootNode(),null);
@ -406,18 +413,24 @@ public class Model {
boneMatrix = new Matrix4f(rootTransformation).mul(boneMatrix);
frame.setMatrix(j, boneMatrix);
*/
//
//bone rotators (turrets, hair, etc)
Bone target_bone = boneMap.get(n.id);
n.transform = n.transform.mul(target_bone.deform);
if(boneRotators.containsKey(target_bone.boneID)){
n.transform.rotate(boneRotators.get(target_bone.boneID).getRotation());
}
Matrix4f bone_matrix = new Matrix4f(n.transform);
//
//static morph (changing nose size, eye distance, etc)
Matrix4d bone_matrix = new Matrix4d(n.transform);
if(staticMorph != null && staticMorph.getBoneTransforms(n.id) != null){
bone_matrix.mul(staticMorph.getBoneTransforms(n.id).getTransform());
n.transform.mul(staticMorph.getBoneTransforms(n.id).getTransform());
}
//
//Calculate final offset from initial bone
bone_matrix.mul(target_bone.inverseBindPoseMatrix);
bone_matrix = new Matrix4f(globalInverseTransform).mul(bone_matrix);
bone_matrix = new Matrix4d(globalInverseTransform).mul(bone_matrix);
target_bone.final_transform = bone_matrix;
// if(!toggled){
// System.out.println(n.id);

View File

@ -18,6 +18,7 @@ import org.joml.Matrix4f;
import org.joml.Quaterniond;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import org.joml.Vector4d;
import org.joml.Vector4f;
/**
@ -247,11 +248,11 @@ public class Actor {
// model.updateNodeTransform();
Bone currentBone = model.boneMap.get(boneName);
if(currentBone != null){
Vector4f result = currentBone.final_transform.transform(new Matrix4f(currentBone.inverseBindPoseMatrix).invert().transform(new Vector4f(rVal.x,rVal.y,rVal.z,1)));
Vector4d result = currentBone.final_transform.transform(new Matrix4d(currentBone.inverseBindPoseMatrix).invert().transform(new Vector4d(rVal.x,rVal.y,rVal.z,1)));
// currentBone.inverseBindPoseMatrix
rVal.x = result.x;
rVal.y = result.y;
rVal.z = result.z;
rVal.x = (float)result.x;
rVal.y = (float)result.y;
rVal.z = (float)result.z;
}
// }
}
@ -270,7 +271,7 @@ public class Actor {
Bone currentBone = model.boneMap.get(boneName);
if(currentBone != null){
AxisAngle4f axisAngle = new AxisAngle4f();
currentBone.final_transform.getRotation(axisAngle);
new Matrix4f(currentBone.final_transform).getRotation(axisAngle);
Quaterniond rotation = new Quaterniond(axisAngle);
rVal.set(rotation);
}
@ -279,8 +280,8 @@ public class Actor {
return rVal;
}
public Matrix4f getBoneTransform(String boneName){
Matrix4f rVal = new Matrix4f();
public Matrix4d getBoneTransform(String boneName){
Matrix4d rVal = new Matrix4d();
Model model = Globals.assetManager.fetchModel(modelPath);
if(model != null){
applyAnimationMasks(model);

View File

@ -25,7 +25,6 @@ public class ActorUtils {
public static void applyBlenderTransformer(Entity actorEntity){
Actor entityActor = EntityUtils.getActor(actorEntity);
entityActor.setAnimationScalar(60f); //should be the value of the fps i think
EntityUtils.getScale(actorEntity).set(0.005f);
}
public static void applyBlenderRotation(Entity actorEntity){

View File

@ -6,9 +6,11 @@ import java.util.Iterator;
import java.util.Map;
import java.util.PriorityQueue;
import org.joml.Matrix4d;
import org.joml.Quaterniond;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import org.joml.Vector4d;
import org.lwjgl.PointerBuffer;
import org.lwjgl.assimp.AIAnimation;
import org.lwjgl.assimp.AIMeshAnim;
@ -17,6 +19,8 @@ import org.lwjgl.assimp.AINodeAnim;
import org.lwjgl.assimp.AIQuatKey;
import org.lwjgl.assimp.AIVectorKey;
import electrosphere.renderer.loading.ModelPretransforms;
/**
*
* @author satellite
@ -69,22 +73,19 @@ public class Animation {
// System.out.println("Ticks per second: " + ticksPerSecond);
// System.out.println("Anim sizeof: " + animData.sizeof());
// System.out.println("Duration: " + duration);
//
//Read in anim channels (bone modifications)
//
int channelCount = animData.mNumChannels();
channels = new ArrayList<AnimChannel>();
if(channelCount > 0){
// System.out.println("Channel count: " + channelCount);
for(int i = 0; i < channelCount; i++){
AINodeAnim currentChannelData = AINodeAnim.create(animData.mChannels().get(i));
// System.out.println("Channel[" + (i + 1) + "]: " + currentChannelData.mNodeName().dataString());
//Create channel
AnimChannel currentChannel = new AnimChannel(duration);
// currentChannel.positionFrame = new ArrayList();
// currentChannel.rotationFrame = new ArrayList();
// currentChannel.scaleFrame = new ArrayList();
currentChannel.nodeID = currentChannelData.mNodeName().dataString();
channels.add(currentChannel);
@ -95,20 +96,17 @@ public class Animation {
if(currentChannelData.mNumPositionKeys() > 0){
org.lwjgl.assimp.AIVectorKey.Buffer buff = currentChannelData.mPositionKeys();
// Iterator<AIVectorKey> keyIterator = buff.iterator();
// while (keyIterator.hasNext()) {
// AIVectorKey key = keyIterator.next();
// Keyframe currentFrame = new Keyframe(key.mTime());
// currentFrame.position = new Vector3f(key.mValue().x(), key.mValue().y(), key.mValue().z());
// currentChannel.positionFrame.add(currentFrame);
// }
if(buff != null && buff.hasRemaining()){
// System.out.println("Position vectors: ");
AIVectorKey key = buff.get();
Keyframe currentFrame = new Keyframe(key.mTime());
currentFrame.position = new Vector3f(key.mValue().x(), key.mValue().y(), key.mValue().z());
Vector4d positionRaw = new Vector4d(
key.mValue().x(),
key.mValue().y(),
key.mValue().z(),
1
);
currentFrame.position = new Vector3f((float)positionRaw.x,(float)positionRaw.y,(float)positionRaw.z);
currentChannel.addPositionFrame(key.mTime(),currentFrame);
// System.out.println(currentFrame.position);
currentChannel.startingPosition = currentFrame.position;
Keyframe previousFrame;
@ -116,10 +114,14 @@ public class Animation {
previousFrame = currentFrame;
key = buff.get();
currentFrame = new Keyframe(key.mTime());
currentFrame.position = new Vector3f(key.mValue().x(), key.mValue().y(), key.mValue().z());
// System.out.println(currentFrame.position);
positionRaw = new Vector4d(
key.mValue().x(),
key.mValue().y(),
key.mValue().z(),
1
);
currentFrame.position = new Vector3f((float)positionRaw.x,(float)positionRaw.y,(float)positionRaw.z);
//check if duplicate
// Keyframe previousFrame = currentChannel.positionFrame.get(currentChannel.positionFrame.size() - 1);
if( previousFrame.position.x == currentFrame.position.x &&
previousFrame.position.y == currentFrame.position.y &&
previousFrame.position.z == currentFrame.position.z
@ -138,7 +140,6 @@ public class Animation {
Keyframe currentFrame = new Keyframe(key.mTime());
currentFrame.rotation = new Quaterniond();
currentFrame.rotation.set(key.mValue().x(), key.mValue().y(), key.mValue().z(), key.mValue().w());
// currentFrame.rotation = new Quaternionf(key.mValue().x(),key.mValue().y(),key.mValue().z(),key.mValue().w());
currentChannel.addRotationFrame(key.mTime(),currentFrame);
currentChannel.startingRotation = currentFrame.rotation;
@ -150,9 +151,7 @@ public class Animation {
currentFrame = new Keyframe(key.mTime());
currentFrame.rotation = new Quaterniond();
currentFrame.rotation.set(key.mValue().x(), key.mValue().y(), key.mValue().z(), key.mValue().w());
// currentFrame.rotation = new Quaternionf(key.mValue().x(),key.mValue().y(),key.mValue().z(),key.mValue().w());
//check for duplicate
// Keyframe previousFrame = currentChannel.rotationFrame.get(currentChannel.rotationFrame.size() - 1);
if( previousFrame.rotation.w == currentFrame.rotation.w &&
previousFrame.rotation.x == currentFrame.rotation.x &&
previousFrame.rotation.y == currentFrame.rotation.y &&
@ -163,35 +162,29 @@ public class Animation {
}
}
}
// Iterator<AIQuatKey> keyIterator = buff.iterator();
// while(keyIterator.hasNext()){
// AIQuatKey key = keyIterator.next();
// Keyframe currentFrame = new Keyframe(key.mTime());
// currentFrame.rotation = new Quaternionf(key.mValue().w(),key.mValue().x(),key.mValue().y(),key.mValue().z());
// currentChannel.rotationFrame.add(currentFrame);
// }
}
if(currentChannelData.mNumScalingKeys() > 0){
org.lwjgl.assimp.AIVectorKey.Buffer buff = currentChannelData.mScalingKeys();
// Iterator<AIVectorKey> keyIterator = buff.iterator();
// while (keyIterator.hasNext()) {
// AIVectorKey key = keyIterator.next();
// Keyframe currentFrame = new Keyframe(key.mTime());
// currentFrame.scale = new Vector3f(key.mValue().x(), key.mValue().y(), key.mValue().z());
// currentChannel.scaleFrame.add(currentFrame);
// }
if(buff != null && buff.hasRemaining()){
AIVectorKey key = buff.get();
Keyframe currentFrame = new Keyframe(key.mTime());
currentFrame.scale = new Vector3f(key.mValue().x(), key.mValue().y(), key.mValue().z());
currentFrame.scale = new Vector3f(
(float)(key.mValue().x()),
(float)(key.mValue().y()),
(float)(key.mValue().z())
);
currentChannel.addScaleFrame(key.mTime(),currentFrame);
Keyframe previousFrame;
while(buff.hasRemaining()){
previousFrame = currentFrame;
key = buff.get();
currentFrame = new Keyframe(key.mTime());
currentFrame.scale = new Vector3f(key.mValue().x(), key.mValue().y(), key.mValue().z());
currentFrame.scale = new Vector3f(
(float)(key.mValue().x()),
(float)(key.mValue().y()),
(float)(key.mValue().z())
);
if( currentFrame.scale.x == previousFrame.scale.x &&
currentFrame.scale.y == previousFrame.scale.y &&
currentFrame.scale.z == previousFrame.scale.z
@ -204,33 +197,8 @@ public class Animation {
}
// System.out.println("end times");
// for(int j = 0; j < currentChannelData.mNumPositionKeys(); j++){
// org.lwjgl.assimp.AIVectorKey.Buffer buff = currentChannelData.mPositionKeys();
// Iterator<AIVectorKey> keyIterator = buff.iterator();
// AIVectorKey posKey = currentChannelData.mPositionKeys().get(i);
// Keyframe currentFrame = new Keyframe(posKey.mTime());
// currentFrame.position = new Vector3f(posKey.mValue().x(),posKey.mValue().y(),posKey.mValue().z());
// }
// for(int j = 0; j < currentChannelData.mNumRotationKeys(); j++){
// AIQuatKey rotKey = currentChannelData.mRotationKeys().get(i);
// HashMap test = new HashMap();
// System.out.println(new Quaternionf(rotKey.mValue().w(),rotKey.mValue().x(),rotKey.mValue().y(),rotKey.mValue().z()));
// }
// for(int j = 0; j < currentChannelData.mNumScalingKeys(); j++){
// AIVectorKey scaleKey = currentChannelData.mScalingKeys().get(i);
//// scaleKey.mValue().
// System.out.println(new Vector3f(scaleKey.mValue().x(),scaleKey.mValue().y(),scaleKey.mValue().z()));
// }
}
}
// int meshChannelCount = animData.mNumMeshChannels();
// meshChannelData = new ArrayList();
// if(meshChannelCount > 0){
// for(int i = 0; i < meshChannelCount; i++){
// AIMeshAnim test = AIMeshAnim.create(animData.mMeshChannels().get(i));
// }
// }
//gotta free things
nodeChannelData = null;
meshChannelData = null;

View File

@ -38,7 +38,9 @@ public class ModelLoader {
aiProcess_JoinIdenticalVertices |
aiProcess_Triangulate |
aiProcess_FixInfacingNormals |
aiProcess_LimitBoneWeights);
aiProcess_LimitBoneWeights |
aiProcess_GlobalScale
);
if(rVal == null){
throw new IllegalStateException(aiGetErrorString());
}

View File

@ -49,6 +49,8 @@ public class ModelPretransforms {
List<MeshMetadata> meshes;
//Map relating path->mesh metadata
Map<String,MeshMetadata> meshDataMap;
//Optional global transform
GlobalTransform globalTransform;
/**
* Initializes the ModelMetadata object
@ -76,6 +78,14 @@ public class ModelPretransforms {
public String getPath(){
return path;
}
/**
* Gets the global transform metadata
* @return The global transform metadata
*/
public GlobalTransform getGlobalTransform(){
return globalTransform;
}
}
/**
@ -122,4 +132,50 @@ public class ModelPretransforms {
return new Vector3d(scale.get(0),scale.get(1),scale.get(2));
}
}
/**
* Holds metadata for pretransforming all meshes and potentially all animations
*/
public class GlobalTransform {
List<Double> rotation;
List<Double> offset;
List<Double> scale;
boolean applyToAnimations;
/**
* gets the rotation of the transform as a JOML Quaterniond
* !!WARNING!! unsafe: If there aren't at least 4 doubles in the array it out of bounds
* @return The rotation of the transform
*/
public Quaterniond getRotation(){
return new Quaterniond(rotation.get(0),rotation.get(1),rotation.get(2),rotation.get(3));
}
/**
* gets the offset of the transform as a JOML vector3d
* !!WARNING!! unsafe: If there aren't at least 3 doubles in the array it out of bounds
* @return The offset of the transform
*/
public Vector3d getOffset(){
return new Vector3d(offset.get(0),offset.get(1),offset.get(2));
}
/**
* gets the scale of the transform as a JOML vector3d
* !!WARNING!! unsafe: If there aren't at least 3 doubles in the array it out of bounds
* @return The scale of the transform
*/
public Vector3d getScale(){
return new Vector3d(scale.get(0),scale.get(1),scale.get(2));
}
/**
* Gets whether the global transform should be applied to animations
* @return True if should apply to animations, false otherwise
*/
public boolean getApplyToAnimations(){
return applyToAnimations;
}
}
}

View File

@ -7,9 +7,11 @@ import java.util.Map;
import java.util.PriorityQueue;
import org.joml.AxisAngle4f;
import org.joml.Matrix4d;
import org.joml.Matrix4f;
import org.joml.Quaterniond;
import org.joml.Vector3f;
import org.joml.Vector4d;
import org.joml.Vector4f;
import electrosphere.engine.Globals;
@ -243,7 +245,7 @@ public class PoseActor {
Bone currentBone = model.boneMap.get(boneName);
if(currentBone != null){
AxisAngle4f axisAngle = new AxisAngle4f();
currentBone.final_transform.getRotation(axisAngle);
new Matrix4f(currentBone.final_transform).getRotation(axisAngle);
Quaterniond rotation = new Quaterniond(axisAngle);
rVal.set(rotation);
}
@ -268,11 +270,11 @@ public class PoseActor {
// model.updateNodeTransform();
Bone currentBone = model.boneMap.get(boneName);
if(currentBone != null){
Vector4f result = currentBone.final_transform.transform(new Matrix4f(currentBone.inverseBindPoseMatrix).invert().transform(new Vector4f(rVal.x,rVal.y,rVal.z,1)));
Vector4d result = currentBone.final_transform.transform(new Matrix4d(currentBone.inverseBindPoseMatrix).invert().transform(new Vector4d(rVal.x,rVal.y,rVal.z,1)));
// currentBone.inverseBindPoseMatrix
rVal.x = result.x;
rVal.y = result.y;
rVal.z = result.z;
rVal.x = (float)result.x;
rVal.y = (float)result.y;
rVal.z = (float)result.z;
}
// }
}

View File

@ -9,7 +9,6 @@ public class PoseActorUtils {
public static void applyBlenderTransformer(Entity actorEntity){
PoseActor entityActor = EntityUtils.getPoseActor(actorEntity);
entityActor.setAnimationScalar(60f); //should be the value of the fps i think
EntityUtils.getScale(actorEntity).set(0.005f);
}
public static void applyBlenderRotation(Entity actorEntity){

View File

@ -33,7 +33,7 @@ public class PoseModel {
List<Bone> bones;
Map<String,Bone> boneMap;
Matrix4f globalInverseTransform;
Matrix4d globalInverseTransform;
Map<String,AnimNode> nodeMap;
AnimNode rootAnimNode;
List<Animation> animations;
@ -47,6 +47,10 @@ public class PoseModel {
*/
public PoseModel(String path, AIScene scene){
ModelPretransforms.ModelMetadata modelMetadata = Globals.modelPretransforms.getModel(path);
ModelPretransforms.GlobalTransform globalTransform = null;
if(modelMetadata != null){
globalTransform = modelMetadata.getGlobalTransform();
}
bones = new ArrayList<Bone>();
boneMap = new HashMap<String, Bone>();
@ -77,7 +81,10 @@ public class PoseModel {
//parse animation nodes and form hierarchy
//
AINode rootNode = scene.mRootNode();
globalInverseTransform = electrosphere.util.Utilities.convertAIMatrix(rootNode.mTransformation());
globalInverseTransform = electrosphere.util.Utilities.convertAIMatrixd(rootNode.mTransformation());
if(globalTransform != null){
globalInverseTransform.scale(globalTransform.getScale());
}
rootAnimNode = buildAnimNodeMap(scene.mRootNode(),null);
//
@ -173,13 +180,13 @@ public class PoseModel {
if(boneRotators.containsKey(target_bone.boneID)){
n.transform.rotate(boneRotators.get(target_bone.boneID).getRotation());
}
Matrix4f bone_matrix = new Matrix4f(n.transform);
Matrix4d bone_matrix = new Matrix4d(n.transform);
if(staticMorph != null && staticMorph.getBoneTransforms(n.id) != null){
bone_matrix.mul(staticMorph.getBoneTransforms(n.id).getTransform());
n.transform.mul(staticMorph.getBoneTransforms(n.id).getTransform());
}
bone_matrix.mul(target_bone.inverseBindPoseMatrix);
bone_matrix = new Matrix4f(globalInverseTransform).mul(bone_matrix);
bone_matrix = new Matrix4d(globalInverseTransform).mul(bone_matrix);
target_bone.final_transform = bone_matrix;
} else {
//not a bone, so use transform directly from data

View File

@ -25,6 +25,8 @@ import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.joml.Matrix4d;
import org.joml.Matrix4f;
import org.joml.Quaternionf;
import org.joml.Vector3f;
@ -85,6 +87,47 @@ public class Utilities {
return rVal;
}
public static Matrix4d convertAIMatrixd(AIMatrix4x4 mat){
Matrix4d rVal = new Matrix4d();
//Old, wrong approach:
// mat.set(
// mat.a1(),
// mat.b1(),
// mat.c1(),
// mat.d1(),
// mat.a2(),
// mat.b2(),
// mat.c2(),
// mat.d2(),
// mat.a3(),
// mat.b3(),
// mat.c3(),
// mat.d3(),
// mat.a4(),
// mat.b4(),
// mat.c4(),
// mat.d4()
// );
//as demo'd in https://github.com/lwjglgamedev/lwjglbook/blob/master/chapter27/c27-p2/src/main/java/org/lwjglb/engine/loaders/assimp/AnimMeshesLoader.java
rVal.m00(mat.a1());
rVal.m10(mat.a2());
rVal.m20(mat.a3());
rVal.m30(mat.a4());
rVal.m01(mat.b1());
rVal.m11(mat.b2());
rVal.m21(mat.b3());
rVal.m31(mat.b4());
rVal.m02(mat.c1());
rVal.m12(mat.c2());
rVal.m22(mat.c3());
rVal.m32(mat.c4());
rVal.m03(mat.d1());
rVal.m13(mat.d2());
rVal.m23(mat.d3());
rVal.m33(mat.d4());
return rVal;
}
public static void saveTestTextureMapToLocation(String s){