Added deferred fallback mode, which renders the G-buffer in 2 passes.
Made the OpenGL extensions mandatory to unify expected functionality with Direct3D9 mode.
This commit is contained in:
parent
1e086c84f6
commit
fe495f6bcc
@ -1,5 +1,6 @@
|
||||
<technique>
|
||||
<pass name="gbuffer" vs="GBuffer" ps="GBuffer_Diff" />
|
||||
<pass name="gbuffer2" vs="GBuffer" ps="GBuffer_DiffPass2" depthwrite="false" />
|
||||
<pass name="base" vs="Forward" ps="Forward_DiffAmbient" />
|
||||
<pass name="litbase" vs="Forward" ps="Forward_DiffAmbient" />
|
||||
<pass name="light" vs="Forward" ps="Forward_Diff" depthwrite="false" blend="add" />
|
||||
|
@ -1,5 +1,6 @@
|
||||
<technique>
|
||||
<pass name="gbuffer" vs="GBuffer" ps="GBuffer_DiffMask" alphamask="true" />
|
||||
<pass name="gbuffer2" vs="GBuffer" ps="GBuffer_DiffMaskPass2" alphamask="true" depthwrite="false" />
|
||||
<pass name="base" vs="Forward" ps="Forward_DiffAmbient" alphatest="true" />
|
||||
<pass name="litbase" vs="Forward" ps="Forward_DiffAmbient" alphatest="true" />
|
||||
<pass name="light" vs="Forward" ps="Forward_Diff" alphatest="true" depthwrite="false" blend="add" />
|
||||
|
@ -1,5 +1,6 @@
|
||||
<technique>
|
||||
<pass name="gbuffer" vs="GBuffer_Normal" ps="GBuffer_DiffNormal" />
|
||||
<pass name="gbuffer2" vs="GBuffer_Normal" ps="GBuffer_DiffNormalPass2" depthwrite="false" />
|
||||
<pass name="base" vs="Forward" ps="Forward_DiffAmbient" />
|
||||
<pass name="litbase" vs="Forward_Normal" ps="Forward_DiffNormalAmbient" />
|
||||
<pass name="light" vs="Forward_Normal" ps="Forward_DiffNormal" depthwrite="false" blend="add" />
|
||||
|
@ -1,4 +1,6 @@
|
||||
<technique>
|
||||
<pass name="gbuffer" vs="GBuffer_Normal" ps="GBuffer_DiffNormalMask" alphamask="true" />
|
||||
<pass name="gbuffer2" vs="GBuffer_Normal" ps="GBuffer_DiffNormalMaskPass2" alphamask="true" depthwrite="false" />
|
||||
<pass name="base" vs="Forward" ps="Forward_DiffAmbient" alphatest="true" />
|
||||
<pass name="litbase" vs="Forward_Normal" ps="Forward_DiffNormalAmbient" alphatest="true" />
|
||||
<pass name="light" vs="Forward_Normal" ps="Forward_DiffNormal" alphatest="true" depthwrite="false" blend="add" />
|
||||
|
@ -1,5 +1,6 @@
|
||||
<technique>
|
||||
<pass name="gbuffer" vs="GBuffer" ps="GBuffer" />
|
||||
<pass name="gbuffer2" vs="GBuffer" ps="GBuffer_Pass2" depthwrite="false" />
|
||||
<pass name="base" vs="Forward" ps="Forward_Ambient" />
|
||||
<pass name="litbase" vs="Forward" ps="Forward_Ambient" />
|
||||
<pass name="light" vs="Forward" ps="Forward" depthwrite="false" blend="add" />
|
||||
|
@ -29,7 +29,7 @@ To actually make Urho3D.exe do something useful, it must be supplied with the na
|
||||
|
||||
\page Running Running Urho3D
|
||||
|
||||
For Windows & Direct3D9 mode, Urho3D requires Windows XP or newer, DirectX 9.0c, and a display adapter with SM2.0 support. SM3.0 is highly recommended. For OpenGL mode, an OpenGL 2.0 capable display adapter is required as a minimum; shadows and deferred rendering additionally require the frame buffer object and packed depth stencil extensions.
|
||||
For Windows & Direct3D9 mode, Urho3D requires Windows XP or newer, DirectX 9.0c, and a display adapter with SM2.0 support. SM3.0 is highly recommended. For OpenGL mode, an OpenGL 2.0 capable display adapter with EXT_framebuffer_object and EXT_packed_depth_stencil extensions is required.
|
||||
|
||||
The main executable Urho3D.exe in the Bin directory contains all the engine runtime functionality. However, it does not contain any inbuilt logic or application, and therefore must be supplied with the name of the application script file it should run:
|
||||
|
||||
@ -121,7 +121,7 @@ Urho3D.exe understands the following command line options:
|
||||
\endverbatim
|
||||
|
||||
(*) Only forward rendering supports hardware multisampling. In deferred rendering temporal antialiasing will be used instead.
|
||||
(**) Relevant only on Direct3D9
|
||||
(**) Relevant only on Direct3D9.
|
||||
|
||||
|
||||
\page Structure Overall structure
|
||||
|
@ -373,9 +373,9 @@ Screen resolution, fullscreen/windowed, vertical sync, forward/deferred mode, an
|
||||
|
||||
When setting the initial screen mode, Graphics does a few checks:
|
||||
|
||||
- For Direct3D9, it checks which shader model is supported. 2.0 is minimum, but 3.0 will be used if available. %Shader model 2.0 can be forced by calling \ref Graphics::SetForceSM2() "SetForceSM2()" before calling SetMode() for the first time.
|
||||
- For OpenGL, version 2.0 is required as a minimum. Shadows and deferred rendering additionally require the frame buffer object and packed depth stencil extensions.
|
||||
- Are multiple render targets supported? If not, only forward rendering will be available.
|
||||
- For Direct3D9, the supported shader model is checked. 2.0 is minimum, but 3.0 will be used if available. %Shader model 2.0 can be forced by calling \ref Graphics::SetForceSM2() "SetForceSM2()" before calling SetMode() for the first time.
|
||||
- For OpenGL, version 2.0 with EXT_framebuffer_object and EXT_packed_depth_stencil is checked for.
|
||||
- Are multiple render targets supported? If not, a fallback mode for deferred rendering (use 2 passes for the G-buffer, do not render specular lighting) is chosen.
|
||||
- Are hardware shadow maps supported? Both ATI & NVIDIA style shadow maps can be used. If neither are available, a fallback mode with non-filtered shadows will be chosen instead.
|
||||
|
||||
\section Rendering_Renderer Renderer
|
||||
@ -442,9 +442,9 @@ For details on how Direct3D9 and OpenGL rendering differs, see \ref APIDifferenc
|
||||
|
||||
- Shader resources are stored in different locations depending on the API: CoreData/Shaders/SM2 or CoreData/Shaders/SM3 on Direct3D9, and CoreData/Shaders/GLSL for OpenGL.
|
||||
|
||||
- In deferred rendering, OpenGL does not need to allocate a separate render target for linear depth. Instead the hardware depth buffer will be read directly, and linear depth will be reconstructed in the pixel shader. This results in less GPU memory bandwidth needed, but can introduce inaccuracy to depth calculations.
|
||||
- In deferred rendering, OpenGL does not need to allocate a separate render target for linear depth. Instead the hardware depth buffer will be read directly, and linear depth will be reconstructed in the pixel shader. Direct3D9 will behave similarly if the INTZ depth format is supported.
|
||||
|
||||
- On OpenGL there is never a "device lost" condition, which would cause dynamic textures or vertex/index buffers to lose their contents. However, when the screen mode is changed, the context (along with all GPU resources) will be manually destroyed and recreated. This would be strictly necessary only when changing the multisampling mode, but as bugs may otherwise occur with some GPU drivers, it is best to do for any mode change.
|
||||
- On OpenGL there is never a "device lost" condition, which would cause dynamic textures or vertex/index buffers to lose their contents. However, when the screen mode is changed, the context (along with all GPU resources) will be manually destroyed and recreated. This would be strictly necessary only when changing the multisampling mode, but as bugs may otherwise occur with some GPU drivers, it is best to do for any mode change.
|
||||
|
||||
- At least for now, instancing is not supported for OpenGL. It still benefits from the instance group rendering loop, which only changes the model transform for each object with the same material and light, instead of setting the whole renderstate.
|
||||
|
||||
@ -638,9 +638,16 @@ Opaque objects are rendered to the G-buffer first, then an initial full-screen q
|
||||
|
||||
After light accumulation, emissive properties of materials as well as effects like environment mapping need to be rendered in an additional pass for objects that need them.
|
||||
|
||||
\section ForwardDeferred_Fallback Fallback deferred rendering
|
||||
|
||||
If multiple render targets are not available on Direct3D9, a fallback G-buffer format is used for deferred rendering. It is rendered in two separate passes, and as there is no room for specular properties, specular lighting calculations are omitted:
|
||||
|
||||
- %Pass 1: diffuse albedo and high bits of depth (D3DFMT_A8R8G8B8)
|
||||
- %Pass 2: world-space normal and low bits of depth (D3DFMT_A8R8G8B8)
|
||||
|
||||
\section ForwardDeferred_DeferredAntiAlias Deferred antialiasing
|
||||
|
||||
As actual hardware multisampling is incompatible with deferred rendering, a temporal antialiasing post-process filter will be used instead. Depending on the GPU speed, this has a low-to-moderate performance impact.
|
||||
As actual hardware multisampling is incompatible with deferred rendering, a temporal antialiasing post-process filter will be used instead. Depending on the GPU speed, this has a low-to-moderate performance impact. RGB value minimum/maximum clamping will be used to eliminate or reduce ghosting artifacts, but some ghosting can nevertheless appear if both the camera and objects move.
|
||||
|
||||
\section ForwardDeferred_Conclusion Conclusion
|
||||
|
||||
|
@ -1984,7 +1984,6 @@ Properties:<br>
|
||||
- bool deviceLost (readonly)
|
||||
- uint numPrimitives (readonly)
|
||||
- uint numBatches (readonly)
|
||||
- bool renderTargetSupport (readonly)
|
||||
- bool fallback (readonly)
|
||||
- bool sm3Support (readonly)
|
||||
- bool hardwareShadowSupport (readonly)
|
||||
|
@ -716,7 +716,6 @@ static void RegisterGraphics(asIScriptEngine* engine)
|
||||
engine->RegisterObjectMethod("Graphics", "bool get_deviceLost() const", asMETHOD(Graphics, IsDeviceLost), asCALL_THISCALL);
|
||||
engine->RegisterObjectMethod("Graphics", "uint get_numPrimitives() const", asMETHOD(Graphics, GetNumPrimitives), asCALL_THISCALL);
|
||||
engine->RegisterObjectMethod("Graphics", "uint get_numBatches() const", asMETHOD(Graphics, GetNumBatches), asCALL_THISCALL);
|
||||
engine->RegisterObjectMethod("Graphics", "bool get_renderTargetSupport() const", asMETHOD(Graphics, GetRenderTargetSupport), asCALL_THISCALL);
|
||||
engine->RegisterObjectMethod("Graphics", "bool get_fallback() const", asMETHOD(Graphics, GetFallback), asCALL_THISCALL);
|
||||
engine->RegisterObjectMethod("Graphics", "bool get_sm3Support() const", asMETHOD(Graphics, GetSM3Support), asCALL_THISCALL);
|
||||
engine->RegisterObjectMethod("Graphics", "bool get_hardwareShadowSupport() const", asMETHOD(Graphics, GetHardwareShadowSupport), asCALL_THISCALL);
|
||||
|
@ -2223,7 +2223,7 @@ void Graphics::CreateRenderTargets()
|
||||
normalBuffer_->SetSize(0, 0, GetRGBAFormat(), TEXTURE_RENDERTARGET);
|
||||
}
|
||||
|
||||
if (!depthBuffer_)
|
||||
if (!depthBuffer_ && !fallback_)
|
||||
{
|
||||
depthBuffer_ = new Texture2D(context_);
|
||||
if (!hardwareDepthSupport_)
|
||||
|
@ -173,6 +173,7 @@ enum TextureUsage
|
||||
enum PassType
|
||||
{
|
||||
PASS_GBUFFER,
|
||||
PASS_GBUFFER2,
|
||||
PASS_BASE,
|
||||
PASS_LITBASE,
|
||||
PASS_LIGHT,
|
||||
|
@ -129,14 +129,12 @@ Graphics::Graphics(Context* context_) :
|
||||
vsync_(false),
|
||||
tripleBuffer_(false),
|
||||
flushGPU_(true),
|
||||
renderTargetSupport_(false),
|
||||
deferredSupport_(false),
|
||||
numPrimitives_(0),
|
||||
numBatches_(0),
|
||||
immediateVertexCount_(0),
|
||||
defaultTextureFilterMode_(FILTER_BILINEAR),
|
||||
shadowMapFormat_(0),
|
||||
hiresShadowMapFormat_(0),
|
||||
shadowMapFormat_(GL_DEPTH_COMPONENT16),
|
||||
hiresShadowMapFormat_(GL_DEPTH_COMPONENT24),
|
||||
shaderParameterFrame_(0)
|
||||
{
|
||||
ResetCachedState();
|
||||
@ -247,13 +245,19 @@ bool Graphics::SetMode(RenderMode mode, int width, int height, bool fullscreen,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_GLEE_EXT_framebuffer_object || !_GLEE_EXT_packed_depth_stencil)
|
||||
{
|
||||
LOGERROR("EXT_framebuffer_object and EXT_packed_depth_stencil OpenGL extensions are required");
|
||||
glfwCloseWindow(impl_->window_);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set window close callback
|
||||
glfwSetWindowCloseCallback(CloseCallback);
|
||||
|
||||
// Associate GLFW window with the execution context
|
||||
SetWindowContext(impl_->window_, context_);
|
||||
}
|
||||
|
||||
|
||||
// Set vsync
|
||||
glfwSwapInterval(vsync ? 1 : 0);
|
||||
@ -262,17 +266,8 @@ bool Graphics::SetMode(RenderMode mode, int width, int height, bool fullscreen,
|
||||
glGetIntegerv(GL_DEPTH_BITS, &impl_->windowDepthBits_);
|
||||
impl_->depthBits_ = impl_->windowDepthBits_;
|
||||
|
||||
// Create the FBO if fully supported
|
||||
if (_GLEE_EXT_framebuffer_object && _GLEE_EXT_packed_depth_stencil)
|
||||
{
|
||||
glGenFramebuffersEXT(1, &impl_->fbo_);
|
||||
|
||||
// Shadows, render targets and deferred rendering all depend on FBO & packed depth stencil
|
||||
shadowMapFormat_ = GL_DEPTH_COMPONENT16;
|
||||
hiresShadowMapFormat_ = GL_DEPTH_COMPONENT24;
|
||||
renderTargetSupport_ = true;
|
||||
deferredSupport_ = true;
|
||||
}
|
||||
// Create the FBO
|
||||
glGenFramebuffersEXT(1, &impl_->fbo_);
|
||||
|
||||
// Set initial state to match Direct3D
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
@ -1180,7 +1175,7 @@ void Graphics::ResetDepthStencil()
|
||||
|
||||
void Graphics::SetRenderTarget(unsigned index, RenderSurface* renderTarget)
|
||||
{
|
||||
if (index >= MAX_RENDERTARGETS || !impl_->fbo_)
|
||||
if (index >= MAX_RENDERTARGETS)
|
||||
return;
|
||||
|
||||
if (renderTarget != renderTargets_[index])
|
||||
@ -1257,7 +1252,7 @@ void Graphics::SetRenderTarget(unsigned index, Texture2D* renderTexture)
|
||||
|
||||
void Graphics::SetDepthStencil(RenderSurface* depthStencil)
|
||||
{
|
||||
if (impl_->fbo_ && depthStencil != depthStencil_)
|
||||
if (depthStencil != depthStencil_)
|
||||
{
|
||||
// If we are using a rendertarget texture, it is required in OpenGL to also have an own depth stencil
|
||||
// Create a new depth stencil texture as necessary to be able to provide similar behaviour.
|
||||
|
@ -241,8 +241,6 @@ public:
|
||||
unsigned GetShadowMapFormat() const { return shadowMapFormat_; }
|
||||
/// Return 24-bit shadow map depth texture format, or 0 if not supported.
|
||||
unsigned GetHiresShadowMapFormat() const { return hiresShadowMapFormat_; }
|
||||
/// Return whether texture render targets are supported.
|
||||
bool GetRenderTargetSupport() const { return renderTargetSupport_; }
|
||||
/// Return whether fallback shaders are required. Always false on OpenGL.
|
||||
bool GetFallback() const { return false; }
|
||||
/// Return whether Shader Model 3 is supported. Always false on OpenGL.
|
||||
@ -402,10 +400,6 @@ private:
|
||||
bool tripleBuffer_;
|
||||
/// Flush GPU command queue flag.
|
||||
bool flushGPU_;
|
||||
/// Texture render target support flag.
|
||||
bool renderTargetSupport_;
|
||||
/// Deferred rendering support flag.
|
||||
bool deferredSupport_;
|
||||
/// Number of primitives this frame.
|
||||
unsigned numPrimitives_;
|
||||
/// Number of batches this frame.
|
||||
|
@ -87,8 +87,6 @@ bool RenderSurface::CreateRenderBuffer(unsigned width, unsigned height, unsigned
|
||||
Graphics* graphics = parentTexture_->GetGraphics();
|
||||
if (!graphics)
|
||||
return false;
|
||||
if (!graphics->GetRenderTargetSupport())
|
||||
return false;
|
||||
|
||||
Release();
|
||||
|
||||
|
@ -149,9 +149,6 @@ bool Texture2D::SetSize(int width, int height, unsigned format, TextureUsage usa
|
||||
|
||||
if (usage >= TEXTURE_RENDERTARGET)
|
||||
{
|
||||
if (!graphics_->GetRenderTargetSupport())
|
||||
return false;
|
||||
|
||||
renderSurface_ = new RenderSurface(this, GL_TEXTURE_2D);
|
||||
dynamic_ = true;
|
||||
|
||||
|
@ -763,12 +763,9 @@ void Renderer::ResetViews()
|
||||
|
||||
bool Renderer::AddView(RenderSurface* renderTarget, const Viewport& viewport)
|
||||
{
|
||||
// If using a render target texture, make sure it is supported, and will not be rendered to multiple times
|
||||
// If using a render target texture, make sure it will not be rendered to multiple times
|
||||
if (renderTarget)
|
||||
{
|
||||
if (!graphics_->GetRenderTargetSupport())
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < numViews_; ++i)
|
||||
{
|
||||
if (views_[i]->GetRenderTarget() == renderTarget)
|
||||
@ -1004,7 +1001,8 @@ void Renderer::SetLightVolumeShaders(Batch& batch)
|
||||
if (light->GetShadowMap())
|
||||
psi += DLPS_SHADOW;
|
||||
|
||||
if (specularLighting_ && light->GetSpecularIntensity() > 0.0f)
|
||||
// Deferred fallback mode does not support specular
|
||||
if (specularLighting_ && light->GetSpecularIntensity() > 0.0f && !graphics_->GetFallback())
|
||||
psi += DLPS_SPEC;
|
||||
|
||||
if (batch.camera_->IsOrthographic())
|
||||
@ -1042,18 +1040,27 @@ void Renderer::LoadShaders()
|
||||
lightPS_.Resize(MAX_DEFERRED_LIGHT_PS_VARIATIONS);
|
||||
|
||||
unsigned shadows = (graphics_->GetHardwareShadowSupport() ? 1 : 0) | (shadowQuality_ & SHADOWQUALITY_HIGH_16BIT);
|
||||
unsigned fallback = graphics_->GetFallback() ? 1 : 0;
|
||||
if (fallback)
|
||||
shadows = SHADOWQUALITY_HIGH_16BIT;
|
||||
|
||||
for (unsigned i = 0; i < MAX_DEFERRED_LIGHT_VS_VARIATIONS; ++i)
|
||||
lightVS_[i] = GetVertexShader("Light_" + deferredLightVSVariations[i]);
|
||||
|
||||
for (unsigned i = 0; i < MAX_DEFERRED_LIGHT_PS_VARIATIONS; ++i)
|
||||
{
|
||||
unsigned linear = !graphics_->GetHardwareDepthSupport() && i < DLPS_ORTHO ? 1 : 0;
|
||||
unsigned linear = fallback == 0 && !graphics_->GetHardwareDepthSupport() && i < DLPS_ORTHO ? 1 : 0;
|
||||
|
||||
if (i & DLPS_SHADOW)
|
||||
lightPS_[i] = GetPixelShader("Light_" + linearVariations[linear] + lightPSVariations[i] + shadowVariations[shadows]);
|
||||
{
|
||||
lightPS_[i] = GetPixelShader("Light_" + linearVariations[linear] + lightPSVariations[i] +
|
||||
shadowVariations[shadows] + fallbackVariations[fallback]);
|
||||
}
|
||||
else
|
||||
lightPS_[i] = GetPixelShader("Light_" + linearVariations[linear] + lightPSVariations[i]);
|
||||
{
|
||||
lightPS_[i] = GetPixelShader("Light_" + linearVariations[linear] + lightPSVariations[i] +
|
||||
fallbackVariations[fallback]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1078,7 +1085,11 @@ void Renderer::LoadMaterialShaders(Technique* technique)
|
||||
else
|
||||
{
|
||||
if (technique->HasPass(PASS_GBUFFER))
|
||||
{
|
||||
LoadPassShaders(technique, PASS_GBUFFER);
|
||||
if (graphics_->GetFallback())
|
||||
LoadPassShaders(technique, PASS_GBUFFER2);
|
||||
}
|
||||
else
|
||||
{
|
||||
LoadPassShaders(technique, PASS_BASE);
|
||||
@ -1106,12 +1117,17 @@ void Renderer::LoadPassShaders(Technique* technique, PassType type, bool allowSh
|
||||
|
||||
unsigned shadows = (graphics_->GetHardwareShadowSupport() ? 1 : 0) | (shadowQuality_ & SHADOWQUALITY_HIGH_16BIT);
|
||||
unsigned fallback = graphics_->GetFallback() ? 1 : 0;
|
||||
if (fallback)
|
||||
shadows = SHADOWQUALITY_HIGH_16BIT;
|
||||
|
||||
// If INTZ depth is used, do not write depth into a rendertarget in the G-buffer pass
|
||||
if (type == PASS_GBUFFER)
|
||||
if (type == PASS_GBUFFER || type == PASS_GBUFFER2)
|
||||
{
|
||||
unsigned depth = graphics_->GetHardwareDepthSupport() ? 0 : 1;
|
||||
pixelShaderName += depthVariations[depth];
|
||||
if (fallback)
|
||||
pixelShaderName += fallbackVariations[fallback];
|
||||
else
|
||||
pixelShaderName += depthVariations[depth];
|
||||
}
|
||||
|
||||
if (type == PASS_SHADOW)
|
||||
|
@ -34,6 +34,7 @@
|
||||
static const String passNames[] =
|
||||
{
|
||||
"gbuffer",
|
||||
"gbuffer2",
|
||||
"base",
|
||||
"litbase",
|
||||
"light",
|
||||
|
@ -177,6 +177,7 @@ void View::Update(const FrameInfo& frame)
|
||||
occluders_.Clear();
|
||||
shadowOccluders_.Clear();
|
||||
gBufferQueue_.Clear();
|
||||
gBuffer2Queue_.Clear();
|
||||
baseQueue_.Clear();
|
||||
extraQueue_.Clear();
|
||||
transparentQueue_.Clear();
|
||||
@ -393,6 +394,8 @@ void View::GetBatches()
|
||||
maxLightsDrawables_.Clear();
|
||||
lightQueueIndex_.Clear();
|
||||
|
||||
bool fallback = graphics_->GetFallback();
|
||||
|
||||
// Go through lights
|
||||
{
|
||||
PROFILE_MULTIPLE(GetLightBatches, lights_.Size());
|
||||
@ -577,6 +580,17 @@ void View::GetBatches()
|
||||
baseBatch.hasPriority_ = !pass->GetAlphaTest() && !pass->GetAlphaMask();
|
||||
gBufferQueue_.AddBatch(baseBatch);
|
||||
|
||||
// In fallback mode, add also G-buffer second pass batch
|
||||
if (fallback)
|
||||
{
|
||||
pass = tech->GetPass(PASS_GBUFFER2);
|
||||
if (pass)
|
||||
{
|
||||
renderer_->SetBatchShaders(baseBatch, tech, pass);
|
||||
gBuffer2Queue_.AddBatch(baseBatch);
|
||||
}
|
||||
}
|
||||
|
||||
// Check also for an additional pass (possibly for emissive)
|
||||
pass = tech->GetPass(PASS_EXTRA);
|
||||
if (pass)
|
||||
@ -775,6 +789,8 @@ void View::RenderBatchesDeferred()
|
||||
Texture2D* normalBuffer = graphics_->GetNormalBuffer();
|
||||
Texture2D* depthBuffer = graphics_->GetDepthBuffer();
|
||||
|
||||
bool fallback = graphics_->GetFallback();
|
||||
|
||||
// Check for temporal antialiasing in deferred mode. Only use it on the main view (null rendertarget)
|
||||
bool temporalAA = (!renderTarget_) && (graphics_->GetMultiSample() > 1);
|
||||
if (temporalAA)
|
||||
@ -799,27 +815,47 @@ void View::RenderBatchesDeferred()
|
||||
PROFILE(RenderGBuffer);
|
||||
|
||||
graphics_->SetRenderTarget(0, diffBuffer);
|
||||
graphics_->SetDepthStencil(depthBuffer);
|
||||
if (graphics_->GetHardwareDepthSupport())
|
||||
{
|
||||
graphics_->SetDepthStencil(depthBuffer);
|
||||
graphics_->SetViewport(screenRect_);
|
||||
graphics_->Clear(CLEAR_COLOR | CLEAR_DEPTH | CLEAR_STENCIL);
|
||||
graphics_->SetRenderTarget(1, normalBuffer);
|
||||
|
||||
RenderBatchQueue(gBufferQueue_);
|
||||
}
|
||||
else
|
||||
else if (!fallback)
|
||||
{
|
||||
graphics_->SetDepthStencil(depthStencil_);
|
||||
graphics_->SetViewport(screenRect_);
|
||||
graphics_->Clear(CLEAR_DEPTH | CLEAR_STENCIL);
|
||||
graphics_->SetRenderTarget(1, normalBuffer);
|
||||
graphics_->SetRenderTarget(2, depthBuffer);
|
||||
|
||||
RenderBatchQueue(gBufferQueue_);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback mode: render the G-buffer in 2 passes without MRT
|
||||
graphics_->SetDepthStencil(depthStencil_);
|
||||
graphics_->SetViewport(screenRect_);
|
||||
graphics_->Clear(CLEAR_COLOR | CLEAR_DEPTH | CLEAR_STENCIL, Color(0.f, 0.f, 0.f, 1.0f));
|
||||
|
||||
RenderBatchQueue(gBufferQueue_);
|
||||
|
||||
graphics_->SetRenderTarget(0, normalBuffer);
|
||||
graphics_->SetViewport(screenRect_);
|
||||
graphics_->Clear(CLEAR_COLOR, Color(0.5f, 0.5f, 0.5f, 1.0f));
|
||||
|
||||
RenderBatchQueue(gBuffer2Queue_);
|
||||
}
|
||||
|
||||
RenderBatchQueue(gBufferQueue_);
|
||||
|
||||
graphics_->SetAlphaTest(false);
|
||||
graphics_->SetBlendMode(BLEND_REPLACE);
|
||||
|
||||
// If hardware depth is not available, perform a post-step to initialize the parts of the G-buffer that were not rendered into
|
||||
// (it is less expensive than clearing all the buffers in the first place)
|
||||
if (!graphics_->GetHardwareDepthSupport())
|
||||
if (!graphics_->GetHardwareDepthSupport() && !fallback)
|
||||
{
|
||||
graphics_->SetDepthTest(CMP_LESSEQUAL);
|
||||
graphics_->SetDepthWrite(false);
|
||||
@ -847,7 +883,10 @@ void View::RenderBatchesDeferred()
|
||||
graphics_->SetDepthStencil(depthStencil_);
|
||||
graphics_->SetViewport(screenRect_);
|
||||
graphics_->SetTexture(TU_DIFFBUFFER, diffBuffer);
|
||||
graphics_->SetTexture(TU_DEPTHBUFFER, depthBuffer);
|
||||
if (fallback)
|
||||
graphics_->SetTexture(TU_NORMALBUFFER, normalBuffer);
|
||||
else
|
||||
graphics_->SetTexture(TU_DEPTHBUFFER, depthBuffer);
|
||||
|
||||
String pixelShaderName = "Ambient";
|
||||
#ifdef USE_OPENGL
|
||||
@ -856,8 +895,10 @@ void View::RenderBatchesDeferred()
|
||||
// On OpenGL, set up a stencil operation to reset the stencil during ambient quad rendering
|
||||
graphics_->SetStencilTest(true, CMP_ALWAYS, OP_ZERO, OP_KEEP, OP_KEEP);
|
||||
#else
|
||||
if (camera_->IsOrthographic() || !graphics_->GetHardwareDepthSupport())
|
||||
if (!fallback && (camera_->IsOrthographic() || !graphics_->GetHardwareDepthSupport()))
|
||||
pixelShaderName += "_Linear";
|
||||
else if (fallback)
|
||||
pixelShaderName += "_FB";
|
||||
#endif
|
||||
|
||||
DrawFullScreenQuad(*camera_, renderer_->GetVertexShader("Ambient"), renderer_->GetPixelShader(pixelShaderName),
|
||||
@ -961,9 +1002,13 @@ void View::RenderBatchesDeferred()
|
||||
{
|
||||
vsName += "_Ortho";
|
||||
psName += "_Ortho";
|
||||
if (fallback)
|
||||
psName += "FB";
|
||||
}
|
||||
else if (!graphics_->GetHardwareDepthSupport())
|
||||
else if (!fallback && !graphics_->GetHardwareDepthSupport())
|
||||
psName += "_Linear";
|
||||
else if (fallback)
|
||||
psName += "_FB";
|
||||
|
||||
graphics_->SetAlphaTest(false);
|
||||
graphics_->SetBlendMode(BLEND_REPLACE);
|
||||
@ -986,7 +1031,13 @@ void View::RenderBatchesDeferred()
|
||||
graphics_->SetShaderParameter(PSP_VIEWPROJ, camera_->GetProjection(false) * lastCameraView_);
|
||||
graphics_->SetTexture(TU_DIFFBUFFER, graphics_->GetScreenBuffer(jitterCounter_ & 1));
|
||||
graphics_->SetTexture(TU_NORMALBUFFER, graphics_->GetScreenBuffer((jitterCounter_ + 1) & 1));
|
||||
graphics_->SetTexture(TU_DEPTHBUFFER, graphics_->GetDepthBuffer());
|
||||
if (!fallback)
|
||||
graphics_->SetTexture(TU_DEPTHBUFFER, graphics_->GetDepthBuffer());
|
||||
else
|
||||
{
|
||||
graphics_->SetTexture(TU_DETAIL, graphics_->GetDiffBuffer());
|
||||
graphics_->SetTexture(TU_ENVIRONMENT, graphics_->GetNormalBuffer());
|
||||
}
|
||||
|
||||
DrawFullScreenQuad(*camera_, vertexShader, pixelShader, false, shaderParameters_);
|
||||
|
||||
@ -1876,6 +1927,7 @@ void View::SortBatches()
|
||||
if (mode_ != RENDER_FORWARD)
|
||||
{
|
||||
gBufferQueue_.SortFrontToBack();
|
||||
gBuffer2Queue_.SortFrontToBack();
|
||||
noShadowLightQueue_.SortFrontToBack();
|
||||
}
|
||||
|
||||
@ -1897,6 +1949,7 @@ void View::PrepareInstancingBuffer()
|
||||
unsigned totalInstances = 0;
|
||||
|
||||
totalInstances += gBufferQueue_.GetNumInstances(renderer_);
|
||||
totalInstances += gBuffer2Queue_.GetNumInstances(renderer_);
|
||||
totalInstances += baseQueue_.GetNumInstances(renderer_);
|
||||
totalInstances += extraQueue_.GetNumInstances(renderer_);
|
||||
|
||||
@ -1914,6 +1967,7 @@ void View::PrepareInstancingBuffer()
|
||||
if (lockedData)
|
||||
{
|
||||
gBufferQueue_.SetTransforms(renderer_, lockedData, freeIndex);
|
||||
gBuffer2Queue_.SetTransforms(renderer_, lockedData, freeIndex);
|
||||
baseQueue_.SetTransforms(renderer_, lockedData, freeIndex);
|
||||
extraQueue_.SetTransforms(renderer_, lockedData, freeIndex);
|
||||
|
||||
|
@ -260,6 +260,8 @@ private:
|
||||
HashMap<Light*, Rect> lightScissorCache_;
|
||||
/// G-buffer batches.
|
||||
BatchQueue gBufferQueue_;
|
||||
/// G-buffer pass 2 batches (fallback mode only.)
|
||||
BatchQueue gBuffer2Queue_;
|
||||
/// Base pass batches.
|
||||
BatchQueue baseQueue_;
|
||||
/// Extra pass batches.
|
||||
|
@ -56,14 +56,12 @@ void main()
|
||||
diff *= GetShadow(vShadowPos);
|
||||
#endif
|
||||
|
||||
#ifdef SPOTLIGHT
|
||||
#if defined(SPOTLIGHT)
|
||||
lightColor = vSpotPos.w > 0.0 ? texture2DProj(sLightSpotMap, vSpotPos).rgb * cLightColor.rgb : vec3(0.0, 0.0, 0.0);
|
||||
#elif defined(CUBEMASK)
|
||||
lightColor = textureCube(sLightCubeMap, cLightVecRot * lightVec).rgb * cLightColor.rgb;
|
||||
#else
|
||||
#ifdef CUBEMASK
|
||||
lightColor = textureCube(sLightCubeMap, cLightVecRot * lightVec).rgb * cLightColor.rgb;
|
||||
#else
|
||||
lightColor = cLightColor.rgb;
|
||||
#endif
|
||||
lightColor = cLightColor.rgb;
|
||||
#endif
|
||||
|
||||
#ifdef SPECULAR
|
||||
@ -99,14 +97,12 @@ void main()
|
||||
diff = GetDiffusePointOrSpotVolumetric(vWorldPos.xyz, lightVec);
|
||||
#endif
|
||||
|
||||
#ifdef SPOTLIGHT
|
||||
#if defined(SPOTLIGHT)
|
||||
lightColor = vSpotPos.w > 0.0 ? texture2DProj(sLightSpotMap, vSpotPos).rgb * cLightColor.rgb : vec3(0.0, 0.0, 0.0);
|
||||
#elif defined(CUBEMASK)
|
||||
lightColor = textureCube(sLightCubeMap, cLightVecRot * lightVec).rgb * cLightColor.rgb;
|
||||
#else
|
||||
#ifdef CUBEMASK
|
||||
lightColor = textureCube(sLightCubeMap, cLightVecRot * lightVec).rgb * cLightColor.rgb;
|
||||
#else
|
||||
lightColor = cLightColor.rgb;
|
||||
#endif
|
||||
lightColor = cLightColor.rgb;
|
||||
#endif
|
||||
|
||||
vec3 finalColor = diff * lightColor * diffColor.rgb;
|
||||
|
@ -61,15 +61,13 @@ void main()
|
||||
diff *= GetShadow(shadowPos);
|
||||
#endif
|
||||
|
||||
#ifdef SPOTLIGHT
|
||||
#if defined(SPOTLIGHT)
|
||||
vec4 spotPos = cSpotProjPS * vec4(worldPos, 1.0);
|
||||
lightColor = spotPos.w > 0.0 ? texture2DProj(sLightSpotMap, spotPos).rgb * cLightColor.rgb : vec3(0.0, 0.0, 0.0);
|
||||
#elif defined(CUBEMASK)
|
||||
lightColor = textureCube(sLightCubeMap, cLightVecRot * lightVec).rgb * cLightColor.rgb;
|
||||
#else
|
||||
#ifdef CUBEMASK
|
||||
lightColor = textureCube(sLightCubeMap, cLightVecRot * lightVec).rgb * cLightColor.rgb;
|
||||
#else
|
||||
lightColor = cLightColor.rgb;
|
||||
#endif
|
||||
lightColor = cLightColor.rgb;
|
||||
#endif
|
||||
|
||||
#ifdef SPECULAR
|
||||
|
@ -11,13 +11,16 @@ void VS(float4 iPos : POSITION,
|
||||
GetPosition(iPos, oPos);
|
||||
oScreenPos = GetScreenPosPreDiv(oPos);
|
||||
}
|
||||
|
||||
|
||||
void PS(float2 iScreenPos : TEXCOORD0,
|
||||
out float4 oColor : COLOR0)
|
||||
{
|
||||
float4 diffInput = tex2D(sDiffBuffer, iScreenPos);
|
||||
#ifdef LINEAR
|
||||
#if defined(LINEAR)
|
||||
float depth = tex2D(sDepthBuffer, iScreenPos).r;
|
||||
#elif defined(FALLBACK)
|
||||
float4 normalInput = tex2D(sNormalBuffer, iScreenPos);
|
||||
float depth = DecodeDepth(float2(diffInput.w, normalInput.w));
|
||||
#else
|
||||
float depth = ReconstructDepth(tex2D(sDepthBuffer, iScreenPos).r);
|
||||
#endif
|
||||
|
@ -2,5 +2,6 @@
|
||||
<shader name="Ambient" type="vs" />
|
||||
<shader name="Ambient" type="ps">
|
||||
<option name="Linear" define="LINEAR" />
|
||||
<option name="FB" define="FALLBACK" exclude="Linear" require="SM2" />
|
||||
</shader>
|
||||
</shaders>
|
@ -141,14 +141,12 @@ void PS(float2 iTexCoord : TEXCOORD0,
|
||||
diff *= GetShadow(iShadowPos);
|
||||
#endif
|
||||
|
||||
#ifdef SPOTLIGHT
|
||||
#if defined(SPOTLIGHT)
|
||||
lightColor = iSpotPos.w > 0.0 ? tex2Dproj(sLightSpotMap, iSpotPos).rgb * cLightColor.rgb : 0.0;
|
||||
#elif defined(CUBEMASK)
|
||||
lightColor = texCUBE(sLightCubeMap, mul(lightVec, cLightVecRot)).rgb * cLightColor.rgb;
|
||||
#else
|
||||
#ifdef CUBEMASK
|
||||
lightColor = texCUBE(sLightCubeMap, mul(lightVec, cLightVecRot)).rgb * cLightColor.rgb;
|
||||
#else
|
||||
lightColor = cLightColor.rgb;
|
||||
#endif
|
||||
lightColor = cLightColor.rgb;
|
||||
#endif
|
||||
|
||||
#ifdef SPECULAR
|
||||
@ -184,14 +182,12 @@ void PS(float2 iTexCoord : TEXCOORD0,
|
||||
diff = GetDiffusePointOrSpotVolumetric(iWorldPos.xyz, lightVec);
|
||||
#endif
|
||||
|
||||
#ifdef SPOTLIGHT
|
||||
#if defined(SPOTLIGHT)
|
||||
lightColor = iSpotPos.w > 0.0 ? tex2Dproj(sLightSpotMap, iSpotPos).rgb * cLightColor.rgb : 0.0;
|
||||
#elif defined(CUBEMASK)
|
||||
lightColor = texCUBE(sLightCubeMap, mul(lightVec, cLightVecRot)).rgb * cLightColor.rgb;
|
||||
#else
|
||||
#ifdef CUBEMASK
|
||||
lightColor = texCUBE(sLightCubeMap, mul(lightVec, cLightVecRot)).rgb * cLightColor.rgb;
|
||||
#else
|
||||
lightColor = cLightColor.rgb;
|
||||
#endif
|
||||
lightColor = cLightColor.rgb;
|
||||
#endif
|
||||
|
||||
float3 finalColor = diff * lightColor * diffColor.rgb;
|
||||
|
@ -68,8 +68,10 @@ void PS(
|
||||
#ifdef DEPTH
|
||||
out float4 oDepth : COLOR2,
|
||||
#endif
|
||||
out float4 oDiff : COLOR0,
|
||||
out float4 oNormal : COLOR1)
|
||||
#ifndef FALLBACK
|
||||
out float4 oNormal : COLOR1,
|
||||
#endif
|
||||
out float4 oDiff : COLOR0)
|
||||
{
|
||||
#ifdef DIFFMAP
|
||||
float4 diffInput = tex2D(sDiffMap, iTexCoord);
|
||||
@ -97,8 +99,17 @@ void PS(
|
||||
float specPower = cMatSpecProperties.y / 255.0;
|
||||
|
||||
// Take fogging into account here so that deferred lights do not need to calculate it
|
||||
oDiff = GetReverseFogFactor(iDepth) * float4(diffColor, specStrength);
|
||||
oNormal = float4(normal * 0.5 + 0.5, specPower);
|
||||
#ifndef FALLBACK
|
||||
oDiff = GetReverseFogFactor(iDepth) * float4(diffColor, specStrength);
|
||||
oNormal = float4(normal * 0.5 + 0.5, specPower);
|
||||
#else
|
||||
// Fallback G-buffer requires 2 passes, first diffuse and coarse depth, then normal and fine depth
|
||||
#ifndef PASS2
|
||||
oDiff = float4(GetReverseFogFactor(iDepth) * diffColor, floor(iDepth * 255.0) / 255.0);
|
||||
#else
|
||||
oDiff = float4(normal * 0.5 + 0.5, frac(iDepth * 255.0));
|
||||
#endif
|
||||
#endif
|
||||
#ifdef DEPTH
|
||||
oDepth = iDepth;
|
||||
#endif
|
||||
|
@ -12,5 +12,15 @@
|
||||
<option name="Spec" define="SPECMAP" />
|
||||
<option name="Mask" define="ALPHAMASK" include="Diff" />
|
||||
<option name="Depth" define="DEPTH" />
|
||||
<option name="FB" define="FALLBACK" require="SM2">
|
||||
<exclude name="Depth" />
|
||||
<exclude name="Pass2FB" />
|
||||
</option>
|
||||
<option name="Pass2FB" require="SM2">
|
||||
<define name="FALLBACK" />
|
||||
<define name="PASS2" />
|
||||
<exclude name="Depth" />
|
||||
<exclude name="FB" />
|
||||
</option>
|
||||
</shader>
|
||||
</shaders>
|
||||
|
@ -46,33 +46,45 @@ void PS(
|
||||
{
|
||||
// If rendering a directional light quad, optimize out the w divide
|
||||
#ifdef DIRLIGHT
|
||||
float4 normalInput = Sample(sNormalBuffer, iScreenPos);
|
||||
float4 diffInput = Sample(sDiffBuffer, iScreenPos);
|
||||
#ifdef ORTHO
|
||||
float depth = Sample(sDepthBuffer, iScreenPos).r;
|
||||
#ifndef FALLBACK
|
||||
float depth = Sample(sDepthBuffer, iScreenPos).r;
|
||||
#else
|
||||
float depth = DecodeDepth(float2(diffInput.w, normalInput.w));
|
||||
#endif
|
||||
float3 worldPos = lerp(iNearRay, iFarRay, depth);
|
||||
#else
|
||||
#ifdef LINEAR
|
||||
#if defined(LINEAR)
|
||||
float depth = Sample(sDepthBuffer, iScreenPos).r;
|
||||
#elif defined(FALLBACK)
|
||||
float depth = DecodeDepth(float2(diffInput.w, normalInput.w));
|
||||
#else
|
||||
float depth = ReconstructDepth(Sample(sDepthBuffer, iScreenPos).r);
|
||||
#endif
|
||||
float3 worldPos = iFarRay * depth;
|
||||
#endif
|
||||
float4 normalInput = Sample(sNormalBuffer, iScreenPos);
|
||||
float4 diffInput = Sample(sDiffBuffer, iScreenPos);
|
||||
#else
|
||||
float4 normalInput = tex2Dproj(sNormalBuffer, iScreenPos);
|
||||
float4 diffInput = tex2Dproj(sDiffBuffer, iScreenPos);
|
||||
#ifdef ORTHO
|
||||
float depth = tex2Dproj(sDepthBuffer, iScreenPos).r;
|
||||
#ifndef FALLBACK
|
||||
float depth = tex2Dproj(sDepthBuffer, iScreenPos).r;
|
||||
#else
|
||||
float depth = DecodeDepth(float2(diffInput.w, normalInput.w));
|
||||
#endif
|
||||
float3 worldPos = lerp(iNearRay, iFarRay, depth) / iScreenPos.w;
|
||||
#else
|
||||
#ifdef LINEAR
|
||||
#if defined(LINEAR)
|
||||
float depth = tex2Dproj(sDepthBuffer, iScreenPos).r;
|
||||
#elif defined(FALLBACK)
|
||||
float depth = DecodeDepth(float2(diffInput.w, normalInput.w));
|
||||
#else
|
||||
float depth = ReconstructDepth(tex2Dproj(sDepthBuffer, iScreenPos).r);
|
||||
#endif
|
||||
float3 worldPos = iFarRay * depth / iScreenPos.w;
|
||||
#endif
|
||||
float4 normalInput = tex2Dproj(sNormalBuffer, iScreenPos);
|
||||
float4 diffInput = tex2Dproj(sDiffBuffer, iScreenPos);
|
||||
#endif
|
||||
|
||||
// With specular, normalization greatly improves stability of reflections,
|
||||
@ -99,15 +111,13 @@ void PS(
|
||||
diff *= GetShadow(shadowPos);
|
||||
#endif
|
||||
|
||||
#ifdef SPOTLIGHT
|
||||
#if defined(SPOTLIGHT)
|
||||
float4 spotPos = mul(float4(worldPos, 1.0), cSpotProjPS);
|
||||
lightColor = spotPos.w > 0.0 ? tex2Dproj(sLightSpotMap, spotPos).rgb * cLightColor.rgb : 0.0;
|
||||
#elif defined(CUBEMASK)
|
||||
lightColor = texCUBE(sLightCubeMap, mul(lightVec, cLightVecRot)).rgb * cLightColor.rgb;
|
||||
#else
|
||||
#ifdef CUBEMASK
|
||||
lightColor = texCUBE(sLightCubeMap, mul(lightVec, cLightVecRot)).rgb * cLightColor.rgb;
|
||||
#else
|
||||
lightColor = cLightColor.rgb;
|
||||
#endif
|
||||
lightColor = cLightColor.rgb;
|
||||
#endif
|
||||
|
||||
#ifdef SPECULAR
|
||||
|
@ -23,5 +23,11 @@
|
||||
<option name="Spec" define="SPECULAR" />
|
||||
<option name="LQ" define="LQSHADOW" require="SHADOW" />
|
||||
<option name="HW" define="HWSHADOW" require="SHADOW" />
|
||||
<option name="FB" define="FALLBACK" require="SM2">
|
||||
<exclude name="Linear" />
|
||||
<exclude name="Spec" />
|
||||
<exclude name="LQ" />
|
||||
<exclude name="HW" />
|
||||
</option>
|
||||
</shader>
|
||||
</shaders>
|
||||
|
@ -31,13 +31,24 @@ void PS(float2 iScreenPos : TEXCOORD0,
|
||||
float2 vOffset = float2(0, cSampleOffsets.y);
|
||||
float3 current = Sample(sDiffBuffer, iScreenPos).rgb;
|
||||
|
||||
#ifdef FALLBACK
|
||||
float4 diffInput = Sample(sDetailMap, iScreenPos);
|
||||
float4 normalInput = Sample(sEnvMap, iScreenPos);
|
||||
#endif
|
||||
|
||||
// Reconstruct position for this frame's pixel
|
||||
#ifdef ORTHO
|
||||
float depth = Sample(sDepthBuffer, iScreenPos).r;
|
||||
#ifdef FALLBACK
|
||||
float depth = DecodeDepth(float2(diffInput.w, normalInput.w));
|
||||
#else
|
||||
float depth = Sample(sDepthBuffer, iScreenPos).r;
|
||||
#endif
|
||||
float3 worldPos = lerp(iNearRay, iFarRay, depth) + cCameraPosPS;
|
||||
#else
|
||||
#ifdef LINEAR
|
||||
#if defined(LINEAR)
|
||||
float depth = Sample(sDepthBuffer, iScreenPos).r;
|
||||
#elif defined(FALLBACK)
|
||||
float depth = DecodeDepth(float2(diffInput.w, normalInput.w));
|
||||
#else
|
||||
float depth = ReconstructDepth(Sample(sDepthBuffer, iScreenPos).r);
|
||||
#endif
|
||||
|
@ -5,5 +5,6 @@
|
||||
<shader name="TemporalAA" type="ps">
|
||||
<option name="Ortho" define="ORTHO" exclude="Linear" />
|
||||
<option name="Linear" define="LINEAR" exclude="Ortho" />
|
||||
<option name="FB" define="FALLBACK" exclude="Linear" require="SM2" />
|
||||
</shader>
|
||||
</shaders>
|
Loading…
Reference in New Issue
Block a user