performance improvement

This commit is contained in:
RandomityGuy 2024-03-08 01:36:36 +05:30
parent b6eafc57b7
commit 9aafd8b541
14 changed files with 164 additions and 88 deletions

View file

@ -26,6 +26,8 @@ class MeshBatchInfo {
var meshbatch:MeshBatch;
var transparencymeshbatch:MeshBatch;
var mesh:Mesh;
var dtsShader:DtsTexture;
var glowPassDtsShader:DtsTexture;
public function new() {}
}
@ -81,7 +83,7 @@ class InstanceManager {
var opaqueinstances = visibleinstances.filter(x -> x.gameObject.currentOpacity == 1);
minfo.meshbatch.begin(opaqueinstances.length);
for (instance in opaqueinstances) { // Draw the opaque shit first
var dtsShader = minfo.meshbatch.material.mainPass.getShader(DtsTexture);
var dtsShader = minfo.dtsShader; // minfo.meshbatch.material.mainPass.getShader(DtsTexture);
var subOpacity = 1.0;
if (dtsShader != null) {
if (instance.gameObject.animateSubObjectOpacities) {
@ -112,7 +114,7 @@ class InstanceManager {
// handle the glow pass too
var glowPass = minfo.meshbatch.material.getPass("glow");
if (glowPass != null) {
dtsShader = glowPass.getShader(DtsTexture);
dtsShader = minfo.glowPassDtsShader;
if (dtsShader != null)
dtsShader.currentOpacity = instance.gameObject.currentOpacity * subOpacity;
}
@ -124,7 +126,7 @@ class InstanceManager {
var transparentinstances = visibleinstances.filter(x -> x.gameObject.currentOpacity != 1 && x.gameObject.currentOpacity != 0); // Filter out all zero opacity things too
minfo.transparencymeshbatch.begin(transparentinstances.length);
for (instance in transparentinstances) { // Non opaque shit
var dtsShader = minfo.transparencymeshbatch.material.mainPass.getShader(DtsTexture);
var dtsShader = minfo.dtsShader;
if (dtsShader != null) {
dtsShader.currentOpacity = instance.gameObject.currentOpacity;
}
@ -218,6 +220,8 @@ class InstanceManager {
for (shader in addshaders)
gpass.addShader(shader);
minfo.glowPassDtsShader = gpass.getShader(DtsTexture);
minfo.meshbatch.material.addPass(gpass);
}
var refractPass = mat.getPass("refract");
@ -279,6 +283,7 @@ class InstanceManager {
minfo.meshbatch.material.addPass(gpass);
}
minfo.dtsShader = minfo.meshbatch.material.mainPass.getShader(DtsTexture);
// var dtsshader = mat.mainPass.getShader(DtsTexture);
// if (dtsshader != null) {
// minfo.meshbatch.material.mainPass.removeShader(minfo.meshbatch.material.textureShader);

View file

@ -1,5 +1,6 @@
package src;
import collision.CollisionPool;
import net.NetPacket.MarbleNetFlags;
import net.BitStream.OutputBitStream;
import net.ClientConnection;
@ -532,9 +533,10 @@ class Marble extends GameObject {
matWorker.run();
}
function findContacts(collisiomWorld:CollisionWorld, timeState:TimeState) {
function findContacts(collisionWorld:CollisionWorld, timeState:TimeState) {
this.contacts = queuedContacts;
var c = collisiomWorld.sphereIntersection(this.collider, timeState);
CollisionPool.clear();
var c = collisionWorld.sphereIntersection(this.collider, timeState);
this.contactEntities = c.foundEntities;
contacts = contacts.concat(c.contacts);
}
@ -1763,7 +1765,7 @@ class Marble extends GameObject {
if (this.controllable && this.mode != Finish && !MarbleGame.instance.paused && !this.level.isWatching && !this.level.isReplayingMovement) {
if (Net.isClient) {
var axis = getMarbleAxis()[1];
move = Net.clientConnection.moveManager.recordMove(cast this, axis, timeState);
move = Net.clientConnection.recordMove(cast this, axis, timeState);
} else if (Net.isHost) {
var axis = getMarbleAxis()[1];
var innerMove = recordMove();
@ -1772,7 +1774,7 @@ class Marble extends GameObject {
}
var moveId = 65535;
if (!this.controllable && this.connection != null && Net.isHost) {
var nextMove = this.connection.moveManager.getNextMove();
var nextMove = this.connection.getNextMove();
// trace('Moves left: ${@:privateAccess this.connection.moveManager.queuedMoves.length}');
if (nextMove == null) {
var axis = getMarbleAxis()[1];

View file

@ -1,5 +1,6 @@
package src;
import collision.CollisionPool;
import net.GemPredictionStore;
import modes.HuntMode;
import net.NetPacket.MarbleNetFlags;
@ -236,7 +237,7 @@ class MarbleWorld extends Scheduler {
var oobSchedule:Float;
var _cubemapNeedsUpdate:Bool = false;
var _instancesNeedsUpdate:Bool = false;
var lock:Bool = false;
@ -1076,7 +1077,7 @@ class MarbleWorld extends Scheduler {
if (!lastMoves.ourMoveApplied) {
var ourMove = lastMoves.myMarbleUpdate;
if (ourMove != null) {
var ourMoveStruct = Net.clientConnection.moveManager.acknowledgeMove(ourMove.move.id, timeState);
var ourMoveStruct = Net.clientConnection.acknowledgeMove(ourMove.move.id, timeState);
lastMoves.ourMoveApplied = true;
for (client => arr in lastMoves.otherMarbleUpdates) {
var lastMove = null;
@ -1157,11 +1158,11 @@ class MarbleWorld extends Scheduler {
var ourLastMove = lastMoves.myMarbleUpdate;
if (ourLastMove == null || marbleNeedsPrediction == 0)
return -1;
var ackLag = @:privateAccess Net.clientConnection.moveManager.queuedMoves.length;
var ackLag = @:privateAccess Net.clientConnection.getQueuedMovesLength();
var ourLastMoveTime = ourLastMove.serverTicks;
var ourQueuedMoves = @:privateAccess Net.clientConnection.moveManager.queuedMoves.copy();
var ourQueuedMoves = @:privateAccess Net.clientConnection.getQueuedMoves().copy();
var qm = ourQueuedMoves[0];
var advanceTimeState = qm != null ? qm.timeState.clone() : timeState.clone();
@ -1506,14 +1507,12 @@ class MarbleWorld extends Scheduler {
marble.update(timeState, collisionWorld, this.pathedInteriors);
}
}
_cubemapNeedsUpdate = true;
_instancesNeedsUpdate = true;
Renderer.dirtyBuffers = true;
if (this.rewinding) {
// Update camera separately
marble.camera.update(timeState.currentAttemptTime, realDt);
}
ProfilerUI.measure("updateInstances");
this.instanceManager.render();
ProfilerUI.measure("updateParticles");
if (this.rewinding) {
this.particleManager.update(1000 * timeState.timeSinceLoad, -realDt * rewindManager.timeScale);
@ -1555,13 +1554,16 @@ class MarbleWorld extends Scheduler {
asyncLoadResources();
if (this.playGui != null && _ready)
this.playGui.render(e);
if (this.marble != null && this.marble.cubemapRenderer != null && _ready) {
ProfilerUI.measure("renderCubemap");
if (_cubemapNeedsUpdate) {
if (_instancesNeedsUpdate) {
ProfilerUI.measure("updateInstances");
this.instanceManager.render();
if (this.marble != null && this.marble.cubemapRenderer != null && _ready) {
ProfilerUI.measure("renderCubemap");
this.marble.cubemapRenderer.position.load(this.marble.getAbsPos().getPosition());
this.marble.cubemapRenderer.render(e);
_cubemapNeedsUpdate = false;
}
_instancesNeedsUpdate = false;
}
}
@ -2298,6 +2300,8 @@ class MarbleWorld extends Scheduler {
}
}
CollisionPool.freeMemory();
radar.dispose();
if (this.playGui != null)

View file

@ -64,10 +64,12 @@ class CollisionEntity implements IOctreeObject implements IBVHObject {
// Generates the bvh
public function finalize() {
this.generateBoundingBox();
#if hl
this.bvh = new BVHTree();
for (surface in this.surfaces) {
this.bvh.add(surface);
}
#end
// this.bvh.build();
}
@ -240,9 +242,10 @@ class CollisionEntity implements IOctreeObject implements IBVHObject {
// if (testDot > bestDot) {
// bestDot = testDot;
var cinfo = new CollisionInfo();
var cinfo = CollisionPool.alloc();
cinfo.normal = normal.clone();
cinfo.point = closest.clone();
cinfo.collider = null;
// cinfo.collider = this;
cinfo.velocity = this.velocity.clone();
cinfo.contactDistance = Math.sqrt(contactDist);

View file

@ -40,10 +40,11 @@ class CollisionHull extends CollisionEntity {
var pt = GJK.gjk(sph, this.hull).epa;
if (pt != null) {
var cinfo = new CollisionInfo();
var cinfo = CollisionPool.alloc();
cinfo.normal = pt.normalized();
cinfo.point = sph.position.sub(pt);
cinfo.velocity = velocity;
cinfo.collider = null;
cinfo.contactDistance = sph.radius + pt.length();
cinfo.restitution = restitution;
cinfo.otherObject = this.go;

View file

@ -10,12 +10,10 @@ class CollisionInfo {
public var collider:CollisionEntity;
public var otherObject:GameObject;
public var friction:Float;
public var vAtCMag:Float;
public var normalForce:Float;
public var restitution:Float;
public var contactDistance:Float;
public var force:Float;
public var penetration:Float;
public function new() {}
}

View file

@ -0,0 +1,21 @@
package collision;
class CollisionPool {
static var pool:Array<CollisionInfo> = [];
static var currentPtr = 0;
public static function alloc() {
if (pool.length <= currentPtr) {
pool.push(new CollisionInfo());
}
return pool[currentPtr++];
}
public static function clear() {
currentPtr = 0;
}
public static function freeMemory() {
pool = [];
}
}

View file

@ -85,7 +85,7 @@ class SphereCollisionEntity extends CollisionEntity {
if (otherRadius * otherRadius * 1.01 > otherDist.lengthSq()) {
var normDist = otherDist.normalized();
var contact = new CollisionInfo();
var contact = CollisionPool.alloc();
contact.collider = this;
contact.friction = 1;
contact.restitution = 1;
@ -95,7 +95,6 @@ class SphereCollisionEntity extends CollisionEntity {
contact.normal = normDist.multiply(-1);
contact.force = 0;
contact.contactDistance = contact.point.distance(position);
contact.penetration = radius - (position.sub(contact.point).dot(contact.normal));
contacts.push(contact);
// var othercontact = new CollisionInfo();

View file

@ -573,7 +573,8 @@ class HuntMode extends NullMode {
"data/skies/gemCubemapUp3.png",
'data/shapes/items/red.gem.png',
"data/skies/gemCubemapUp.png",
'sound/gem_collect.wav'
'sound/gem_collect.wav',
'sound/opponent_gem_collect.wav'
];
}

View file

@ -4,6 +4,7 @@ import haxe.io.Bytes;
import datachannel.RTCPeerConnection;
import datachannel.RTCDataChannel;
import net.MoveManager;
import src.TimeState;
enum abstract GameplayState(Int) from Int to Int {
var UNKNOWN;
@ -55,5 +56,29 @@ abstract class GameConnection {
state = GameplayState.GAME;
}
public function queueMove(m:NetMove) {
moveManager.queueMove(m);
}
public inline function acknowledgeMove(m:Int, timeState:TimeState) {
return moveManager.acknowledgeMove(m, timeState);
}
public inline function getQueuedMoves() {
return @:privateAccess moveManager.queuedMoves;
}
public inline function getQueuedMovesLength() {
return moveManager.getQueueSize();
}
public function recordMove(marble:src.Marble, motionDir:h3d.Vector, timeState:TimeState) {
return moveManager.recordMove(marble, motionDir, timeState);
}
public function getNextMove() {
return moveManager.getNextMove();
}
public function sendBytes(b:haxe.io.Bytes) {}
}

View file

@ -30,7 +30,8 @@ class MarblePrediction {
if (p.netFlags != 0)
subs += 1;
// if (p.powerUpId != powerupItemId)
// subs += 1; // temp
if (tick % 10 == 0)
subs += 1; // temp
// if (isControl)
// subs += Math.abs(blastAmount - p.blastAmount);
return subs;

View file

@ -343,7 +343,7 @@ class Net {
var movePacket = new MarbleMovePacket();
movePacket.deserialize(input);
var cc = clientIdMap[movePacket.clientId];
cc.moveManager.queueMove(movePacket.move);
cc.queueMove(movePacket.move);
case PowerupPickup:
var powerupPickupPacket = new PowerupPickupPacket();

View file

@ -18,10 +18,6 @@ class Octree {
public function new() {
this.root = new OctreeNode(this, 0);
// Init the octree to a 1x1x1 cube
this.root.bounds = new Bounds();
this.root.bounds.xMin = this.root.bounds.yMin = this.root.bounds.zMin = 0;
this.root.bounds.xMax = this.root.bounds.yMax = this.root.bounds.zMax = 1;
this.objectToNode = new Map();
}
@ -79,22 +75,24 @@ class Octree {
count++;
}
}
averagePoint = averagePoint.multiply(1 / count); // count should be greater than 0, because that's why we're growing in the first place.
averagePoint.load(averagePoint.multiply(1 / count)); // count should be greater than 0, because that's why we're growing in the first place.
// Determine the direction from the root center to the determined point
var rootCenter = this.root.bounds.getCenter().toVector();
var rootCenter = new Vector((this.root.xMax + this.root.xMin) / 2, (this.root.yMax + this.root.yMin) / 2, (this.root.zMax + this.root.zMin) / 2);
var direction = averagePoint.sub(rootCenter); // Determine the "direction of growth"
// Create a new root. The current root will become a quadrant in this new root.
var newRoot = new OctreeNode(this, this.root.depth - 1);
newRoot.bounds = this.root.bounds.clone();
newRoot.bounds.xSize *= 2;
newRoot.bounds.ySize *= 2;
newRoot.bounds.zSize *= 2;
newRoot.xMin = this.root.xMin;
newRoot.yMin = this.root.yMin;
newRoot.zMin = this.root.zMin;
newRoot.xMax = 2 * this.root.xMax - this.root.xMin;
newRoot.yMax = 2 * this.root.yMax - this.root.yMin;
newRoot.zMax = 2 * this.root.zMax - this.root.zMin;
if (direction.x < 0)
newRoot.bounds.xMin -= this.root.bounds.xSize;
newRoot.xMin -= this.root.xMax - this.root.xMin;
if (direction.y < 0)
newRoot.bounds.yMin -= this.root.bounds.ySize;
newRoot.yMin -= this.root.yMax - this.root.yMin;
if (direction.z < 0)
newRoot.bounds.zMin -= this.root.bounds.zSize;
newRoot.zMin -= this.root.zMax - this.root.zMin;
if (this.root.count > 0) {
var octantIndex = ((direction.x < 0) ? 1 : 0) + ((direction.y < 0) ? 2 : 0) + ((direction.z < 0) ? 4 : 0);
newRoot.createOctants();
@ -108,12 +106,12 @@ class Octree {
/** Tries to shrink the octree if large parts of the octree are empty. */
public function shrink() {
if (this.root.bounds.xSize < 1 || this.root.bounds.ySize < 1 || this.root.bounds.zSize < 1 || this.root.objects.length > 0)
if (this.root.xMax - this.root.xMin < 1 || this.root.yMax - this.root.yMin < 1 || this.root.zMax - this.root.zMin < 1 || this.root.objects.length > 0)
return;
if (this.root.count == 0) {
// Reset to default empty octree
this.root.bounds.xMin = this.root.bounds.yMin = this.root.bounds.zMin = 0;
this.root.bounds.xMax = this.root.bounds.yMax = this.root.bounds.zMin = 1;
this.root.xMin = this.root.yMin = this.root.zMin = 0;
this.root.xMax = this.root.yMax = this.root.zMax = 1;
this.root.depth = 0;
return;
}

View file

@ -13,7 +13,13 @@ class OctreeNode implements IOctreeElement {
public var position:Int;
/** The min corner of the bounding box. */
public var bounds:Bounds;
public var xMin:Float;
public var yMin:Float;
public var zMin:Float;
public var xMax:Float;
public var yMax:Float;
public var zMax:Float;
/** The size of the bounding box on all three axes. This forces the bounding box to be a cube. */
public var octants:Array<OctreeNode> = null;
@ -29,6 +35,12 @@ class OctreeNode implements IOctreeElement {
public function new(octree:Octree, depth:Int) {
this.octree = octree;
this.depth = depth;
this.xMin = 0;
this.yMin = 0;
this.zMin = 0;
this.xMax = 1;
this.yMax = 1;
this.zMax = 1;
}
public function insert(object:IOctreeObject) {
@ -80,16 +92,13 @@ class OctreeNode implements IOctreeElement {
for (i in 0...8) {
var newNode = new OctreeNode(this.octree, this.depth + 1);
newNode.parent = this;
var newSize = this.bounds.getSize().multiply(1 / 2);
newNode.bounds = this.bounds.clone();
newNode.bounds.setMin(new Point(this.bounds.xMin
+ newSize.x * ((i & 1) >> 0), this.bounds.yMin
+ newSize.y * ((i & 2) >> 1),
this.bounds.zMin
+ newSize.z * ((i & 4) >> 2)));
newNode.bounds.xSize = newSize.x;
newNode.bounds.ySize = newSize.y;
newNode.bounds.zSize = newSize.z;
var newSize = new Vector(xMax - xMin, yMax - yMin, zMax - zMin);
newNode.xMin = this.xMin + newSize.x * ((i & 1) >> 0);
newNode.yMin = this.yMin + newSize.y * ((i & 2) >> 1);
newNode.zMin = this.zMin + newSize.z * ((i & 4) >> 2);
newNode.xMax = newNode.xMin + newSize.x;
newNode.yMax = newNode.yMin + newSize.y;
newNode.zMax = newNode.zMin + newSize.z;
this.octants.push(newNode);
}
}
@ -141,24 +150,53 @@ class OctreeNode implements IOctreeElement {
this.octants = null; // ...then devare the octants
}
public function largerThan(object:IOctreeObject) {
return this.bounds.containsBounds(object.boundingBox);
public inline function largerThan(object:IOctreeObject) {
return xMin <= object.boundingBox.xMin && yMin <= object.boundingBox.yMin && zMin <= object.boundingBox.zMin && xMax >= object.boundingBox.xMax
&& yMax >= object.boundingBox.yMax && zMax >= object.boundingBox.zMax;
// return this.size > (box.xMax - box.xMin) && this.size > (box.yMax - box.yMin) && this.size > (box.zMax - box.zMin);
}
public function containsCenter(object:IOctreeObject) {
return this.bounds.contains(object.boundingBox.getCenter());
public inline function containsCenter(object:IOctreeObject) {
return this.containsPoint2(object.boundingBox.getCenter());
}
public function containsPoint(point:Vector) {
return this.bounds.contains(point.toPoint());
public inline function containsPoint(p:Vector) {
return p.x >= xMin && p.x < xMax && p.y >= yMin && p.y < yMax && p.z >= zMin && p.z < zMax;
}
public inline function containsPoint2(p:h3d.col.Point) {
return p.x >= xMin && p.x < xMax && p.y >= yMin && p.y < yMax && p.z >= zMin && p.z < zMax;
}
inline function rayIntersection(r:Ray, bestMatch:Bool):Float {
var minTx = (xMin - r.px) / r.lx;
var minTy = (yMin - r.py) / r.ly;
var minTz = (zMin - r.pz) / r.lz;
var maxTx = (xMax - r.px) / r.lx;
var maxTy = (yMax - r.py) / r.ly;
var maxTz = (zMax - r.pz) / r.lz;
var realMinTx = Math.min(minTx, maxTx);
var realMinTy = Math.min(minTy, maxTy);
var realMinTz = Math.min(minTz, maxTz);
var realMaxTx = Math.max(minTx, maxTx);
var realMaxTy = Math.max(minTy, maxTy);
var realMaxTz = Math.max(minTz, maxTz);
var minmax = Math.min(Math.min(realMaxTx, realMaxTy), realMaxTz);
var maxmin = Math.max(Math.max(realMinTx, realMinTy), realMinTz);
if (minmax < maxmin)
return -1;
return maxmin;
}
public function raycast(rayOrigin:Vector, rayDirection:Vector, intersections:Array<OctreeIntersection>) {
var ray = Ray.fromValues(rayOrigin.x, rayOrigin.y, rayOrigin.z, rayDirection.x, rayDirection.y, rayDirection.z);
// Construct the loose bounding box of this node (2x in size, with the regular bounding box in the center)
if (this.bounds.rayIntersection(ray, true) == -1)
if (rayIntersection(ray, true) == -1)
return;
for (obj in this.objects) {
@ -181,42 +219,22 @@ class OctreeNode implements IOctreeElement {
}
}
public function boundingSearch(bounds:Bounds, intersections:Array<IOctreeElement>) {
if (this.bounds.collide(bounds)) {
public function boundingSearch(b:Bounds, intersections:Array<IOctreeElement>) {
if (!(xMin > b.xMax || yMin > b.yMax || zMin > b.zMax || xMax < b.xMin || yMax < b.yMin || zMax < b.zMin)) {
for (obj in this.objects) {
if (obj.boundingBox.collide(bounds))
if (obj.boundingBox.collide(b))
intersections.push(obj);
}
if (octants != null) {
for (octant in this.octants)
octant.boundingSearch(bounds, intersections);
octant.boundingSearch(b, intersections);
}
}
}
public function getClosestPoint(point:Vector) {
var closest = new Vector();
if (this.bounds.xMin > point.x)
closest.x = this.bounds.xMin;
else if (this.bounds.xMax < point.x)
closest.x = this.bounds.xMax;
else
closest.x = point.x;
if (this.bounds.yMin > point.y)
closest.y = this.bounds.yMin;
else if (this.bounds.yMax < point.y)
closest.y = this.bounds.yMax;
else
closest.y = point.y;
if (this.bounds.zMin > point.z)
closest.z = this.bounds.zMin;
else if (this.bounds.zMax < point.z)
closest.z = this.bounds.zMax;
else
closest.z = point.z;
public inline function getClosestPoint(point:Vector) {
var closest = new Vector(Math.min(Math.max(this.xMin, point.x), this.xMax), Math.min(Math.max(this.yMin, point.y), this.yMax),
Math.min(Math.max(this.zMin, point.z), this.zMax));
return closest;
}