Object Occlusion Culling
This commit is contained in:
@ -18,6 +18,13 @@ import iron.object.LightObject;
|
||||
import iron.object.MeshObject;
|
||||
import iron.object.Uniforms;
|
||||
import iron.object.Clipmap;
|
||||
#if lnx_radix
|
||||
import haxe.io.FPHelper;
|
||||
import radix.Radix;
|
||||
#end
|
||||
#if lnx_occlusion_culling
|
||||
import iron.culling.CullSystem;
|
||||
#end
|
||||
#if lnx_vr
|
||||
import iron.math.Vec4;
|
||||
import iron.math.Mat4;
|
||||
@ -50,10 +57,6 @@ class RenderPath {
|
||||
return vrSimulateMode;
|
||||
}
|
||||
|
||||
// TODO: done remove safely
|
||||
public static inline function debugLog(msg: String, once: Bool = true): Void {
|
||||
return;
|
||||
}
|
||||
#end
|
||||
|
||||
public var frameScissor = false;
|
||||
@ -81,6 +84,18 @@ class RenderPath {
|
||||
var renderToXRFramebuffer = false;
|
||||
#end
|
||||
public var drawOrder = DrawOrder.Distance;
|
||||
#if lnx_frustum_culling
|
||||
public var frustumCulling = true;
|
||||
#else
|
||||
public var frustumCulling = false;
|
||||
#end
|
||||
|
||||
#if lnx_occlusion_culling
|
||||
public var occlusionCulling = true;
|
||||
#else
|
||||
public var occlusionCulling = false;
|
||||
#end
|
||||
|
||||
public var paused = false;
|
||||
public var ready(get, never): Bool;
|
||||
function get_ready(): Bool { return loading == 0; }
|
||||
@ -95,6 +110,8 @@ class RenderPath {
|
||||
var lastH = 0;
|
||||
var bindParams: Array<String>;
|
||||
var meshesSorted: Bool;
|
||||
var cullComputed: Bool;
|
||||
var cullFlagsReset: Bool;
|
||||
var scissorSet = false;
|
||||
var viewportScaled = false;
|
||||
var lastFrameTime = 0.0;
|
||||
@ -304,6 +321,8 @@ class RenderPath {
|
||||
currentD = 1;
|
||||
currentFace = -1;
|
||||
meshesSorted = false;
|
||||
cullComputed = false;
|
||||
cullFlagsReset = false;
|
||||
sun = null;
|
||||
|
||||
for (l in Scene.active.lights) {
|
||||
@ -470,6 +489,60 @@ class RenderPath {
|
||||
rt.image.generateMipmaps(1000);
|
||||
}
|
||||
|
||||
#if lnx_radix
|
||||
static var sortDistanceKeys = new Array<Int>();
|
||||
static var sortDistanceMeshesBuf = new Array<MeshObject>();
|
||||
static var sortDistanceKeysBuf = new Array<Int>();
|
||||
|
||||
static var sortIndexKeys = new Array<Int>();
|
||||
static var sortIndexMeshesBuf = new Array<MeshObject>();
|
||||
static var sortIndexKeysBuf = new Array<Int>();
|
||||
|
||||
public static function sortMeshesDistance(meshes: Array<MeshObject>) {
|
||||
var n = meshes.length;
|
||||
var keys = sortDistanceKeys;
|
||||
var meshesBuf = sortDistanceMeshesBuf;
|
||||
var keysBuf = sortDistanceKeysBuf;
|
||||
if (keys.length < n) {
|
||||
keys.resize(n);
|
||||
meshesBuf.resize(n);
|
||||
keysBuf.resize(n);
|
||||
}
|
||||
for (i in 0...n) {
|
||||
var m = meshes[i];
|
||||
var key = FPHelper.floatToI32(m.cameraDistance) >>> 1;
|
||||
#if rp_depth_texture
|
||||
if (m.depthRead) key |= 0x80000000;
|
||||
#end
|
||||
keys[i] = key;
|
||||
}
|
||||
Radix.sortCopyKeyed(meshes, keys, meshesBuf, keysBuf);
|
||||
if (meshesBuf.length > n) meshesBuf.resize(n);
|
||||
}
|
||||
|
||||
public static function sortMeshesIndex(meshes: Array<MeshObject>) {
|
||||
var n = meshes.length;
|
||||
var keys = sortIndexKeys;
|
||||
var meshesBuf = sortIndexMeshesBuf;
|
||||
var keysBuf = sortIndexKeysBuf;
|
||||
if (keys.length < n) {
|
||||
keys.resize(n);
|
||||
meshesBuf.resize(n);
|
||||
keysBuf.resize(n);
|
||||
}
|
||||
for (i in 0...n) {
|
||||
var m = meshes[i];
|
||||
var si = m.data.sortingIndex;
|
||||
var key = si < -0x40000000 ? 0 : si > 0x3fffffff ? 0x7fffffff : si + 0x40000000;
|
||||
#if rp_depth_texture
|
||||
if (m.depthRead) key |= 0x80000000;
|
||||
#end
|
||||
keys[i] = key;
|
||||
}
|
||||
Radix.sortCopyKeyed(meshes, keys, meshesBuf, keysBuf);
|
||||
if (meshesBuf.length > n) meshesBuf.resize(n);
|
||||
}
|
||||
#else
|
||||
static inline function boolToInt(b: Bool): Int {
|
||||
return b ? 1 : 0;
|
||||
}
|
||||
@ -501,6 +574,7 @@ class RenderPath {
|
||||
return a.data.name > b.data.name ? 1 : -1;
|
||||
});
|
||||
}
|
||||
#end
|
||||
|
||||
public function drawMeshes(context: String) {
|
||||
var isShadows = context == "shadowmap" || context == "shadowmap_transparent";
|
||||
@ -519,6 +593,11 @@ class RenderPath {
|
||||
for (i in 0...LightObject.cascadeCount) {
|
||||
light.setCascade(Scene.active.camera, i);
|
||||
currentG.viewport(i * step, 0, step, step);
|
||||
#if lnx_occlusion_culling
|
||||
if (occlusionCulling && CullSystem.active != null) {
|
||||
CullSystem.active.cullShadow(light);
|
||||
}
|
||||
#end
|
||||
submitDraw(context);
|
||||
}
|
||||
drawn = true;
|
||||
@ -529,7 +608,14 @@ class RenderPath {
|
||||
if (context == "mesh") LightObject.updateClusters(Scene.active.camera);
|
||||
#end
|
||||
|
||||
if (!drawn) submitDraw(context);
|
||||
if (!drawn) {
|
||||
#if lnx_occlusion_culling
|
||||
if (isShadows && occlusionCulling && CullSystem.active != null) {
|
||||
CullSystem.active.cullShadow(light);
|
||||
}
|
||||
#end
|
||||
submitDraw(context);
|
||||
}
|
||||
|
||||
// Callbacks to specific context
|
||||
if (contextEvents != null) {
|
||||
@ -546,7 +632,34 @@ class RenderPath {
|
||||
var meshes = Scene.active.meshes;
|
||||
MeshObject.lastPipeline = null;
|
||||
|
||||
if (!meshesSorted && camera != null) { // Order max once per frame for now
|
||||
#if lnx_occlusion_culling
|
||||
if (!cullFlagsReset && !occlusionCulling) {
|
||||
cullFlagsReset = true;
|
||||
for (m in meshes) {
|
||||
m.occlusionVisible = true;
|
||||
m.shadowOcclusionVisible = true;
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
if (!cullComputed && (context == "mesh" || context == "depth")) {
|
||||
#if lnx_occlusion_culling
|
||||
if (occlusionCulling) {
|
||||
if (CullSystem.active == null) CullSystem.init();
|
||||
if (CullSystem.active != null && camera != null) {
|
||||
if (CullSystem.active.proxiesDirty) {
|
||||
CullSystem.active.loadOccluderProxies();
|
||||
CullSystem.active.proxiesDirty = false;
|
||||
}
|
||||
CullSystem.active.cull(camera);
|
||||
}
|
||||
}
|
||||
#end
|
||||
cullComputed = true;
|
||||
}
|
||||
|
||||
var isShadowCtx = context == "shadowmap" || context == "shadowmap_transparent";
|
||||
if (!meshesSorted && camera != null && !isShadowCtx) {
|
||||
var camX = camera.transform.worldx();
|
||||
var camY = camera.transform.worldy();
|
||||
var camZ = camera.transform.worldz();
|
||||
@ -571,8 +684,20 @@ class RenderPath {
|
||||
|
||||
static inline function meshRenderLoop(g: Graphics, context: String, _bindParams: Array<String>, _meshes: Array<MeshObject>) {
|
||||
var isReadingDepth = false;
|
||||
#if lnx_occlusion_culling
|
||||
var cullSys = CullSystem.active;
|
||||
#end
|
||||
|
||||
for (m in _meshes) {
|
||||
#if lnx_occlusion_culling
|
||||
if (cullSys != null && !m.occlusionVisible && (context == "mesh" || context == "depth" || context == "translucent")) {
|
||||
continue;
|
||||
}
|
||||
if (cullSys != null && !m.shadowOcclusionVisible && (context == "shadowmap" || context == "shadowmap_transparent")) {
|
||||
continue;
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_depth_texture
|
||||
// First mesh that reads depth
|
||||
if (!isReadingDepth && m.depthRead) {
|
||||
|
||||
Reference in New Issue
Block a user