diff --git a/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java b/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java index 23c6101d..36a868da 100644 --- a/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java +++ b/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java @@ -1,5 +1,6 @@ package electrosphere.engine.loadingthreads; +import java.util.Random; import java.util.concurrent.TimeUnit; import org.joml.Quaterniond; @@ -239,12 +240,17 @@ public class ClientLoading { } }); - // for(int i = 0; i < 6; i++){ - Entity tree = ProceduralTree.clientGenerateProceduralTree("oak", 0); + Random rand = new Random(0); + { + Entity tree = ProceduralTree.clientGenerateProceduralTree("oak", rand.nextLong()); EntityUtils.getPosition(tree).set(5,0,5); - EntityUtils.getScale(tree).set(0.5f); - EntityUtils.getRotation(tree).rotateLocalX(0.5); - // EntityUtils.getPosition(tree).set(5,0,i * 3); + } + // for(int i = 0; i < 6; i++){ + // Entity tree = ProceduralTree.clientGenerateProceduralTree("oak", rand.nextLong()); + // // EntityUtils.getPosition(tree).set(5,0,5); + // // EntityUtils.getScale(tree).set(0.5f); + // // EntityUtils.getRotation(tree).rotateLocalX(0.5); + // EntityUtils.getPosition(tree).set(5,0,i * 5); // } } diff --git a/src/main/java/electrosphere/entity/types/attach/AttachUtils.java b/src/main/java/electrosphere/entity/types/attach/AttachUtils.java index 860899d2..d30e09f9 100644 --- a/src/main/java/electrosphere/entity/types/attach/AttachUtils.java +++ b/src/main/java/electrosphere/entity/types/attach/AttachUtils.java @@ -252,6 +252,15 @@ public class AttachUtils { } } + /** + * Updates the transform for the attachment + * @param toAttach The entity that is attached + * @param transform The transform + */ + public static void updateAttachTransform(Entity toAttach, Matrix4f transform){ + toAttach.putData(EntityDataStrings.ATTACH_TRANSFORM, transform); + } + /** * Semantically attaches an entity to another entity diff --git a/src/main/java/electrosphere/entity/types/tree/ProceduralTree.java b/src/main/java/electrosphere/entity/types/tree/ProceduralTree.java index 8d9a64a4..822de4e7 100644 --- a/src/main/java/electrosphere/entity/types/tree/ProceduralTree.java +++ b/src/main/java/electrosphere/entity/types/tree/ProceduralTree.java @@ -1,6 +1,8 @@ package electrosphere.entity.types.tree; import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; import java.util.Map; import java.util.Random; @@ -10,6 +12,7 @@ import org.joml.Quaterniond; import org.joml.Quaternionf; import org.joml.Vector3d; import org.joml.Vector3f; +import org.joml.Vector4d; import org.joml.Vector4f; import electrosphere.engine.Globals; @@ -95,25 +98,17 @@ public class ProceduralTree { instancedActor.setAttribute(boneMatrixAttribute, new Matrix4f().identity()); instancedActor.setAttribute(modelMatrixAttribute, new Matrix4f().identity()); instancedActor.setAttribute(baseSizeAttribute, 1.0f); - // EntityCreationUtils.makeEntityDrawable(trunkChild, "Models/proceduralTree2/proceduralTree2.fbx"); //call recursive branching routine to generate branches from trunk + leaf blobs - Matrix4f transform = new Matrix4f().identity().translate(0,3,0); FoliageType foliageType = Globals.gameConfigCurrent.getFoliageMap().getFoliage(type); TreeModel treeModel = foliageType.getTreeModel(); - // clientGenerateBranches( - // treeModel, - // trunkChild, - // treeRandom, - // transform, - // 1, - // 1, - // true - // ); + //generate branches clientGenerateBranchesAlt( treeModel, trunkChild, treeRandom, + 0, + 0, new Vector3d(0,0,0), new Quaterniond(0,0,0,1), new Vector3d(0,3,0), @@ -123,17 +118,15 @@ public class ProceduralTree { true ); - //attach btress - //..attach wind - //... - return trunkChild; } - public static void clientGenerateBranchesAlt( + public static List clientGenerateBranchesAlt( TreeModel type, Entity parent, Random rand, + double parentPeel, + double parentRotationOffset, Vector3d parentPosition, // The parent's origin bone's position in space Quaterniond parentRotation, // The parent's origin bone's rotation Vector3d offsetFromParent, // The offset from the parent's origin bone that this branch's origin bone should be at @@ -142,6 +135,7 @@ public class ProceduralTree { int currentSegmentNumber, boolean isCentralTrunk ){ + List rVal = new LinkedList(); //how fast do the branches shrink in size float scalarFalloffFactor = type.getLimbScalarFalloffFactor(); //the minimum branch size before we stop generating branch segments/trunk segments @@ -245,14 +239,6 @@ public class ProceduralTree { //calculates the bone transform matrix Matrix4f boneTransform = new Matrix4f().identity().rotate(boneRotation); - //calculate attachment transform - // Matrix4f attachmentTransform = new Matrix4f().identity().rotate(new Quaternionf( - // (float)currentAbsoluteRotation.x, - // (float)currentAbsoluteRotation.y, - // (float)currentAbsoluteRotation.z, - // (float)currentAbsoluteRotation.w - // )).translate(0,treeSegmentHeight,0); - //new position transform Matrix4f newPositionTransform = new Matrix4f().rotate(boneRotation).translate(0,treeSegmentHeight,0); @@ -263,7 +249,12 @@ public class ProceduralTree { float newScalar = scalar - scalarFalloffFactor; + + + + //create entity + Entity branch = EntityCreationUtils.createClientSpatialEntity(); InstancedActor instancedActor = InstancedEntityUtils.makeEntityInstancedWithModelTransform(branch, branchInstanceTemplate, modelMatrixAttribute); instancedActor.setAttribute(boneMatrixAttribute, boneTransform.scale(newScalar,1,newScalar)); @@ -277,27 +268,41 @@ public class ProceduralTree { // AttachUtils.clientAttachEntityAtCurrentOffset(parent, branch); AttachUtils.clientAttachEntityAtTransform(parent, branch, transformFromParent); - //debug stuff - // Vector4f newPositionF = newPositionTransform.transform(new Vector4f(0,0,0,1)); - // Vector3d newAbsolutePosition = new Vector3d(newPositionF.x,newPositionF.y,newPositionF.z); - // Entity debugSphere = EntityCreationUtils.createClientSpatialEntity(); - // EntityCreationUtils.makeEntityDrawable(debugSphere, "Models/unitsphere_1.fbx"); - // EntityUtils.getScale(debugSphere).set(0.5f); - // EntityUtils.getPosition(debugSphere).set(newAbsolutePosition); + rVal.add(branch); + + + + //attach leaf blobs if( !isCentralTrunk && currentSegmentNumber >= minimumSegmentToSpawnLeaves ){ - // createLeafBlobsOnBranch(type,rand,transform,boneTransform,branch); + createLeafBlobsOnBranch( + type, + branch, + rand, + currentPosition, + currentAbsoluteRotation, + newPosition, + boneRotation, + scalar - scalarFalloffFactor, + currentSegmentNumber + 1, + false //can't be central trunk + ); } + + + //recurse - clientGenerateBranchesAlt( + List childBranches = clientGenerateBranchesAlt( type, branch, rand, + peelRotation, + offsetRotation, currentPosition, currentAbsoluteRotation, newPosition, @@ -306,8 +311,22 @@ public class ProceduralTree { currentSegmentNumber + 1, false //can't be central trunk ); + + //add behavior tree to update all child branch attachment points to new point + if(childBranches.size() > 0){ + Globals.clientSceneWrapper.getScene().registerBehaviorTree(new BranchBehaviorTree( + parent, + branch, + childBranches, + newScalar, + parentPeel, + offsetRotation, + treeSegmentHeight + )); + } } } + return rVal; } /** @@ -528,22 +547,293 @@ public class ProceduralTree { } } + + + /** + * Creates leaf blobs around branch segments + * @param type The type of tree + * @param rand The random + * @param transform The current branch segment transform + * @param boneTransform The bone transform to the next branch segment + * @param branch The branch entity + */ + private static void createLeafBlobsOnBranch( + TreeModel type, + Entity parent, + Random rand, + Vector3d parentPosition, // The parent's origin bone's position in space + Quaterniond parentRotation, // The parent's origin bone's rotation + Vector3d offsetFromParent, // The offset from the parent's origin bone that this branch's origin bone should be at + Quaternionf rotationFromParent, // The rotation of the parent's extended bone. Should be equivalent to the origin bone's rotation on this branch + float scalar, + int currentSegmentNumber, + boolean isCentralTrunk + ){ + //get type data + float minBranchHeightToStartSpawningLeaves = type.getMinBranchHeightToStartSpawningLeaves(); + float maxBranchHeightToStartSpawningLeaves = type.getMaxBranchHeightToStartSpawningLeaves(); + float leafIncrement = type.getLeafIncrement(); + int minLeavesToSpawnPerPoint = type.getMinLeavesToSpawnPerPoint(); + int maxLeavesToSpawnPerPoint = type.getMaxLeavesToSpawnPerPoint(); + + for( + float positionAlongBranch = minBranchHeightToStartSpawningLeaves; + positionAlongBranch < maxBranchHeightToStartSpawningLeaves; + positionAlongBranch = positionAlongBranch + leafIncrement + ){ + int numToSpawn = rand.nextInt(maxLeavesToSpawnPerPoint - minLeavesToSpawnPerPoint) + minLeavesToSpawnPerPoint; + double currentLeafRotation = rand.nextFloat(); + float distanceFromCenter = type.getLeafDistanceFromCenter(); + for(int leafIncrementer = 0; leafIncrementer < numToSpawn; leafIncrementer++){ + //what we want to solve for: + //get parent position + rotation + //get an offset from the parent position for this position + //get a rotation from the parent rotation for this rotation + + //offset radially + float xOffset = (float)Math.sin(currentLeafRotation) * distanceFromCenter; + float zOffset = (float)Math.cos(currentLeafRotation) * distanceFromCenter; + + //update offsetrotation + currentLeafRotation = currentLeafRotation + (leafIncrementer + 1) * 2.0 * Math.PI / (float)numToSpawn; + + //calculate the transform from parent + Quaterniond parentLocalRotationFromVertical = new Quaterniond().rotationTo(new Vector3d(0,1,0), offsetFromParent); + Vector4d transformedPos = parentLocalRotationFromVertical.transform(new Vector4d(xOffset,positionAlongBranch,zOffset,1)); + + //calculate transform from parent entity + //this is the transform that will be applied every time the attachutils updates + Matrix4f transformFromParent = new Matrix4f() + .translate(new Vector3f( + (float)transformedPos.x, + (float)transformedPos.y, + (float)transformedPos.z + )) + .rotate(new Quaternionf( + (float)rotationFromParent.x, + (float)rotationFromParent.y, + (float)rotationFromParent.z, + (float)rotationFromParent.w + )); + + + //create entity + Entity leaf = EntityCreationUtils.createClientSpatialEntity(); + InstancedActor leafInstancedActor = InstancedEntityUtils.makeEntityInstancedWithModelTransform(leaf, leafInstanceTemplate, modelMatrixAttribute); + leafInstancedActor.setAttribute(modelMatrixAttribute, new Matrix4f().identity()); + leafInstancedActor.setAttribute(leafColorAttribute, new Vector3f(36/255.0f,173/255.0f,31/255.0f)); + + //set entity stuuff + // EntityUtils.getPosition(leaf).set(leafCurrentPosition); + EntityUtils.getScale(leaf).set(1,1,1); + EntityUtils.getRotation(leaf).set(new Quaterniond().identity()); + AttachUtils.clientAttachEntityAtCurrentOffset(parent, leaf); + // AttachUtils.clientAttachEntityAtCurrentOffset(parent, branch); + AttachUtils.clientAttachEntityAtTransform(parent, leaf, transformFromParent); + } + } + // for(int i = 0; i < branchNum; i++){ + + // //what we want to solve for: + // //get parent position + rotation + // //get an offset from the parent position for this position + // //get a rotation from the parent rotation for this rotation + + // Quaterniond parentLocalRotationFromVertical = new Quaterniond().rotationTo(new Vector3d(0,1,0), offsetFromParent); + // parentLocalRotationFromVertical.transform(new Vector4d(0,0,0,1)); + + // //calculate transform from parent entity + // //this is the transform that will be applied every time the attachutils updates + // Matrix4f transformFromParent = new Matrix4f() + // .translate(new Vector3f( + // (float)offsetFromParent.x, + // (float)offsetFromParent.y, + // (float)offsetFromParent.z + // )) + // .rotate(new Quaternionf( + // (float)rotationFromParent.x, + // (float)rotationFromParent.y, + // (float)rotationFromParent.z, + // (float)rotationFromParent.w + // )); + + // //calculate combined transform + // Matrix4f combinedTransform = new Matrix4f().translate(new Vector3f( + // (float)parentPosition.x, + // (float)parentPosition.y, + // (float)parentPosition.z + // )).rotate(new Quaternionf( + // (float)parentRotation.x, + // (float)parentRotation.y, + // (float)parentRotation.z, + // (float)parentRotation.w + // )).mul(transformFromParent); + + + + + + + + // //calculate current branch's stuff + // //get current position + // Vector4f currentPositionf = combinedTransform.transform(new Vector4f( + // 0, + // 0, + // 0, + // 1 + // )); + // Vector3d currentPosition = new Vector3d(currentPositionf.x,currentPositionf.y,currentPositionf.z); + + // //The new absolute rotation at the end of the bone + // Quaterniond currentAbsoluteRotation = combinedTransform.getNormalizedRotation(new Quaterniond()).normalize(); + + + + + + + + + + // //calculate child stuff + + // //update offsetrotation + // offsetRotation = rotationInitialOffset + (i + 1) * (2.0 * Math.PI / (float)branchNum); + // //get new rotation + // double pitchFactor = Math.sin(offsetRotation); + // double rollFactor = Math.cos(offsetRotation); + + // //the rotation applied to the bone + // Quaternionf boneRotation = new Quaternionf(0,0,0,1).rotateLocalX((float)(pitchFactor * peelRotation)).rotateLocalZ((float)(rollFactor * peelRotation)).normalize(); + + + // //calculates the bone transform matrix + // Matrix4f boneTransform = new Matrix4f().identity().rotate(boneRotation); + + // //new position transform + // Matrix4f newPositionTransform = new Matrix4f().rotate(boneRotation).translate(0,treeSegmentHeight,0); + + // Vector4f newPositionRaw = newPositionTransform.transform(new Vector4f(0,0,0,1)); + // Vector3d newPosition = new Vector3d(newPositionRaw.x,newPositionRaw.y,newPositionRaw.z); + + // //get new scalar + // float newScalar = scalar - scalarFalloffFactor; + + + + + + + // //create entity + + // Entity branch = EntityCreationUtils.createClientSpatialEntity(); + // InstancedActor instancedActor = InstancedEntityUtils.makeEntityInstancedWithModelTransform(branch, branchInstanceTemplate, modelMatrixAttribute); + // instancedActor.setAttribute(boneMatrixAttribute, boneTransform.scale(newScalar,1,newScalar)); + // instancedActor.setAttribute(baseSizeAttribute, scalar); + // instancedActor.setAttribute(modelMatrixAttribute, new Matrix4f().identity()); + + // //set entity stuuff + // EntityUtils.getPosition(branch).set(currentPosition); + // EntityUtils.getScale(branch).set(1,1,1); + // EntityUtils.getRotation(branch).set(currentAbsoluteRotation); + // // AttachUtils.clientAttachEntityAtCurrentOffset(parent, branch); + // AttachUtils.clientAttachEntityAtTransform(parent, branch, transformFromParent); + // } + } + /** * The behavior tree for branches swaying in the wind */ static class BranchBehaviorTree implements BehaviorTree { + //The parent that the branch is attached to + Entity parent; + + //The branch that is having its offset changed + Entity branch; + + //the initial peel for the branch + double initialPeel; + + //The current peel for the branch + double currentPeel; + + //The initial yaw for the branch + double initialYaw; + + //the current yaw for the branch + double currentYaw; + + //The height of the + float treeSegmentHeight; + + //Every child branch + List children; + + //The current scalar of the branch + double currentScalar; + /** * Constructor * @param branch The branch entity */ - protected BranchBehaviorTree(Entity branch){ - + protected BranchBehaviorTree(Entity parent, Entity branch, List children, double currentScalar, double peel, double yaw, float treeSegmentHeight){ + this.parent = parent; + this.branch = branch; + this.initialPeel = peel; + this.currentPeel = peel; + this.initialYaw = yaw; + this.currentYaw = yaw; + this.treeSegmentHeight = treeSegmentHeight; + this.children = children; + this.currentScalar = currentScalar; } @Override public void simulate(float deltaTime) { - + + System.out.println(currentYaw); + // currentYaw = currentYaw * Math.abs(currentYaw - initialYaw) + new Random().nextDouble() * (1 - Math.abs(currentYaw - initialYaw)); + currentPeel = initialPeel * Math.abs(currentPeel - initialPeel) + new Random().nextDouble() * (1 - Math.abs(currentPeel - initialPeel)); + + //get new rotation + double pitchFactor = Math.sin(currentYaw); + double rollFactor = Math.cos(currentYaw); + + //the rotation applied to the bone + Quaternionf boneRotation = new Quaternionf(0,0,0,1).rotateLocalX((float)(pitchFactor * currentPeel)).rotateLocalZ((float)(rollFactor * currentPeel)).normalize(); + + + //calculates the bone transform matrix + Matrix4f boneTransform = new Matrix4f().identity().rotate(boneRotation); + + //new position transform + Matrix4f newPositionTransform = new Matrix4f().rotate(boneRotation).translate(0,treeSegmentHeight,0); + Vector4f newPositionRaw = newPositionTransform.transform(new Vector4f(0,0,0,1)); + + Matrix4f transformFromParent = new Matrix4f() + .translate(new Vector3f( + (float)newPositionRaw.x, + (float)newPositionRaw.y, + (float)newPositionRaw.z + )) + .rotate(new Quaternionf( + (float)boneRotation.x, + (float)boneRotation.y, + (float)boneRotation.z, + (float)boneRotation.w + )); + + + //update branch actor branch matrix + InstancedActor branchActor = InstancedActor.getInstancedActor(branch); + branchActor.setAttribute(boneMatrixAttribute, new Matrix4f(transformFromParent).scale((float)currentScalar,1,(float)currentScalar)); + + //update children positions + for(Entity child : children){ + AttachUtils.updateAttachTransform(child,transformFromParent); + } } }