Skip to content

Instantly share code, notes, and snippets.

@JakubNei
Last active September 25, 2020 15:34
Show Gist options
  • Save JakubNei/b4b8b4a4b11ef5549a40 to your computer and use it in GitHub Desktop.
Save JakubNei/b4b8b4a4b11ef5549a40 to your computer and use it in GitHub Desktop.
Lame Implementation of Area and Portal Occlusion Culling based on DOOM 3 BFG http://www.iddevnet.com/doom3/visportals.php https://github.com/id-Software/DOOM-3-BFG
Occlusion.ConvexPolygon CreatePolygonFor(VoxelDungeon.Corridor corridor, VoxelDungeon.Corridor.PositionNode pathNode)
{
Vector3 pos = new Vector3(pathNode.position.x, mapData.config.groundPlaneHeight, pathNode.position.y) - Vector3.one;
float h = corridor.height+2;
int width = corridor.width;
int wStart = width / 2;
int wEnd = width - wStart;
Quaternion rot;
if(MapData.IsHorizontalFromTop(pathNode.direction)) rot=Quaternion.LookRotation(new Vector3(1,0,0), Vector3.up);
else rot=Quaternion.LookRotation(new Vector3(0,0,1), Vector3.up);
var polygon = new Occlusion.ConvexPolygon();
polygon.points.Add(rot * new Vector3(-wStart, h, 0) + pos);
polygon.points.Add(rot * new Vector3(wEnd, h, 0) + pos);
polygon.points.Add(rot * new Vector3(wEnd, 0, 0) + pos);
polygon.points.Add(rot * new Vector3(-wStart, 0, 0) + pos);
return polygon;
}
void Update()
{
if (!isGenerated) return;
Camera cam = manager.camera.current;
Vector3 poi = cam.transform.position;// manager.actor.player.position;
Int3 poii = WorldToLocal(poi);
VoxelDungeon.OwnerNode owner = null;
for (int i = 0; i < 8 && owner == null; i++)
{
owner = mapData.GetOwnerAt(
poii.x + tilesOffsets[i, 0],
poii.y + tilesOffsets[i, 1],
poii.z + tilesOffsets[i, 2]
);
}
if (owner == null) return;
NodeData node;
if (!voxelMapNodeToContainer.TryGetValue(owner, out node)) return;
node.occlusionArea.StartPropagate(cam);
}
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Extensions;
namespace Occlusion
{
public class Area : MonoBehaviour
{
public float turnInvisibleInSec = 10;
public Dictionary<Area,Portal> portals = new Dictionary<Area,Portal>();
void LateUpdate()
{
if (turnInvisibleInSec>0)
{
turnInvisibleInSec-=Time.deltaTime;
if (turnInvisibleInSec<=0)
this.gameObject.SetActive(false);
}
}
public void TurnVisible()
{
turnInvisibleInSec = 10;
this.gameObject.SetActive(true);
}
public void StartPropagate(Camera cam)
{
Vector3 origin = cam.transform.position;
var planes = GeometryUtility.CalculateFrustumPlanes(cam);
var toUsePlanes = new List<Plane>();
var excludeNormal = cam.transform.forward;
foreach (var plane in planes)
{
var d = plane.normal.Dot(excludeNormal);
if (d < 0.9f && d > -0.9f) toUsePlanes.Add(plane);
}
this.Propagate_r(null, origin, toUsePlanes.ToArray());
}
void Propagate_r(Portal parentPortal, Vector3 origin, Plane[] planes)
{
TurnVisible();
foreach (var kvp in portals)
{
var portal = kvp.Value;
if (parentPortal == portal) continue;
var area = kvp.Key;
var polygon = portal.polygon.Clone();
bool isVisible = true;
foreach (var plane in planes)
{
isVisible &= polygon.Clip(plane);
}
if (isVisible)
{
portal.polygon.DebugDrawLines(Color.blue);
polygon.DebugDrawLines(Color.red);
}
else
{
portal.polygon.DebugDrawLines(Color.yellow);
continue;
}
var points = polygon.points;
int numPoints = points.Count;
Plane[] portalPlanes = new Plane[numPoints];
for (int i = 0; i < numPoints; i++)
{
portalPlanes[i] = new Plane(points[i], points[(i + 1) % numPoints], origin);
}
area.Propagate_r(portal, origin, portalPlanes);
}
}
}
}
using UnityEngine;
using System.Collections.Generic;
using Extensions;
namespace Occlusion
{
// based on idWinding class from Doom 3 BFG source by ID
public class ConvexPolygon
{
//public Plane plane;
public List<Vector3> points = new List<Vector3>();
public ConvexPolygon Clone()
{
return new ConvexPolygon() { points = new List<Vector3>(this.points) };
}
public void DebugOnTick()
{
DebugDrawLines(Color.blue);
var oldPoints = this.points.ToArray();
var planes = GeometryUtility.CalculateFrustumPlanes(Camera.main);
var excludeNormal = Camera.main.transform.forward;
foreach (var plane in planes)
{
var d = plane.normal.Dot(excludeNormal);
if (d < 0.9f && d > -0.9f) Clip(plane);
}
DebugDrawLines(Color.red);
points = new List<Vector3>(oldPoints);
}
public void DebugDrawLines(Color color = default(Color))
{
int numPoints = points.Count;
for (int i = 0; i < numPoints; i++)
{
Debug.DrawLine(points[i], points[(i + 1) % numPoints], color);
}
}
public bool Clip(Plane plane, float epsilon = 0.0f)
{
const int SIDE_BEHIND = 0;
const int SIDE_FRONT = 1;
const int SIDE_ON = 2;
List<Vector3> newPoints = new List<Vector3>();
int numPoints = points.Count;
float dist = 0;
int[] sides = new int[numPoints];
float[] dists = new float[numPoints];
int[] counts = new int[3];
for (int i = 0; i < numPoints; i++)
{
dists[i] = dist = plane.GetDistanceToPoint(points[i]);
if (dist > epsilon) sides[i] = SIDE_FRONT;
else if (dist < -epsilon) sides[i] = SIDE_BEHIND;
else sides[i] = SIDE_ON;
counts[sides[i]]++;
}
// no point is clipped
if (counts[SIDE_BEHIND] == 0) return true;
if (counts[SIDE_FRONT] + counts[SIDE_ON] == 0) return false;
for (int i = 0; i < numPoints; i++)
{
if (sides[i] == SIDE_BEHIND)
{
continue;
}
if (sides[i] == SIDE_FRONT || sides[i] == SIDE_ON)
{
newPoints.Add(points[i]);
}
int otherI;
bool insertAtEnd = true;
if (sides[otherI = (i + 1) % numPoints] == SIDE_BEHIND) insertAtEnd = true;
else if (sides[otherI = (numPoints + i - 1) % numPoints] == SIDE_BEHIND) insertAtEnd = false;
else continue;
float t = dists[i] / (dists[i] - dists[otherI]);
newPoints.Insert(
insertAtEnd ? newPoints.Count : newPoints.Count - 1,
points[i] * (1 - t) + points[otherI] * (t)
);
}
points = newPoints;
return true;
}
}
}
@Sacristan
Copy link

Hi!

using Extensions library is missing - probably with it -> NodeData, Portal, etc.

Could You, please, share that too ?

@JakubNei
Copy link
Author

JakubNei commented Oct 12, 2015

This is meant just as a general idea on how to do it. It is tightly integrated into 1gb project, You ought to understand it and modify it to suit your needs. I pretty much only converted the DOOM code into C#.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment