pathedinterior stuff

This commit is contained in:
RandomityGuy 2021-05-29 21:40:19 +05:30
parent 435c606927
commit 38bcab6c62
10 changed files with 816 additions and 21 deletions

View file

@ -1,5 +1,6 @@
package src;
import src.PathedInterior;
import h3d.Vector;
import collision.CollisionSurface;
import collision.CollisionEntity;
@ -249,4 +250,217 @@ class DifBuilder {
return ig;
}
public static function loadDifAsPI(path:String, loader:Loader) {
var dif = Dif.Load(path);
var geo = dif.interiors[0];
var hulls = geo.convexHulls;
var triangles = [];
var textures = [];
var collider = new CollisionEntity();
for (i in 0...hulls.length) {
var hullTris = [];
var hull = hulls[i];
for (j in hull.surfaceStart...(hull.surfaceStart + hull.surfaceCount)) {
var surfaceindex = geo.hullSurfaceIndices[j];
var surface = geo.surfaces[surfaceindex];
var planeindex = surface.planeIndex;
var planeFlipped = (planeindex & 0x8000) == 0x8000;
if (planeFlipped)
planeindex &= ~0x8000;
var plane = geo.planes[planeindex];
var normal = geo.normals[plane.normalIndex];
if (planeFlipped)
normal = normal.scalar(-1);
var texture = geo.materialList[surface.textureIndex];
if (!textures.contains(texture))
textures.push(texture);
var points = geo.points;
var colliderSurface = new CollisionSurface();
colliderSurface.points = [];
colliderSurface.normals = [];
colliderSurface.indices = [];
for (k in (surface.windingStart + 2)...(surface.windingStart + surface.windingCount)) {
var p1, p2, p3;
if ((k - (surface.windingStart + 2)) % 2 == 0) {
p1 = points[geo.windings[k]];
p2 = points[geo.windings[k - 1]];
p3 = points[geo.windings[k - 2]];
} else {
p1 = points[geo.windings[k - 2]];
p2 = points[geo.windings[k - 1]];
p3 = points[geo.windings[k]];
}
var texgen = geo.texGenEQs[surface.texGenIndex];
var uv1 = new Point2F(p1.x * texgen.planeX.x
+ p1.y * texgen.planeX.y
+ p1.z * texgen.planeX.z
+ texgen.planeX.d,
p1.x * texgen.planeY.x
+ p1.y * texgen.planeY.y
+ p1.z * texgen.planeY.z
+ texgen.planeY.d);
var uv2 = new Point2F(p2.x * texgen.planeX.x
+ p2.y * texgen.planeX.y
+ p2.z * texgen.planeX.z
+ texgen.planeX.d,
p2.x * texgen.planeY.x
+ p2.y * texgen.planeY.y
+ p2.z * texgen.planeY.z
+ texgen.planeY.d);
var uv3 = new Point2F(p3.x * texgen.planeX.x
+ p3.y * texgen.planeX.y
+ p3.z * texgen.planeX.z
+ texgen.planeX.d,
p3.x * texgen.planeY.x
+ p3.y * texgen.planeY.y
+ p3.z * texgen.planeY.z
+ texgen.planeY.d);
var tri = new DifBuilderTriangle();
tri.texture = texture;
tri.normal1 = normal;
tri.normal2 = normal;
tri.normal3 = normal;
tri.p1 = p1;
tri.p2 = p2;
tri.p3 = p3;
tri.uv1 = uv1;
tri.uv2 = uv2;
tri.uv3 = uv3;
triangles.push(tri);
hullTris.push(tri);
colliderSurface.points.push(new Vector(-p1.x, p1.y, p1.z));
colliderSurface.points.push(new Vector(-p2.x, p2.y, p2.z));
colliderSurface.points.push(new Vector(-p3.x, p3.y, p3.z));
colliderSurface.normals.push(new Vector(-normal.x, normal.y, normal.z));
colliderSurface.normals.push(new Vector(-normal.x, normal.y, normal.z));
colliderSurface.normals.push(new Vector(-normal.x, normal.y, normal.z));
colliderSurface.indices.push(colliderSurface.indices.length);
colliderSurface.indices.push(colliderSurface.indices.length);
colliderSurface.indices.push(colliderSurface.indices.length);
}
colliderSurface.generateBoundingBox();
collider.addSurface(colliderSurface);
}
}
var mats = new Map<String, Array<DifBuilderTriangle>>();
for (index => value in triangles) {
if (mats.exists(value.texture)) {
mats[value.texture].push(value);
} else {
mats.set(value.texture, [value]);
}
}
collider.generateBoundingBox();
var ig = new PathedInterior();
ig.collider = collider;
function canFindTex(tex:String) {
if (tex.indexOf('/') != -1) {
tex = tex.split('/')[1];
}
if (File.exists(Path.directory(path) + "/" + tex + ".jpg")) {
return true;
}
if (File.exists(Path.directory(path) + "/" + tex + ".png")) {
return true;
}
var prevDir = Path.directory(Path.directory(path));
if (File.exists(prevDir + "/" + tex + ".jpg")) {
return true;
}
if (File.exists(prevDir + "/" + tex + ".png")) {
return true;
}
return false;
}
function tex(tex:String):String {
if (tex.indexOf('/') != -1) {
tex = tex.split('/')[1];
}
if (File.exists(Path.directory(path) + "/" + tex + ".jpg")) {
return Path.directory(path) + "/" + tex + ".jpg";
}
if (File.exists(Path.directory(path) + "/" + tex + ".png")) {
return Path.directory(path) + "/" + tex + ".png";
}
var prevDir = Path.directory(Path.directory(path));
if (File.exists(prevDir + "/" + tex + ".jpg")) {
return prevDir + "/" + tex + ".jpg";
}
if (File.exists(prevDir + "/" + tex + ".png")) {
return prevDir + "/" + tex + ".png";
}
return null;
}
for (grp => tris in mats) {
var points = [];
var normals = [];
var uvs = [];
for (tri in tris) {
var p1 = new Point(-tri.p1.x, tri.p1.y, tri.p1.z);
var p2 = new Point(-tri.p2.x, tri.p2.y, tri.p2.z);
var p3 = new Point(-tri.p3.x, tri.p3.y, tri.p3.z);
var n1 = new Point(-tri.normal1.x, tri.normal1.y, tri.normal1.z);
var n2 = new Point(-tri.normal2.x, tri.normal2.y, tri.normal2.z);
var n3 = new Point(-tri.normal3.x, tri.normal3.y, tri.normal3.z);
var uv1 = new UV(tri.uv1.x, tri.uv1.y);
var uv2 = new UV(tri.uv2.x, tri.uv2.y);
var uv3 = new UV(tri.uv3.x, tri.uv3.y);
points.push(p3);
points.push(p2);
points.push(p1);
normals.push(n3);
normals.push(n2);
normals.push(n1);
uvs.push(uv3);
uvs.push(uv2);
uvs.push(uv1);
}
var prim = new Polygon(points);
prim.uvs = uvs;
prim.normals = normals;
var texture:Texture = loader.load(tex(grp)).toImage().toTexture();
texture.wrap = Wrap.Repeat;
var material = h3d.mat.Material.create(texture);
// material.mainPass.wireframe = true;
var mesh = new Mesh(prim, material, ig);
}
return ig;
}
}

View file

@ -1,5 +1,8 @@
package;
import h3d.Quat;
import src.PathedInteriorMarker;
import src.PathedInterior;
import src.MarbleWorld;
import collision.CollisionWorld;
import src.Marble;
@ -31,6 +34,38 @@ class Main extends hxd.App {
var db = DifBuilder.loadDif("interiors/beginner/beginner_finish.dif", loader);
world.addInterior(db);
var pi = DifBuilder.loadDifAsPI("interiors/addon/smallplatform.dif", loader);
var pim = pi.getTransform();
pim.setPosition(new Vector(5, 0, 0));
pi.setTransform(pim);
var cube = new Cube();
cube.addUVs();
cube.addNormals();
var mat = Material.create();
var m1 = new PathedInteriorMarker();
m1.msToNext = 5;
m1.position = new Vector(5, 0, 0);
m1.smoothingType = "";
m1.rotation = new Quat();
var m2 = new PathedInteriorMarker();
m2.msToNext = 3;
m2.position = new Vector(5, 0, 5);
m2.smoothingType = "";
m2.rotation = new Quat();
var m3 = new PathedInteriorMarker();
m3.msToNext = 5;
m3.position = new Vector(5, 0, 0);
m3.smoothingType = "";
m3.rotation = new Quat();
pi.markerData = [m1, m2, m3];
world.addPathedInterior(pi);
// for (surf in db.collider.surfaces) {
// var surfmin = new CustomObject(cube, mat, s3d);
// var bound = surf.boundingBox;
@ -40,8 +75,6 @@ class Main extends hxd.App {
// surfmax.setPosition(bound.xMax, bound.yMax, bound.zMax);
// }
s3d.addChild(db);
// var mat = Material.create();
// var so = new CustomObject(cube, mat);
// so.setPosition(0, 0, 0);
@ -60,7 +93,7 @@ class Main extends hxd.App {
var marble = new Marble();
marble.controllable = true;
world.addMarble(marble);
marble.setPosition(0, 0, 5);
marble.setPosition(6, 0, 5);
// marble.setPosition(-10, -5, 5);
}

View file

@ -1,5 +1,9 @@
package src;
import dif.math.Point3F;
import dif.math.PlaneF;
import collision.CollisionSurface;
import src.PathedInterior;
import collision.SphereCollisionEntity;
import hxd.Key;
import collision.CollisionInfo;
@ -76,9 +80,9 @@ class Marble extends Object {
this.collider = new SphereCollisionEntity(cast this);
}
function findContacts(collisiomWorld:CollisionWorld) {
function findContacts(collisiomWorld:CollisionWorld, dt:Float) {
this.contacts = queuedContacts;
var c = collisiomWorld.sphereIntersection(this.collider);
var c = collisiomWorld.sphereIntersection(this.collider, dt);
contacts = contacts.concat(c);
}
@ -366,8 +370,296 @@ class Marble extends Object {
this._bounceNormal = normal;
}
function testMove(velocity:Vector, position:Vector, deltaT:Float, radius:Float, testPIs:Bool, collisionWorld:CollisionWorld) {
var velLen = velocity.length();
if (velLen < 0.001)
return false;
var velocityDir = velocity.normalized();
var deltaPosition = velocity.multiply(deltaT);
var finalPosition = position.add(deltaPosition);
var expandedcollider = new SphereCollisionEntity(cast this);
expandedcollider.transform = Matrix.T(position.x, position.y, position.z);
expandedcollider.radius = this.getAbsPos().getPosition().distance(position) + radius;
var foundObjs = collisionWorld.radiusSearch(position, expandedcollider.radius);
var finalT = deltaT;
var marbleCollisionTime = finalT;
var marbleCollisionNormal = new Vector(0, 0, 1);
var lastContactPos = new Vector();
function toDifPoint(vec:Vector) {
return new Point3F(vec.x, vec.y, vec.z);
}
function fromDifPoint(vec:Point3F) {
return new Vector(vec.x, vec.y, vec.z);
}
var contactPoly:{v0:Vector, v:Vector, v2:Vector};
for (obj in foundObjs) {
if (obj.velocity.length() != 0) { // Its an MP so bruh
var invMatrix = obj.transform.clone();
invMatrix.invert();
var localpos = position.clone();
localpos.transform(invMatrix);
var surfaces = obj.octree.radiusSearch(localpos, expandedcollider.radius);
for (surf in surfaces) {
var surface:CollisionSurface = cast obj;
var i = 0;
while (i < surface.indices.length) {
var v0 = surface.points[surface.indices[i]].transformed(obj.transform);
var v = surface.points[surface.indices[i + 1]].transformed(obj.transform);
var v2 = surface.points[surface.indices[i + 2]].transformed(obj.transform);
var polyPlane = PlaneF.ThreePoints(toDifPoint(v0), toDifPoint(v), toDifPoint(v2));
// If we're going the wrong direction or not going to touch the plane, ignore...
if (!(polyPlane.getNormal().dot(toDifPoint(velocityDir)) > -0.001
|| polyPlane.getNormal().dot(toDifPoint(finalPosition)) + polyPlane.d > radius)) {
// Time until collision with the plane
var collisionTime = (radius
- (polyPlane.getNormal().dot(toDifPoint(position)) + polyPlane.d)) / polyPlane.getNormal().dot(toDifPoint(velocity));
// Are we going to touch the plane during this time step?
if (collisionTime >= 0.0 && finalT >= collisionTime) {
var lastVertIndex = surface.indices[surface.indices.length - 1];
var lastVert = surface.points[lastVertIndex];
var collisionPos = velocity.multiply(collisionTime).add(position);
var isOnEdge:Bool = false;
for (i in 0...surface.indices.length) {
{
var thisVert = surface.points[surface.indices[i]];
if (thisVert != lastVert) {
var edgePlane = PlaneF.ThreePoints(toDifPoint(thisVert).add(polyPlane.getNormal()), toDifPoint(thisVert),
toDifPoint(lastVert));
lastVert = thisVert;
// if we are on the far side of the edge
if (edgePlane.getNormal().dot(toDifPoint(collisionPos)) + edgePlane.d < 0.0)
break;
}
}
isOnEdge = i != surface.indices.length;
}
// If we're inside the poly, just get the position
if (!isOnEdge) {
finalT = collisionTime;
finalPosition = collisionPos;
lastContactPos = fromDifPoint(polyPlane.project(toDifPoint(collisionPos)));
contactPoly = {v0: v0, v: v, v2: v2};
i += 3;
continue;
}
}
// We *might* be colliding with an edge
var lastVert = surface.points[surface.indices[surface.indices.length - 1]];
if (surface.indices.length == 0) {
i += 3;
continue;
}
var radSq = radius * radius;
for (iter in 0...surface.indices.length) {
var thisVert = surface.points[surface.indices[i]];
var vertDiff = lastVert.sub(thisVert);
var posDiff = position.sub(thisVert);
var velRejection = vertDiff.cross(velocity);
var posRejection = vertDiff.cross(posDiff);
// Build a quadratic equation to solve for the collision time
var a = velRejection.lengthSq();
var halfB = posRejection.dot(velRejection);
var b = halfB + halfB;
var discriminant = b * b - (posRejection.lengthSq() - vertDiff.lengthSq() * radSq) * (a * 4.0);
// If it's not quadratic or has no solution, ignore this edge.
if (a == 0.0 || discriminant < 0.0) {
lastVert = thisVert;
continue;
}
var oneOverTwoA = 0.5 / a;
var discriminantSqrt = Math.sqrt(discriminant);
// Solve using the quadratic formula
var edgeCollisionTime = (discriminantSqrt - b) * oneOverTwoA;
var edgeCollisionTime2 = (-b - discriminantSqrt) * oneOverTwoA;
// Make sure the 2 times are in ascending order
if (edgeCollisionTime2 < edgeCollisionTime) {
var temp = edgeCollisionTime2;
edgeCollisionTime2 = edgeCollisionTime;
edgeCollisionTime = temp;
}
// If the collision doesn't happen on this time step, ignore this edge.
if (edgeCollisionTime2 <= 0.0001 || finalT <= edgeCollisionTime) {
lastVert = thisVert;
continue;
}
// Check if the collision hasn't already happened
if (edgeCollisionTime >= 0.0) {
var edgeLen = vertDiff.length();
var relativeCollisionPos = velocity.multiply(edgeCollisionTime).add(position).sub(thisVert);
var distanceAlongEdge = relativeCollisionPos.dot(vertDiff) / edgeLen;
// If the collision happens outside the boundaries of the edge, ignore this edge.
if (-radius > distanceAlongEdge || edgeLen + radius < distanceAlongEdge) {
lastVert = thisVert;
continue;
}
// If the collision is within the edge, resolve the collision and continue.
if (distanceAlongEdge >= 0.0 && distanceAlongEdge <= edgeLen) {
finalT = edgeCollisionTime;
finalPosition = velocity.multiply(edgeCollisionTime).add(position);
lastContactPos = vertDiff.multiply(distanceAlongEdge / edgeLen).add(thisVert);
contactPoly = {v0: v0, v: v, v2: v2};
lastVert = thisVert;
continue;
}
}
// This is what happens when we collide with a corner
var speedSq = velocity.lengthSq();
// Build a quadratic equation to solve for the collision time
var posVertDiff = position.sub(thisVert);
var halfCornerB = posVertDiff.dot(velocity);
var cornerB = halfCornerB + halfCornerB;
var fourA = speedSq * 4.0;
var cornerDiscriminant = cornerB * cornerB - (posVertDiff.lengthSq() - radSq) * fourA;
// If it's quadratic and has a solution ...
if (speedSq != 0.0 && cornerDiscriminant >= 0.0) {
var oneOver2A = 0.5 / speedSq;
var cornerDiscriminantSqrt = Math.sqrt(cornerDiscriminant);
// Solve using the quadratic formula
var cornerCollisionTime = (cornerDiscriminantSqrt - cornerB) * oneOver2A;
var cornerCollisionTime2 = (-cornerB - cornerDiscriminantSqrt) * oneOver2A;
// Make sure the 2 times are in ascending order
if (cornerCollisionTime2 < cornerCollisionTime) {
var temp = cornerCollisionTime2;
cornerCollisionTime2 = cornerCollisionTime;
cornerCollisionTime = temp;
}
// If the collision doesn't happen on this time step, ignore this corner
if (cornerCollisionTime2 > 0.0001 && finalT > cornerCollisionTime) {
// Adjust to make sure very small negative times are counted as zero
if (cornerCollisionTime <= 0.0 && cornerCollisionTime > -0.0001)
cornerCollisionTime = 0.0;
// Check if the collision hasn't already happened
if (cornerCollisionTime >= 0.0) {
// Resolve it and continue
finalT = cornerCollisionTime;
contactPoly = {v0: v0, v: v, v2: v2};
finalPosition = velocity.multiply(cornerCollisionTime).add(position);
lastContactPos = thisVert;
}
}
}
// We still need to check the other corner ...
// Build one last quadratic equation to solve for the collision time
var lastVertDiff = position.sub(lastVert);
var lastCornerHalfB = lastVertDiff.dot(velocity);
var lastCornerB = lastCornerHalfB + lastCornerHalfB;
var lastCornerDiscriminant = lastCornerB * lastCornerB - (lastVertDiff.lengthSq() - radSq) * fourA;
// If it's not quadratic or has no solution, then skip this corner
if (speedSq == 0.0 || lastCornerDiscriminant < 0.0) {
lastVert = thisVert;
continue;
}
var lastCornerOneOver2A = 0.5 / speedSq;
var lastCornerDiscriminantSqrt = Math.sqrt(lastCornerDiscriminant);
// Solve using the quadratic formula
var lastCornerCollisionTime = (lastCornerDiscriminantSqrt - lastCornerB) * lastCornerOneOver2A;
var lastCornerCollisionTime2 = (-lastCornerB - lastCornerDiscriminantSqrt) * lastCornerOneOver2A;
// Make sure the 2 times are in ascending order
if (lastCornerCollisionTime2 < lastCornerCollisionTime) {
var temp = lastCornerCollisionTime2;
lastCornerCollisionTime2 = lastCornerCollisionTime;
lastCornerCollisionTime = temp;
}
// If the collision doesn't happen on this time step, ignore this corner
if (lastCornerCollisionTime2 <= 0.0001 || finalT <= lastCornerCollisionTime) {
lastVert = thisVert;
continue;
}
// Adjust to make sure very small negative times are counted as zero
if (lastCornerCollisionTime <= 0.0 && lastCornerCollisionTime > -0.0001)
lastCornerCollisionTime = 0.0;
// Check if the collision hasn't already happened
if (lastCornerCollisionTime < 0.0) {
lastVert = thisVert;
continue;
}
// Resolve it and continue
finalT = lastCornerCollisionTime;
finalPosition = velocity.multiply(lastCornerCollisionTime).add(position);
lastContactPos = lastVert;
contactPoly = {v0: v0, v: v, v2: v2};
lastVert = thisVert;
}
}
i += 3;
}
}
}
}
position = finalPosition;
var contacted = false;
if (deltaT > finalT) {
contacted = true;
}
return true;
}
function advancePhysics(m:Move, dt:Float, collisionWorld:CollisionWorld) {
this.findContacts(collisionWorld);
this.findContacts(collisionWorld, dt);
var cmf = this.computeMoveForces(m);
var isCentered:Bool = cmf.result;
var aControl = cmf.aControl;
@ -387,7 +679,7 @@ class Marble extends Object {
this.queuedContacts = [];
}
public function update(dt:Float, collisionWorld:CollisionWorld) {
public function update(currentTime:Float, dt:Float, collisionWorld:CollisionWorld, pathedInteriors:Array<PathedInterior>) {
var move = new Move();
move.d = new Vector();
if (this.controllable) {
@ -430,6 +722,12 @@ class Marble extends Object {
it++;
} while (it <= 10);
if (this.controllable) {
for (interior in pathedInteriors) {
interior.update(currentTime, dt);
}
}
this.camera.target.load(this.getAbsPos().getPosition().toPoint());
}
}

View file

@ -1,5 +1,6 @@
package src;
import src.PathedInterior;
import hxd.Key;
import h3d.Vector;
import src.InteriorGeometry;
@ -12,8 +13,11 @@ class MarbleWorld {
var collisionWorld:CollisionWorld;
public var interiors:Array<InteriorGeometry> = [];
public var pathedInteriors:Array<PathedInterior> = [];
public var marbles:Array<Marble> = [];
public var currentTime:Float = 0;
var scene:Scene;
public function new(scene:Scene) {
@ -27,6 +31,13 @@ class MarbleWorld {
this.scene.addChild(obj);
}
public function addPathedInterior(obj:PathedInterior) {
this.pathedInteriors.push(obj);
this.collisionWorld.addMovingEntity(obj.collider);
this.scene.addChild(obj);
obj.init();
}
public function addMarble(marble:Marble) {
this.marbles.push(marble);
if (marble.controllable) {
@ -38,7 +49,8 @@ class MarbleWorld {
public function update(dt:Float) {
for (marble in marbles) {
marble.update(dt, collisionWorld);
marble.update(currentTime, dt, collisionWorld, this.pathedInteriors);
}
currentTime += dt;
}
}

150
src/PathedInterior.hx Normal file
View file

@ -0,0 +1,150 @@
package src;
import h3d.Matrix;
import h3d.Vector;
import src.Util;
import src.PathedInteriorMarker;
import src.InteriorGeometry;
class PathedInterior extends InteriorGeometry {
public var markerData:Array<PathedInteriorMarker> = [];
var duration:Float;
var currentTime:Float;
var targetTime:Float;
var changeTime:Float;
var prevPosition:Vector;
var currentPosition:Vector;
var velocity:Vector;
public function new() {
super();
}
public function init() {
this.computeDuration();
this.reset();
}
public function update(currentTime:Float, dt:Float) {
var transform = this.getTransformAtTime(this.getInternalTime(currentTime));
this.updatePosition();
var position = transform.getPosition();
this.prevPosition = this.currentPosition;
this.currentPosition = position;
velocity = position.sub(this.prevPosition).multiply(1 / dt);
}
function computeDuration() {
var total = 0.0;
for (marker in markerData) {
total += marker.msToNext;
}
this.duration = total;
}
public function setTargetTime(now:Float, target:Float) {
var currentInternalTime = this.getInternalTime(now);
this.currentTime = currentInternalTime; // Start where the interior currently is
this.targetTime = target;
this.changeTime = now;
}
public function getInternalTime(externalTime:Float) {
if (this.targetTime < 0) {
var direction = (this.targetTime == -1) ? 1 : (this.targetTime == -2) ? -1 : 0;
return Util.adjustedMod(this.currentTime + (externalTime - this.changeTime) * direction, this.duration);
} else {
var dur = Math.abs(this.currentTime - this.targetTime);
var compvarion = Util.clamp(dur > 0 ? (externalTime - this.changeTime) / dur : 1, 0, 1);
return Util.clamp(Util.lerp(this.currentTime, this.targetTime, compvarion), 0, this.duration);
}
}
function updatePosition() {
var tform = this.collider.transform;
tform.setPosition(this.currentPosition);
this.setTransform(tform);
this.collider.setTransform(tform);
this.collider.velocity = this.velocity;
}
function getTransformAtTime(time:Float) {
var m1:PathedInteriorMarker = this.markerData[0];
var m2:PathedInteriorMarker = this.markerData[1];
if (m1 == null) {
// Incase there are no markers at all
var mat = this.getTransform();
return mat;
} else {
m1 = this.markerData[0];
}
// Find the two markers in question
var currentEndTime = m1.msToNext;
var i = 2;
while (currentEndTime < time && i < this.markerData.length) {
m1 = m2;
m2 = this.markerData[i++];
currentEndTime += m1.msToNext;
}
if (m2 == null)
m2 = m1;
var m1Time = currentEndTime - m1.msToNext;
var m2Time = currentEndTime;
var duration = m2Time - m1Time;
var position:Vector = null;
var compvarion = Util.clamp(duration > 0 ? (time - m1Time) / duration : 1, 0, 1);
if (m1.smoothingType == "Accelerate") {
// A simple easing function
compvarion = Math.sin(compvarion * Math.PI - (Math.PI / 2)) * 0.5 + 0.5;
} else if (m1.smoothingType == "Spline") {
// Smooth the path like it's a Catmull-Rom spline.
var preStart = (i - 2) - 1;
var postEnd = (i - 1) + 1;
if (postEnd >= this.markerData.length)
postEnd = 0;
if (preStart < 0)
preStart = this.markerData.length - 1;
var p0 = this.markerData[preStart].position;
var p1 = m1.position;
var p2 = m2.position;
var p3 = this.markerData[postEnd].position;
position = new Vector();
position.x = Util.catmullRom(compvarion, p0.x, p1.x, p2.x, p3.x);
position.y = Util.catmullRom(compvarion, p0.y, p1.y, p2.y, p3.y);
position.z = Util.catmullRom(compvarion, p0.z, p1.z, p2.z, p3.z);
}
if (position == null) {
var p1 = m1.position;
var p2 = m2.position;
position = Util.lerpThreeVectors(p1, p2, compvarion);
}
// Offset by the position of the first marker
var firstPosition = this.markerData[0].position;
position.sub(firstPosition);
var tform = this.getTransform().clone();
var basePosition = tform.getPosition();
position.add(basePosition); // Add the base position
tform.setPosition(position);
return tform;
}
function reset() {
this.currentTime = 0;
this.targetTime = -1;
this.changeTime = 0;
// Reset the position
var transform = this.getTransformAtTime(this.getInternalTime(0));
var position = transform.getPosition();
this.prevPosition = position.clone();
this.currentPosition = position;
this.velocity = new Vector();
updatePosition();
}
}

View file

@ -0,0 +1,22 @@
package src;
import h3d.Quat;
import h3d.Vector;
class PathedInteriorMarker {
public var msToNext:Float;
public var smoothingType:String;
public var position:Vector;
public var rotation:Quat;
public function new() {}
public function clone() {
var ret = new PathedInteriorMarker();
ret.msToNext = msToNext;
ret.smoothingType = smoothingType;
ret.position = position;
ret.rotation = rotation;
return ret;
}
}

35
src/Util.hx Normal file
View file

@ -0,0 +1,35 @@
package src;
import h3d.Vector;
class Util {
public static function adjustedMod(a:Float, n:Float) {
var r1 = a % n;
var r2 = (r1 + n) % n;
return r2;
}
public static function clamp(value:Float, min:Float, max:Float) {
if (value < min)
return min;
if (value > max)
return max;
return value;
}
public static function lerp(a:Float, b:Float, t:Float) {
return a + (b - a) * t;
}
public static function catmullRom(t:Float, p0:Float, p1:Float, p2:Float, p3:Float) {
var point = t * t * t * ((-1) * p0 + 3 * p1 - 3 * p2 + p3) / 2;
point += t * t * (2 * p0 - 5 * p1 + 4 * p2 - p3) / 2;
point += t * ((-1) * p0 + p2) / 2;
point += p1;
return point;
}
public static function lerpThreeVectors(v1:Vector, v2:Vector, t:Float) {
return new Vector(lerp(v1.x, v2.x, t), lerp(v1.y, v2.y, t), lerp(v1.z, v2.z, t));
}
}

View file

@ -13,12 +13,13 @@ import h3d.col.Bounds;
class CollisionEntity implements IOctreeObject {
public var boundingBox:Bounds;
var octree:Octree;
public var octree:Octree;
public var surfaces:Array<CollisionSurface>;
public var priority:Int;
public var position:Int;
public var velocity:Vector = new Vector();
public var transform:Matrix;
@ -61,7 +62,7 @@ class CollisionEntity implements IOctreeObject {
this.priority = priority;
}
public function sphereIntersection(collisionEntity:SphereCollisionEntity) {
public function sphereIntersection(collisionEntity:SphereCollisionEntity, dt:Float) {
var position = collisionEntity.transform.getPosition();
var velocity = collisionEntity.velocity;
var radius = collisionEntity.radius;
@ -72,6 +73,9 @@ class CollisionEntity implements IOctreeObject {
localpos.transform(invMatrix);
var surfaces = octree.radiusSearch(localpos, radius * 1.1);
var tform = transform.clone();
// tform.setPosition(tform.getPosition().add(velocity.multiply(dt)));
var contacts = [];
for (obj in surfaces) {
@ -79,11 +83,11 @@ class CollisionEntity implements IOctreeObject {
var i = 0;
while (i < surface.indices.length) {
var v0 = surface.points[surface.indices[i]].transformed(transform);
var v = surface.points[surface.indices[i + 1]].transformed(transform);
var v2 = surface.points[surface.indices[i + 2]].transformed(transform);
var v0 = surface.points[surface.indices[i]].transformed(tform);
var v = surface.points[surface.indices[i + 1]].transformed(tform);
var v2 = surface.points[surface.indices[i + 2]].transformed(tform);
var surfacenormal = surface.normals[surface.indices[i]].transformed(transform);
var surfacenormal = surface.normals[surface.indices[i]].transformed3x3(transform);
var res = Collision.IntersectTriangleSphere(v0, v, v2, surfacenormal, position, radius);
var closest = res.point;
@ -99,7 +103,7 @@ class CollisionEntity implements IOctreeObject {
cinfo.normal = res.normal; // surface.normals[surface.indices[i]];
cinfo.point = closest;
// cinfo.collider = this;
cinfo.velocity = new Vector();
cinfo.velocity = this.velocity;
cinfo.penetration = radius - (position.sub(closest).dot(normal));
cinfo.restitution = 1;
cinfo.friction = 1;

View file

@ -1,5 +1,6 @@
package collision;
import h3d.col.Bounds;
import h3d.col.Sphere;
import h3d.Vector;
import octree.Octree;
@ -13,11 +14,11 @@ class CollisionWorld {
this.octree = new Octree();
}
public function sphereIntersection(spherecollision:SphereCollisionEntity) {
public function sphereIntersection(spherecollision:SphereCollisionEntity, dt:Float) {
var position = spherecollision.transform.getPosition();
var radius = spherecollision.radius;
var velocity = spherecollision.velocity;
var searchdist = velocity.length() + radius;
var searchdist = (velocity.length() * dt) + radius;
var intersections = this.octree.radiusSearch(position, searchdist);
var contacts = [];
@ -25,17 +26,44 @@ class CollisionWorld {
for (obj in intersections) {
var entity:CollisionEntity = cast obj;
contacts = contacts.concat(entity.sphereIntersection(spherecollision));
contacts = contacts.concat(entity.sphereIntersection(spherecollision, dt));
}
for (obj in dynamicEntities) {
if (obj != spherecollision) {
contacts = contacts.concat(obj.sphereIntersection(spherecollision));
contacts = contacts.concat(obj.sphereIntersection(spherecollision, dt));
}
}
return contacts;
}
public function radiusSearch(center:Vector, radius:Float) {
var intersections = this.octree.radiusSearch(center, radius);
var box = new Bounds();
box.xMin = center.x - radius;
box.yMin = center.y - radius;
box.zMin = center.z - radius;
box.xMax = center.x - radius;
box.yMax = center.y - radius;
box.zMax = center.z - radius;
var contacts:Array<CollisionEntity> = [];
for (obj in intersections) {
var entity:CollisionEntity = cast obj;
contacts = contacts.concat(entity);
}
for (obj in dynamicEntities) {
if (obj.boundingBox.collide(box))
contacts = contacts.concat(obj);
}
return contacts;
}
public function addEntity(entity:CollisionEntity) {
this.octree.insert(entity);
this.entities.push(entity);

View file

@ -8,7 +8,6 @@ import h3d.col.Bounds;
class SphereCollisionEntity extends CollisionEntity {
public var radius:Float;
public var velocity:Vector;
public var marble:Marble;
public function new(marble:Marble) {
@ -31,7 +30,7 @@ class SphereCollisionEntity extends CollisionEntity {
return boundingBox.rayIntersection(Ray.fromValues(rayOrigin.x, rayOrigin.y, rayOrigin.z, rayDirection.x, rayDirection.y, rayDirection.z), true) != -1;
}
public override function sphereIntersection(collisionEntity:SphereCollisionEntity) {
public override function sphereIntersection(collisionEntity:SphereCollisionEntity, dt:Float) {
var contacts = [];
var thispos = transform.getPosition();
var position = collisionEntity.transform.getPosition();