/* * 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