Files
GTASource/game/renderer/RenderPhases/RenderPhaseMirrorReflection.cpp
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

1564 lines
54 KiB
C++

// =====================================================
// renderer/RenderPhases/RenderPhaseMirrorReflection.cpp
// (c) 2011 RockstarNorth
// =====================================================
// Rage headers
#include "profile/timebars.h"
#include "grmodel/shaderfx.h"
#include "grcore/debugdraw.h"
#include "grcore/stateblock.h"
#include "grcore/stateblock_internal.h"
#include "grcore/quads.h"
#include "system/memops.h"
#include "system/param.h"
#if RSG_ORBIS
#include "grcore/texturefactory_gnm.h"
#endif
// Framework Headers
#include "fwmaths/vector.h"
#include "fwmaths/vectorutil.h"
#include "fwmaths/PortalCorners.h"
#include "fwrenderer/renderlistgroup.h"
#include "fwscene/scan/RenderPhaseCullShape.h"
#include "fwscene/scan/Scan.h"
#include "fwscene/world/InteriorLocation.h"
#include "fwscene/world/InteriorSceneGraphNode.h"
#include "fwsys/timer.h"
// Game headers
#include "camera/CamInterface.h"
#include "camera/viewports/Viewport.h"
#include "camera/viewports/ViewportManager.h"
#include "Cutscene/CutSceneManagerNew.h"
#include "debug/TiledScreenCapture.h"
#include "game/clock.h"
#include "modelinfo/MloModelInfo.h"
#include "peds/Ped.h"
#include "peds/rendering/PedDamage.h"
#include "profile/profiler.h"
#include "renderer/DrawLists/drawlistMgr.h"
#include "renderer/Lights/lights.h"
#include "renderer/Lights/LightGroup.h"
#include "renderer/Mirrors.h"
#include "renderer/occlusion.h"
#include "renderer/PostProcessFX.h"
#include "renderer/renderListGroup.h"
#include "renderer/RenderListBuilder.h"
#include "renderer/RenderPhases/RenderPhaseMirrorReflection.h"
#include "renderer/RenderPhases/RenderPhaseReflection.h"
#include "renderer/RenderPhases/RenderPhaseWaterReflection.h"
#include "renderer/RenderPhases/RenderPhaseCascadeShadows.h"
#include "renderer/rendertargets.h"
#include "renderer/water.h"
#include "scene/portals/FrustumDebug.h"
#include "scene/portals/Portal.h"
#include "scene/scene.h"
#include "shaders/CustomShaderEffectMirror.h"
#include "timecycle/TimeCycle.h"
#include "Vfx/Sky/Sky.h"
#include "Vfx/GPUParticles/PtFxGPUManager.h"
#include "Vfx/particles/PtFxManager.h"
#include "vfx/VfxHelper.h"
#include "Vfx/VisualEffects.h"
EXT_PF_GROUP(BuildRenderList);
PF_TIMER(CRenderPhaseMirrorReflectionRL,BuildRenderList);
EXT_PF_GROUP(RenderPhase);
PF_TIMER(CRenderPhaseMirrorReflection,RenderPhase);
// ================================================================================================
static u32 g_mirrorReflectionRenderSettings =
RENDER_SETTING_RENDER_PARTICLES |
// RENDER_SETTING_RENDER_WATER |
// RENDER_SETTING_STORE_WATER_OCCLUDERS |
RENDER_SETTING_RENDER_ALPHA_POLYS |
// RENDER_SETTING_RENDER_SHADOWS | // mirrors are generally in deep interiors (so they require neither directional light nor shadow)
RENDER_SETTING_RENDER_DECAL_POLYS | // allow ped decals
RENDER_SETTING_RENDER_CUTOUT_POLYS |
// RENDER_SETTING_RENDER_UI_EFFECTS |
// RENDER_SETTING_ALLOW_PRERENDER |
RENDER_SETTING_RENDER_DISTANT_LIGHTS |
RENDER_SETTING_RENDER_DISTANT_LOD_LIGHTS |
0;
static u32 g_mirrorReflectionVisMaskFlags =
// VIS_ENTITY_MASK_OTHER |
VIS_ENTITY_MASK_PED |
VIS_ENTITY_MASK_OBJECT |
// VIS_ENTITY_MASK_DUMMY_OBJECT |
VIS_ENTITY_MASK_VEHICLE |
VIS_ENTITY_MASK_ANIMATED_BUILDING |
// VIS_ENTITY_MASK_LOLOD_BUILDING | // interiors don't need LOLOD
VIS_ENTITY_MASK_HILOD_BUILDING |
VIS_ENTITY_MASK_LIGHT |
// VIS_ENTITY_MASK_TREE | // interiors don't have trees
0;
static u32 g_mirrorReflectionAlphaBlendingPasses =
// BIT(RPASS_VISIBLE) |
// BIT(RPASS_LOD ) |
BIT(RPASS_CUTOUT ) | // alpha blend if we disable alpha test for this pass in rag
BIT(RPASS_DECAL ) | // allow ped decals
BIT(RPASS_FADING ) |
BIT(RPASS_ALPHA ) |
// BIT(RPASS_WATER ) | // not applicable
BIT(RPASS_TREE ) | // applicable if we're rendering exteriors ..
0;
static u32 g_mirrorReflectionDepthWritingPasses =
BIT(RPASS_VISIBLE) |
BIT(RPASS_LOD ) |
BIT(RPASS_CUTOUT ) |
// BIT(RPASS_DECAL ) | // not applicable
// BIT(RPASS_FADING ) |
// BIT(RPASS_ALPHA ) |
// BIT(RPASS_WATER ) | // not applicable
// BIT(RPASS_TREE ) |
0;
static bool g_mirrorReflectionEnableMSAA = true;
static CRenderPhaseScanned* g_mirrorRenderPhase = NULL;
static grcViewport* g_mirrorReflectionViewport = NULL;
#if __PS3
static grcViewport g_mirrorReflectionViewportNoObliqueProjection(grcViewport::DoNotInitialize);
#endif // __PS3
static bool g_mirrorReflectionUsingWaterReflectionTechnique = false;
//thread local copy of water reflection technique state. Because we have many renderthreads and we need to make sure that
//it's initialized to false
DECLARE_MTR_THREAD static bool g_mirrorReflectionUsingWaterReflectionTechniqueRT = false;
DECLARE_MTR_THREAD static bool g_mirrorReflectionUsingWaterSurfaceRT = false;
CRenderPhaseMirrorReflection::CRenderPhaseMirrorReflection(CViewport* pGameViewport) : CRenderPhaseScanned(pGameViewport, "Mirror Reflection", DL_RENDERPHASE_MIRROR_REFLECTION, 0.0f)
#if __BANK
, m_debugDrawMirror(false)
, m_debugDrawMirrorOffset(0.01f)
#endif // __BANK
{
g_mirrorRenderPhase = this;
SetRenderFlags(g_mirrorReflectionRenderSettings);
GetEntityVisibilityMask().SetAllFlags((u16)g_mirrorReflectionVisMaskFlags);
SetVisibilityType(VIS_PHASE_MIRROR_REFLECTION);
SetEntityListIndex(gRenderListGroup.RegisterRenderPhase(RPTYPE_REFLECTION, this));
CMirrors::SetMirrorRenderPhase(this);
CCustomShaderEffectMirror::Initialise();
}
CRenderPhaseMirrorReflection::~CRenderPhaseMirrorReflection()
{
CMirrors::SetMirrorRenderPhase(NULL);
}
u32 CRenderPhaseMirrorReflection::GetCullFlags() const
{
#if __BANK
if (TiledScreenCapture::IsEnabled())
{
return 0;
}
#endif // __BANK
if (!CMirrors::GetIsMirrorVisible())
{
return 0;
}
u32 flags =
CULL_SHAPE_FLAG_RENDER_INTERIOR |
CULL_SHAPE_FLAG_GEOMETRY_FRUSTUM |
CULL_SHAPE_FLAG_MIRROR;
const CPortalFlags portalFlags = CMirrors::GetMirrorPortalFlags();
bool bIsMirrorFloor = portalFlags.GetIsMirrorFloor();
bool bUsePortalTraversal = portalFlags.GetIsMirrorUsingPortalTraversal() || bIsMirrorFloor;
bool bCanSeeExteriorView = fwScan::GetScanResults().GetMirrorCanSeeExteriorView();
CutSceneManager* csMgr = CutSceneManager::GetInstance();
Assert(csMgr);
if(csMgr->IsCutscenePlayingBack())
{
bCanSeeExteriorView = true;
}
#if MIRROR_DEV
if (CMirrors::ms_debugMirrorForcePortalTraversalOn) { bUsePortalTraversal = true; }
else if (CMirrors::ms_debugMirrorForcePortalTraversalOff) { bUsePortalTraversal = false; }
if (CMirrors::ms_debugMirrorForceExteriorViewOn) { bCanSeeExteriorView = true; }
else if (CMirrors::ms_debugMirrorForceExteriorViewOff) { bCanSeeExteriorView = false; }
if (CMirrors::ms_debugMirrorFloor)
{
bIsMirrorFloor = true;
}
#endif // MIRROR_DEV
if (bUsePortalTraversal)
{
flags |= CULL_SHAPE_FLAG_TRAVERSE_PORTALS;
if (MIRROR_DEV_SWITCH(CMirrors::ms_debugMirrorClipAndStorePortals, false)) // TODO -- re-enable this once BS#992094 is resolved
{
flags |= (CULL_SHAPE_FLAG_CLIP_AND_STORE_PORTALS | CULL_SHAPE_FLAG_USE_SCREEN_QUAD_PAIRS);
}
}
if (bCanSeeExteriorView)
{
flags |= CULL_SHAPE_FLAG_RENDER_EXTERIOR;
if (MIRROR_DEV_SWITCH(CMirrors::ms_debugMirrorExteriorViewRenderLODs, false))
{
flags |= CULL_SHAPE_FLAG_RENDER_LOD_BUILDING_BASED_ON_INTERIOR;
}
}
return flags;
}
fwRoomSceneGraphNode* CRenderPhaseMirrorReflection::GetMirrorRoomSceneNode()
{
if (CMirrors::GetIsMirrorVisible())
{
return CMirrors::GetScanMirrorRoomSceneNode();
}
return NULL;
}
// TODO -- ugly hack!!
static bool gMirrorScanCameraIsInInterior = false;
void CRenderPhaseMirrorReflection::SetMirrorScanCameraIsInInterior(bool b)
{
gMirrorScanCameraIsInInterior = b;
}
bool CRenderPhaseMirrorReflection::GetMirrorScanFromGBufStartingNode()
{
bool bFromGBuf = false;
if (fwScan::GetScanResults().GetMirrorFloorVisible())
{
// mirror floors start scanning from gbuf node if the camera is in an interior or the portal is water surface
// TODO -- maybe we should just always set bFromGBuf to true if a mirror floor is visible?
if (gMirrorScanCameraIsInInterior || Water::IsUsingMirrorWaterSurface())
{
bFromGBuf = true;
}
#if MIRROR_DEV
if (CMirrors::ms_debugMirrorFloorScanFromGBufStartingNodeOn ) { bFromGBuf = true; }
else if (CMirrors::ms_debugMirrorFloorScanFromGBufStartingNodeOff) { bFromGBuf = false; }
#endif // MIRROR_DEV
}
return bFromGBuf;
}
#if MIRROR_DEV
static float gMirrorScreenBoundsX = 0.0f;
static float gMirrorScreenBoundsY = 0.0f;
static float gMirrorScreenBoundsW = 0.0f;
static float gMirrorScreenBoundsH = 0.0f;
#endif // MIRROR_DEV
static bool gMirrorAllowRestrictedProjection = true; // [HACK GTAV]
void CRenderPhaseMirrorReflection::UpdateViewport()
{
g_mirrorReflectionViewport = NULL;
#if __BANK
if (TiledScreenCapture::IsEnabled())
{
return;
}
#endif // __BANK
#if MIRROR_DEV
if (CMirrors::ms_debugMirrorShowInfo)
{
grcDebugDraw::AddDebugOutput(CMirrors::ms_debugMirrorShowInfoMessage);
}
if (fwScan::GetScanResults().GetWaterSurfaceHeightMismatch())
{
grcDebugDraw::AddDebugOutput(Color32(fwTimer::GetFrameCount()%4?255:0,0,0,255), "INTERIOR WATER HEIGHT MISMATCH");
}
#endif // MIRROR_DEV
if (!CMirrors::GetIsMirrorVisible())
{
return;
}
SetActive(true);
Vec3V mirrorCorners[4];
mirrorCorners[0] = CMirrors::GetScanMirrorCorner(0);
mirrorCorners[1] = CMirrors::GetScanMirrorCorner(1);
mirrorCorners[2] = CMirrors::GetScanMirrorCorner(2);
mirrorCorners[3] = CMirrors::GetScanMirrorCorner(3);
#if MIRROR_DEV
if (CMirrors::ms_debugMirrorShowInfo)
{
grcDebugDraw::AddDebugOutput(" distance=%f, plane=%.3f,%.3f,%.3f,%.3f", fwScan::GetScanResults().GetMirrorDistance(), VEC4V_ARGS(CMirrors::GetMirrorPlane()));
if (fwScan::GetScanResults().GetMirrorFloorVisible())
{
grcDebugDraw::AddDebugOutput(" floor quads=%d, water surface=%s", fwScan::GetScanResults().GetMirrorFloorQuadCount(), fwScan::GetScanResults().GetWaterSurfaceVisible() ? "true" : "false");
}
if (fwScan::GetScanResults().GetMirrorCanSeeDirectionalLight())
{
grcDebugDraw::AddDebugOutput(" can see directional light");
}
if (fwScan::GetScanResults().GetMirrorCanSeeExteriorView())
{
grcDebugDraw::AddDebugOutput(" can see exterior view");
}
if (fwScan::GetScanResults().m_skyPortalBounds_MirrorReflection.GetIsSkyPortalVisInterior())
{
grcDebugDraw::AddDebugOutput(" sky portals=%d", fwScan::GetScanResults().m_skyPortalBounds_MirrorReflection.GetSkyPortalCount());
}
}
#endif // MIRROR_DEV
// set location (room and portal info)
{
const fwRoomSceneGraphNode* pMirrorRoomSceneNode = GetMirrorRoomSceneNode();
if (pMirrorRoomSceneNode)
{
const fwInteriorLocation location = pMirrorRoomSceneNode->GetInteriorLocation();
const CInteriorProxy* pInteriorProxy = CInteriorProxy::GetFromLocation(location);
Assert(pInteriorProxy);
const CInteriorInst* pInteriorInst = pInteriorProxy->GetInteriorInst();
const CMloModelInfo* pMloModelInfo = static_cast<const CMloModelInfo*>(pInteriorInst->GetBaseModelInfo());
const int portalIndex = CMirrors::GetScanMirrorPortalIndex();
Assert(pMloModelInfo->GetIsStreamType());
const CPortalFlags portalFlags = pMloModelInfo->GetPortalFlags(portalIndex);
Assert(portalFlags.GetIsMirrorPortal());
Assert(portalFlags.GetIsOneWayPortal());
#if MIRROR_DEV
if (CMirrors::ms_debugMirrorShowInfo)
{
char portalFlagsString[32] = "";
// every f-ing portal flag
if (portalFlags.GetIsOneWayPortal ()) { strcat(portalFlagsString, "O"); }
if (portalFlags.GetIsLinkPortal ()) { strcat(portalFlagsString, "L"); }
if (portalFlags.GetIsMirrorPortal ()) { strcat(portalFlagsString, "M"); }
if (portalFlags.GetMirrorCanSeeDirectionalLight()) { strcat(portalFlagsString, "D"); }
if (portalFlags.GetMirrorCanSeeExteriorView ()) { strcat(portalFlagsString, "E"); }
if (portalFlags.GetIsMirrorUsingPortalTraversal()) { strcat(portalFlagsString, "P"); }
if (portalFlags.GetIsMirrorFloor ()) { strcat(portalFlagsString, "F"); }
if (portalFlags.GetIsWaterSurface ()) { strcat(portalFlagsString, "W"); }
if (portalFlags.GetIgnoreModifier ()) { strcat(portalFlagsString, "I"); }
if (portalFlags.GetLowLODOnly ()) { strcat(portalFlagsString, "X"); }
if (portalFlags.GetAllowClosing ()) { strcat(portalFlagsString, "C"); }
grcDebugDraw::AddDebugOutput(
" interior=%s, room=%s [%s]%s",
pMloModelInfo->GetModelName(),
pInteriorInst->GetRoomName(location.GetRoomIndex()),
portalFlagsString,
GetMirrorScanFromGBufStartingNode() ? " - scanning from gbuf node" : ""
);
}
#endif // MIRROR_DEV
CMirrors::SetMirrorPortalFlags(portalFlags);
}
else
{
#if MIRROR_DEV
if (CMirrors::ms_debugMirrorShowInfo)
{
grcDebugDraw::AddDebugOutput(" no interior room node found");
}
#endif // MIRROR_DEV
CMirrors::SetMirrorPortalFlags(CPortalFlags(0));
}
}
const Vec3V mirrorNormal = Normalize(Cross(mirrorCorners[0] - mirrorCorners[1], mirrorCorners[2] - mirrorCorners[1]));
const Vec3V mirrorOffset = mirrorNormal*ScalarV(MIRROR_DEFAULT_OFFSET MIRROR_DEV_ONLY(+ CMirrors::ms_debugMirrorOffset));
mirrorCorners[0] += mirrorOffset;
mirrorCorners[1] += mirrorOffset;
mirrorCorners[2] += mirrorOffset;
mirrorCorners[3] += mirrorOffset;
#if MIRROR_DEV
if (CMirrors::ms_debugMirrorScale != 0.0f)
{
const Vec3V centre = (mirrorCorners[0] + mirrorCorners[1] + mirrorCorners[2] + mirrorCorners[3])*ScalarV(V_QUARTER);
mirrorCorners[0] += (mirrorCorners[0] - centre)*ScalarV(CMirrors::ms_debugMirrorScale - 1.0f);
mirrorCorners[1] += (mirrorCorners[1] - centre)*ScalarV(CMirrors::ms_debugMirrorScale - 1.0f);
mirrorCorners[2] += (mirrorCorners[2] - centre)*ScalarV(CMirrors::ms_debugMirrorScale - 1.0f);
mirrorCorners[3] += (mirrorCorners[3] - centre)*ScalarV(CMirrors::ms_debugMirrorScale - 1.0f);
}
mirrorCorners[0] += CMirrors::ms_debugMirrorOffsetV;
mirrorCorners[1] += CMirrors::ms_debugMirrorOffsetV;
mirrorCorners[2] += CMirrors::ms_debugMirrorOffsetV;
mirrorCorners[3] += CMirrors::ms_debugMirrorOffsetV;
#endif // MIRROR_DEV
// [HACK GTAV] hack for BS#1574691 - no restricted projection on mirror during cutscene 'arm_1_mcs_2_concat' (to avoid green/yellow artefacts on 360)
if (CutSceneManager::GetInstance() &&
CutSceneManager::GetInstance()->IsRunning() &&
CutSceneManager::GetInstance()->GetSceneHashString()->GetHash() == ATSTRINGHASH("arm_1_mcs_2_concat", 0x5BCF8C95))
{
gMirrorAllowRestrictedProjection = false;
}
else
{
gMirrorAllowRestrictedProjection = true;
}
const bool bIsUsingMirrorWaterSurface = Water::IsUsingMirrorWaterSurface();
const bool bIsUsingRestrictedProjection = gMirrorAllowRestrictedProjection && !bIsUsingMirrorWaterSurface MIRROR_DEV_ONLY(&& CMirrors::ms_debugMirrorRestrictedProjection);
const Vec4V mirrorPlane = BuildPlane(mirrorCorners[0], mirrorNormal);
CMirrors::SetMirrorCorners(mirrorCorners);
CMirrors::SetMirrorPlane(mirrorPlane);
// ===
CRenderPhaseScanned::UpdateViewport();
grcViewport& viewport = GetGrcViewport();
Vec2V mirrorBoundsMin;
Vec2V mirrorBoundsMax;
// compute local bounds
{
const Mat34V localToWorld = viewport.GetCameraMtx();
const Vec2V invTanFOV = Vec2V(1.0f/viewport.GetTanHFOV(), 1.0f/viewport.GetTanVFOV());
Vec3V local[4 + 5];
int localCount = 0;
#if MIRROR_DEV
if (CMirrors::ms_debugMirrorClipMode != CMirrors::MIRROR_CLIP_MODE_VIEWSPACE)
{
local[localCount++] = mirrorCorners[0];
local[localCount++] = mirrorCorners[1];
local[localCount++] = mirrorCorners[2];
local[localCount++] = mirrorCorners[3];
}
else
#endif // MIRROR_DEV
{
localCount = PolyClipToFrustumWithoutNearPlane(local, mirrorCorners, 4, viewport.GetCompositeMtx());
}
if (localCount >= 3)
{
mirrorBoundsMin = Vec2V(V_FLT_MAX);
mirrorBoundsMax = Vec2V(V_NEG_FLT_MAX);
for (int i = 0; i < localCount; i++)
{
const Vec3V temp = UnTransformOrtho(localToWorld, local[i]);
const Vec2V xy = -temp.GetXY()/temp.GetZ();
mirrorBoundsMin = Min(xy, mirrorBoundsMin);
mirrorBoundsMax = Max(xy, mirrorBoundsMax);
}
}
else // mirror is clipped to nothing, it shouldn't be drawn .. force the bounds to 0
{
mirrorBoundsMin = Vec2V(V_ZERO);
mirrorBoundsMax = Vec2V(V_ZERO);
}
// [-1..1] in screenspace
mirrorBoundsMin *= invTanFOV;
mirrorBoundsMax *= invTanFOV;
#if MIRROR_DEV
if (CMirrors::ms_debugMirrorClipMode == CMirrors::MIRROR_CLIP_MODE_SCREENSPACE)
{
mirrorBoundsMin = Max(mirrorBoundsMin, Vec2V(V_NEGONE));
mirrorBoundsMax = Min(mirrorBoundsMax, Vec2V(V_ONE));
}
#endif // MIRROR_DEV
// make sure the bounds isn't actually zero, otherwise we can get shader errors
{
mirrorBoundsMax = Max(mirrorBoundsMin + Vec2V(V_FLT_SMALL_5), mirrorBoundsMax);
mirrorBoundsMin = Min(mirrorBoundsMax - Vec2V(V_FLT_SMALL_5), mirrorBoundsMin);
}
}
#if MIRROR_DEV
// [0..1]
const Vec2V screenBoundsMin = Vec2V(V_HALF) + Vec2V(0.5f, -0.5f)*mirrorBoundsMin;
const Vec2V screenBoundsMax = Vec2V(V_HALF) + Vec2V(0.5f, -0.5f)*mirrorBoundsMax;
// compute screen bounds
{
const float x0 = screenBoundsMin.GetXf();
const float y0 = screenBoundsMin.GetYf();
const float x1 = screenBoundsMax.GetXf();
const float y1 = screenBoundsMax.GetYf();
gMirrorScreenBoundsX = (x0 )*(float)GRCDEVICE.GetWidth ();
gMirrorScreenBoundsY = (y1 )*(float)GRCDEVICE.GetHeight(); // flip y
gMirrorScreenBoundsW = (x1 - x0)*(float)GRCDEVICE.GetWidth ();
gMirrorScreenBoundsH = (y0 - y1)*(float)GRCDEVICE.GetHeight();
}
if (CMirrors::ms_debugMirrorShowInfo)
{
grcDebugDraw::AddDebugOutput(
" screen bounds x=%d, y=%d, w=%d, h=%d",
(int)gMirrorScreenBoundsX,
(int)gMirrorScreenBoundsY,
(int)gMirrorScreenBoundsW,
(int)gMirrorScreenBoundsH
);
}
if (CMirrors::ms_debugMirrorShowBounds)
{
grcDebugDraw::RectAxisAligned(screenBoundsMin, screenBoundsMax, Color32(255,0,0,32), true);
grcDebugDraw::RectAxisAligned(screenBoundsMin, screenBoundsMax, Color32(255,0,0,255), false);
}
if (CMirrors::ms_debugMirrorShowBoundsRT)
{
CRenderTargets::ShowRenderTargetSetBounds(gMirrorScreenBoundsX, gMirrorScreenBoundsY, gMirrorScreenBoundsW, gMirrorScreenBoundsH);
}
#endif // MIRROR_DEV
#if DEBUG_DRAW
if (m_debugDrawMirror)
{
const Vec3V offset = mirrorNormal*ScalarV(m_debugDrawMirrorOffset); // mirror already renders at MIRROR_DEFAULT_OFFSET, so offset a bit more to make it visible
grcDebugDraw::Quad(
mirrorCorners[0] + offset,
mirrorCorners[1] + offset,
mirrorCorners[2] + offset,
mirrorCorners[3] + offset,
Color_BlueViolet.MultiplyAlpha(64),
false, // double-sided
true // solid
);
grcDebugDraw::Quad(
mirrorCorners[0] + offset,
mirrorCorners[1] + offset,
mirrorCorners[2] + offset,
mirrorCorners[3] + offset,
Color_BlueViolet,
false, // double-sided
false // solid
);
}
#endif // DEBUG_DRAW
// reflect camera matrix
{
Mat34V cameraMtx = PlaneReflectMatrix(mirrorPlane, viewport.GetCameraMtx());
#if MIRROR_USE_STENCIL_MASK
if (!CMirrors::ms_debugMirrorStencilMaskEnabled)
#endif // MIRROR_USE_STENCIL_MASK
{
cameraMtx.SetCol0(-cameraMtx.GetCol0()); // flip x
}
viewport.SetCameraMtx(cameraMtx);
}
viewport.SetNearClip(0.1f);
#if MIRROR_USE_STENCIL_MASK
if (CMirrors::ms_debugMirrorStencilMaskEnabled)
{
viewport.SetNormWindow(0.0f, 0.0f, 1.0f, 1.0f);
CMirrors::SetMirrorBounds(0.5f, 0.5f, -0.5f, -0.5f);
}
else
#endif // MIRROR_USE_STENCIL_MASK
if (bIsUsingRestrictedProjection)
{
const Vec2V windowCentre = (mirrorBoundsMax + mirrorBoundsMin)*ScalarV(V_HALF);
const Vec2V windowExtent = (mirrorBoundsMax - mirrorBoundsMin)*ScalarV(V_HALF);
const float cx = windowCentre.GetXf();
const float cy = windowCentre.GetYf();
const float ex = windowExtent.GetXf();
const float ey = windowExtent.GetYf();
float windowX = 0.0f;
float windowY = 0.0f;
float windowW = 1.0f;
float windowH = 1.0f;
float borderedWindowX = 0.0f;
float borderedWindowY = 0.0f;
float borderedWindowW = 1.0f;
float borderedWindowH = 1.0f;
float borderedWindowScaleX = 1.0f;
float borderedWindowScaleY = 1.0f;
#if MIRROR_DEV
if (CMirrors::ms_debugMirrorMaxPixelDensityEnabled)
#endif // MIRROR_DEV
{
const float maxPixelDensity = MIRROR_DEV_SWITCH(CMirrors::ms_debugMirrorMaxPixelDensity, MIRROR_DEFAULT_MAX_PIXEL_DENSITY);
// mirror bounds in pixels
const float pixelW = Max<float>(4.0f, maxPixelDensity*ex*(float)GRCDEVICE.GetWidth ());
const float pixelH = Max<float>(4.0f, maxPixelDensity*ey*(float)GRCDEVICE.GetHeight());
windowW = Min<float>(1.0f, 2.0f*ceilf(pixelW/2.0f)/(float)CMirrors::GetMirrorRenderTarget()->GetWidth ());
windowH = Min<float>(1.0f, 2.0f*ceilf(pixelH/2.0f)/(float)CMirrors::GetMirrorRenderTarget()->GetHeight());
windowX = 0.5f - 0.5f*windowW; // centre
windowY = 0.5f - 0.5f*windowH; // centre
const float border = MIRROR_DEV_SWITCH(CMirrors::ms_debugMirrorMaxPixelDensityBorder, MIRROR_DEFAULT_MAX_PIXEL_DENSITY_BORDER);
borderedWindowW = Min<float>(1.0f, windowW + border/(float)CMirrors::GetMirrorRenderTarget()->GetWidth ());
borderedWindowH = Min<float>(1.0f, windowH + border/(float)CMirrors::GetMirrorRenderTarget()->GetHeight());
borderedWindowX = 0.5f - 0.5f*borderedWindowW; // centre
borderedWindowY = 0.5f - 0.5f*borderedWindowH; // centre
borderedWindowScaleX = borderedWindowW/windowW;
borderedWindowScaleY = borderedWindowH/windowH;
}
viewport.SetNormWindowPortal_UpdateThreadOnly(cx*0.5f + 0.5f, cy*0.5f + 0.5f, ex*borderedWindowScaleX, ey*borderedWindowScaleY, borderedWindowX, borderedWindowY, borderedWindowW, borderedWindowH);
CMirrors::SetMirrorBounds((cx/ex)*0.5f + 0.5f, (cy/ey)*0.5f + 0.5f, -0.5f/ex, -0.5f/ey, windowX, windowY, windowW, windowH);
}
else // no restricted projection
{
viewport.SetNormWindow(0.0f, 0.0f, 1.0f, 1.0f);
CMirrors::SetMirrorBounds(0.5f, 0.5f, -0.5f, -0.5f);
}
#if __PS3
g_mirrorReflectionViewportNoObliqueProjection = viewport;
#endif // __PS3
#if __PS3 || MIRROR_DEV
bool bUseObliqueProjection = false;
#if __PS3
bUseObliqueProjection = true;
#elif MIRROR_DEV
if (!CMirrors::ms_debugMirrorUseHWClipPlane)
{
bUseObliqueProjection = true;
}
#endif // MIRROR_DEV
#if MIRROR_DEV
if (!CMirrors::ms_debugMirrorUseObliqueProjection)
{
bUseObliqueProjection = false;
}
#endif // MIRROR_DEV
if (bUseObliqueProjection)
{
const ScalarV projScale = ScalarV(MIRROR_DEV_SWITCH(CMirrors::ms_debugMirrorUseObliqueProjectionScale, MIRROR_DEFAULT_OBLIQUE_PROJ_SCALE));
viewport.ApplyObliqueProjection(CMirrors::GetAdjustedClipPlaneForInteriorWater(mirrorPlane*projScale));
}
#endif // __PS3 || MIRROR_DEV
if (bIsUsingMirrorWaterSurface)
{
Water::SetReflectionMatrix(PS3_SWITCH(g_mirrorReflectionViewportNoObliqueProjection, viewport).GetCompositeMtx());
}
g_mirrorReflectionViewport = &viewport;
}
void CRenderPhaseMirrorReflection::SetCullShape(fwRenderPhaseCullShape& cullShape)
{
#if MIRROR_DEV
if (!CMirrors::ms_debugMirrorCullingPlanesEnabled)
{
spdTransposedPlaneSet8 frustum;
sysMemSet(&frustum, 0, sizeof(frustum));
cullShape.SetFrustum(frustum);
}
else
#endif // MIRROR_DEV
{
const Vec3V* mirrorCorners = CMirrors::GetMirrorCorners();
const Vec4V mirrorPlane = CMirrors::GetMirrorPlane();
const Vec3V mirrorNormal = mirrorPlane.GetXYZ();
const Vec3V camPos = gVpMan.GetCurrentGameGrcViewport()->GetCameraPosition();
const Vec3V apex = camPos - mirrorNormal*PlaneDistanceTo(mirrorPlane, camPos)*ScalarV(V_TWO);
spdTransposedPlaneSet8 frustum;
const grcViewport& viewport = GetGrcViewport();
const Vec4V noCull = CMirrors::GetIsMirrorFrustumCullDisabled() ? Vec4V(V_ZERO) : Vec4V(V_ONE);
const Vec4V plane0 = -noCull*viewport.GetFrustumClipPlane(grcViewport::CLIP_PLANE_LEFT );
const Vec4V plane1 = -noCull*viewport.GetFrustumClipPlane(grcViewport::CLIP_PLANE_RIGHT );
const Vec4V plane2 = -noCull*viewport.GetFrustumClipPlane(grcViewport::CLIP_PLANE_TOP );
const Vec4V plane3 = -noCull*viewport.GetFrustumClipPlane(grcViewport::CLIP_PLANE_BOTTOM);
const Vec4V plane4 = BuildPlane(apex, mirrorCorners[0], mirrorCorners[1]);
const Vec4V plane5 = BuildPlane(apex, mirrorCorners[1], mirrorCorners[2]);
const Vec4V plane6 = BuildPlane(apex, mirrorCorners[2], mirrorCorners[3]);
const Vec4V plane7 = BuildPlane(apex, mirrorCorners[3], mirrorCorners[0]);
frustum.SetPlanes(
MIRROR_DEV_SWITCH((CMirrors::ms_debugMirrorCullingPlaneFlags & BIT(0)), true) ? plane0 : Vec4V(V_ZERO),
MIRROR_DEV_SWITCH((CMirrors::ms_debugMirrorCullingPlaneFlags & BIT(1)), true) ? plane1 : Vec4V(V_ZERO),
MIRROR_DEV_SWITCH((CMirrors::ms_debugMirrorCullingPlaneFlags & BIT(2)), true) ? plane2 : Vec4V(V_ZERO),
MIRROR_DEV_SWITCH((CMirrors::ms_debugMirrorCullingPlaneFlags & BIT(3)), true) ? plane3 : Vec4V(V_ZERO),
MIRROR_DEV_SWITCH((CMirrors::ms_debugMirrorCullingPlaneFlags & BIT(4)), true) ? plane4 : Vec4V(V_ZERO),
MIRROR_DEV_SWITCH((CMirrors::ms_debugMirrorCullingPlaneFlags & BIT(5)), true) ? plane5 : Vec4V(V_ZERO),
MIRROR_DEV_SWITCH((CMirrors::ms_debugMirrorCullingPlaneFlags & BIT(6)), true) ? plane6 : Vec4V(V_ZERO),
MIRROR_DEV_SWITCH((CMirrors::ms_debugMirrorCullingPlaneFlags & BIT(7)), true) ? plane7 : Vec4V(V_ZERO)
);
cullShape.SetFrustum(frustum);
}
cullShape.SetMirrorPlane(CMirrors::GetMirrorPlane());
}
void CRenderPhaseMirrorReflection::BuildRenderList()
{
#if __BANK
if (TiledScreenCapture::IsEnabled())
{
return;
}
#endif // __BANK
if (!CMirrors::GetIsMirrorVisible() || !GetViewport()->IsActive())
{
return;
}
PF_FUNC(CRenderPhaseMirrorReflectionRL);
bool bUseDirectionalLighting = fwScan::GetScanResults().GetMirrorCanSeeDirectionalLight();
bool bCanSeeExteriorView = fwScan::GetScanResults().GetMirrorCanSeeExteriorView();
#if MIRROR_DEV
if (CMirrors::ms_debugMirrorForceDirectionalLightingOn) { bUseDirectionalLighting = true; }
else if (CMirrors::ms_debugMirrorForceDirectionalLightingOff) { bUseDirectionalLighting = false; }
if (CMirrors::ms_debugMirrorForceExteriorViewOn) { bCanSeeExteriorView = true; }
else if (CMirrors::ms_debugMirrorForceExteriorViewOff) { bCanSeeExteriorView = false; }
#endif // MIRROR_DEV
CutSceneManager* csMgr = CutSceneManager::GetInstance();
Assert(csMgr);
if(csMgr->IsCutscenePlayingBack())
{
bCanSeeExteriorView = true;
}
if (MIRROR_DEV_SWITCH(CMirrors::ms_debugMirrorForceDirectionalLightingOnForExteriorView, true) && bCanSeeExteriorView)
{
bUseDirectionalLighting = true;
}
const u32 exteriorVisMaskFlags =
VIS_ENTITY_MASK_OTHER |
VIS_ENTITY_MASK_DUMMY_OBJECT |
VIS_ENTITY_MASK_LOLOD_BUILDING |
VIS_ENTITY_MASK_TREE |
0;
SetRenderFlags(g_mirrorReflectionRenderSettings | (bUseDirectionalLighting ? RENDER_SETTING_RENDER_SHADOWS : 0));
GetEntityVisibilityMask().SetAllFlags((u16)(g_mirrorReflectionVisMaskFlags | (bCanSeeExteriorView ? exteriorVisMaskFlags : 0)));
COcclusion::BeforeSetupRender(false, false, SHADOWTYPE_NONE, true, GetGrcViewport());
CScene::SetupRender(GetEntityListIndex(), GetRenderFlags(), GetGrcViewport(), this);
COcclusion::AfterPreRender();
}
static void RenderStateSetupMirrorReflection(fwRenderPassId pass, fwRenderBucket bucket, fwRenderMode, int, fwRenderGeneralFlags)
{
if (pass == RPASS_CUTOUT MIRROR_DEV_ONLY(&& CMirrors::ms_debugMirrorUseAlphaTestForCutout))
{
DLC(dlCmdSetBlendState, (grcStateBlock::BS_Default));
DLC_Add(CShaderLib::SetAlphaTestRef, (MIRROR_DEV_SWITCH(CMirrors::ms_debugMirrorUseAlphaTestForCutoutAlphaRef, 128.f/255.f)));
}
else if (BIT(pass) & g_mirrorReflectionAlphaBlendingPasses)
{
DLC(dlCmdSetBlendState, (grcStateBlock::BS_Normal));
}
else
{
DLC(dlCmdSetBlendState, (grcStateBlock::BS_Default)); // no alpha blending
}
if (BIT(pass) & g_mirrorReflectionDepthWritingPasses)
{
DLC(dlCmdSetDepthStencilState, (grcStateBlock::DSS_LessEqual));
}
else
{
DLC(dlCmdSetDepthStencilState, (grcStateBlock::DSS_TestOnly_LessEqual)); // no depth writing
}
if(!g_mirrorReflectionUsingWaterReflectionTechnique)
{
if(bucket == CRenderer::RB_CUTOUT)
{
DLC_Add(Lights::SetLightweightTechniquePassType, Lights::kLightPassCutOut);
}
}
DLC(dlCmdGrcLightStateSetEnabled, (!g_mirrorReflectionUsingWaterReflectionTechnique));
DLC(dlCmdSetBucketsAndRenderMode, (bucket, CRenderer::GenerateSubBucketMask(CRenderer::RB_MODEL_MIRROR), rmStandard)); // damn lies.
}
static void RenderStateCleanupMirrorReflection(fwRenderPassId pass, fwRenderBucket bucket, fwRenderMode rm, int subphase, fwRenderGeneralFlags generalFlags)
{
if(!g_mirrorReflectionUsingWaterReflectionTechnique)
{
if(bucket == CRenderer::RB_CUTOUT)
{
DLC_Add(Lights::SetLightweightTechniquePassType, Lights::kLightPassNormal);
}
}
CRenderListBuilder::RenderStateCleanupSimpleFlush(pass, bucket, rm, subphase, generalFlags);
}
static void RenderStateSetupCustomFlagsChangedMirrorReflection(fwRenderPassId MIRROR_DEV_ONLY(pass), fwRenderBucket MIRROR_DEV_ONLY(bucket), fwRenderMode MIRROR_DEV_ONLY(renderMode), int MIRROR_DEV_ONLY(subphasePass), fwRenderGeneralFlags MIRROR_DEV_ONLY(generalFlags), u16 MIRROR_DEV_ONLY(previousCustomFlags), u16 currentCustomFlags)
{
CDrawListPrototypeManager::Flush();
const bool bInInterior = (currentCustomFlags & fwEntityList::CUSTOM_FLAGS_INTERIOR_SORT) != 0;
DLC_Add(Lights::SetupDirectionalGlobals, bInInterior ? 0.0f : 1.0f);
#if MIRROR_DEV
if (0 && CMirrors::ms_debugMirrorShowInfo)
{
grcDebugDraw::AddDebugOutput("mirror: custom flags changed 0x%04x -> 0x%04x (in interior = %s), pass=%d, bucket=%d, mode=%d, subphase=%d, flags=%d", previousCustomFlags, currentCustomFlags, bInInterior ? "TRUE" : "FALSE", pass, bucket, renderMode, subphasePass, generalFlags);
}
#endif // MIRROR_DEV
}
static void MirrorSetDirLighting(bool bEnable)
{
Lights::m_lightingGroup.SetDirectionalLightingGlobals(bEnable);
Lights::m_lightingGroup.SetAmbientLightingGlobals();
g_timeCycle.SetShaderData();
}
static void MirrorRestoreDirLighting()
{
Lights::m_lightingGroup.SetDirectionalLightingGlobals(true);
}
#if __PS3
extern bool SetEdgeNoPixelTestDisableIfFarFromOrigin_Begin(const grcViewport* viewport);
extern void SetEdgeNoPixelTestDisableIfFarFromOrigin_End(bool bCamDistFarFromOrigin);
#endif // __PS3
#if RSG_ORBIS
void GenerateMips(grcRenderTarget* target)
{
target->GenerateMipmaps();
}
static void FinishMirrorRendering()
{
static_cast<grcTextureFactoryGNM&>( grcTextureFactory::GetInstance() ).FinishRendering();
}
#endif // RSG_ORBIS
void SetupMirrorDepthTarget(bool bIsUsingMirrorWaterSurface)
{
//do this only for PC and Durango (if MSAA is enabled)
#if __D3D11
if(!bIsUsingMirrorWaterSurface)
{
//Let's switch of clip planes as this is a full screen pass
DLC(dlCmdSetClipPlaneEnable, (0x0));
#if DEVICE_MSAA
if (CMirrors::GetMSAA() > 1)
{
DLC_Add(CMirrors::ResolveMirrorDepthTarget);
}
else
#endif //DEVICE_MSAA
{
//If read only is not allowed then make a copy of the buffer
if(!GRCDEVICE.IsReadOnlyDepthAllowed())
{
DLC_Add(CRenderTargets::CopyDepthBuffer, CMirrors::GetMirrorDepthTarget(), CMirrors::GetMirrorDepthTarget_Copy());
}
}
//Switch clip planes back on
DLC(dlCmdSetClipPlaneEnable, (0x1));
}
#endif //__D3D11
}
void CRenderPhaseMirrorReflection::BuildDrawList()
{
#if __BANK
if (TiledScreenCapture::IsEnabled())
{
return;
}
#endif // __BANK
// Cannot call Water::UsePlanarReflection() in update viewport since I don't have occlusion query data yet
// Cannot call Water::IsUsingMirrorWaterSurface() in update viewport since I don't have visibility data yet
if ( !(CMirrors::GetIsMirrorVisible() && fwScan::GetScanResults().GetMirrorVisible()) ||
!HasEntityListIndex() ||
(Water::IsUsingMirrorWaterSurface() && !Water::UsePlanarReflection()))
{
g_mirrorReflectionUsingWaterReflectionTechnique = false;
return;
}
DrawListPrologue();
const bool bIsUsingMirrorWaterSurface = Water::IsUsingMirrorWaterSurface();
grcRenderTarget *clearTarget;
g_mirrorReflectionEnableMSAA = true;
if (bIsUsingMirrorWaterSurface)
{
clearTarget = CMirrors::GetMirrorWaterRenderTarget();
#if RSG_PC
g_mirrorReflectionEnableMSAA = CMirrors::GetMirrorWaterMSAARenderTarget() != NULL;
#endif // RSG_PC
}
else
{
clearTarget = CMirrors::GetMirrorRenderTarget(g_mirrorReflectionEnableMSAA);
}
DLC(dlCmdLockRenderTarget, (0, clearTarget, NULL));
DLC(dlCmdClearRenderTarget, (true, Color32(0), false, 1.0f, false, 0));
DLC(dlCmdUnLockRenderTarget, (0));
DLC_Add(CShaderLib::SetUseFogRay, false);
DLC_Add(CShaderLib::SetFogRayTexture);
PF_FUNC(CRenderPhaseMirrorReflection);
if (!Water::IsUsingMirrorWaterSurface())
PEDDAMAGEMANAGER.AddToDrawList(false,true);
grcViewport& viewport = GetGrcViewport();
bool bForcingLODs = false;
if (fwScan::GetScanResults().GetMirrorFloorVisible() && MIRROR_DEV_SWITCH(CMirrors::ms_debugMirrorFloorUseLODs, true))
{
dlDrawListMgr::SetHighestLOD(false, dlDrawListMgr::DLOD_MED, dlDrawListMgr::DLOD_MED, dlDrawListMgr::VLOD_HIGH, dlDrawListMgr::PLOD_LOD);
bForcingLODs = true;
}
CMirrors::SetShaderParams();
float localLightIntensity = g_timeCycle.GetCurrUpdateKeyframe().GetVar(TCVAR_MIRROR_REFLECTION_LOCAL_LIGHT_INTENSITY);
#if MIRROR_DEV
if (CMirrors::ms_debugMirrorLocalLightIntensityOverrideEnabled)
{
localLightIntensity = CMirrors::ms_debugMirrorLocalLightIntensityOverride;
}
#endif // MIRROR_DEV
grcRenderTarget* depthBuffer = CMirrors::GetMirrorDepthTarget();
#if __D3D11
#if DEVICE_MSAA
if (CMirrors::GetMSAA()>1)
{
depthBuffer = CMirrors::GetMirrorDepthResolved();
}
else
#endif //DEVICE_MSAA
{
//If read only is not allowed then make a copy of the buffer
if(!GRCDEVICE.IsReadOnlyDepthAllowed())
{
depthBuffer = CMirrors::GetMirrorDepthTarget_Copy();
}
}
#endif //__D3D11
DLC_Add(CShaderLib::SetGlobalEmissiveScale, 1.0f, false);
DLC_Add(CRenderPhaseReflection::SetReflectionMap);
DLC_Add(CRenderPhaseCascadeShadowsInterface::SetCloudShadowParams);
DLC_Add(CPtFxManager::UpdateDepthBuffer, depthBuffer);
DLC_Add(CLightGroup::SetLocalLightForwardIntensityScale, localLightIntensity);
DLC_Add(CTimeCycle::SetShaderParams);
#if __XENON
DLC_Add(PostFX::SetLDR10bitHDR10bit);
#elif __PS3
DLC_Add(PostFX::SetLDR8bitHDR8bit);
#else
DLC_Add(PostFX::SetLDR16bitHDR16bit);
#endif
const bool bIsUsingRestrictedProjection = gMirrorAllowRestrictedProjection && !bIsUsingMirrorWaterSurface MIRROR_DEV_ONLY(&& CMirrors::ms_debugMirrorRestrictedProjection);
const bool bIsUsingWaterReflectionTechnique = CMirrors::GetIsMirrorUsingWaterReflectionTechnique(bIsUsingMirrorWaterSurface);
bool bSkyIsVisible = false;
g_mirrorReflectionUsingWaterReflectionTechnique = bIsUsingWaterReflectionTechnique; // save this so it can be accessed by RenderStateSetupMirrorReflection
//Adding draw command to set the renderthread copy to whatever the main thread copy is.
//This is used for places where we don't support rendering into the water reflections.
DLC_Add(CRenderPhaseMirrorReflectionInterface::SetIsMirrorUsingWaterReflectionTechniqueAndSurface_Render,
g_mirrorReflectionUsingWaterReflectionTechnique, bIsUsingMirrorWaterSurface);
#if MIRROR_DEV
if (CMirrors::ms_debugMirrorRenderSkyAlways)
{
bSkyIsVisible = true;
}
else
#endif // MIRROR_DEV
if (gMirrorScanCameraIsInInterior)
{
bSkyIsVisible = (fwScan::GetScanResults().m_skyPortalBounds_MirrorReflection.GetSkyPortalCount() > 0);
}
else
{
bSkyIsVisible = fwScan::GetScanResults().GetMirrorCanSeeExteriorView();
}
CMirrors::eMirrorRenderSkyMode renderSkyMode = CMirrors::MIRROR_RENDER_SKY_MODE_NONE;
CVisualEffects::eRenderMode renderSkyVfxMode = bIsUsingWaterReflectionTechnique ? CVisualEffects::RM_WATER_REFLECTION : CVisualEffects::RM_MIRROR_REFLECTION;
if (bSkyIsVisible)
{
renderSkyMode = MIRROR_DEV_SWITCH((CMirrors::eMirrorRenderSkyMode)CMirrors::ms_debugMirrorRenderSkyMode, CMirrors::MIRROR_RENDER_SKY_MODE_DEFAULT);
}
Color32 clearColour = Color32(0);
// Color32 clearColour = Color32(255,0,0,255); // hack to make border visible
#if __BANK
if (bIsUsingMirrorWaterSurface && !CRenderPhaseWaterReflectionInterface::IsSkyEnabled())
{
renderSkyMode = CMirrors::MIRROR_RENDER_SKY_MODE_NONE; // no sky, it's disabled for water reflection in rag
clearColour = Color32(CRenderPhaseWaterReflectionInterface::GetWaterReflectionClearColour());
}
#endif // __BANK
grcRenderTarget* depthTarget;
#if __D3D11
grcRenderTarget* depthTargetCopy = NULL;
grcRenderTarget* depthTargetTargetRO = NULL;
#endif //__D3D11
#if MIRROR_USE_STENCIL_MASK
if (CMirrors::ms_debugMirrorStencilMaskEnabled)
{
#if !__XENON
DLC_Add(CRenderTargets::BindCustomRenderTarget);
#endif // !__XENON
DLC(dlCmdSetCurrentViewport, (&viewport));
if (CMirrors::ms_debugMirrorStencilMaskScissor)
{
const int scissorX = Clamp<int>((int)gMirrorScreenBoundsX - 1, 0, GRCDEVICE.GetWidth ()); // expand by 1 pixel
const int scissorY = Clamp<int>((int)gMirrorScreenBoundsY - 1, 0, GRCDEVICE.GetHeight());
const int scissorW = Min<int>(GRCDEVICE.GetWidth () - scissorX, (int)gMirrorScreenBoundsW + 2);
const int scissorH = Min<int>(GRCDEVICE.GetHeight() - scissorY, (int)gMirrorScreenBoundsH + 2);
DLC(dlCmdGrcDeviceSetScissor, (scissorX, scissorY, scissorW, scissorH));
}
// render mirror portal into stencil buffer, setting pixels to 96
DLC_Add(CMirrors::RenderDebug, true);
// pass only stencil=96
{
static grcDepthStencilStateHandle ds_handle = grcStateBlock::DSS_Invalid;
static grcRasterizerStateHandle rs_handle = grcStateBlock::RS_Invalid;
if (ds_handle == grcStateBlock::DSS_Invalid)
{
grcDepthStencilStateDesc ds; // no depth test, pass only stencil=96
grcRasterizerStateDesc rs; // cull front (because reflection is flipped)
ds.StencilEnable = true;
ds.StencilReadMask = 96;
ds.StencilWriteMask = 0;
ds.FrontFace.StencilFailOp = grcRSV::STENCILOP_KEEP;
ds.FrontFace.StencilDepthFailOp = grcRSV::STENCILOP_KEEP;
ds.FrontFace.StencilPassOp = grcRSV::STENCILOP_KEEP;
ds.FrontFace.StencilFunc = grcRSV::CMP_EQUAL;
ds.BackFace = ds.FrontFace;
rs.CullMode = grcRSV::CULL_FRONT;
ds_handle = grcStateBlock::CreateDepthStencilState(ds);
rs_handle = grcStateBlock::CreateRasterizerState (rs);
}
// TODO -- save the state handles here, but don't set until we're about to render
DLC(dlCmdSetStates, (rs_handle, ds_handle, grcStateBlock::BS_Default));
}
}
else
#endif // MIRROR_USE_STENCIL_MASK
{
grcRenderTarget* colorTarget;
if (bIsUsingMirrorWaterSurface)
{
colorTarget =
#if RSG_PC
g_mirrorReflectionEnableMSAA ? CMirrors::GetMirrorWaterMSAARenderTarget() :
#endif
CMirrors::GetMirrorWaterRenderTarget();
depthTarget = CMirrors::GetMirrorWaterDepthTarget();
#if __D3D11
depthTargetCopy = CMirrors::GetMirrorWaterDepthTarget_Copy();
depthTargetTargetRO = CMirrors::GetMirrorWaterDepthTarget_ReadOnly();
#endif //__D3D11
}
else
{
colorTarget = CMirrors::GetMirrorRenderTarget(g_mirrorReflectionEnableMSAA);
depthTarget = CMirrors::GetMirrorDepthTarget();
#if __D3D11
depthTargetCopy = CMirrors::GetMirrorDepthTarget_Copy();
depthTargetTargetRO = CMirrors::GetMirrorDepthTarget_ReadOnly();
#endif //__D3D11
}
DLC(dlCmdLockRenderTarget, (0, colorTarget, depthTarget));
// hack to make border visible
//DLC(dlCmdSetCurrentViewport, (gVpMan.GetUpdateGameGrcViewport()));
//DLC(dlCmdClearRenderTarget, (renderSkyMode == CMirrors::MIRROR_RENDER_SKY_MODE_NONE, clearColour, true, 1.0f, true, 0));
DLC(dlCmdSetCurrentViewport, (&PS3_SWITCH(g_mirrorReflectionViewportNoObliqueProjection, viewport)));
XENON_ONLY(DLC_Add(dlCmdEnableAutomaticHiZ, true));
DLC(dlCmdClearRenderTarget, (renderSkyMode == CMirrors::MIRROR_RENDER_SKY_MODE_NONE, clearColour, true, 1.0f, true, 0));
// TODO -- save the state handles here, but don't set until we're about to render
// [STATE OVERRIDE] force backface culling (which is the default anyway), otherwise the mirror might render the wall behind
DLC(dlCmdSetStates, (grcStateBlock::XENON_SWITCH(RS_Default_HalfPixelOffset, RS_Default), grcStateBlock::DSS_LessEqual, grcStateBlock::BS_Default));
}
DLC_Add(CRenderPhaseCascadeShadowsInterface::SetSharedShaderVars);
DLC_Add(CShaderLib::ApplyDayNightBalance); // update shaders
if (renderSkyMode == CMirrors::MIRROR_RENDER_SKY_MODE_FIRST)
{
// Only used when renderSkyVfxMode = CVisualEffects::RM_WATER_REFLECTION or CVisualEffects::RM_MIRROR_REFLECTION (see CVisualEffects::RenderSky()).
D3D11_ONLY(DLC_Add(CVisualEffects::SetTargetsForDX11ReadOnlyDepth, (renderSkyVfxMode == CVisualEffects::RM_WATER_REFLECTION) ? false : true, depthTarget, depthTargetCopy, depthTargetTargetRO));
DLC_Add(CVisualEffects::RenderSky, renderSkyVfxMode, false, bIsUsingRestrictedProjection, -1, -1, -1, -1, true, 1.0f);
D3D11_ONLY(DLC_Add(CVisualEffects::SetTargetsForDX11ReadOnlyDepth, false, (grcRenderTarget *)NULL, (grcRenderTarget *)NULL, (grcRenderTarget *)NULL));
}
bool bUseDirectionalLighting = fwScan::GetScanResults().GetMirrorCanSeeDirectionalLight();
bool bCanSeeExteriorView = fwScan::GetScanResults().GetMirrorCanSeeExteriorView();
CutSceneManager* csMgr = CutSceneManager::GetInstance();
Assert(csMgr);
if(csMgr->IsCutscenePlayingBack())
{
bCanSeeExteriorView = true;
}
#if MIRROR_DEV
if (CMirrors::ms_debugMirrorForceDirectionalLightingOn) { bUseDirectionalLighting = true; }
else if (CMirrors::ms_debugMirrorForceDirectionalLightingOff) { bUseDirectionalLighting = false; }
if (CMirrors::ms_debugMirrorForceExteriorViewOn) { bCanSeeExteriorView = true; }
else if (CMirrors::ms_debugMirrorForceExteriorViewOff) { bCanSeeExteriorView = false; }
if (CMirrors::ms_debugMirrorWireframe)
{
DLC_Add(grcStateBlock::SetWireframeOverride, true);
DLC_Add(grcStateBlock::SetRasterizerState, grcStateBlock::RS_Default); // [STATE OVERRIDE]
}
#endif // MIRROR_DEV
if (MIRROR_DEV_SWITCH(CMirrors::ms_debugMirrorForceDirectionalLightingOnForExteriorView, true) && bCanSeeExteriorView)
{
bUseDirectionalLighting = true;
}
int fullFilter = CRenderListBuilder::RENDER_DONT_RENDER_PLANTS;
if ( MIRROR_DEV_SWITCH(CMirrors::ms_debugMirrorDrawFilter_RENDER_OPAQUE , true )) { fullFilter |= CRenderListBuilder::RENDER_OPAQUE ; }
if ( MIRROR_DEV_SWITCH(CMirrors::ms_debugMirrorDrawFilter_RENDER_ALPHA , true )) { fullFilter |= CRenderListBuilder::RENDER_ALPHA ; }
if ( MIRROR_DEV_SWITCH(CMirrors::ms_debugMirrorDrawFilter_RENDER_FADING , true )) { fullFilter |= CRenderListBuilder::RENDER_FADING ; }
if (!MIRROR_DEV_SWITCH(CMirrors::ms_debugMirrorDrawFilter_RENDER_TREES , false)) { fullFilter |= CRenderListBuilder::RENDER_DONT_RENDER_TREES ; }
if (!MIRROR_DEV_SWITCH(CMirrors::ms_debugMirrorDrawFilter_RENDER_DECALS_CUTOUTS, true )) { fullFilter |= CRenderListBuilder::RENDER_DONT_RENDER_DECALS_CUTOUTS; }
if (bCanSeeExteriorView)
{
// force trees in exterior view
fullFilter &= ~CRenderListBuilder::RENDER_DONT_RENDER_TREES;
}
const int opaqueFilter = (fullFilter & ~(CRenderListBuilder::RENDER_ALPHA | CRenderListBuilder::RENDER_FADING));
const int alphaFilter = (fullFilter & (CRenderListBuilder::RENDER_ALPHA | CRenderListBuilder::RENDER_FADING)) | CRenderListBuilder::RENDER_MIRROR_ALPHA;
DLC_Add(MirrorSetDirLighting, bUseDirectionalLighting);
PS3_ONLY(const bool bCamDistFarFromOrigin = SetEdgeNoPixelTestDisableIfFarFromOrigin_Begin(&viewport));
#if !__PS3
#if MIRROR_DEV
if (CMirrors::ms_debugMirrorUseHWClipPlane)
#endif // MIRROR_DEV
{
DLC(dlCmdSetClipPlane, (0, CMirrors::GetAdjustedClipPlaneForInteriorWater(CMirrors::GetMirrorPlane())));
DLC(dlCmdSetClipPlaneEnable, (0x1));
}
#endif // !__PS3
CRenderListBuilder::eDrawMode drawMode = (CRenderListBuilder::eDrawMode)0;
bool bForceTechnique = false;
bool bForceLightweight0 = false;
if (bIsUsingWaterReflectionTechnique)
{
DLC(dlCmdShaderFxPushForcedTechnique, (CRenderPhaseWaterReflectionInterface::GetWaterReflectionTechniqueGroupId()));
drawMode = CRenderListBuilder::USE_SIMPLE_LIGHTING;
bForceTechnique = true;
}
else
{
DLC_Add(Lights::BeginLightweightTechniques);
DLC_Add(Lights::SelectLightweightTechniques, 0, false);
drawMode = CRenderListBuilder::USE_FORWARD_LIGHTING;
bForceLightweight0 = true;
}
if (renderSkyMode == CMirrors::MIRROR_RENDER_SKY_MODE_BEFORE_ALPHA)
{
PS3_ONLY(DLC(dlCmdSetCurrentViewport, (&viewport));)
// opaque pass
DLCPushTimebar("Opaque");
RENDERLIST_DUMP_PASS_INFO_BEGIN("CRenderPhaseMirrorReflection - opaque");
CRenderListBuilder::AddToDrawList(
GetEntityListIndex(),
opaqueFilter,
drawMode,//CRenderListBuilder::USE_FORWARD_LIGHTING
SUBPHASE_NONE,
RenderStateSetupMirrorReflection,
RenderStateCleanupMirrorReflection,
RenderStateSetupCustomFlagsChangedMirrorReflection
);
RENDERLIST_DUMP_PASS_INFO_END();
DLCPopTimebar();
PS3_ONLY(DLC(dlCmdSetCurrentViewport, (&g_mirrorReflectionViewportNoObliqueProjection));)
#if !__PS3
#if MIRROR_DEV
if (CMirrors::ms_debugMirrorUseHWClipPlane)
#endif // MIRROR_DEV
{
DLC(dlCmdSetClipPlaneEnable, (0x0));
}
#endif // !__PS3
// Only used when renderSkyVfxMode = CVisualEffects::RM_WATER_REFLECTION or CVisualEffects::RM_MIRROR_REFLECTION (see CVisualEffects::RenderSky()).
D3D11_ONLY(DLC_Add(CVisualEffects::SetTargetsForDX11ReadOnlyDepth, (renderSkyVfxMode == CVisualEffects::RM_WATER_REFLECTION) ? false : true, depthTarget, depthTargetCopy, depthTargetTargetRO));
// sky pass
DLC_Add(CVisualEffects::RenderSky, renderSkyVfxMode, false, bIsUsingRestrictedProjection, -1, -1, -1, -1, true, 1.0f);
D3D11_ONLY(DLC_Add(CVisualEffects::SetTargetsForDX11ReadOnlyDepth, false, (grcRenderTarget *)NULL, (grcRenderTarget *)NULL, (grcRenderTarget *)NULL));
SetupMirrorDepthTarget(bIsUsingMirrorWaterSurface);
#if !__PS3
#if MIRROR_DEV
if (CMirrors::ms_debugMirrorUseHWClipPlane)
#endif // MIRROR_DEV
{
DLC(dlCmdSetClipPlaneEnable, (0x1));
}
#endif // !__PS3
DLC(dlCmdSetCurrentViewport, (&viewport));
// alpha pass
DLCPushTimebar("Alpha/Decals");
RENDERLIST_DUMP_PASS_INFO_BEGIN("CRenderPhaseMirrorReflection - alpha");
CRenderListBuilder::AddToDrawList(
GetEntityListIndex(),
alphaFilter,
drawMode,//CRenderListBuilder::USE_FORWARD_LIGHTING,
SUBPHASE_NONE,
RenderStateSetupMirrorReflection,
RenderStateCleanupMirrorReflection,
RenderStateSetupCustomFlagsChangedMirrorReflection
);
RENDERLIST_DUMP_PASS_INFO_END();
DLCPopTimebar();
PS3_ONLY(DLC(dlCmdSetCurrentViewport, (&g_mirrorReflectionViewportNoObliqueProjection));)
}
else
{
PS3_ONLY(DLC(dlCmdSetCurrentViewport, (&viewport));)
// opaque
DLCPushTimebar("Opaque");
RENDERLIST_DUMP_PASS_INFO_BEGIN("CRenderPhaseMirrorReflection - Opaque");
CRenderListBuilder::AddToDrawList(
GetEntityListIndex(),
opaqueFilter,
drawMode,
SUBPHASE_NONE,
RenderStateSetupMirrorReflection,
RenderStateCleanupMirrorReflection,
RenderStateSetupCustomFlagsChangedMirrorReflection
);
RENDERLIST_DUMP_PASS_INFO_END();
DLCPopTimebar();
SetupMirrorDepthTarget(bIsUsingMirrorWaterSurface);
DLC(dlCmdSetCurrentViewport, (&viewport));
// alpha pass
DLCPushTimebar("Alpha/Decals");
RENDERLIST_DUMP_PASS_INFO_BEGIN("CRenderPhaseMirrorReflection - Alpha/Decals");
CRenderListBuilder::AddToDrawList(
GetEntityListIndex(),
alphaFilter,
drawMode,
SUBPHASE_NONE,
RenderStateSetupMirrorReflection,
RenderStateCleanupMirrorReflection,
RenderStateSetupCustomFlagsChangedMirrorReflection
);
RENDERLIST_DUMP_PASS_INFO_END();
DLCPopTimebar();
PS3_ONLY(DLC(dlCmdSetCurrentViewport, (&g_mirrorReflectionViewportNoObliqueProjection));)
}
#if !__PS3
#if MIRROR_DEV
if (CMirrors::ms_debugMirrorUseHWClipPlane)
#endif // MIRROR_DEV
{
DLC(dlCmdSetClipPlaneEnable, (0x0));
}
#endif // !__PS3
PS3_ONLY(SetEdgeNoPixelTestDisableIfFarFromOrigin_End(bCamDistFarFromOrigin));
DLC_Add(MirrorRestoreDirLighting);
if (bForceTechnique)
{
DLC(dlCmdShaderFxPopForcedTechnique, ());
}
if (bForceLightweight0)
{
DLC_Add(Lights::EndLightweightTechniques);
}
#if MIRROR_DEV
if (CMirrors::ms_debugMirrorWireframe)
{
DLC_Add(grcStateBlock::SetWireframeOverride, false); // restore
}
#endif // MIRROR_DEV
if (renderSkyMode == CMirrors::MIRROR_RENDER_SKY_MODE_LAST)
{
// Only used when renderSkyVfxMode = CVisualEffects::RM_WATER_REFLECTION or CVisualEffects::RM_MIRROR_REFLECTION (see CVisualEffects::RenderSky()).
D3D11_ONLY(DLC_Add(CVisualEffects::SetTargetsForDX11ReadOnlyDepth, (renderSkyVfxMode == CVisualEffects::RM_WATER_REFLECTION) ? false : true, depthTarget, depthTargetCopy, depthTargetTargetRO));
DLC_Add(CVisualEffects::RenderSky, renderSkyVfxMode, false, bIsUsingRestrictedProjection, -1, -1, -1, -1, true, 1.0f);
D3D11_ONLY(DLC_Add(CVisualEffects::SetTargetsForDX11ReadOnlyDepth, false, (grcRenderTarget *)NULL, (grcRenderTarget *)NULL, (grcRenderTarget *)NULL));
}
if (bCanSeeExteriorView && MIRROR_DEV_SWITCH(CMirrors::ms_debugMirrorRenderDistantLights, false))
{
DLC_Add(CVisualEffects::RenderDistantLights, CVisualEffects::RM_MIRROR_REFLECTION, GetRenderFlags(), 1.0f);
}
#if MIRROR_DEV
if (CMirrors::ms_debugMirrorRenderCoronas)
#endif // MIRROR_DEV
{
DLC_Add(CVisualEffects::RenderCoronas, CVisualEffects::RM_MIRROR_REFLECTION, 1.0f, 1.0f);
}
#if MIRROR_USE_STENCIL_MASK
if (CMirrors::ms_debugMirrorStencilMaskEnabled)
{
if (CMirrors::ms_debugMirrorStencilMaskScissor)
{
DLC(dlCmdGrcDeviceDisableScissor, ());
}
#if !__XENON
DLC_Add(CRenderTargets::ReleaseCustomRenderTarget);
#endif // !__XENON
}
else
#endif // MIRROR_USE_STENCIL_MASK
{
#if RSG_ORBIS
DLC_Add(FinishMirrorRendering);
#endif
grcResolveFlags flags;
flags.ClearColor = true;
DLC(dlCmdUnLockRenderTarget, (0, &flags));
#if DEVICE_MSAA
#if RSG_PC
if (bIsUsingMirrorWaterSurface && CRenderPhaseWaterReflection::GetMSAARenderTargetColor())
{
DLC_Add(CRenderPhaseWaterReflection::ResolveMSAA);
}
#endif // #if RSG_PC
if (!bIsUsingMirrorWaterSurface && g_mirrorReflectionEnableMSAA)
{
DLC_Add(CMirrors::ResolveMirrorRenderTarget);
}
#endif //DEVICE_MSAA
}
#if __XENON || __PS3
if (bIsUsingMirrorWaterSurface)
{
if (bIsUsingWaterReflectionTechnique)
{
#if __PS3
DLC_Add(CRenderPhaseReflection::MSAAResolve, Water::GetReflectionRT(), CMirrors::GetMirrorWaterRenderTarget(), 0, 4);
#endif // __PS3
}
else
{
DLC_Add(ConvertToWaterReflectionGamma);
}
}
#endif // __XENON || __PS3
#if RSG_ORBIS
if(bIsUsingMirrorWaterSurface)
DLC_Add(GenerateMips, clearTarget);
#endif
DLC(dlCmdSetCurrentViewportToNULL, ());
if (bForcingLODs)
{
dlDrawListMgr::ResetHighestLOD(false);
}
DLC_Add(CLightGroup::SetLocalLightForwardIntensityScale, 1.0f);
DLC_Add(CShaderLib::SetUseFogRay, true);
//Reset the renderthread copy back to false
DLC_Add(CRenderPhaseMirrorReflectionInterface::SetIsMirrorUsingWaterReflectionTechniqueAndSurface_Render, false, false);
DrawListEpilogue();
}
#if __BANK
void CRenderPhaseMirrorReflection::AddWidgets(bkGroup& group)
{
CMirrors::AddWidgets(group);
group.AddToggle("Debug Draw Mirror", &m_debugDrawMirror);
group.AddSlider("Debug Draw Offset", &m_debugDrawMirrorOffset, -10.0f, 10.0f, 1.0f/64.0f);
#if DEVICE_MSAA && !RSG_PC
// We can't use non-AA reflection with AA depth, so for PC we can't disable MSAA just like that
group.AddToggle("Enable MSAA", &g_mirrorReflectionEnableMSAA);
#endif
#if MIRROR_DEV
group.AddTitle("Alpha-Blending Passes");
group.AddToggle("RPASS_VISIBLE", &g_mirrorReflectionAlphaBlendingPasses, BIT(RPASS_VISIBLE));
group.AddToggle("RPASS_LOD ", &g_mirrorReflectionAlphaBlendingPasses, BIT(RPASS_LOD ));
group.AddToggle("RPASS_CUTOUT ", &g_mirrorReflectionAlphaBlendingPasses, BIT(RPASS_CUTOUT ));
group.AddToggle("RPASS_DECAL ", &g_mirrorReflectionAlphaBlendingPasses, BIT(RPASS_DECAL ));
group.AddToggle("RPASS_FADING ", &g_mirrorReflectionAlphaBlendingPasses, BIT(RPASS_FADING ));
group.AddToggle("RPASS_ALPHA ", &g_mirrorReflectionAlphaBlendingPasses, BIT(RPASS_ALPHA ));
group.AddToggle("RPASS_WATER ", &g_mirrorReflectionAlphaBlendingPasses, BIT(RPASS_WATER ));
group.AddToggle("RPASS_TREE ", &g_mirrorReflectionAlphaBlendingPasses, BIT(RPASS_TREE ));
group.AddTitle("Depth-Writing Passes");
group.AddToggle("RPASS_VISIBLE", &g_mirrorReflectionDepthWritingPasses, BIT(RPASS_VISIBLE));
group.AddToggle("RPASS_LOD ", &g_mirrorReflectionDepthWritingPasses, BIT(RPASS_LOD ));
group.AddToggle("RPASS_CUTOUT ", &g_mirrorReflectionDepthWritingPasses, BIT(RPASS_CUTOUT ));
group.AddToggle("RPASS_DECAL ", &g_mirrorReflectionDepthWritingPasses, BIT(RPASS_DECAL ));
group.AddToggle("RPASS_FADING ", &g_mirrorReflectionDepthWritingPasses, BIT(RPASS_FADING ));
group.AddToggle("RPASS_ALPHA ", &g_mirrorReflectionDepthWritingPasses, BIT(RPASS_ALPHA ));
group.AddToggle("RPASS_WATER ", &g_mirrorReflectionDepthWritingPasses, BIT(RPASS_WATER ));
group.AddToggle("RPASS_TREE ", &g_mirrorReflectionDepthWritingPasses, BIT(RPASS_TREE ));
#endif // MIRROR_DEV
}
#endif // __BANK
__COMMENT(static) const grcViewport* CRenderPhaseMirrorReflectionInterface::GetViewport()
{
return g_mirrorReflectionViewport;
}
__COMMENT(static) const grcViewport* CRenderPhaseMirrorReflectionInterface::GetViewportNoObliqueProjection()
{
return PS3_SWITCH(&g_mirrorReflectionViewportNoObliqueProjection, g_mirrorReflectionViewport);
}
__COMMENT(static) CRenderPhaseScanned* CRenderPhaseMirrorReflectionInterface::GetRenderPhase()
{
return g_mirrorRenderPhase;
}
__COMMENT(static) void CRenderPhaseMirrorReflectionInterface::SetIsMirrorUsingWaterReflectionTechniqueAndSurface_Render(
bool bIsMirrorUsingWaterReflectionTechnique, bool bIsMirrorUsingWaterSurface)
{
g_mirrorReflectionUsingWaterReflectionTechniqueRT = bIsMirrorUsingWaterReflectionTechnique;
g_mirrorReflectionUsingWaterSurfaceRT = bIsMirrorUsingWaterSurface;
}
__COMMENT(static) bool CRenderPhaseMirrorReflectionInterface::GetIsMirrorUsingWaterReflectionTechnique_Render()
{
return g_mirrorReflectionUsingWaterReflectionTechniqueRT;
}
__COMMENT(static) bool CRenderPhaseMirrorReflectionInterface::GetIsMirrorUsingWaterSurface_Render()
{
return g_mirrorReflectionUsingWaterSurfaceRT;
}
#if __XENON
__COMMENT(static) bool CRenderPhaseMirrorReflectionInterface::GetIsMirrorUsingWaterReflectionTechnique_Update()
{
return g_mirrorReflectionUsingWaterReflectionTechnique;
}
#endif // __XENON