mirror of
https://github.com/RandomityGuy/MBHaxe.git
synced 2025-10-30 08:11:25 +00:00
improve gjk a bit to reduce some lag
This commit is contained in:
parent
81bf76bfb2
commit
97d9db8295
7 changed files with 113 additions and 56 deletions
|
|
@ -916,7 +916,7 @@ class Marble extends GameObject {
|
|||
rollVolume = 0;
|
||||
|
||||
var slipVolume = 0.0;
|
||||
if (slipAmount > 0) {
|
||||
if (slipAmount > 1e-4) {
|
||||
slipVolume = slipAmount / 5;
|
||||
if (slipVolume > 1)
|
||||
slipVolume = 1;
|
||||
|
|
@ -1337,7 +1337,7 @@ class Marble extends GameObject {
|
|||
sph.position = finalPos;
|
||||
sph.radius = _radius;
|
||||
|
||||
var pt = GJK.gjk(sph, chull);
|
||||
var pt = GJK.gjk(sph, chull).epa;
|
||||
|
||||
while (pt != null) {
|
||||
if (pt.lengthSq() < 0.0001) {
|
||||
|
|
@ -1346,7 +1346,7 @@ class Marble extends GameObject {
|
|||
trace('Separating Vector Len: ${pt.length()}');
|
||||
finalPos = finalPos.sub(pt);
|
||||
sph.position = finalPos;
|
||||
pt = GJK.gjk(sph, chull);
|
||||
pt = GJK.gjk(sph, chull).epa;
|
||||
}
|
||||
|
||||
// if (pt != null) {
|
||||
|
|
|
|||
|
|
@ -1518,7 +1518,7 @@ class MarbleWorld extends Scheduler {
|
|||
|
||||
if (this.finishTime == null) {
|
||||
if (spherebounds.collide(this.endPad.finishBounds)) {
|
||||
if (collision.gjk.GJK.gjk(gjkSphere, this.endPad.finishCollider) != null) {
|
||||
if (collision.gjk.GJK.gjk(gjkSphere, this.endPad.finishCollider, false) != null) {
|
||||
if (!endPad.inFinish) {
|
||||
touchFinish();
|
||||
endPad.inFinish = true;
|
||||
|
|
@ -1527,6 +1527,9 @@ class MarbleWorld extends Scheduler {
|
|||
if (endPad.inFinish)
|
||||
endPad.inFinish = false;
|
||||
}
|
||||
} else {
|
||||
if (endPad.inFinish)
|
||||
endPad.inFinish = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ class CollisionHull extends CollisionEntity {
|
|||
newTform.setPosition(newpos);
|
||||
hull.setTransform(newTform);
|
||||
|
||||
var pt = GJK.gjk(sph, this.hull);
|
||||
var pt = GJK.gjk(sph, this.hull).epa;
|
||||
if (pt != null) {
|
||||
var cinfo = new CollisionInfo();
|
||||
cinfo.normal = pt.normalized();
|
||||
|
|
|
|||
23
src/collision/gjk/Cylinder.hx
Normal file
23
src/collision/gjk/Cylinder.hx
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
package collision.gjk;
|
||||
|
||||
import h3d.Vector;
|
||||
|
||||
@:publicFields
|
||||
class Cylinder implements GJKShape {
|
||||
var p1:Vector;
|
||||
var p2:Vector;
|
||||
var radius:Float;
|
||||
|
||||
public function new() {}
|
||||
|
||||
public function getCenter():Vector {
|
||||
return p1.add(p2).multiply(0.5);
|
||||
}
|
||||
|
||||
public function support(dir:Vector) {
|
||||
var axis = p2.sub(p1);
|
||||
var v = axis.dot(dir) > 0 ? p2 : p1;
|
||||
var rejection = dir.sub(axis.multiply(dir.dot(axis) / (axis.dot(axis) * dir.dot(dir)))).normalized().multiply(radius);
|
||||
return v.add(rejection);
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,10 @@ class GJK {
|
|||
public static var maxEpaLooseEdges = 64;
|
||||
public static var maxEpaIterations = 64;
|
||||
|
||||
public static function gjk(s1:GJKShape, s2:GJKShape) {
|
||||
static var epaFaces:Array<Array<Vector>>;
|
||||
static var loose_edges:Array<Array<Vector>>;
|
||||
|
||||
public static function gjk(s1:GJKShape, s2:GJKShape, doEpa:Bool = true) {
|
||||
var searchDir = s1.getCenter().sub(s2.getCenter());
|
||||
var a = new Vector();
|
||||
var b = new Vector();
|
||||
|
|
@ -21,7 +24,10 @@ class GJK {
|
|||
searchDir = c.multiply(-1);
|
||||
b = s2.support(searchDir).sub(s1.support(searchDir.multiply(-1)));
|
||||
if (b.dot(searchDir) < 0)
|
||||
return null;
|
||||
return {
|
||||
result: false,
|
||||
epa: null
|
||||
};
|
||||
|
||||
searchDir = c.sub(b).cross(b.multiply(-1)).cross(c.sub(b));
|
||||
if (searchDir.length() == 0) {
|
||||
|
|
@ -35,7 +41,10 @@ class GJK {
|
|||
for (i in 0...maxIterations) {
|
||||
a = s2.support(searchDir).sub(s1.support(searchDir.multiply(-1)));
|
||||
if (a.dot(searchDir) < 0) {
|
||||
return null;
|
||||
return {
|
||||
result: false,
|
||||
epa: null
|
||||
};
|
||||
}
|
||||
|
||||
simpDim++;
|
||||
|
|
@ -83,44 +92,57 @@ class GJK {
|
|||
b = a;
|
||||
searchDir = adb;
|
||||
} else {
|
||||
return epa(a, b, c, d, s1, s2);
|
||||
if (doEpa)
|
||||
return {
|
||||
result: true,
|
||||
epa: epa(a, b, c, d, s1, s2)
|
||||
};
|
||||
return {
|
||||
result: true,
|
||||
epa: null
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return {
|
||||
result: false,
|
||||
epa: null
|
||||
};
|
||||
}
|
||||
|
||||
public static function epa(a:Vector, b:Vector, c:Vector, d:Vector, s1:GJKShape, s2:GJKShape) {
|
||||
var faces = [];
|
||||
for (i in 0...maxEpaFaces)
|
||||
faces.push([new Vector(), new Vector(), new Vector(), new Vector()]);
|
||||
if (epaFaces == null) {
|
||||
epaFaces = [];
|
||||
for (i in 0...maxEpaFaces)
|
||||
epaFaces.push([new Vector(), new Vector(), new Vector(), new Vector()]);
|
||||
}
|
||||
|
||||
faces[0][0] = a;
|
||||
faces[0][1] = b;
|
||||
faces[0][2] = c;
|
||||
faces[0][3] = b.sub(a).cross(c.sub(a)).normalized(); // ABC
|
||||
faces[1][0] = a;
|
||||
faces[1][1] = c;
|
||||
faces[1][2] = d;
|
||||
faces[1][3] = c.sub(a).cross(d.sub(a)).normalized();
|
||||
faces[2][0] = a;
|
||||
faces[2][1] = d;
|
||||
faces[2][2] = b;
|
||||
faces[2][3] = d.sub(a).cross(b.sub(a)).normalized();
|
||||
faces[3][0] = b;
|
||||
faces[3][1] = d;
|
||||
faces[3][2] = c;
|
||||
faces[3][3] = d.sub(b).cross(c.sub(b)).normalized();
|
||||
epaFaces[0][0] = a;
|
||||
epaFaces[0][1] = b;
|
||||
epaFaces[0][2] = c;
|
||||
epaFaces[0][3] = b.sub(a).cross(c.sub(a)).normalized(); // ABC
|
||||
epaFaces[1][0] = a;
|
||||
epaFaces[1][1] = c;
|
||||
epaFaces[1][2] = d;
|
||||
epaFaces[1][3] = c.sub(a).cross(d.sub(a)).normalized();
|
||||
epaFaces[2][0] = a;
|
||||
epaFaces[2][1] = d;
|
||||
epaFaces[2][2] = b;
|
||||
epaFaces[2][3] = d.sub(a).cross(b.sub(a)).normalized();
|
||||
epaFaces[3][0] = b;
|
||||
epaFaces[3][1] = d;
|
||||
epaFaces[3][2] = c;
|
||||
epaFaces[3][3] = d.sub(b).cross(c.sub(b)).normalized();
|
||||
|
||||
var numFaces = 4;
|
||||
var closestFace = 0;
|
||||
|
||||
for (iteration in 0...maxEpaIterations) {
|
||||
// Find face that's closest to origin
|
||||
var min_dist = faces[0][0].dot(faces[0][3]);
|
||||
var min_dist = epaFaces[0][0].dot(epaFaces[0][3]);
|
||||
closestFace = 0;
|
||||
for (i in 1...numFaces) {
|
||||
var dist = faces[i][0].dot(faces[i][3]);
|
||||
var dist = epaFaces[i][0].dot(epaFaces[i][3]);
|
||||
if (dist < min_dist) {
|
||||
min_dist = dist;
|
||||
closestFace = i;
|
||||
|
|
@ -128,28 +150,30 @@ class GJK {
|
|||
}
|
||||
|
||||
// search normal to face that's closest to origin
|
||||
var search_dir = faces[closestFace][3];
|
||||
var search_dir = epaFaces[closestFace][3];
|
||||
var p = s2.support(search_dir).sub(s1.support(search_dir.multiply(-1)));
|
||||
if (p.dot(search_dir) - min_dist < epaTolerance) {
|
||||
// Convergence (new point is not significantly further from origin)
|
||||
return faces[closestFace][3].multiply(p.dot(search_dir)); // dot vertex with normal to resolve collision along normal!
|
||||
return epaFaces[closestFace][3].multiply(p.dot(search_dir)); // dot vertex with normal to resolve collision along normal!
|
||||
}
|
||||
if (loose_edges == null) {
|
||||
loose_edges = [];
|
||||
for (i in 0...maxEpaLooseEdges)
|
||||
loose_edges.push([new Vector(), new Vector()]);
|
||||
}
|
||||
var loose_edges = [];
|
||||
for (i in 0...maxEpaLooseEdges)
|
||||
loose_edges.push([new Vector(), new Vector()]);
|
||||
|
||||
var num_loose_edges = 0;
|
||||
|
||||
// Find all triangles that are facing p
|
||||
var i = 0;
|
||||
while (i < numFaces) {
|
||||
if (faces[i][3].dot(p.sub(faces[i][0])) > 0) // triangle i faces p, remove it
|
||||
if (epaFaces[i][3].dot(p.sub(epaFaces[i][0])) > 0) // triangle i faces p, remove it
|
||||
{
|
||||
// Add removed triangle's edges to loose edge list.
|
||||
// If it's already there, remove it (both triangles it belonged to are gone)
|
||||
for (j in 0...3) // Three edges per face
|
||||
{
|
||||
var current_edge = [faces[i][j], faces[i][(j + 1) % 3]];
|
||||
var current_edge = [epaFaces[i][j], epaFaces[i][(j + 1) % 3]];
|
||||
var found_edge = false;
|
||||
for (k in 0...num_loose_edges) // Check if current edge is already in list
|
||||
{
|
||||
|
|
@ -178,10 +202,10 @@ class GJK {
|
|||
}
|
||||
|
||||
// Remove triangle i from list
|
||||
faces[i][0] = faces[numFaces - 1][0];
|
||||
faces[i][1] = faces[numFaces - 1][1];
|
||||
faces[i][2] = faces[numFaces - 1][2];
|
||||
faces[i][3] = faces[numFaces - 1][3];
|
||||
epaFaces[i][0] = epaFaces[numFaces - 1][0];
|
||||
epaFaces[i][1] = epaFaces[numFaces - 1][1];
|
||||
epaFaces[i][2] = epaFaces[numFaces - 1][2];
|
||||
epaFaces[i][3] = epaFaces[numFaces - 1][3];
|
||||
numFaces--;
|
||||
i--;
|
||||
} // endif p can see triangle i
|
||||
|
|
@ -194,22 +218,22 @@ class GJK {
|
|||
// assert(num_faces<EPA_MAX_NUM_FACES);
|
||||
if (numFaces >= maxEpaFaces)
|
||||
break;
|
||||
faces[numFaces][0] = loose_edges[i][0];
|
||||
faces[numFaces][1] = loose_edges[i][1];
|
||||
faces[numFaces][2] = p;
|
||||
faces[numFaces][3] = loose_edges[i][0].sub(loose_edges[i][1]).cross(loose_edges[i][0].sub(p)).normalized();
|
||||
epaFaces[numFaces][0] = loose_edges[i][0];
|
||||
epaFaces[numFaces][1] = loose_edges[i][1];
|
||||
epaFaces[numFaces][2] = p;
|
||||
epaFaces[numFaces][3] = loose_edges[i][0].sub(loose_edges[i][1]).cross(loose_edges[i][0].sub(p)).normalized();
|
||||
|
||||
// Check for wrong normal to maintain CCW winding
|
||||
var bias = 0.000001; // in case dot result is only slightly < 0 (because origin is on face)
|
||||
if (faces[numFaces][0].dot(faces[numFaces][3]) + bias < 0) {
|
||||
var temp = faces[numFaces][0];
|
||||
faces[numFaces][0] = faces[numFaces][1];
|
||||
faces[numFaces][1] = temp;
|
||||
faces[numFaces][3] = faces[numFaces][3].multiply(-1);
|
||||
if (epaFaces[numFaces][0].dot(epaFaces[numFaces][3]) + bias < 0) {
|
||||
var temp = epaFaces[numFaces][0];
|
||||
epaFaces[numFaces][0] = epaFaces[numFaces][1];
|
||||
epaFaces[numFaces][1] = temp;
|
||||
epaFaces[numFaces][3] = epaFaces[numFaces][3].multiply(-1);
|
||||
}
|
||||
numFaces++;
|
||||
}
|
||||
}
|
||||
return faces[closestFace][3].multiply(faces[closestFace][0].dot(faces[closestFace][3]));
|
||||
return epaFaces[closestFace][3].multiply(epaFaces[closestFace][0].dot(epaFaces[closestFace][3]));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ class EnterNameDlg extends GuiControl {
|
|||
enterNameText.position = new Vector(37, 23);
|
||||
enterNameText.extent = new Vector(345, 85);
|
||||
// enterNameText.justify = Center;
|
||||
enterNameText.text.text = '<font face="Arial14"><br/></font><p align="center"><font face="DomCasual48">Well Done!<br/></font><font face="DomCasual32">You have the${["", " second", " third", " fourth", "fifth"][place]} top time!</font></p>';
|
||||
enterNameText.text.text = '<font face="Arial14"><br/></font><p align="center"><font face="DomCasual48">Well Done!<br/></font><font face="DomCasual32">You have the${["", " second", " third", " fourth", " fifth"][place]} top time!</font></p>';
|
||||
dlg.addChild(enterNameText);
|
||||
|
||||
dlg.addChild(enterNameEdit);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package shapes;
|
||||
|
||||
import src.MarbleGame;
|
||||
import collision.gjk.Cylinder;
|
||||
import src.AudioManager;
|
||||
import h3d.Quat;
|
||||
import h3d.mat.Material;
|
||||
|
|
@ -25,7 +27,7 @@ import h3d.mat.Texture;
|
|||
class EndPad extends DtsObject {
|
||||
var fireworks:Array<Firework> = [];
|
||||
|
||||
var finishCollider:ConvexHull;
|
||||
var finishCollider:Cylinder;
|
||||
var finishBounds:Bounds;
|
||||
var inFinish:Bool = false;
|
||||
|
||||
|
|
@ -72,7 +74,12 @@ class EndPad extends DtsObject {
|
|||
vertices.push(new Vector(x * radius * this.scaleX, (i != 0 ? 4.8 : 0) * 1, z * radius * this.scaleY));
|
||||
}
|
||||
}
|
||||
finishCollider = new ConvexHull(vertices);
|
||||
finishCollider = new Cylinder();
|
||||
finishCollider.p1 = this.getAbsPos().getPosition();
|
||||
finishCollider.p2 = finishCollider.p1.clone();
|
||||
var vertDir = this.getAbsPos().up();
|
||||
finishCollider.p2 = finishCollider.p2.add(vertDir.multiply(height));
|
||||
finishCollider.radius = radius * this.scaleY;
|
||||
|
||||
finishBounds = new Bounds();
|
||||
for (vert in vertices)
|
||||
|
|
@ -85,7 +92,7 @@ class EndPad extends DtsObject {
|
|||
var tform = this.getAbsPos().clone();
|
||||
tform.prependRotation(Math.PI / 2, 0, 0);
|
||||
|
||||
finishCollider.transform = tform;
|
||||
// finishCollider.transform = tform;
|
||||
|
||||
finishBounds.transform(tform);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue