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;
|
rollVolume = 0;
|
||||||
|
|
||||||
var slipVolume = 0.0;
|
var slipVolume = 0.0;
|
||||||
if (slipAmount > 0) {
|
if (slipAmount > 1e-4) {
|
||||||
slipVolume = slipAmount / 5;
|
slipVolume = slipAmount / 5;
|
||||||
if (slipVolume > 1)
|
if (slipVolume > 1)
|
||||||
slipVolume = 1;
|
slipVolume = 1;
|
||||||
|
|
@ -1337,7 +1337,7 @@ class Marble extends GameObject {
|
||||||
sph.position = finalPos;
|
sph.position = finalPos;
|
||||||
sph.radius = _radius;
|
sph.radius = _radius;
|
||||||
|
|
||||||
var pt = GJK.gjk(sph, chull);
|
var pt = GJK.gjk(sph, chull).epa;
|
||||||
|
|
||||||
while (pt != null) {
|
while (pt != null) {
|
||||||
if (pt.lengthSq() < 0.0001) {
|
if (pt.lengthSq() < 0.0001) {
|
||||||
|
|
@ -1346,7 +1346,7 @@ class Marble extends GameObject {
|
||||||
trace('Separating Vector Len: ${pt.length()}');
|
trace('Separating Vector Len: ${pt.length()}');
|
||||||
finalPos = finalPos.sub(pt);
|
finalPos = finalPos.sub(pt);
|
||||||
sph.position = finalPos;
|
sph.position = finalPos;
|
||||||
pt = GJK.gjk(sph, chull);
|
pt = GJK.gjk(sph, chull).epa;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (pt != null) {
|
// if (pt != null) {
|
||||||
|
|
|
||||||
|
|
@ -1518,7 +1518,7 @@ class MarbleWorld extends Scheduler {
|
||||||
|
|
||||||
if (this.finishTime == null) {
|
if (this.finishTime == null) {
|
||||||
if (spherebounds.collide(this.endPad.finishBounds)) {
|
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) {
|
if (!endPad.inFinish) {
|
||||||
touchFinish();
|
touchFinish();
|
||||||
endPad.inFinish = true;
|
endPad.inFinish = true;
|
||||||
|
|
@ -1527,6 +1527,9 @@ class MarbleWorld extends Scheduler {
|
||||||
if (endPad.inFinish)
|
if (endPad.inFinish)
|
||||||
endPad.inFinish = false;
|
endPad.inFinish = false;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (endPad.inFinish)
|
||||||
|
endPad.inFinish = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ class CollisionHull extends CollisionEntity {
|
||||||
newTform.setPosition(newpos);
|
newTform.setPosition(newpos);
|
||||||
hull.setTransform(newTform);
|
hull.setTransform(newTform);
|
||||||
|
|
||||||
var pt = GJK.gjk(sph, this.hull);
|
var pt = GJK.gjk(sph, this.hull).epa;
|
||||||
if (pt != null) {
|
if (pt != null) {
|
||||||
var cinfo = new CollisionInfo();
|
var cinfo = new CollisionInfo();
|
||||||
cinfo.normal = pt.normalized();
|
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 maxEpaLooseEdges = 64;
|
||||||
public static var maxEpaIterations = 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 searchDir = s1.getCenter().sub(s2.getCenter());
|
||||||
var a = new Vector();
|
var a = new Vector();
|
||||||
var b = new Vector();
|
var b = new Vector();
|
||||||
|
|
@ -21,7 +24,10 @@ class GJK {
|
||||||
searchDir = c.multiply(-1);
|
searchDir = c.multiply(-1);
|
||||||
b = s2.support(searchDir).sub(s1.support(searchDir.multiply(-1)));
|
b = s2.support(searchDir).sub(s1.support(searchDir.multiply(-1)));
|
||||||
if (b.dot(searchDir) < 0)
|
if (b.dot(searchDir) < 0)
|
||||||
return null;
|
return {
|
||||||
|
result: false,
|
||||||
|
epa: null
|
||||||
|
};
|
||||||
|
|
||||||
searchDir = c.sub(b).cross(b.multiply(-1)).cross(c.sub(b));
|
searchDir = c.sub(b).cross(b.multiply(-1)).cross(c.sub(b));
|
||||||
if (searchDir.length() == 0) {
|
if (searchDir.length() == 0) {
|
||||||
|
|
@ -35,7 +41,10 @@ class GJK {
|
||||||
for (i in 0...maxIterations) {
|
for (i in 0...maxIterations) {
|
||||||
a = s2.support(searchDir).sub(s1.support(searchDir.multiply(-1)));
|
a = s2.support(searchDir).sub(s1.support(searchDir.multiply(-1)));
|
||||||
if (a.dot(searchDir) < 0) {
|
if (a.dot(searchDir) < 0) {
|
||||||
return null;
|
return {
|
||||||
|
result: false,
|
||||||
|
epa: null
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
simpDim++;
|
simpDim++;
|
||||||
|
|
@ -83,44 +92,57 @@ class GJK {
|
||||||
b = a;
|
b = a;
|
||||||
searchDir = adb;
|
searchDir = adb;
|
||||||
} else {
|
} 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) {
|
public static function epa(a:Vector, b:Vector, c:Vector, d:Vector, s1:GJKShape, s2:GJKShape) {
|
||||||
var faces = [];
|
if (epaFaces == null) {
|
||||||
|
epaFaces = [];
|
||||||
for (i in 0...maxEpaFaces)
|
for (i in 0...maxEpaFaces)
|
||||||
faces.push([new Vector(), new Vector(), new Vector(), new Vector()]);
|
epaFaces.push([new Vector(), new Vector(), new Vector(), new Vector()]);
|
||||||
|
}
|
||||||
|
|
||||||
faces[0][0] = a;
|
epaFaces[0][0] = a;
|
||||||
faces[0][1] = b;
|
epaFaces[0][1] = b;
|
||||||
faces[0][2] = c;
|
epaFaces[0][2] = c;
|
||||||
faces[0][3] = b.sub(a).cross(c.sub(a)).normalized(); // ABC
|
epaFaces[0][3] = b.sub(a).cross(c.sub(a)).normalized(); // ABC
|
||||||
faces[1][0] = a;
|
epaFaces[1][0] = a;
|
||||||
faces[1][1] = c;
|
epaFaces[1][1] = c;
|
||||||
faces[1][2] = d;
|
epaFaces[1][2] = d;
|
||||||
faces[1][3] = c.sub(a).cross(d.sub(a)).normalized();
|
epaFaces[1][3] = c.sub(a).cross(d.sub(a)).normalized();
|
||||||
faces[2][0] = a;
|
epaFaces[2][0] = a;
|
||||||
faces[2][1] = d;
|
epaFaces[2][1] = d;
|
||||||
faces[2][2] = b;
|
epaFaces[2][2] = b;
|
||||||
faces[2][3] = d.sub(a).cross(b.sub(a)).normalized();
|
epaFaces[2][3] = d.sub(a).cross(b.sub(a)).normalized();
|
||||||
faces[3][0] = b;
|
epaFaces[3][0] = b;
|
||||||
faces[3][1] = d;
|
epaFaces[3][1] = d;
|
||||||
faces[3][2] = c;
|
epaFaces[3][2] = c;
|
||||||
faces[3][3] = d.sub(b).cross(c.sub(b)).normalized();
|
epaFaces[3][3] = d.sub(b).cross(c.sub(b)).normalized();
|
||||||
|
|
||||||
var numFaces = 4;
|
var numFaces = 4;
|
||||||
var closestFace = 0;
|
var closestFace = 0;
|
||||||
|
|
||||||
for (iteration in 0...maxEpaIterations) {
|
for (iteration in 0...maxEpaIterations) {
|
||||||
// Find face that's closest to origin
|
// 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;
|
closestFace = 0;
|
||||||
for (i in 1...numFaces) {
|
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) {
|
if (dist < min_dist) {
|
||||||
min_dist = dist;
|
min_dist = dist;
|
||||||
closestFace = i;
|
closestFace = i;
|
||||||
|
|
@ -128,28 +150,30 @@ class GJK {
|
||||||
}
|
}
|
||||||
|
|
||||||
// search normal to face that's closest to origin
|
// 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)));
|
var p = s2.support(search_dir).sub(s1.support(search_dir.multiply(-1)));
|
||||||
if (p.dot(search_dir) - min_dist < epaTolerance) {
|
if (p.dot(search_dir) - min_dist < epaTolerance) {
|
||||||
// Convergence (new point is not significantly further from origin)
|
// 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!
|
||||||
}
|
}
|
||||||
var loose_edges = [];
|
if (loose_edges == null) {
|
||||||
|
loose_edges = [];
|
||||||
for (i in 0...maxEpaLooseEdges)
|
for (i in 0...maxEpaLooseEdges)
|
||||||
loose_edges.push([new Vector(), new Vector()]);
|
loose_edges.push([new Vector(), new Vector()]);
|
||||||
|
}
|
||||||
|
|
||||||
var num_loose_edges = 0;
|
var num_loose_edges = 0;
|
||||||
|
|
||||||
// Find all triangles that are facing p
|
// Find all triangles that are facing p
|
||||||
var i = 0;
|
var i = 0;
|
||||||
while (i < numFaces) {
|
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.
|
// Add removed triangle's edges to loose edge list.
|
||||||
// If it's already there, remove it (both triangles it belonged to are gone)
|
// If it's already there, remove it (both triangles it belonged to are gone)
|
||||||
for (j in 0...3) // Three edges per face
|
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;
|
var found_edge = false;
|
||||||
for (k in 0...num_loose_edges) // Check if current edge is already in list
|
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
|
// Remove triangle i from list
|
||||||
faces[i][0] = faces[numFaces - 1][0];
|
epaFaces[i][0] = epaFaces[numFaces - 1][0];
|
||||||
faces[i][1] = faces[numFaces - 1][1];
|
epaFaces[i][1] = epaFaces[numFaces - 1][1];
|
||||||
faces[i][2] = faces[numFaces - 1][2];
|
epaFaces[i][2] = epaFaces[numFaces - 1][2];
|
||||||
faces[i][3] = faces[numFaces - 1][3];
|
epaFaces[i][3] = epaFaces[numFaces - 1][3];
|
||||||
numFaces--;
|
numFaces--;
|
||||||
i--;
|
i--;
|
||||||
} // endif p can see triangle i
|
} // endif p can see triangle i
|
||||||
|
|
@ -194,22 +218,22 @@ class GJK {
|
||||||
// assert(num_faces<EPA_MAX_NUM_FACES);
|
// assert(num_faces<EPA_MAX_NUM_FACES);
|
||||||
if (numFaces >= maxEpaFaces)
|
if (numFaces >= maxEpaFaces)
|
||||||
break;
|
break;
|
||||||
faces[numFaces][0] = loose_edges[i][0];
|
epaFaces[numFaces][0] = loose_edges[i][0];
|
||||||
faces[numFaces][1] = loose_edges[i][1];
|
epaFaces[numFaces][1] = loose_edges[i][1];
|
||||||
faces[numFaces][2] = p;
|
epaFaces[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][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
|
// 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)
|
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) {
|
if (epaFaces[numFaces][0].dot(epaFaces[numFaces][3]) + bias < 0) {
|
||||||
var temp = faces[numFaces][0];
|
var temp = epaFaces[numFaces][0];
|
||||||
faces[numFaces][0] = faces[numFaces][1];
|
epaFaces[numFaces][0] = epaFaces[numFaces][1];
|
||||||
faces[numFaces][1] = temp;
|
epaFaces[numFaces][1] = temp;
|
||||||
faces[numFaces][3] = faces[numFaces][3].multiply(-1);
|
epaFaces[numFaces][3] = epaFaces[numFaces][3].multiply(-1);
|
||||||
}
|
}
|
||||||
numFaces++;
|
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.position = new Vector(37, 23);
|
||||||
enterNameText.extent = new Vector(345, 85);
|
enterNameText.extent = new Vector(345, 85);
|
||||||
// enterNameText.justify = Center;
|
// 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(enterNameText);
|
||||||
|
|
||||||
dlg.addChild(enterNameEdit);
|
dlg.addChild(enterNameEdit);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package shapes;
|
package shapes;
|
||||||
|
|
||||||
|
import src.MarbleGame;
|
||||||
|
import collision.gjk.Cylinder;
|
||||||
import src.AudioManager;
|
import src.AudioManager;
|
||||||
import h3d.Quat;
|
import h3d.Quat;
|
||||||
import h3d.mat.Material;
|
import h3d.mat.Material;
|
||||||
|
|
@ -25,7 +27,7 @@ import h3d.mat.Texture;
|
||||||
class EndPad extends DtsObject {
|
class EndPad extends DtsObject {
|
||||||
var fireworks:Array<Firework> = [];
|
var fireworks:Array<Firework> = [];
|
||||||
|
|
||||||
var finishCollider:ConvexHull;
|
var finishCollider:Cylinder;
|
||||||
var finishBounds:Bounds;
|
var finishBounds:Bounds;
|
||||||
var inFinish:Bool = false;
|
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));
|
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();
|
finishBounds = new Bounds();
|
||||||
for (vert in vertices)
|
for (vert in vertices)
|
||||||
|
|
@ -85,7 +92,7 @@ class EndPad extends DtsObject {
|
||||||
var tform = this.getAbsPos().clone();
|
var tform = this.getAbsPos().clone();
|
||||||
tform.prependRotation(Math.PI / 2, 0, 0);
|
tform.prependRotation(Math.PI / 2, 0, 0);
|
||||||
|
|
||||||
finishCollider.transform = tform;
|
// finishCollider.transform = tform;
|
||||||
|
|
||||||
finishBounds.transform(tform);
|
finishBounds.transform(tform);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue