mirror of
https://github.com/RandomityGuy/MBHaxe.git
synced 2025-10-30 08:11:25 +00:00
fix magnet sound persist, use BVH for interior CD (cleaner, similar perf), cull instances not in frustum, overall FPS improvements
This commit is contained in:
parent
b7652955b5
commit
ba5f06a40d
7 changed files with 226 additions and 21 deletions
|
|
@ -1,5 +1,6 @@
|
|||
package src;
|
||||
|
||||
import h3d.prim.Instanced;
|
||||
import h3d.shader.pbr.PropsValues;
|
||||
import shaders.Billboard;
|
||||
import shaders.DtsTexture;
|
||||
|
|
@ -37,8 +38,21 @@ class InstanceManager {
|
|||
public function update(dt:Float) {
|
||||
for (meshes in objects) {
|
||||
for (minfo in meshes) {
|
||||
var visibleinstances = [];
|
||||
// Culling
|
||||
if (minfo.meshbatch != null || minfo.transparencymeshbatch != null) {
|
||||
for (inst in minfo.instances) {
|
||||
var objBounds = @:privateAccess cast(minfo.meshbatch.primitive, Instanced).baseBounds.clone();
|
||||
objBounds.transform(inst.emptyObj.getAbsPos());
|
||||
if (scene.camera.frustum.hasBounds(objBounds)) {
|
||||
visibleinstances.push(inst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Emit non culled primitives
|
||||
if (minfo.meshbatch != null) {
|
||||
var opaqueinstances = minfo.instances.filter(x -> x.gameObject.currentOpacity == 1);
|
||||
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);
|
||||
|
|
@ -53,7 +67,7 @@ class InstanceManager {
|
|||
}
|
||||
}
|
||||
if (minfo.transparencymeshbatch != null) {
|
||||
var transparentinstances = minfo.instances.filter(x -> x.gameObject.currentOpacity != 1);
|
||||
var transparentinstances = visibleinstances.filter(x -> x.gameObject.currentOpacity != 1);
|
||||
minfo.transparencymeshbatch.begin(transparentinstances.length);
|
||||
for (instance in transparentinstances) { // Non opaque shit
|
||||
var dtsShader = minfo.transparencymeshbatch.material.mainPass.getShader(DtsTexture);
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ class Marble extends GameObject {
|
|||
// mat.mainPass.culling = None;
|
||||
|
||||
if (Settings.optionsSettings.reflectiveMarble) {
|
||||
this.cubemapRenderer = new CubemapRenderer(level.scene);
|
||||
this.cubemapRenderer = new CubemapRenderer(level.scene, level.sky);
|
||||
mat.mainPass.addShader(new MarbleReflection(this.cubemapRenderer.cubemap));
|
||||
}
|
||||
}
|
||||
|
|
@ -833,7 +833,7 @@ class Marble extends GameObject {
|
|||
+ relLocalVel.z * deltaT * 2,
|
||||
radius * 1.1);
|
||||
|
||||
var surfaces = obj.grid == null ? obj.octree.boundingSearch(boundThing).map(x -> cast x) : obj.grid.boundingSearch(boundThing);
|
||||
var surfaces = obj.bvh == null ? obj.octree.boundingSearch(boundThing).map(x -> cast x) : obj.bvh.boundingSearch(boundThing);
|
||||
|
||||
for (surf in surfaces) {
|
||||
var surface:CollisionSurface = cast surf;
|
||||
|
|
@ -1118,7 +1118,7 @@ class Marble extends GameObject {
|
|||
boundThing.addSpherePos(localpos.x + relLocalVel.x * dt * 2, localpos.y + relLocalVel.y * dt * 2, localpos.z + relLocalVel.z * dt * 2,
|
||||
radius * 1.1);
|
||||
|
||||
var surfaces = obj.grid == null ? obj.octree.boundingSearch(boundThing).map(x -> cast x) : obj.grid.boundingSearch(boundThing);
|
||||
var surfaces = obj.bvh == null ? obj.octree.boundingSearch(boundThing).map(x -> cast x) : obj.bvh.boundingSearch(boundThing);
|
||||
|
||||
var tform = obj.transform.clone();
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ import src.ResourceLoaderWorker;
|
|||
class Sky extends Object {
|
||||
public var dmlPath:String;
|
||||
|
||||
public var cubemap:Texture;
|
||||
|
||||
var imageResources:Array<Resource<Image>> = [];
|
||||
|
||||
public function new() {
|
||||
|
|
@ -51,6 +53,7 @@ class Sky extends Object {
|
|||
var shad = new Skybox(texture);
|
||||
skyMesh.material.mainPass.addShader(shad);
|
||||
skyMesh.material.mainPass.depthWrite = false;
|
||||
cubemap = texture;
|
||||
onFinish();
|
||||
});
|
||||
// skyMesh.material.shadows = false;
|
||||
|
|
|
|||
183
src/collision/BVHTree.hx
Normal file
183
src/collision/BVHTree.hx
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
package collision;
|
||||
|
||||
import h3d.col.Bounds;
|
||||
import h3d.Vector;
|
||||
|
||||
// https://github.com/Sopiro/DynamicBVH/blob/master/src/aabbtree.ts
|
||||
|
||||
@:publicFields
|
||||
class BVHNode {
|
||||
var bounds:Bounds;
|
||||
var objects:Array<CollisionSurface>;
|
||||
var objectBounds:Bounds; // total bounds for objects stored in THIS node
|
||||
var left:BVHNode;
|
||||
var right:BVHNode;
|
||||
var surfaceArea:Float;
|
||||
|
||||
public function new(bounds:Bounds) {
|
||||
this.bounds = bounds.clone();
|
||||
surfaceArea = this.bounds.xSize * this.bounds.ySize + this.bounds.xSize * this.bounds.zSize + this.bounds.ySize * this.bounds.zSize;
|
||||
}
|
||||
|
||||
function getSplitCost(objs:Array<{obj:CollisionSurface, centroid:h3d.col.Point}>, axis:Int) {
|
||||
// Pick best axis to split
|
||||
switch (axis) {
|
||||
case 0:
|
||||
objs.sort((x, y) -> x.centroid.x > y.centroid.x ? 1 : -1);
|
||||
case 1:
|
||||
objs.sort((x, y) -> x.centroid.y > y.centroid.y ? 1 : -1);
|
||||
case 2:
|
||||
objs.sort((x, y) -> x.centroid.z > y.centroid.z ? 1 : -1);
|
||||
};
|
||||
|
||||
var leftObjects = objs.slice(0, Math.ceil(objs.length / 2));
|
||||
var rightObjects = objs.slice(Math.ceil(objs.length / 2));
|
||||
var leftAABB = new Bounds();
|
||||
var rightAABB = new Bounds();
|
||||
for (o in leftObjects)
|
||||
leftAABB.add(o.obj.boundingBox);
|
||||
for (o in rightObjects)
|
||||
rightAABB.add(o.obj.boundingBox);
|
||||
var leftSA = leftAABB.xSize * leftAABB.ySize + leftAABB.xSize * leftAABB.zSize + leftAABB.ySize * leftAABB.zSize;
|
||||
var rightSA = rightAABB.xSize * rightAABB.ySize + rightAABB.xSize * rightAABB.zSize + rightAABB.ySize * rightAABB.zSize;
|
||||
var splitCost = leftSA + rightSA;
|
||||
var bestSplit = {
|
||||
cost: splitCost,
|
||||
left: leftObjects,
|
||||
right: rightObjects,
|
||||
leftBounds: leftAABB,
|
||||
rightBounds: rightAABB,
|
||||
axis: axis
|
||||
};
|
||||
return bestSplit;
|
||||
}
|
||||
|
||||
public function split() {
|
||||
// Splitting first time
|
||||
// Calculate the centroids of all objects
|
||||
var objs = objects.map(x -> {
|
||||
x.generateBoundingBox();
|
||||
return {obj: x, centroid: x.boundingBox.getCenter()};
|
||||
});
|
||||
|
||||
// Find the best split cost
|
||||
var costs = [getSplitCost(objs, 0), getSplitCost(objs, 1), getSplitCost(objs, 2)];
|
||||
costs.sort((x, y) -> x.cost > y.cost ? 1 : -1);
|
||||
var bestSplit = costs[0];
|
||||
|
||||
// Sort the objects according to where they should go
|
||||
var leftObjs = [];
|
||||
var rightObjs = [];
|
||||
var intersectObjs = [];
|
||||
for (o in bestSplit.left.concat(bestSplit.right)) {
|
||||
var inleft = bestSplit.leftBounds.containsBounds(o.obj.boundingBox);
|
||||
var inright = bestSplit.rightBounds.containsBounds(o.obj.boundingBox);
|
||||
if (inleft && inright) {
|
||||
intersectObjs.push(o.obj);
|
||||
} else if (inleft) {
|
||||
leftObjs.push(o.obj);
|
||||
} else if (inright) {
|
||||
rightObjs.push(o.obj);
|
||||
}
|
||||
}
|
||||
|
||||
// Only one side has objects, egh
|
||||
if (leftObjs.length == 0 || rightObjs.length == 0) {
|
||||
var thisobjs = leftObjs.concat(rightObjs).concat(intersectObjs);
|
||||
this.objects = thisobjs;
|
||||
this.objectBounds = new Bounds();
|
||||
for (o in thisobjs)
|
||||
this.objectBounds.add(o.boundingBox);
|
||||
return;
|
||||
}
|
||||
|
||||
// Make the child nodes
|
||||
var leftBounds = new Bounds();
|
||||
var rightBounds = new Bounds();
|
||||
for (o in leftObjs)
|
||||
leftBounds.add(o.boundingBox);
|
||||
for (o in rightObjs)
|
||||
rightBounds.add(o.boundingBox);
|
||||
left = new BVHNode(leftBounds);
|
||||
right = new BVHNode(rightBounds);
|
||||
left.objects = leftObjs;
|
||||
right.objects = rightObjs;
|
||||
this.objects = intersectObjs;
|
||||
this.objectBounds = new Bounds();
|
||||
for (o in intersectObjs)
|
||||
this.objectBounds.add(o.boundingBox);
|
||||
|
||||
left.split();
|
||||
right.split();
|
||||
}
|
||||
|
||||
public function boundingSearch(searchbox:Bounds) {
|
||||
if (this.bounds.containsBounds(searchbox) || this.bounds.collide(searchbox)) {
|
||||
var intersects = [];
|
||||
if (this.left != null && this.right != null) {
|
||||
intersects = intersects.concat(this.left.boundingSearch(searchbox));
|
||||
intersects = intersects.concat(this.right.boundingSearch(searchbox));
|
||||
}
|
||||
if (this.objectBounds.collide(searchbox) || this.objectBounds.containsBounds(searchbox)) {
|
||||
for (o in this.objects) {
|
||||
if (o.boundingBox.containsBounds(searchbox) || o.boundingBox.collide(searchbox))
|
||||
intersects.push(o);
|
||||
}
|
||||
}
|
||||
return intersects;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
public function rayCast(origin:Vector, direction:Vector) {
|
||||
var ray = h3d.col.Ray.fromValues(origin.x, origin.y, origin.z, direction.x, direction.y, direction.z);
|
||||
if (ray.collide(this.bounds)) {
|
||||
var intersects = [];
|
||||
if (this.left != null && this.right != null) {
|
||||
intersects = intersects.concat(this.left.rayCast(origin, direction));
|
||||
intersects = intersects.concat(this.right.rayCast(origin, direction));
|
||||
}
|
||||
if (ray.collide(this.objectBounds)) {
|
||||
for (o in this.objects) {
|
||||
if (ray.collide(o.boundingBox))
|
||||
intersects = intersects.concat(o.rayCast(origin, direction));
|
||||
}
|
||||
}
|
||||
return intersects;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BVHTree {
|
||||
public var bounds:Bounds;
|
||||
|
||||
var surfaces:Array<CollisionSurface> = [];
|
||||
|
||||
var root:BVHNode;
|
||||
|
||||
public function new(bounds:Bounds) {
|
||||
this.bounds = bounds.clone();
|
||||
}
|
||||
|
||||
public function insert(surf:CollisionSurface) {
|
||||
surfaces.push(surf);
|
||||
}
|
||||
|
||||
public function build() {
|
||||
root = new BVHNode(bounds);
|
||||
// Add all children
|
||||
root.objects = this.surfaces;
|
||||
root.split();
|
||||
}
|
||||
|
||||
public function boundingSearch(searchbox:Bounds) {
|
||||
return this.root.boundingSearch(searchbox);
|
||||
}
|
||||
|
||||
public function rayCast(origin:Vector, direction:Vector) {
|
||||
return this.root.rayCast(origin, direction);
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ class CollisionEntity implements IOctreeObject {
|
|||
|
||||
public var octree:Octree;
|
||||
|
||||
public var grid:Grid;
|
||||
public var bvh:BVHTree;
|
||||
|
||||
public var surfaces:Array<CollisionSurface>;
|
||||
|
||||
|
|
@ -52,13 +52,14 @@ class CollisionEntity implements IOctreeObject {
|
|||
}
|
||||
}
|
||||
|
||||
// Generates the grid
|
||||
// Generates the bvh
|
||||
public function finalize() {
|
||||
this.generateBoundingBox();
|
||||
this.grid = new Grid(this.boundingBox);
|
||||
this.bvh = new BVHTree(this.boundingBox);
|
||||
for (surface in this.surfaces) {
|
||||
this.grid.insert(surface);
|
||||
this.bvh.insert(surface);
|
||||
}
|
||||
this.bvh.build();
|
||||
}
|
||||
|
||||
public function setTransform(transform:Matrix) {
|
||||
|
|
@ -102,7 +103,7 @@ class CollisionEntity implements IOctreeObject {
|
|||
var rStart = rayOrigin.clone();
|
||||
rStart.transform(invMatrix);
|
||||
var rDir = rayDirection.transformed3x3(invMatrix);
|
||||
if (grid == null) {
|
||||
if (bvh == null) {
|
||||
var intersections = octree.raycast(rStart, rDir);
|
||||
var iData:Array<RayIntersectionData> = [];
|
||||
for (i in intersections) {
|
||||
|
|
@ -113,7 +114,7 @@ class CollisionEntity implements IOctreeObject {
|
|||
}
|
||||
return iData;
|
||||
} else {
|
||||
var intersections = this.grid.rayCast(rStart, rDir);
|
||||
var intersections = this.bvh.rayCast(rStart, rDir);
|
||||
for (i in intersections) {
|
||||
i.point.transform(transform);
|
||||
i.normal.transform3x3(transform);
|
||||
|
|
@ -146,7 +147,7 @@ class CollisionEntity implements IOctreeObject {
|
|||
sphereBounds.addSpherePos(position.x, position.y, position.z, radius * 1.1);
|
||||
sphereBounds.transform(invMatrix);
|
||||
sphereBounds.addSpherePos(localPos.x, localPos.y, localPos.z, radius * 1.1);
|
||||
var surfaces = grid == null ? octree.boundingSearch(sphereBounds).map(x -> cast x) : grid.boundingSearch(sphereBounds);
|
||||
var surfaces = bvh == null ? octree.boundingSearch(sphereBounds).map(x -> cast x) : bvh.boundingSearch(sphereBounds);
|
||||
|
||||
var tform = transform.clone();
|
||||
// tform.setPosition(tform.getPosition().add(this.velocity.multiply(timeState.dt)));
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package shaders;
|
||||
|
||||
import src.Sky;
|
||||
import h3d.Vector;
|
||||
import h3d.scene.Scene;
|
||||
import h3d.Engine;
|
||||
|
|
@ -8,18 +9,17 @@ import h3d.mat.Texture;
|
|||
|
||||
class CubemapRenderer {
|
||||
public var cubemap:Texture;
|
||||
|
||||
public var sky:Sky;
|
||||
public var position:Vector;
|
||||
|
||||
var camera:Camera;
|
||||
|
||||
var scene:Scene;
|
||||
|
||||
var nextFaceToRender:Int;
|
||||
|
||||
public function new(scene:Scene) {
|
||||
public function new(scene:Scene, sky:Sky) {
|
||||
this.scene = scene;
|
||||
this.cubemap = new Texture(128, 128, [Cube, Dynamic, Target]);
|
||||
this.sky = sky;
|
||||
this.cubemap = new Texture(128, 128, [Cube, Dynamic, Target], h3d.mat.Data.TextureFormat.RGB8);
|
||||
this.camera = new Camera(90, 1, 1, 0.02);
|
||||
this.position = new Vector();
|
||||
this.nextFaceToRender = 0;
|
||||
|
|
|
|||
|
|
@ -43,10 +43,14 @@ class Magnet extends ForceObject {
|
|||
public override function update(timeState:src.TimeState) {
|
||||
super.update(timeState);
|
||||
|
||||
var seffect = this.soundChannel.getEffect(Spatialization);
|
||||
seffect.position = this.getAbsPos().getPosition();
|
||||
if (this.soundChannel != null) {
|
||||
var seffect = this.soundChannel.getEffect(Spatialization);
|
||||
seffect.position = this.getAbsPos().getPosition();
|
||||
seffect.fadeDistance = 15;
|
||||
// seffect.maxDistance = 5;
|
||||
|
||||
if (this.soundChannel.pause)
|
||||
this.soundChannel.pause = false;
|
||||
if (this.soundChannel.pause)
|
||||
this.soundChannel.pause = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue