You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
526 lines
18 KiB
C++
526 lines
18 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
|
|
// Description : shadow volume AABB functionality for overlap testings
|
|
|
|
|
|
#ifndef CRYINCLUDE_CRYCOMMON_AABBSV_H
|
|
#define CRYINCLUDE_CRYCOMMON_AABBSV_H
|
|
#pragma once
|
|
|
|
#include "Cry_Geo.h"
|
|
|
|
struct Shadowvolume
|
|
{
|
|
uint32 sideamount;
|
|
uint32 nplanes;
|
|
|
|
Plane oplanes[10];
|
|
};
|
|
|
|
namespace NAABB_SV
|
|
{
|
|
//***************************************************************************************
|
|
//***************************************************************************************
|
|
//*** Calculate a ShadowVolume using an AABB and a point-light ***
|
|
//***************************************************************************************
|
|
//*** The planes of the AABB facing away from the point-light are the far-planes ***
|
|
//*** of the ShadowVolume. There can be 3-6 far-planes. ***
|
|
//***************************************************************************************
|
|
void AABB_ReceiverShadowVolume(const Vec3& PointLight, const AABB& Occluder, Shadowvolume& sv);
|
|
|
|
//***************************************************************************************
|
|
//***************************************************************************************
|
|
//*** Calculate a ShadowVolume using an AABB and a point-light ***
|
|
//***************************************************************************************
|
|
//*** The planes of the AABB facing the point-light are the near-planes of the ***
|
|
//*** the ShadowVolume. There can be 1-3 near-planes. ***
|
|
//*** The far-plane is defined by lightrange. ***
|
|
//***************************************************************************************
|
|
void AABB_ShadowVolume(const Vec3& PointLight, const AABB& Occluder, Shadowvolume& sv, f32 lightrange);
|
|
|
|
//***************************************************************************************
|
|
//*** this is the "fast" version to check if an AABB is overlapping a shadowvolume ***
|
|
//***************************************************************************************
|
|
bool Is_AABB_In_ShadowVolume(const Shadowvolume& sv, const AABB& Receiver);
|
|
|
|
//***************************************************************************************
|
|
//*** this is the "hierarchical" check ***
|
|
//***************************************************************************************
|
|
char Is_AABB_In_ShadowVolume_hierarchical(const Shadowvolume& sv, const AABB& Receiver);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
inline void NAABB_SV::AABB_ReceiverShadowVolume(const Vec3& PointLight, const AABB& Occluder, Shadowvolume& sv)
|
|
{
|
|
sv.sideamount = 0;
|
|
sv.nplanes = 0;
|
|
|
|
//------------------------------------------------------------------------------
|
|
//-- check if PointLight is in front of any occluder plane or inside occluder --
|
|
//------------------------------------------------------------------------------
|
|
uint32 front = 0;
|
|
if (PointLight.x < Occluder.min.x)
|
|
{
|
|
front |= 0x01;
|
|
}
|
|
if (PointLight.x > Occluder.max.x)
|
|
{
|
|
front |= 0x02;
|
|
}
|
|
if (PointLight.y < Occluder.min.y)
|
|
{
|
|
front |= 0x04;
|
|
}
|
|
if (PointLight.y > Occluder.max.y)
|
|
{
|
|
front |= 0x08;
|
|
}
|
|
if (PointLight.z < Occluder.min.z)
|
|
{
|
|
front |= 0x10;
|
|
}
|
|
if (PointLight.z > Occluder.max.z)
|
|
{
|
|
front |= 0x20;
|
|
}
|
|
|
|
sv.sideamount = BoxSides[(front << 3) + 7];
|
|
|
|
uint32 back = front ^ 0x3f;
|
|
if (back & 0x01)
|
|
{
|
|
sv.oplanes[sv.nplanes].SetPlane(Vec3(-1, +0, +0), Occluder.min);
|
|
sv.nplanes++;
|
|
}
|
|
if (back & 0x02)
|
|
{
|
|
sv.oplanes[sv.nplanes].SetPlane(Vec3(+1, +0, +0), Occluder.max);
|
|
sv.nplanes++;
|
|
}
|
|
if (back & 0x04)
|
|
{
|
|
sv.oplanes[sv.nplanes].SetPlane(Vec3(+0, -1, +0), Occluder.min);
|
|
sv.nplanes++;
|
|
}
|
|
if (back & 0x08)
|
|
{
|
|
sv.oplanes[sv.nplanes].SetPlane(Vec3(+0, +1, +0), Occluder.max);
|
|
sv.nplanes++;
|
|
}
|
|
if (back & 0x10)
|
|
{
|
|
sv.oplanes[sv.nplanes].SetPlane(Vec3(+0, +0, -1), Occluder.min);
|
|
sv.nplanes++;
|
|
}
|
|
if (back & 0x20)
|
|
{
|
|
sv.oplanes[sv.nplanes].SetPlane(Vec3(+0, +0, +1), Occluder.max);
|
|
sv.nplanes++;
|
|
}
|
|
|
|
if (front == 0)
|
|
{
|
|
return; //light is inside occluder
|
|
}
|
|
//all 8 vertices of a AABB
|
|
Vec3 o[8] =
|
|
{
|
|
Vec3(Occluder.min.x, Occluder.min.y, Occluder.min.z),
|
|
Vec3(Occluder.max.x, Occluder.min.y, Occluder.min.z),
|
|
Vec3(Occluder.min.x, Occluder.max.y, Occluder.min.z),
|
|
Vec3(Occluder.max.x, Occluder.max.y, Occluder.min.z),
|
|
Vec3(Occluder.min.x, Occluder.min.y, Occluder.max.z),
|
|
Vec3(Occluder.max.x, Occluder.min.y, Occluder.max.z),
|
|
Vec3(Occluder.min.x, Occluder.max.y, Occluder.max.z),
|
|
Vec3(Occluder.max.x, Occluder.max.y, Occluder.max.z)
|
|
};
|
|
|
|
//---------------------------------------------------------------------
|
|
//--- find the silhouette-vertices of the occluder-AABB ---
|
|
//---------------------------------------------------------------------
|
|
uint32 p0 = BoxSides[(front << 3) + 0];
|
|
uint32 p1 = BoxSides[(front << 3) + 1];
|
|
uint32 p2 = BoxSides[(front << 3) + 2];
|
|
uint32 p3 = BoxSides[(front << 3) + 3];
|
|
uint32 p4 = BoxSides[(front << 3) + 4];
|
|
uint32 p5 = BoxSides[(front << 3) + 5];
|
|
|
|
float a;
|
|
if (sv.sideamount == 4)
|
|
{
|
|
//sv.oplanes[sv.nplanes+0] = Plane::CreatePlane( o[p0],o[p1], PointLight );
|
|
//sv.oplanes[sv.nplanes+1] = Plane::CreatePlane( o[p1],o[p2], PointLight );
|
|
//sv.oplanes[sv.nplanes+2] = Plane::CreatePlane( o[p2],o[p3], PointLight );
|
|
//sv.oplanes[sv.nplanes+3] = Plane::CreatePlane( o[p3],o[p0], PointLight );
|
|
sv.sideamount = 0;
|
|
a = (o[p1] - o[p0]) | (o[p0] - PointLight);
|
|
if (a)
|
|
{
|
|
sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p0], o[p1], PointLight);
|
|
sv.sideamount++;
|
|
}
|
|
a = (o[p2] - o[p1]) | (o[p1] - PointLight);
|
|
if (a)
|
|
{
|
|
sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p1], o[p2], PointLight);
|
|
sv.sideamount++;
|
|
}
|
|
a = (o[p3] - o[p2]) | (o[p2] - PointLight);
|
|
if (a)
|
|
{
|
|
sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p2], o[p3], PointLight);
|
|
sv.sideamount++;
|
|
}
|
|
a = (o[p0] - o[p3]) | (o[p3] - PointLight);
|
|
if (a)
|
|
{
|
|
sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p3], o[p0], PointLight);
|
|
sv.sideamount++;
|
|
}
|
|
}
|
|
|
|
if (sv.sideamount == 6)
|
|
{
|
|
//sv.oplanes[sv.nplanes+0] = Plane::CreatePlane( o[p0],o[p1], PointLight );
|
|
//sv.oplanes[sv.nplanes+1] = Plane::CreatePlane( o[p1],o[p2], PointLight );
|
|
//sv.oplanes[sv.nplanes+2] = Plane::CreatePlane( o[p2],o[p3], PointLight );
|
|
//sv.oplanes[sv.nplanes+3] = Plane::CreatePlane( o[p3],o[p4], PointLight );
|
|
//sv.oplanes[sv.nplanes+4] = Plane::CreatePlane( o[p4],o[p5], PointLight );
|
|
//sv.oplanes[sv.nplanes+5] = Plane::CreatePlane( o[p5],o[p0], PointLight );
|
|
|
|
sv.sideamount = 0;
|
|
a = (o[p1] - o[p0]) | (o[p0] - PointLight);
|
|
assert(sv.nplanes + sv.sideamount < 10);
|
|
PREFAST_ASSUME(sv.nplanes + sv.sideamount < 10);
|
|
if (a)
|
|
{
|
|
sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p0], o[p1], PointLight);
|
|
sv.sideamount++;
|
|
}
|
|
a = (o[p2] - o[p1]) | (o[p1] - PointLight);
|
|
assert(sv.nplanes + sv.sideamount < 10);
|
|
PREFAST_ASSUME(sv.nplanes + sv.sideamount < 10);
|
|
if (a)
|
|
{
|
|
sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p1], o[p2], PointLight);
|
|
sv.sideamount++;
|
|
}
|
|
a = (o[p3] - o[p2]) | (o[p2] - PointLight);
|
|
assert(sv.nplanes + sv.sideamount < 10);
|
|
PREFAST_ASSUME(sv.nplanes + sv.sideamount < 10);
|
|
if (a)
|
|
{
|
|
sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p2], o[p3], PointLight);
|
|
sv.sideamount++;
|
|
}
|
|
a = (o[p4] - o[p3]) | (o[p3] - PointLight);
|
|
assert(sv.nplanes + sv.sideamount < 10);
|
|
PREFAST_ASSUME(sv.nplanes + sv.sideamount < 10);
|
|
if (a)
|
|
{
|
|
sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p3], o[p4], PointLight);
|
|
sv.sideamount++;
|
|
}
|
|
a = (o[p5] - o[p4]) | (o[p4] - PointLight);
|
|
assert(sv.nplanes + sv.sideamount < 10);
|
|
PREFAST_ASSUME(sv.nplanes + sv.sideamount < 10);
|
|
if (a)
|
|
{
|
|
sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p4], o[p5], PointLight);
|
|
sv.sideamount++;
|
|
}
|
|
a = (o[p0] - o[p5]) | (o[p5] - PointLight);
|
|
assert(sv.nplanes + sv.sideamount < 10);
|
|
PREFAST_ASSUME(sv.nplanes + sv.sideamount < 10);
|
|
if (a)
|
|
{
|
|
sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p5], o[p0], PointLight);
|
|
sv.sideamount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void NAABB_SV::AABB_ShadowVolume(const Vec3& PointLight, const AABB& Occluder, Shadowvolume& sv, f32 lightrange)
|
|
{
|
|
sv.sideamount = 0;
|
|
sv.nplanes = 0;
|
|
|
|
//------------------------------------------------------------------------------
|
|
//-- check if PointLight is in front of any occluder plane or inside occluder --
|
|
//------------------------------------------------------------------------------
|
|
uint32 front = 0;
|
|
if (PointLight.x < Occluder.min.x)
|
|
{
|
|
front |= 0x01;
|
|
}
|
|
if (PointLight.x > Occluder.max.x)
|
|
{
|
|
front |= 0x02;
|
|
}
|
|
if (PointLight.y < Occluder.min.y)
|
|
{
|
|
front |= 0x04;
|
|
}
|
|
if (PointLight.y > Occluder.max.y)
|
|
{
|
|
front |= 0x08;
|
|
}
|
|
if (PointLight.z < Occluder.min.z)
|
|
{
|
|
front |= 0x10;
|
|
}
|
|
if (PointLight.z > Occluder.max.z)
|
|
{
|
|
front |= 0x20;
|
|
}
|
|
if (front == 0)
|
|
{
|
|
return; //light is inside occluder
|
|
}
|
|
sv.sideamount = BoxSides[(front << 3) + 7];
|
|
|
|
if (front & 0x01)
|
|
{
|
|
sv.oplanes[sv.nplanes].SetPlane(Vec3(-1, +0, +0), Occluder.min);
|
|
sv.nplanes++;
|
|
}
|
|
if (front & 0x02)
|
|
{
|
|
sv.oplanes[sv.nplanes].SetPlane(Vec3(+1, +0, +0), Occluder.max);
|
|
sv.nplanes++;
|
|
}
|
|
if (front & 0x04)
|
|
{
|
|
sv.oplanes[sv.nplanes].SetPlane(Vec3(+0, -1, +0), Occluder.min);
|
|
sv.nplanes++;
|
|
}
|
|
if (front & 0x08)
|
|
{
|
|
sv.oplanes[sv.nplanes].SetPlane(Vec3(+0, +1, +0), Occluder.max);
|
|
sv.nplanes++;
|
|
}
|
|
if (front & 0x10)
|
|
{
|
|
sv.oplanes[sv.nplanes].SetPlane(Vec3(+0, +0, -1), Occluder.min);
|
|
sv.nplanes++;
|
|
}
|
|
if (front & 0x20)
|
|
{
|
|
sv.oplanes[sv.nplanes].SetPlane(Vec3(+0, +0, +1), Occluder.max);
|
|
sv.nplanes++;
|
|
}
|
|
|
|
//all 8 vertices of a AABB
|
|
Vec3 o[8] =
|
|
{
|
|
Vec3(Occluder.min.x, Occluder.min.y, Occluder.min.z),
|
|
Vec3(Occluder.max.x, Occluder.min.y, Occluder.min.z),
|
|
Vec3(Occluder.min.x, Occluder.max.y, Occluder.min.z),
|
|
Vec3(Occluder.max.x, Occluder.max.y, Occluder.min.z),
|
|
Vec3(Occluder.min.x, Occluder.min.y, Occluder.max.z),
|
|
Vec3(Occluder.max.x, Occluder.min.y, Occluder.max.z),
|
|
Vec3(Occluder.min.x, Occluder.max.y, Occluder.max.z),
|
|
Vec3(Occluder.max.x, Occluder.max.y, Occluder.max.z)
|
|
};
|
|
|
|
//---------------------------------------------------------------------
|
|
//--- find the silhouette-vertices of the occluder-AABB ---
|
|
//---------------------------------------------------------------------
|
|
uint32 p0 = BoxSides[(front << 3) + 0];
|
|
uint32 p1 = BoxSides[(front << 3) + 1];
|
|
uint32 p2 = BoxSides[(front << 3) + 2];
|
|
uint32 p3 = BoxSides[(front << 3) + 3];
|
|
uint32 p4 = BoxSides[(front << 3) + 4];
|
|
uint32 p5 = BoxSides[(front << 3) + 5];
|
|
|
|
//the new center-position in world-space
|
|
Vec3 MiddleOfOccluder = (Occluder.max + Occluder.min) * 0.5f;
|
|
sv.oplanes[sv.nplanes] = Plane::CreatePlane((MiddleOfOccluder - PointLight).GetNormalized(), (MiddleOfOccluder - PointLight).GetNormalized() * lightrange + PointLight);
|
|
sv.nplanes++;
|
|
|
|
float a;
|
|
if (sv.sideamount == 4)
|
|
{
|
|
sv.sideamount = 0;
|
|
a = (o[p1] - o[p0]) | (o[p0] - PointLight);
|
|
if (a)
|
|
{
|
|
sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p0], o[p1], PointLight);
|
|
sv.sideamount++;
|
|
}
|
|
a = (o[p2] - o[p1]) | (o[p1] - PointLight);
|
|
if (a)
|
|
{
|
|
sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p1], o[p2], PointLight);
|
|
sv.sideamount++;
|
|
}
|
|
a = (o[p3] - o[p2]) | (o[p2] - PointLight);
|
|
if (a)
|
|
{
|
|
sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p2], o[p3], PointLight);
|
|
sv.sideamount++;
|
|
}
|
|
a = (o[p0] - o[p3]) | (o[p3] - PointLight);
|
|
if (a)
|
|
{
|
|
sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p3], o[p0], PointLight);
|
|
sv.sideamount++;
|
|
}
|
|
}
|
|
|
|
if (sv.sideamount == 6)
|
|
{
|
|
sv.sideamount = 0;
|
|
a = (o[p1] - o[p0]) | (o[p0] - PointLight);
|
|
if (a)
|
|
{
|
|
sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p0], o[p1], PointLight);
|
|
sv.sideamount++;
|
|
}
|
|
a = (o[p2] - o[p1]) | (o[p1] - PointLight);
|
|
if (a)
|
|
{
|
|
sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p1], o[p2], PointLight);
|
|
sv.sideamount++;
|
|
}
|
|
a = (o[p3] - o[p2]) | (o[p2] - PointLight);
|
|
if (a)
|
|
{
|
|
sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p2], o[p3], PointLight);
|
|
sv.sideamount++;
|
|
}
|
|
a = (o[p4] - o[p3]) | (o[p3] - PointLight);
|
|
if (a)
|
|
{
|
|
sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p3], o[p4], PointLight);
|
|
sv.sideamount++;
|
|
}
|
|
a = (o[p5] - o[p4]) | (o[p4] - PointLight);
|
|
if (a)
|
|
{
|
|
sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p4], o[p5], PointLight);
|
|
sv.sideamount++;
|
|
}
|
|
a = (o[p0] - o[p5]) | (o[p5] - PointLight);
|
|
if (a)
|
|
{
|
|
sv.oplanes[sv.nplanes + sv.sideamount] = Plane::CreatePlane(o[p5], o[p0], PointLight);
|
|
sv.sideamount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
inline bool NAABB_SV::Is_AABB_In_ShadowVolume(const Shadowvolume& sv, const AABB& Receiver)
|
|
{
|
|
uint32 pa = sv.sideamount + sv.nplanes;
|
|
|
|
f32 d;
|
|
const Vec3* pAABB = &Receiver.min;
|
|
|
|
union f32_u
|
|
{
|
|
float floatVal;
|
|
uint32 uintVal;
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
//---- check if receiver-AABB is in front of any of these planes ------
|
|
//------------------------------------------------------------------------------
|
|
for (uint32 x = 0; x < pa; x++)
|
|
{
|
|
d = sv.oplanes[x].d;
|
|
|
|
//avoid breaking strict aliasing rules
|
|
f32_u ux;
|
|
ux.floatVal = sv.oplanes[x].n.x;
|
|
f32_u uy;
|
|
uy.floatVal = sv.oplanes[x].n.y;
|
|
f32_u uz;
|
|
uz.floatVal = sv.oplanes[x].n.z;
|
|
const uint32 bitX = ux.uintVal >> 31;
|
|
const uint32 bitY = uy.uintVal >> 31;
|
|
const uint32 bitZ = uz.uintVal >> 31;
|
|
|
|
d += sv.oplanes[x].n.x * pAABB[bitX].x;
|
|
d += sv.oplanes[x].n.y * pAABB[bitY].y;
|
|
d += sv.oplanes[x].n.z * pAABB[bitZ].z;
|
|
if (d > 0)
|
|
{
|
|
return CULL_EXCLUSION;
|
|
}
|
|
}
|
|
return CULL_OVERLAP;
|
|
}
|
|
|
|
inline char NAABB_SV::Is_AABB_In_ShadowVolume_hierarchical(const Shadowvolume& sv, const AABB& Receiver)
|
|
{
|
|
uint32 pa = sv.sideamount + sv.nplanes;
|
|
const Vec3* pAABB = &Receiver.min;
|
|
|
|
f32 dot1, dot2;
|
|
uint32 notOverlap = 0x80000000; // will be reset to 0 if there's at least one overlapping
|
|
|
|
union f32_u
|
|
{
|
|
float floatVal;
|
|
uint32 uintVal;
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
//---- check if receiver-AABB is in front of any of these planes ------
|
|
//------------------------------------------------------------------------------
|
|
for (uint32 x = 0; x < pa; x++)
|
|
{
|
|
dot1 = dot2 = sv.oplanes[x].d;
|
|
|
|
//avoid breaking strict aliasing rules
|
|
f32_u ux;
|
|
ux.floatVal = sv.oplanes[x].n.x;
|
|
f32_u uy;
|
|
uy.floatVal = sv.oplanes[x].n.y;
|
|
f32_u uz;
|
|
uz.floatVal = sv.oplanes[x].n.z;
|
|
const uint32 bitX = ux.uintVal >> 31;
|
|
const uint32 bitY = uy.uintVal >> 31;
|
|
const uint32 bitZ = uz.uintVal >> 31;
|
|
|
|
dot1 += sv.oplanes[x].n.x * pAABB[0 + bitX].x;
|
|
dot2 += sv.oplanes[x].n.x * pAABB[1 - bitX].x;
|
|
dot1 += sv.oplanes[x].n.y * pAABB[0 + bitY].y;
|
|
dot2 += sv.oplanes[x].n.y * pAABB[1 - bitY].y;
|
|
dot1 += sv.oplanes[x].n.z * pAABB[0 + bitZ].z;
|
|
dot2 += sv.oplanes[x].n.z * pAABB[1 - bitZ].z;
|
|
PREFAST_SUPPRESS_WARNING(6001) f32_u d;
|
|
d.floatVal = dot1;
|
|
if (!(d.uintVal & 0x80000000))
|
|
{
|
|
return CULL_EXCLUSION;
|
|
}
|
|
PREFAST_SUPPRESS_WARNING(6001) f32_u d2;
|
|
d2.floatVal = dot2;
|
|
notOverlap &= d2.uintVal;
|
|
}
|
|
if (notOverlap)
|
|
{
|
|
return CULL_INCLUSION;
|
|
}
|
|
return CULL_OVERLAP;
|
|
}
|
|
|
|
#endif // CRYINCLUDE_CRYCOMMON_AABBSV_H
|
|
|