Includes a fix to get lights to render more correctly in the reflection pass. Also includes a helper function to force a render from a passed in transform and frustum.

This commit is contained in:
Areloch 2017-07-07 02:55:56 -05:00
parent 412c0380f4
commit 212fc80dfc
4 changed files with 265 additions and 12 deletions

View file

@ -33,6 +33,8 @@
#include "core/module.h"
#include "console/engineAPI.h"
#include "platform/output/IDisplayDevice.h"
#include "postFx/postEffectManager.h"
#include "gfx/gfxTransformSaver.h"
static void RegisterGameFunctions();
static void Process3D();
@ -432,7 +434,197 @@ void GameRenderWorld()
PROFILE_END();
}
//================================================================================================
//Render a full frame from a given transform and frustum, and render out to a target
//================================================================================================
void renderFrame(GFXTextureTargetRef* target, MatrixF transform, Frustum frustum, U32 typeMask, ColorI canvasClearColor)
{
if (!GFX->allowRender() || GFX->canCurrentlyRender())
return;
PROFILE_START(GameFunctions_RenderFrame);
GFX->setActiveRenderTarget(*target);
if (!GFX->getActiveRenderTarget())
return;
GFXTarget* renderTarget = GFX->getActiveRenderTarget();
if (renderTarget == NULL)
return;
// Make sure the root control is the size of the canvas.
Point2I size = renderTarget->getSize();
if (size.x == 0 || size.y == 0)
return;
//Now, getting to the meat of it!
#ifdef TORQUE_GFX_STATE_DEBUG
GFX->getDebugStateManager()->startFrame();
#endif
RectI targetRect(0, 0, size.x, size.y);
// Signal the interested parties.
GuiCanvas::getGuiCanvasFrameSignal().trigger(true);
GFXTransformSaver saver;
// Gross hack to make sure we don't end up with advanced lighting and msaa
// at the same time, which causes artifacts. At the same time we don't
// want to just throw the settings the user has chosen if the light manager
// changes at a later time.
/*GFXVideoMode mode = mPlatformWindow->getVideoMode();
if (dStricmp(LIGHTMGR->getId(), "ADVLM") == 0 && mode.antialiasLevel > 0)
{
const char *pref = Con::getVariable("$pref::Video::mode");
mode.parseFromString(pref);
mode.antialiasLevel = 0;
mPlatformWindow->setVideoMode(mode);
Con::printf("AntiAliasing has been disabled; it is not compatible with AdvancedLighting.");
}
else if (dStricmp(LIGHTMGR->getId(), "BLM") == 0)
{
const char *pref = Con::getVariable("$pref::Video::mode");
U32 prefAA = dAtoi(StringUnit::getUnit(pref, 5, " "));
if (prefAA != mode.antialiasLevel)
{
mode.parseFromString(pref);
mPlatformWindow->setVideoMode(mode);
Con::printf("AntiAliasing has been enabled while running BasicLighting.");
}
}*/
// Begin GFX
PROFILE_START(GameFunctions_RenderFrame_GFXBeginScene);
bool beginSceneRes = GFX->beginScene();
PROFILE_END();
PROFILE_START(GameFunctions_RenderFrame_OffscreenCanvases);
// Render all offscreen canvas objects here since we may need them in the render loop
if (GuiOffscreenCanvas::sList.size() != 0)
{
// Reset the entire state since oculus shit will have barfed it.
GFX->updateStates(true);
for (Vector<GuiOffscreenCanvas*>::iterator itr = GuiOffscreenCanvas::sList.begin(); itr != GuiOffscreenCanvas::sList.end(); itr++)
{
(*itr)->renderFrame(false, false);
}
GFX->setActiveRenderTarget(renderTarget);
}
PROFILE_END();
// Can't render if waiting for device to reset.
if (!beginSceneRes)
{
// Since we already triggered the signal once for begin-of-frame,
// we should be consistent and trigger it again for end-of-frame.
GuiCanvas::getGuiCanvasFrameSignal().trigger(false);
return;
}
// Clear the current viewport area
GFX->setViewport(targetRect);
GFX->clear(GFXClearZBuffer | GFXClearStencil | GFXClearTarget, canvasClearColor, 1.0f, 0);
// Make sure we have a clean matrix state
// before we start rendering anything!
GFX->setWorldMatrix(MatrixF::Identity);
GFX->setViewMatrix(MatrixF::Identity);
GFX->setProjectionMatrix(MatrixF::Identity);
{
GFXStateBlockDesc d;
d.cullDefined = true;
d.cullMode = GFXCullNone;
d.zDefined = true;
d.zEnable = false;
GFXStateBlockRef mDefaultGuiSB = GFX->createStateBlock(d);
GFX->setClipRect(targetRect);
GFX->setStateBlock(mDefaultGuiSB);
GFXTargetRef origTarget = GFX->getActiveRenderTarget();
U32 origStyle = GFX->getCurrentRenderStyle();
// Clear the zBuffer so GUI doesn't hose object rendering accidentally
GFX->clear(GFXClearZBuffer, ColorI(20, 20, 20), 1.0f, 0);
GFX->setFrustum(frustum);
MatrixF mSaveProjection = GFX->getProjectionMatrix();
// We're going to be displaying this render at size of this control in
// pixels - let the scene know so that it can calculate e.g. reflections
// correctly for that final display result.
gClientSceneGraph->setDisplayTargetResolution(size);
// Set the GFX world matrix to the world-to-camera transform, but don't
// change the cameraMatrix in mLastCameraQuery. This is because
// mLastCameraQuery.cameraMatrix is supposed to contain the camera-to-world
// transform. In-place invert would save a copy but mess up any GUIs that
// depend on that value.
CameraQuery camera;
GameProcessCameraQuery(&camera);
MatrixF worldToCamera = transform;
RotationF tranRot = RotationF(transform);
EulerF trf = tranRot.asEulerF(RotationF::Degrees);
Point3F pos = transform.getPosition();
GFX->setWorldMatrix(worldToCamera);
mSaveProjection = GFX->getProjectionMatrix();
MatrixF mSaveModelview = GFX->getWorldMatrix();
Point2F mSaveWorldToScreenScale = GFX->getWorldToScreenScale();
Frustum mSaveFrustum = GFX->getFrustum();
mSaveFrustum.setTransform(transform);
// Set the default non-clip projection as some
// objects depend on this even in non-reflect cases.
gClientSceneGraph->setNonClipProjection(mSaveProjection);
// Give the post effect manager the worldToCamera, and cameraToScreen matrices
PFXMGR->setFrameMatrices(mSaveModelview, mSaveProjection);
//renderWorld(guiViewport);
PROFILE_START(GameFunctions_RenderFrame_RenderWorld);
FrameAllocator::setWaterMark(0);
gClientSceneGraph->renderScene(SPT_Reflect, typeMask);
// renderScene leaves some states dirty, which causes problems if GameTSCtrl is the last Gui object rendered
GFX->updateStates();
AssertFatal(FrameAllocator::getWaterMark() == 0,
"Error, someone didn't reset the water mark on the frame allocator!");
FrameAllocator::setWaterMark(0);
PROFILE_END();
}
PROFILE_START(GameFunctions_RenderFrame_GFXEndScene);
GFX->endScene();
PROFILE_END();
#ifdef TORQUE_GFX_STATE_DEBUG
GFX->getDebugStateManager()->endFrame();
#endif
saver.restore();
PROFILE_END();
}
//================================================================================================
static void Process3D()
{
MATMGR->updateTime();

View file

@ -29,6 +29,15 @@
#ifndef _MMATRIX_H_
#include "math/mMatrix.h"
#endif
#ifndef _GFXTARGET_H_
#include "gfx/gfxTarget.h"
#endif
#ifndef _MATHUTIL_FRUSTUM_H_
#include "math/util/frustum.h"
#endif
#ifndef _COLOR_H_
#include "core/color.h"
#endif
struct CameraQuery;
@ -37,6 +46,10 @@ struct CameraQuery;
/// scene ONLY - new guis, no damage flashes.
void GameRenderWorld();
/// Does a full, top-to-bottom call to render a frame. This does all the setup to make a render happen
/// Allowing setting of a intended render target, a view transform, the view frustum, resolution, objects-to-render typemask, and the clear color
void renderFrame(GFXTextureTargetRef* target, MatrixF transform, Frustum frustum, U32 typeMask, ColorI canvasClearColor);
/// Renders overlays such as damage flashes, white outs, and water masks.
/// These are usually a color applied over the entire screen.
void GameRenderFilters(const CameraQuery& camq);

View file

@ -267,7 +267,7 @@ void AdvancedLightBinManager::render( SceneRenderState *state )
sgData.init( state );
// There are cases where shadow rendering is disabled.
const bool disableShadows = state->isReflectPass() || ShadowMapPass::smDisableShadows;
const bool disableShadows = /*state->isReflectPass() || */ShadowMapPass::smDisableShadows;
// Pick the right material for rendering the sunlight... we only
// cast shadows when its enabled and we're not in a reflection.
@ -300,6 +300,8 @@ void AdvancedLightBinManager::render( SceneRenderState *state )
GFX->setVertexBuffer( mFarFrustumQuadVerts );
GFX->setPrimitiveBuffer( NULL );
vectorMatInfo->matInstance->mSpecialLight = true;
// Render the material passes
while( vectorMatInfo->matInstance->setupPass( state, sgData ) )
{
@ -337,6 +339,8 @@ void AdvancedLightBinManager::render( SceneRenderState *state )
lsp->getOcclusionQuery()->begin();
curLightMat->matInstance->mSpecialLight = false;
// Render the material passes
while( curLightMat->matInstance->setupPass( state, sgData ) )
{
@ -497,6 +501,17 @@ void AdvancedLightBinManager::_setupPerFrameParameters( const SceneRenderState *
farPlane,
vsFarPlane);
}
MatrixSet &matrixSet = getRenderPass()->getMatrixSet();
//matrixSet.restoreSceneViewProjection();
const MatrixF &worldToCameraXfm = matrixSet.getWorldToCamera();
MatrixF inverseViewMatrix = worldToCameraXfm;
//inverseViewMatrix.fullInverse();
//inverseViewMatrix.transpose();
//MatrixF inverseViewMatrix = MatrixF::Identity;
}
void AdvancedLightBinManager::setupSGData( SceneData &data, const SceneRenderState* state, LightInfo *light )
@ -747,6 +762,10 @@ bool LightMatInstance::setupPass( SceneRenderState *state, const SceneData &sgDa
mProcessedMaterial->getNumPasses() == 0 )
return false;
U32 reflectStatus = Base;
if (state->isReflectPass())
reflectStatus = Reflecting;
// Fetch the lightmap params
const LightMapParams *lmParams = sgData.lights[0]->getExtended<LightMapParams>();
@ -795,14 +814,21 @@ bool LightMatInstance::setupPass( SceneRenderState *state, const SceneData &sgDa
{
// If this is not an internal pass, and this light is represented in lightmaps
// than only effect non-lightmapped geometry for this pass
if(lmParams->representedInLightmap)
GFX->setStateBlock(mLitState[StaticLightNonLMGeometry]);
if (lmParams->representedInLightmap)
{
GFX->setStateBlock(mLitState[StaticLightNonLMGeometry][reflectStatus]);
}
else // This is a normal, dynamic light.
GFX->setStateBlock(mLitState[DynamicLight]);
{
if (mSpecialLight)
GFX->setStateBlock(mLitState[SunLight][reflectStatus]);
else
GFX->setStateBlock(mLitState[DynamicLight][reflectStatus]);
}
}
else // Internal pass, this is the add-specular/multiply-darken-color pass
GFX->setStateBlock(mLitState[StaticLightLMGeometry]);
GFX->setStateBlock(mLitState[StaticLightLMGeometry][reflectStatus]);
return bRetVal;
}
@ -832,17 +858,32 @@ bool LightMatInstance::init( const FeatureSet &features, const GFXVertexFormat *
//DynamicLight State: This will effect lightmapped and non-lightmapped geometry
// in the same way.
litState.separateAlphaBlendDefined = true;
litState.separateAlphaBlendEnable = false;
litState.stencilMask = RenderDeferredMgr::OpaqueDynamicLitMask | RenderDeferredMgr::OpaqueStaticLitMask;
mLitState[DynamicLight] = GFX->createStateBlock(litState);
litState.setCullMode(GFXCullCW);
mLitState[DynamicLight][Base] = GFX->createStateBlock(litState);
litState.setCullMode(GFXCullCCW);
mLitState[DynamicLight][Reflecting] = GFX->createStateBlock(litState);
litState.separateAlphaBlendDefined = true;
litState.separateAlphaBlendEnable = false;
litState.stencilMask = RenderDeferredMgr::OpaqueDynamicLitMask | RenderDeferredMgr::OpaqueStaticLitMask;
litState.setCullMode(GFXCullCCW);
mLitState[SunLight][Base] = GFX->createStateBlock(litState);
litState.setCullMode(GFXCullCCW);
mLitState[SunLight][Reflecting] = GFX->createStateBlock(litState);
// StaticLightNonLMGeometry State: This will treat non-lightmapped geometry
// in the usual way, but will not effect lightmapped geometry.
litState.separateAlphaBlendDefined = true;
litState.separateAlphaBlendEnable = false;
litState.stencilMask = RenderDeferredMgr::OpaqueDynamicLitMask;
mLitState[StaticLightNonLMGeometry] = GFX->createStateBlock(litState);
litState.setCullMode(GFXCullCW);
mLitState[StaticLightNonLMGeometry][Base] = GFX->createStateBlock(litState);
litState.setCullMode(GFXCullCCW);
mLitState[StaticLightNonLMGeometry][Reflecting] = GFX->createStateBlock(litState);
// StaticLightLMGeometry State: This will add specular information (alpha) but
// multiply-darken color information.
@ -854,7 +895,10 @@ bool LightMatInstance::init( const FeatureSet &features, const GFXVertexFormat *
litState.separateAlphaBlendSrc = GFXBlendOne;
litState.separateAlphaBlendDest = GFXBlendOne;
litState.separateAlphaBlendOp = GFXBlendOpAdd;
mLitState[StaticLightLMGeometry] = GFX->createStateBlock(litState);
litState.setCullMode(GFXCullCW);
mLitState[StaticLightLMGeometry][Base] = GFX->createStateBlock(litState);
litState.setCullMode(GFXCullCCW);
mLitState[StaticLightLMGeometry][Reflecting] = GFX->createStateBlock(litState);
return true;
}

View file

@ -60,19 +60,23 @@ protected:
enum
{
DynamicLight = 0,
SunLight,
StaticLightNonLMGeometry,
StaticLightLMGeometry,
NUM_LIT_STATES
NUM_LIT_STATES,
Base = 0,
Reflecting = 1
};
GFXStateBlockRef mLitState[NUM_LIT_STATES];
GFXStateBlockRef mLitState[NUM_LIT_STATES][2];
public:
LightMatInstance(Material &mat) : Parent(mat), mLightMapParamsSC(NULL), mInternalPass(false) {}
virtual bool init( const FeatureSet &features, const GFXVertexFormat *vertexFormat );
virtual bool setupPass( SceneRenderState *state, const SceneData &sgData );
};
bool mSpecialLight;
};
class AdvancedLightBinManager : public RenderTexTargetBinManager
{