mirror of
https://github.com/lubosz/overte.git
synced 2025-08-08 03:08:00 +02:00
Merge pull request #6837 from zzmp/feat/render-shadow
Add RenderShadowTask
This commit is contained in:
commit
29945bba92
36 changed files with 889 additions and 285 deletions
|
@ -188,6 +188,7 @@ Item {
|
||||||
visible: root.expanded;
|
visible: root.expanded;
|
||||||
text: "\tItems Rendered Opaque: " + root.opaqueRendered +
|
text: "\tItems Rendered Opaque: " + root.opaqueRendered +
|
||||||
" / Translucent: " + root.translucentRendered +
|
" / Translucent: " + root.translucentRendered +
|
||||||
|
" / Shadow: " + root.shadowRendered +
|
||||||
" / Other: " + root.otherRendered;
|
" / Other: " + root.otherRendered;
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
|
@ -198,6 +199,14 @@ Item {
|
||||||
" / Out of view: " + root.opaqueOutOfView +
|
" / Out of view: " + root.opaqueOutOfView +
|
||||||
" / Too small: " + root.opaqueTooSmall;
|
" / Too small: " + root.opaqueTooSmall;
|
||||||
}
|
}
|
||||||
|
Text {
|
||||||
|
color: root.fontColor;
|
||||||
|
font.pixelSize: root.fontSize
|
||||||
|
visible: root.expanded;
|
||||||
|
text: "\tShadow considered: " + root.shadowConsidered +
|
||||||
|
" / Out of view: " + root.shadowOutOfView +
|
||||||
|
" / Too small: " + root.shadowTooSmall;
|
||||||
|
}
|
||||||
Text {
|
Text {
|
||||||
color: root.fontColor;
|
color: root.fontColor;
|
||||||
font.pixelSize: root.fontSize
|
font.pixelSize: root.fontSize
|
||||||
|
|
|
@ -348,6 +348,10 @@ void Stats::setRenderDetails(const RenderDetails& details) {
|
||||||
STAT_UPDATE(opaqueOutOfView, details._opaque._outOfView);
|
STAT_UPDATE(opaqueOutOfView, details._opaque._outOfView);
|
||||||
STAT_UPDATE(opaqueTooSmall, details._opaque._tooSmall);
|
STAT_UPDATE(opaqueTooSmall, details._opaque._tooSmall);
|
||||||
STAT_UPDATE(opaqueRendered, (int)details._opaque._rendered);
|
STAT_UPDATE(opaqueRendered, (int)details._opaque._rendered);
|
||||||
|
STAT_UPDATE(shadowConsidered, (int)details._shadow._considered);
|
||||||
|
STAT_UPDATE(shadowOutOfView, details._shadow._outOfView);
|
||||||
|
STAT_UPDATE(shadowTooSmall, details._shadow._tooSmall);
|
||||||
|
STAT_UPDATE(shadowRendered, (int)details._shadow._rendered);
|
||||||
STAT_UPDATE(translucentConsidered, (int)details._translucent._considered);
|
STAT_UPDATE(translucentConsidered, (int)details._translucent._considered);
|
||||||
STAT_UPDATE(translucentOutOfView, details._translucent._outOfView);
|
STAT_UPDATE(translucentOutOfView, details._translucent._outOfView);
|
||||||
STAT_UPDATE(translucentTooSmall, details._translucent._tooSmall);
|
STAT_UPDATE(translucentTooSmall, details._translucent._tooSmall);
|
||||||
|
|
|
@ -64,6 +64,10 @@ class Stats : public QQuickItem {
|
||||||
STATS_PROPERTY(int, opaqueOutOfView, 0)
|
STATS_PROPERTY(int, opaqueOutOfView, 0)
|
||||||
STATS_PROPERTY(int, opaqueTooSmall, 0)
|
STATS_PROPERTY(int, opaqueTooSmall, 0)
|
||||||
STATS_PROPERTY(int, opaqueRendered, 0)
|
STATS_PROPERTY(int, opaqueRendered, 0)
|
||||||
|
STATS_PROPERTY(int, shadowConsidered, 0)
|
||||||
|
STATS_PROPERTY(int, shadowOutOfView, 0)
|
||||||
|
STATS_PROPERTY(int, shadowTooSmall, 0)
|
||||||
|
STATS_PROPERTY(int, shadowRendered, 0)
|
||||||
STATS_PROPERTY(int, translucentConsidered, 0)
|
STATS_PROPERTY(int, translucentConsidered, 0)
|
||||||
STATS_PROPERTY(int, translucentOutOfView, 0)
|
STATS_PROPERTY(int, translucentOutOfView, 0)
|
||||||
STATS_PROPERTY(int, translucentTooSmall, 0)
|
STATS_PROPERTY(int, translucentTooSmall, 0)
|
||||||
|
@ -151,6 +155,10 @@ signals:
|
||||||
void opaqueOutOfViewChanged();
|
void opaqueOutOfViewChanged();
|
||||||
void opaqueTooSmallChanged();
|
void opaqueTooSmallChanged();
|
||||||
void opaqueRenderedChanged();
|
void opaqueRenderedChanged();
|
||||||
|
void shadowConsideredChanged();
|
||||||
|
void shadowOutOfViewChanged();
|
||||||
|
void shadowTooSmallChanged();
|
||||||
|
void shadowRenderedChanged();
|
||||||
void translucentConsideredChanged();
|
void translucentConsideredChanged();
|
||||||
void translucentOutOfViewChanged();
|
void translucentOutOfViewChanged();
|
||||||
void translucentTooSmallChanged();
|
void translucentTooSmallChanged();
|
||||||
|
|
|
@ -49,7 +49,9 @@ Framebuffer* Framebuffer::create( const Format& colorBufferFormat, const Format&
|
||||||
|
|
||||||
Framebuffer* Framebuffer::createShadowmap(uint16 width) {
|
Framebuffer* Framebuffer::createShadowmap(uint16 width) {
|
||||||
auto framebuffer = Framebuffer::create();
|
auto framebuffer = Framebuffer::create();
|
||||||
auto depthTexture = TexturePointer(Texture::create2D(Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH), width, width));
|
|
||||||
|
auto depthFormat = Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH); // Depth32 texel format
|
||||||
|
auto depthTexture = TexturePointer(Texture::create2D(depthFormat, width, width));
|
||||||
|
|
||||||
Sampler::Desc samplerDesc;
|
Sampler::Desc samplerDesc;
|
||||||
samplerDesc._borderColor = glm::vec4(1.0f);
|
samplerDesc._borderColor = glm::vec4(1.0f);
|
||||||
|
@ -59,8 +61,11 @@ Framebuffer* Framebuffer::createShadowmap(uint16 width) {
|
||||||
samplerDesc._comparisonFunc = LESS_EQUAL;
|
samplerDesc._comparisonFunc = LESS_EQUAL;
|
||||||
|
|
||||||
depthTexture->setSampler(Sampler(samplerDesc));
|
depthTexture->setSampler(Sampler(samplerDesc));
|
||||||
|
framebuffer->setDepthStencilBuffer(depthTexture, depthFormat);
|
||||||
|
|
||||||
framebuffer->setDepthStencilBuffer(depthTexture, Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH));
|
// Use a render buffer to allow use of the DebugDeferredBuffer Job
|
||||||
|
gpu::TexturePointer colorbuffer{gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, width)};
|
||||||
|
framebuffer->setRenderBuffer(0, colorbuffer);
|
||||||
|
|
||||||
return framebuffer;
|
return framebuffer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ void GLBackend::do_setViewportTransform(Batch& batch, size_t paramOffset) {
|
||||||
|
|
||||||
void GLBackend::do_setDepthRangeTransform(Batch& batch, size_t paramOffset) {
|
void GLBackend::do_setDepthRangeTransform(Batch& batch, size_t paramOffset) {
|
||||||
|
|
||||||
Vec2 depthRange(batch._params[paramOffset + 0]._float, batch._params[paramOffset + 1]._float);
|
Vec2 depthRange(batch._params[paramOffset + 1]._float, batch._params[paramOffset + 0]._float);
|
||||||
|
|
||||||
if ((depthRange.x != _transform._depthRange.x) || (depthRange.y != _transform._depthRange.y)) {
|
if ((depthRange.x != _transform._depthRange.x) || (depthRange.y != _transform._depthRange.y)) {
|
||||||
_transform._depthRange = depthRange;
|
_transform._depthRange = depthRange;
|
||||||
|
|
|
@ -736,6 +736,23 @@ void ViewFrustum::getFurthestPointFromCamera(const AACube& box, glm::vec3& furth
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ViewFrustum::Corners ViewFrustum::getCorners(const float& depth) {
|
||||||
|
glm::vec3 normal = glm::normalize(_direction);
|
||||||
|
|
||||||
|
auto getCorner = [&](enum::BoxVertex nearCorner, enum::BoxVertex farCorner) {
|
||||||
|
auto dir = glm::normalize(_cornersWorld[nearCorner] - _cornersWorld[farCorner]);
|
||||||
|
auto factor = depth / glm::dot(dir, normal);
|
||||||
|
return _position + factor * dir;
|
||||||
|
};
|
||||||
|
|
||||||
|
return Corners{
|
||||||
|
getCorner(TOP_LEFT_NEAR, TOP_LEFT_FAR),
|
||||||
|
getCorner(TOP_RIGHT_NEAR, TOP_RIGHT_FAR),
|
||||||
|
getCorner(BOTTOM_LEFT_NEAR, BOTTOM_LEFT_FAR),
|
||||||
|
getCorner(BOTTOM_RIGHT_NEAR, BOTTOM_RIGHT_FAR)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
float ViewFrustum::distanceToCamera(const glm::vec3& point) const {
|
float ViewFrustum::distanceToCamera(const glm::vec3& point) const {
|
||||||
glm::vec3 temp = getPosition() - point;
|
glm::vec3 temp = getPosition() - point;
|
||||||
float distanceToPoint = sqrtf(glm::dot(temp, temp));
|
float distanceToPoint = sqrtf(glm::dot(temp, temp));
|
||||||
|
|
|
@ -61,11 +61,23 @@ public:
|
||||||
float getFarClip() const { return _farClip; }
|
float getFarClip() const { return _farClip; }
|
||||||
float getFocalLength() const { return _focalLength; }
|
float getFocalLength() const { return _focalLength; }
|
||||||
|
|
||||||
|
class Corners {
|
||||||
|
public:
|
||||||
|
Corners(glm::vec3&& topLeft, glm::vec3&& topRight, glm::vec3&& bottomLeft, glm::vec3&& bottomRight)
|
||||||
|
: topLeft{ topLeft }, topRight{ topRight }, bottomLeft{ bottomLeft }, bottomRight{ bottomRight } {}
|
||||||
|
glm::vec3 topLeft;
|
||||||
|
glm::vec3 topRight;
|
||||||
|
glm::vec3 bottomLeft;
|
||||||
|
glm::vec3 bottomRight;
|
||||||
|
// Get the corners depth units from frustum position, along frustum orientation
|
||||||
|
};
|
||||||
|
const Corners getCorners(const float& depth);
|
||||||
|
|
||||||
|
// getters for corners
|
||||||
const glm::vec3& getFarTopLeft() const { return _cornersWorld[TOP_LEFT_FAR]; }
|
const glm::vec3& getFarTopLeft() const { return _cornersWorld[TOP_LEFT_FAR]; }
|
||||||
const glm::vec3& getFarTopRight() const { return _cornersWorld[TOP_RIGHT_FAR]; }
|
const glm::vec3& getFarTopRight() const { return _cornersWorld[TOP_RIGHT_FAR]; }
|
||||||
const glm::vec3& getFarBottomLeft() const { return _cornersWorld[BOTTOM_LEFT_FAR]; }
|
const glm::vec3& getFarBottomLeft() const { return _cornersWorld[BOTTOM_LEFT_FAR]; }
|
||||||
const glm::vec3& getFarBottomRight() const { return _cornersWorld[BOTTOM_RIGHT_FAR]; }
|
const glm::vec3& getFarBottomRight() const { return _cornersWorld[BOTTOM_RIGHT_FAR]; }
|
||||||
|
|
||||||
const glm::vec3& getNearTopLeft() const { return _cornersWorld[TOP_LEFT_NEAR]; }
|
const glm::vec3& getNearTopLeft() const { return _cornersWorld[TOP_LEFT_NEAR]; }
|
||||||
const glm::vec3& getNearTopRight() const { return _cornersWorld[TOP_RIGHT_NEAR]; }
|
const glm::vec3& getNearTopRight() const { return _cornersWorld[TOP_RIGHT_NEAR]; }
|
||||||
const glm::vec3& getNearBottomLeft() const { return _cornersWorld[BOTTOM_LEFT_NEAR]; }
|
const glm::vec3& getNearBottomLeft() const { return _cornersWorld[BOTTOM_LEFT_NEAR]; }
|
||||||
|
@ -156,6 +168,7 @@ private:
|
||||||
// Used to project points
|
// Used to project points
|
||||||
glm::mat4 _ourModelViewProjectionMatrix;
|
glm::mat4 _ourModelViewProjectionMatrix;
|
||||||
};
|
};
|
||||||
|
using ViewFrustumPointer = std::shared_ptr<ViewFrustum>;
|
||||||
|
|
||||||
float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeScale);
|
float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeScale);
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include "GeometryCache.h"
|
#include "GeometryCache.h"
|
||||||
#include "FramebufferCache.h"
|
#include "FramebufferCache.h"
|
||||||
|
#include "DeferredLightingEffect.h"
|
||||||
|
|
||||||
#include "debug_deferred_buffer_vert.h"
|
#include "debug_deferred_buffer_vert.h"
|
||||||
#include "debug_deferred_buffer_frag.h"
|
#include "debug_deferred_buffer_frag.h"
|
||||||
|
@ -31,45 +32,53 @@ enum Slots {
|
||||||
Normal,
|
Normal,
|
||||||
Specular,
|
Specular,
|
||||||
Depth,
|
Depth,
|
||||||
Lighting
|
Lighting,
|
||||||
|
Shadow
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::string DEEFAULT_DIFFUSE_SHADER {
|
static const std::string DEFAULT_DIFFUSE_SHADER {
|
||||||
"vec4 getFragmentColor() {"
|
"vec4 getFragmentColor() {"
|
||||||
" return vec4(pow(texture(diffuseMap, uv).xyz, vec3(1.0 / 2.2)), 1.0);"
|
" return vec4(pow(texture(diffuseMap, uv).xyz, vec3(1.0 / 2.2)), 1.0);"
|
||||||
" }"
|
" }"
|
||||||
};
|
};
|
||||||
static const std::string DEEFAULT_ALPHA_SHADER {
|
static const std::string DEFAULT_ALPHA_SHADER {
|
||||||
"vec4 getFragmentColor() {"
|
"vec4 getFragmentColor() {"
|
||||||
" return vec4(vec3(texture(diffuseMap, uv).a), 1.0);"
|
" return vec4(vec3(texture(diffuseMap, uv).a), 1.0);"
|
||||||
" }"
|
" }"
|
||||||
};
|
};
|
||||||
static const std::string DEEFAULT_SPECULAR_SHADER {
|
static const std::string DEFAULT_SPECULAR_SHADER {
|
||||||
"vec4 getFragmentColor() {"
|
"vec4 getFragmentColor() {"
|
||||||
" return vec4(texture(specularMap, uv).xyz, 1.0);"
|
" return vec4(texture(specularMap, uv).xyz, 1.0);"
|
||||||
" }"
|
" }"
|
||||||
};
|
};
|
||||||
static const std::string DEEFAULT_ROUGHNESS_SHADER {
|
static const std::string DEFAULT_ROUGHNESS_SHADER {
|
||||||
"vec4 getFragmentColor() {"
|
"vec4 getFragmentColor() {"
|
||||||
" return vec4(vec3(texture(specularMap, uv).a), 1.0);"
|
" return vec4(vec3(texture(specularMap, uv).a), 1.0);"
|
||||||
" }"
|
" }"
|
||||||
};
|
};
|
||||||
static const std::string DEEFAULT_NORMAL_SHADER {
|
static const std::string DEFAULT_NORMAL_SHADER {
|
||||||
"vec4 getFragmentColor() {"
|
"vec4 getFragmentColor() {"
|
||||||
" return vec4(normalize(texture(normalMap, uv).xyz), 1.0);"
|
" return vec4(normalize(texture(normalMap, uv).xyz), 1.0);"
|
||||||
" }"
|
" }"
|
||||||
};
|
};
|
||||||
static const std::string DEEFAULT_DEPTH_SHADER {
|
static const std::string DEFAULT_DEPTH_SHADER {
|
||||||
"vec4 getFragmentColor() {"
|
"vec4 getFragmentColor() {"
|
||||||
" return vec4(vec3(texture(depthMap, uv).x), 1.0);"
|
" return vec4(vec3(texture(depthMap, uv).x), 1.0);"
|
||||||
" }"
|
" }"
|
||||||
};
|
};
|
||||||
static const std::string DEEFAULT_LIGHTING_SHADER {
|
static const std::string DEFAULT_LIGHTING_SHADER {
|
||||||
"vec4 getFragmentColor() {"
|
"vec4 getFragmentColor() {"
|
||||||
" return vec4(pow(texture(lightingMap, uv).xyz, vec3(1.0 / 2.2)), 1.0);"
|
" return vec4(pow(texture(lightingMap, uv).xyz, vec3(1.0 / 2.2)), 1.0);"
|
||||||
" }"
|
" }"
|
||||||
};
|
};
|
||||||
static const std::string DEEFAULT_CUSTOM_SHADER {
|
static const std::string DEFAULT_SHADOW_SHADER {
|
||||||
|
"uniform sampler2D shadowMapColor;"
|
||||||
|
// The actual shadowMap is a sampler2DShadow, so we cannot normally sample it
|
||||||
|
"vec4 getFragmentColor() {"
|
||||||
|
" return vec4(texture(shadowMapColor, uv).xyz, 1.0);"
|
||||||
|
" }"
|
||||||
|
};
|
||||||
|
static const std::string DEFAULT_CUSTOM_SHADER {
|
||||||
"vec4 getFragmentColor() {"
|
"vec4 getFragmentColor() {"
|
||||||
" return vec4(1.0, 0.0, 0.0, 1.0);"
|
" return vec4(1.0, 0.0, 0.0, 1.0);"
|
||||||
" }"
|
" }"
|
||||||
|
@ -98,21 +107,23 @@ DebugDeferredBuffer::DebugDeferredBuffer() {
|
||||||
std::string DebugDeferredBuffer::getShaderSourceCode(Modes mode, std::string customFile) {
|
std::string DebugDeferredBuffer::getShaderSourceCode(Modes mode, std::string customFile) {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case DiffuseMode:
|
case DiffuseMode:
|
||||||
return DEEFAULT_DIFFUSE_SHADER;
|
return DEFAULT_DIFFUSE_SHADER;
|
||||||
case AlphaMode:
|
case AlphaMode:
|
||||||
return DEEFAULT_ALPHA_SHADER;
|
return DEFAULT_ALPHA_SHADER;
|
||||||
case SpecularMode:
|
case SpecularMode:
|
||||||
return DEEFAULT_SPECULAR_SHADER;
|
return DEFAULT_SPECULAR_SHADER;
|
||||||
case RoughnessMode:
|
case RoughnessMode:
|
||||||
return DEEFAULT_ROUGHNESS_SHADER;
|
return DEFAULT_ROUGHNESS_SHADER;
|
||||||
case NormalMode:
|
case NormalMode:
|
||||||
return DEEFAULT_NORMAL_SHADER;
|
return DEFAULT_NORMAL_SHADER;
|
||||||
case DepthMode:
|
case DepthMode:
|
||||||
return DEEFAULT_DEPTH_SHADER;
|
return DEFAULT_DEPTH_SHADER;
|
||||||
case LightingMode:
|
case LightingMode:
|
||||||
return DEEFAULT_LIGHTING_SHADER;
|
return DEFAULT_LIGHTING_SHADER;
|
||||||
|
case ShadowMode:
|
||||||
|
return DEFAULT_SHADOW_SHADER;
|
||||||
case CustomMode:
|
case CustomMode:
|
||||||
return getFileContent(customFile, DEEFAULT_CUSTOM_SHADER);
|
return getFileContent(customFile, DEFAULT_CUSTOM_SHADER);
|
||||||
}
|
}
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
return std::string();
|
return std::string();
|
||||||
|
@ -158,6 +169,7 @@ const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Modes mode, std::st
|
||||||
slotBindings.insert(gpu::Shader::Binding("specularMap", Specular));
|
slotBindings.insert(gpu::Shader::Binding("specularMap", Specular));
|
||||||
slotBindings.insert(gpu::Shader::Binding("depthMap", Depth));
|
slotBindings.insert(gpu::Shader::Binding("depthMap", Depth));
|
||||||
slotBindings.insert(gpu::Shader::Binding("lightingMap", Lighting));
|
slotBindings.insert(gpu::Shader::Binding("lightingMap", Lighting));
|
||||||
|
slotBindings.insert(gpu::Shader::Binding("shadowMapColor", Shadow));
|
||||||
gpu::Shader::makeProgram(*program, slotBindings);
|
gpu::Shader::makeProgram(*program, slotBindings);
|
||||||
|
|
||||||
auto pipeline = gpu::Pipeline::create(program, std::make_shared<gpu::State>());
|
auto pipeline = gpu::Pipeline::create(program, std::make_shared<gpu::State>());
|
||||||
|
@ -182,10 +194,18 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren
|
||||||
assert(renderContext->getArgs());
|
assert(renderContext->getArgs());
|
||||||
assert(renderContext->getArgs()->_viewFrustum);
|
assert(renderContext->getArgs()->_viewFrustum);
|
||||||
RenderArgs* args = renderContext->getArgs();
|
RenderArgs* args = renderContext->getArgs();
|
||||||
|
|
||||||
|
// Guard against unspecified modes
|
||||||
|
auto mode = renderContext->_deferredDebugMode;
|
||||||
|
if (mode > (int)CustomMode) {
|
||||||
|
renderContext->_deferredDebugMode = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||||
const auto geometryBuffer = DependencyManager::get<GeometryCache>();
|
const auto geometryBuffer = DependencyManager::get<GeometryCache>();
|
||||||
const auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
const auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||||
|
const auto& lightStage = DependencyManager::get<DeferredLightingEffect>()->getLightStage();
|
||||||
|
|
||||||
glm::mat4 projMat;
|
glm::mat4 projMat;
|
||||||
Transform viewMat;
|
Transform viewMat;
|
||||||
|
@ -205,6 +225,7 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren
|
||||||
batch.setResourceTexture(Specular, framebufferCache->getDeferredSpecularTexture());
|
batch.setResourceTexture(Specular, framebufferCache->getDeferredSpecularTexture());
|
||||||
batch.setResourceTexture(Depth, framebufferCache->getPrimaryDepthTexture());
|
batch.setResourceTexture(Depth, framebufferCache->getPrimaryDepthTexture());
|
||||||
batch.setResourceTexture(Lighting, framebufferCache->getLightingTexture());
|
batch.setResourceTexture(Lighting, framebufferCache->getLightingTexture());
|
||||||
|
batch.setResourceTexture(Shadow, lightStage.lights[0]->shadow.framebuffer->getRenderBuffer(0));
|
||||||
|
|
||||||
const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f);
|
const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
const glm::vec2 bottomLeft(renderContext->_deferredDebugSize.x, renderContext->_deferredDebugSize.y);
|
const glm::vec2 bottomLeft(renderContext->_deferredDebugSize.x, renderContext->_deferredDebugSize.y);
|
||||||
|
|
|
@ -33,6 +33,7 @@ private:
|
||||||
NormalMode,
|
NormalMode,
|
||||||
DepthMode,
|
DepthMode,
|
||||||
LightingMode,
|
LightingMode,
|
||||||
|
ShadowMode,
|
||||||
|
|
||||||
CustomMode // Needs to stay last
|
CustomMode // Needs to stay last
|
||||||
};
|
};
|
||||||
|
|
|
@ -31,6 +31,10 @@
|
||||||
#include "directional_ambient_light_frag.h"
|
#include "directional_ambient_light_frag.h"
|
||||||
#include "directional_skybox_light_frag.h"
|
#include "directional_skybox_light_frag.h"
|
||||||
|
|
||||||
|
#include "directional_light_shadow_frag.h"
|
||||||
|
#include "directional_ambient_light_shadow_frag.h"
|
||||||
|
#include "directional_skybox_light_shadow_frag.h"
|
||||||
|
|
||||||
#include "point_light_frag.h"
|
#include "point_light_frag.h"
|
||||||
#include "spot_light_frag.h"
|
#include "spot_light_frag.h"
|
||||||
|
|
||||||
|
@ -42,25 +46,24 @@ struct LightLocations {
|
||||||
int texcoordMat;
|
int texcoordMat;
|
||||||
int coneParam;
|
int coneParam;
|
||||||
int deferredTransformBuffer;
|
int deferredTransformBuffer;
|
||||||
|
int shadowTransformBuffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& program, LightLocationsPtr& locations);
|
static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& program, LightLocationsPtr& locations);
|
||||||
|
|
||||||
|
|
||||||
void DeferredLightingEffect::init() {
|
void DeferredLightingEffect::init() {
|
||||||
_directionalLightLocations = std::make_shared<LightLocations>();
|
_directionalLightLocations = std::make_shared<LightLocations>();
|
||||||
_directionalAmbientSphereLightLocations = std::make_shared<LightLocations>();
|
_directionalAmbientSphereLightLocations = std::make_shared<LightLocations>();
|
||||||
_directionalSkyboxLightLocations = std::make_shared<LightLocations>();
|
_directionalSkyboxLightLocations = std::make_shared<LightLocations>();
|
||||||
|
|
||||||
_pointLightLocations = std::make_shared<LightLocations>();
|
_pointLightLocations = std::make_shared<LightLocations>();
|
||||||
_spotLightLocations = std::make_shared<LightLocations>();
|
_spotLightLocations = std::make_shared<LightLocations>();
|
||||||
|
|
||||||
|
// TODO: To use shadowmaps, replace directional_*_light_frag with directional_*_light_shadow_frag shaders.
|
||||||
loadLightProgram(deferred_light_vert, directional_light_frag, false, _directionalLight, _directionalLightLocations);
|
loadLightProgram(deferred_light_vert, directional_light_frag, false, _directionalLight, _directionalLightLocations);
|
||||||
|
|
||||||
loadLightProgram(deferred_light_vert, directional_ambient_light_frag, false, _directionalAmbientSphereLight, _directionalAmbientSphereLightLocations);
|
loadLightProgram(deferred_light_vert, directional_ambient_light_frag, false, _directionalAmbientSphereLight, _directionalAmbientSphereLightLocations);
|
||||||
|
|
||||||
loadLightProgram(deferred_light_vert, directional_skybox_light_frag, false, _directionalSkyboxLight, _directionalSkyboxLightLocations);
|
loadLightProgram(deferred_light_vert, directional_skybox_light_frag, false, _directionalSkyboxLight, _directionalSkyboxLightLocations);
|
||||||
|
|
||||||
|
|
||||||
loadLightProgram(deferred_light_limited_vert, point_light_frag, true, _pointLight, _pointLightLocations);
|
loadLightProgram(deferred_light_limited_vert, point_light_frag, true, _pointLight, _pointLightLocations);
|
||||||
loadLightProgram(deferred_light_spot_vert, spot_light_frag, true, _spotLight, _spotLightLocations);
|
loadLightProgram(deferred_light_spot_vert, spot_light_frag, true, _spotLight, _spotLightLocations);
|
||||||
|
|
||||||
|
@ -69,6 +72,8 @@ void DeferredLightingEffect::init() {
|
||||||
_allocatedLights.push_back(std::make_shared<model::Light>());
|
_allocatedLights.push_back(std::make_shared<model::Light>());
|
||||||
|
|
||||||
model::LightPointer lp = _allocatedLights[0];
|
model::LightPointer lp = _allocatedLights[0];
|
||||||
|
// Add the global light to the light stage (for later shadow rendering)
|
||||||
|
_lightStage.addLight(lp);
|
||||||
|
|
||||||
lp->setDirection(-glm::vec3(1.0f, 1.0f, 1.0f));
|
lp->setDirection(-glm::vec3(1.0f, 1.0f, 1.0f));
|
||||||
lp->setColor(glm::vec3(1.0f));
|
lp->setColor(glm::vec3(1.0f));
|
||||||
|
@ -172,6 +177,12 @@ void DeferredLightingEffect::render(RenderArgs* args) {
|
||||||
batch.setResourceTexture(2, framebufferCache->getDeferredSpecularTexture());
|
batch.setResourceTexture(2, framebufferCache->getDeferredSpecularTexture());
|
||||||
batch.setResourceTexture(3, framebufferCache->getPrimaryDepthTexture());
|
batch.setResourceTexture(3, framebufferCache->getPrimaryDepthTexture());
|
||||||
|
|
||||||
|
assert(_lightStage.lights.size() > 0);
|
||||||
|
const auto& globalShadow = _lightStage.lights[0]->shadow;
|
||||||
|
|
||||||
|
// Bind the shadow buffer
|
||||||
|
batch.setResourceTexture(4, globalShadow.map);
|
||||||
|
|
||||||
// THe main viewport is assumed to be the mono viewport (or the 2 stereo faces side by side within that viewport)
|
// THe main viewport is assumed to be the mono viewport (or the 2 stereo faces side by side within that viewport)
|
||||||
auto monoViewport = args->_viewport;
|
auto monoViewport = args->_viewport;
|
||||||
float sMin = args->_viewport.x / (float)framebufferSize.width();
|
float sMin = args->_viewport.x / (float)framebufferSize.width();
|
||||||
|
@ -291,6 +302,10 @@ void DeferredLightingEffect::render(RenderArgs* args) {
|
||||||
program = _directionalAmbientSphereLight;
|
program = _directionalAmbientSphereLight;
|
||||||
locations = _directionalAmbientSphereLightLocations;
|
locations = _directionalAmbientSphereLightLocations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (locations->shadowTransformBuffer >= 0) {
|
||||||
|
batch.setUniformBuffer(locations->shadowTransformBuffer, globalShadow.getBuffer());
|
||||||
|
}
|
||||||
batch.setPipeline(program);
|
batch.setPipeline(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -478,17 +493,18 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), 1));
|
slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), 1));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), 2));
|
slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), 2));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), 3));
|
slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), 3));
|
||||||
|
slotBindings.insert(gpu::Shader::Binding(std::string("shadowMap"), 4));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), 5));
|
slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), 5));
|
||||||
|
|
||||||
static const int LIGHT_GPU_SLOT = 3;
|
static const int LIGHT_GPU_SLOT = 3;
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), LIGHT_GPU_SLOT));
|
|
||||||
static const int ATMOSPHERE_GPU_SLOT = 4;
|
static const int ATMOSPHERE_GPU_SLOT = 4;
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("atmosphereBufferUnit"), ATMOSPHERE_GPU_SLOT));
|
|
||||||
static const int DEFERRED_TRANSFORM_BUFFER_SLOT = 2;
|
static const int DEFERRED_TRANSFORM_BUFFER_SLOT = 2;
|
||||||
|
slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), LIGHT_GPU_SLOT));
|
||||||
|
slotBindings.insert(gpu::Shader::Binding(std::string("atmosphereBufferUnit"), ATMOSPHERE_GPU_SLOT));
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("deferredTransformBuffer"), DEFERRED_TRANSFORM_BUFFER_SLOT));
|
slotBindings.insert(gpu::Shader::Binding(std::string("deferredTransformBuffer"), DEFERRED_TRANSFORM_BUFFER_SLOT));
|
||||||
|
|
||||||
gpu::Shader::makeProgram(*program, slotBindings);
|
gpu::Shader::makeProgram(*program, slotBindings);
|
||||||
|
|
||||||
|
|
||||||
locations->radius = program->getUniforms().findLocation("radius");
|
locations->radius = program->getUniforms().findLocation("radius");
|
||||||
locations->ambientSphere = program->getUniforms().findLocation("ambientSphere.L00");
|
locations->ambientSphere = program->getUniforms().findLocation("ambientSphere.L00");
|
||||||
|
|
||||||
|
@ -498,6 +514,7 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo
|
||||||
locations->lightBufferUnit = program->getBuffers().findLocation("lightBuffer");
|
locations->lightBufferUnit = program->getBuffers().findLocation("lightBuffer");
|
||||||
locations->atmosphereBufferUnit = program->getBuffers().findLocation("atmosphereBufferUnit");
|
locations->atmosphereBufferUnit = program->getBuffers().findLocation("atmosphereBufferUnit");
|
||||||
locations->deferredTransformBuffer = program->getBuffers().findLocation("deferredTransformBuffer");
|
locations->deferredTransformBuffer = program->getBuffers().findLocation("deferredTransformBuffer");
|
||||||
|
locations->shadowTransformBuffer = program->getBuffers().findLocation("shadowTransformBuffer");
|
||||||
|
|
||||||
auto state = std::make_shared<gpu::State>();
|
auto state = std::make_shared<gpu::State>();
|
||||||
state->setColorWriteMask(true, true, true, false);
|
state->setColorWriteMask(true, true, true, false);
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
#include "model/Stage.h"
|
#include "model/Stage.h"
|
||||||
#include "model/Geometry.h"
|
#include "model/Geometry.h"
|
||||||
|
|
||||||
|
#include "LightStage.h"
|
||||||
|
|
||||||
class RenderArgs;
|
class RenderArgs;
|
||||||
struct LightLocations;
|
struct LightLocations;
|
||||||
using LightLocationsPtr = std::shared_ptr<LightLocations>;
|
using LightLocationsPtr = std::shared_ptr<LightLocations>;
|
||||||
|
@ -48,10 +50,13 @@ public:
|
||||||
void setAmbientLightMode(int preset);
|
void setAmbientLightMode(int preset);
|
||||||
void setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity, float ambientIntensity);
|
void setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity, float ambientIntensity);
|
||||||
void setGlobalAtmosphere(const model::AtmospherePointer& atmosphere) { _atmosphere = atmosphere; }
|
void setGlobalAtmosphere(const model::AtmospherePointer& atmosphere) { _atmosphere = atmosphere; }
|
||||||
|
|
||||||
void setGlobalSkybox(const model::SkyboxPointer& skybox);
|
void setGlobalSkybox(const model::SkyboxPointer& skybox);
|
||||||
|
|
||||||
|
const LightStage& getLightStage() { return _lightStage; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
LightStage _lightStage;
|
||||||
|
|
||||||
DeferredLightingEffect() = default;
|
DeferredLightingEffect() = default;
|
||||||
|
|
||||||
model::MeshPointer _spotLightMesh;
|
model::MeshPointer _spotLightMesh;
|
||||||
|
@ -71,26 +76,7 @@ private:
|
||||||
gpu::PipelinePointer _spotLight;
|
gpu::PipelinePointer _spotLight;
|
||||||
LightLocationsPtr _spotLightLocations;
|
LightLocationsPtr _spotLightLocations;
|
||||||
|
|
||||||
class PointLight {
|
using Lights = std::vector<model::LightPointer>;
|
||||||
public:
|
|
||||||
glm::vec4 position;
|
|
||||||
float radius;
|
|
||||||
glm::vec4 ambient;
|
|
||||||
glm::vec4 diffuse;
|
|
||||||
glm::vec4 specular;
|
|
||||||
float constantAttenuation;
|
|
||||||
float linearAttenuation;
|
|
||||||
float quadraticAttenuation;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SpotLight : public PointLight {
|
|
||||||
public:
|
|
||||||
glm::vec3 direction;
|
|
||||||
float exponent;
|
|
||||||
float cutoff;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::vector< model::LightPointer > Lights;
|
|
||||||
|
|
||||||
Lights _allocatedLights;
|
Lights _allocatedLights;
|
||||||
std::vector<int> _globalLights;
|
std::vector<int> _globalLights;
|
||||||
|
|
|
@ -183,14 +183,6 @@ void FramebufferCache::releaseFramebuffer(const gpu::FramebufferPointer& framebu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gpu::FramebufferPointer FramebufferCache::getShadowFramebuffer() {
|
|
||||||
if (!_shadowFramebuffer) {
|
|
||||||
const int SHADOW_MAP_SIZE = 2048;
|
|
||||||
_shadowFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::createShadowmap(SHADOW_MAP_SIZE));
|
|
||||||
}
|
|
||||||
return _shadowFramebuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
gpu::FramebufferPointer FramebufferCache::getSelfieFramebuffer() {
|
gpu::FramebufferPointer FramebufferCache::getSelfieFramebuffer() {
|
||||||
if (!_selfieFramebuffer) {
|
if (!_selfieFramebuffer) {
|
||||||
createPrimaryFramebuffer();
|
createPrimaryFramebuffer();
|
||||||
|
|
|
@ -23,6 +23,9 @@ class FramebufferCache : public Dependency {
|
||||||
SINGLETON_DEPENDENCY
|
SINGLETON_DEPENDENCY
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
// Shadow map size is static
|
||||||
|
static const int SHADOW_MAP_SIZE = 2048;
|
||||||
|
|
||||||
/// Sets the desired texture resolution for the framebuffer objects.
|
/// Sets the desired texture resolution for the framebuffer objects.
|
||||||
void setFrameBufferSize(QSize frameBufferSize);
|
void setFrameBufferSize(QSize frameBufferSize);
|
||||||
const QSize& getFrameBufferSize() const { return _frameBufferSize; }
|
const QSize& getFrameBufferSize() const { return _frameBufferSize; }
|
||||||
|
@ -45,9 +48,6 @@ public:
|
||||||
gpu::TexturePointer getLightingTexture();
|
gpu::TexturePointer getLightingTexture();
|
||||||
gpu::FramebufferPointer getLightingFramebuffer();
|
gpu::FramebufferPointer getLightingFramebuffer();
|
||||||
|
|
||||||
/// Returns the framebuffer object used to render shadow maps;
|
|
||||||
gpu::FramebufferPointer getShadowFramebuffer();
|
|
||||||
|
|
||||||
/// Returns the framebuffer object used to render selfie maps;
|
/// Returns the framebuffer object used to render selfie maps;
|
||||||
gpu::FramebufferPointer getSelfieFramebuffer();
|
gpu::FramebufferPointer getSelfieFramebuffer();
|
||||||
|
|
||||||
|
|
91
libraries/render-utils/src/LightStage.cpp
Normal file
91
libraries/render-utils/src/LightStage.cpp
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
//
|
||||||
|
// LightStage.cpp
|
||||||
|
// render-utils/src
|
||||||
|
//
|
||||||
|
// Created by Zach Pomerantz on 1/14/2015.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "ViewFrustum.h"
|
||||||
|
|
||||||
|
#include "LightStage.h"
|
||||||
|
|
||||||
|
LightStage::Shadow::Shadow(model::LightPointer light) : _light{ light}, _frustum{ std::make_shared<ViewFrustum>() } {
|
||||||
|
framebuffer = gpu::FramebufferPointer(gpu::Framebuffer::createShadowmap(MAP_SIZE));
|
||||||
|
map = framebuffer->getDepthStencilBuffer();
|
||||||
|
Schema schema;
|
||||||
|
_schemaBuffer = std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LightStage::Shadow::setKeylightFrustum(ViewFrustum* viewFrustum, float nearDepth, float farDepth) {
|
||||||
|
assert(nearDepth < farDepth);
|
||||||
|
|
||||||
|
// Orient the keylight frustum
|
||||||
|
const auto& direction = glm::normalize(_light->getDirection());
|
||||||
|
glm::quat orientation;
|
||||||
|
if (direction == IDENTITY_UP) {
|
||||||
|
orientation = glm::quat(glm::mat3(IDENTITY_RIGHT, IDENTITY_UP, IDENTITY_FRONT));
|
||||||
|
} else {
|
||||||
|
auto side = glm::normalize(glm::cross(direction, IDENTITY_UP));
|
||||||
|
auto up = glm::normalize(glm::cross(side, direction));
|
||||||
|
orientation = glm::quat_cast(glm::mat3(side, up, -direction));
|
||||||
|
}
|
||||||
|
_frustum->setOrientation(orientation);
|
||||||
|
|
||||||
|
// Position the keylight frustum
|
||||||
|
_frustum->setPosition(viewFrustum->getPosition() - (nearDepth + farDepth)*direction);
|
||||||
|
|
||||||
|
const Transform view{ _frustum->getView()};
|
||||||
|
const Transform viewInverse{ view.getInverseMatrix() };
|
||||||
|
|
||||||
|
viewFrustum->calculate();
|
||||||
|
auto nearCorners = viewFrustum->getCorners(nearDepth);
|
||||||
|
auto farCorners = viewFrustum->getCorners(farDepth);
|
||||||
|
|
||||||
|
vec3 min{ viewInverse.transform(nearCorners.bottomLeft) };
|
||||||
|
vec3 max{ min };
|
||||||
|
// Expand keylight frustum to fit view frustum
|
||||||
|
auto fitFrustum = [&min, &max, &viewInverse](const vec3& viewCorner) {
|
||||||
|
const auto corner = viewInverse.transform(viewCorner);
|
||||||
|
|
||||||
|
min.x = glm::min(min.x, corner.x);
|
||||||
|
min.y = glm::min(min.y, corner.y);
|
||||||
|
min.z = glm::min(min.z, corner.z);
|
||||||
|
|
||||||
|
max.x = glm::max(max.x, corner.x);
|
||||||
|
max.y = glm::max(max.y, corner.y);
|
||||||
|
max.z = glm::max(max.z, corner.z);
|
||||||
|
};
|
||||||
|
fitFrustum(nearCorners.bottomRight);
|
||||||
|
fitFrustum(nearCorners.topLeft);
|
||||||
|
fitFrustum(nearCorners.topRight);
|
||||||
|
fitFrustum(farCorners.bottomLeft);
|
||||||
|
fitFrustum(farCorners.bottomRight);
|
||||||
|
fitFrustum(farCorners.topLeft);
|
||||||
|
fitFrustum(farCorners.topRight);
|
||||||
|
|
||||||
|
glm::mat4 ortho = glm::ortho<float>(min.x, max.x, min.y, max.y, -max.z, -min.z);
|
||||||
|
_frustum->setProjection(ortho);
|
||||||
|
|
||||||
|
// Update the buffer
|
||||||
|
_schemaBuffer.edit<Schema>().projection = ortho;
|
||||||
|
_schemaBuffer.edit<Schema>().viewInverse = viewInverse.getMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
const glm::mat4& LightStage::Shadow::getView() const {
|
||||||
|
return _frustum->getView();
|
||||||
|
}
|
||||||
|
|
||||||
|
const glm::mat4& LightStage::Shadow::getProjection() const {
|
||||||
|
return _frustum->getProjection();
|
||||||
|
}
|
||||||
|
|
||||||
|
const LightStage::LightPointer LightStage::addLight(model::LightPointer light) {
|
||||||
|
Shadow stageShadow{light};
|
||||||
|
LightPointer stageLight = std::make_shared<Light>(std::move(stageShadow));
|
||||||
|
lights.push_back(stageLight);
|
||||||
|
return stageLight;
|
||||||
|
}
|
74
libraries/render-utils/src/LightStage.h
Normal file
74
libraries/render-utils/src/LightStage.h
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
//
|
||||||
|
// LightStage.h
|
||||||
|
// render-utils/src
|
||||||
|
//
|
||||||
|
// Created by Zach Pomerantz on 1/14/2015.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_render_utils_LightStage_h
|
||||||
|
#define hifi_render_utils_LightStage_h
|
||||||
|
|
||||||
|
#include "gpu/Framebuffer.h"
|
||||||
|
|
||||||
|
#include "model/Light.h"
|
||||||
|
|
||||||
|
class ViewFrustum;
|
||||||
|
|
||||||
|
// Light stage to set up light-related rendering tasks
|
||||||
|
class LightStage {
|
||||||
|
public:
|
||||||
|
class Shadow {
|
||||||
|
public:
|
||||||
|
using UniformBufferView = gpu::BufferView;
|
||||||
|
static const int MAP_SIZE = 1024;
|
||||||
|
|
||||||
|
Shadow(model::LightPointer light);
|
||||||
|
|
||||||
|
void setKeylightFrustum(ViewFrustum* viewFrustum, float nearDepth, float farDepth);
|
||||||
|
|
||||||
|
const std::shared_ptr<ViewFrustum> getFrustum() const { return _frustum; }
|
||||||
|
|
||||||
|
const glm::mat4& getView() const;
|
||||||
|
const glm::mat4& getProjection() const;
|
||||||
|
|
||||||
|
const UniformBufferView& getBuffer() const { return _schemaBuffer; }
|
||||||
|
|
||||||
|
gpu::FramebufferPointer framebuffer;
|
||||||
|
gpu::TexturePointer map;
|
||||||
|
protected:
|
||||||
|
model::LightPointer _light;
|
||||||
|
std::shared_ptr<ViewFrustum> _frustum;
|
||||||
|
|
||||||
|
class Schema {
|
||||||
|
public:
|
||||||
|
glm::mat4 projection;
|
||||||
|
glm::mat4 viewInverse;
|
||||||
|
|
||||||
|
glm::float32 bias = 0.005f;
|
||||||
|
glm::float32 scale = 1 / MAP_SIZE;
|
||||||
|
};
|
||||||
|
UniformBufferView _schemaBuffer = nullptr;
|
||||||
|
};
|
||||||
|
using ShadowPointer = std::shared_ptr<Shadow>;
|
||||||
|
|
||||||
|
class Light {
|
||||||
|
public:
|
||||||
|
Light(Shadow&& shadow) : shadow{ shadow } {}
|
||||||
|
|
||||||
|
model::LightPointer light;
|
||||||
|
Shadow shadow;
|
||||||
|
};
|
||||||
|
using LightPointer = std::shared_ptr<Light>;
|
||||||
|
using Lights = std::vector<LightPointer>;
|
||||||
|
|
||||||
|
const LightPointer addLight(model::LightPointer light);
|
||||||
|
// TODO: removeLight
|
||||||
|
|
||||||
|
Lights lights;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -77,30 +77,28 @@ RenderDeferredTask::RenderDeferredTask() : Task() {
|
||||||
ShapePlumberPointer shapePlumber = std::make_shared<ShapePlumber>();
|
ShapePlumberPointer shapePlumber = std::make_shared<ShapePlumber>();
|
||||||
initDeferredPipelines(*shapePlumber);
|
initDeferredPipelines(*shapePlumber);
|
||||||
|
|
||||||
// CPU only, create the list of renderedOpaques items
|
// CPU: Fetch the renderOpaques
|
||||||
addJob<FetchItems>("FetchOpaque", FetchItems([](const RenderContextPointer& context, int count) {
|
auto fetchedOpaques = addJob<FetchItems>("FetchOpaque", FetchItems([](const RenderContextPointer& context, int count) {
|
||||||
context->getItemsConfig().opaque.numFeed = count;
|
context->getItemsConfig().opaque.numFeed = count;
|
||||||
}));
|
}));
|
||||||
addJob<CullItems<RenderDetails::OPAQUE_ITEM>>("CullOpaque", _jobs.back().getOutput());
|
auto culledOpaques = addJob<CullItems<RenderDetails::OPAQUE_ITEM>>("CullOpaque", fetchedOpaques);
|
||||||
addJob<DepthSortItems>("DepthSortOpaque", _jobs.back().getOutput());
|
auto opaques = addJob<DepthSortItems>("DepthSortOpaque", culledOpaques);
|
||||||
auto& renderedOpaques = _jobs.back().getOutput();
|
|
||||||
|
|
||||||
// CPU only, create the list of renderedTransparents items
|
// CPU only, create the list of renderedTransparents items
|
||||||
addJob<FetchItems>("FetchTransparent", FetchItems(
|
auto fetchedTransparents = addJob<FetchItems>("FetchTransparent", FetchItems(
|
||||||
ItemFilter::Builder::transparentShape().withoutLayered(),
|
ItemFilter::Builder::transparentShape().withoutLayered(),
|
||||||
[](const RenderContextPointer& context, int count) {
|
[](const RenderContextPointer& context, int count) {
|
||||||
context->getItemsConfig().transparent.numFeed = count;
|
context->getItemsConfig().transparent.numFeed = count;
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
addJob<CullItems<RenderDetails::TRANSLUCENT_ITEM>>("CullTransparent", _jobs.back().getOutput());
|
auto culledTransparents = addJob<CullItems<RenderDetails::TRANSLUCENT_ITEM>>("CullTransparent", fetchedTransparents);
|
||||||
addJob<DepthSortItems>("DepthSortTransparent", _jobs.back().getOutput(), DepthSortItems(false));
|
auto transparents = addJob<DepthSortItems>("DepthSortTransparent", culledTransparents, DepthSortItems(false));
|
||||||
auto& renderedTransparents = _jobs.back().getOutput();
|
|
||||||
|
|
||||||
// GPU Jobs: Start preparing the deferred and lighting buffer
|
// GPU Jobs: Start preparing the deferred and lighting buffer
|
||||||
addJob<PrepareDeferred>("PrepareDeferred");
|
addJob<PrepareDeferred>("PrepareDeferred");
|
||||||
|
|
||||||
// Render opaque objects in DeferredBuffer
|
// Render opaque objects in DeferredBuffer
|
||||||
addJob<DrawOpaqueDeferred>("DrawOpaqueDeferred", renderedOpaques, shapePlumber);
|
addJob<DrawOpaqueDeferred>("DrawOpaqueDeferred", opaques, shapePlumber);
|
||||||
|
|
||||||
// Once opaque is all rendered create stencil background
|
// Once opaque is all rendered create stencil background
|
||||||
addJob<DrawStencilDeferred>("DrawOpaqueStencil");
|
addJob<DrawStencilDeferred>("DrawOpaqueStencil");
|
||||||
|
@ -116,16 +114,16 @@ RenderDeferredTask::RenderDeferredTask() : Task() {
|
||||||
|
|
||||||
// AO job, to be revisited
|
// AO job, to be revisited
|
||||||
addJob<AmbientOcclusion>("AmbientOcclusion");
|
addJob<AmbientOcclusion>("AmbientOcclusion");
|
||||||
_jobs.back().setEnabled(false);
|
|
||||||
_occlusionJobIndex = (int)_jobs.size() - 1;
|
_occlusionJobIndex = (int)_jobs.size() - 1;
|
||||||
|
enableJob(_occlusionJobIndex, false);
|
||||||
|
|
||||||
// AA job to be revisited
|
// AA job to be revisited
|
||||||
addJob<Antialiasing>("Antialiasing");
|
addJob<Antialiasing>("Antialiasing");
|
||||||
_jobs.back().setEnabled(false);
|
|
||||||
_antialiasingJobIndex = (int)_jobs.size() - 1;
|
_antialiasingJobIndex = (int)_jobs.size() - 1;
|
||||||
|
enableJob(_antialiasingJobIndex, false);
|
||||||
|
|
||||||
// Render transparent objects forward in LigthingBuffer
|
// Render transparent objects forward in LigthingBuffer
|
||||||
addJob<DrawTransparentDeferred>("DrawTransparentDeferred", renderedTransparents, shapePlumber);
|
addJob<DrawTransparentDeferred>("DrawTransparentDeferred", transparents, shapePlumber);
|
||||||
|
|
||||||
// Lighting Buffer ready for tone mapping
|
// Lighting Buffer ready for tone mapping
|
||||||
addJob<ToneMappingDeferred>("ToneMapping");
|
addJob<ToneMappingDeferred>("ToneMapping");
|
||||||
|
@ -133,24 +131,24 @@ RenderDeferredTask::RenderDeferredTask() : Task() {
|
||||||
|
|
||||||
// Debugging Deferred buffer job
|
// Debugging Deferred buffer job
|
||||||
addJob<DebugDeferredBuffer>("DebugDeferredBuffer");
|
addJob<DebugDeferredBuffer>("DebugDeferredBuffer");
|
||||||
_jobs.back().setEnabled(false);
|
|
||||||
_drawDebugDeferredBufferIndex = (int)_jobs.size() - 1;
|
_drawDebugDeferredBufferIndex = (int)_jobs.size() - 1;
|
||||||
|
enableJob(_drawDebugDeferredBufferIndex, false);
|
||||||
|
|
||||||
// Status icon rendering job
|
// Status icon rendering job
|
||||||
{
|
{
|
||||||
// Grab a texture map representing the different status icons and assign that to the drawStatsuJob
|
// Grab a texture map representing the different status icons and assign that to the drawStatsuJob
|
||||||
auto iconMapPath = PathUtils::resourcesPath() + "icons/statusIconAtlas.svg";
|
auto iconMapPath = PathUtils::resourcesPath() + "icons/statusIconAtlas.svg";
|
||||||
auto statusIconMap = DependencyManager::get<TextureCache>()->getImageTexture(iconMapPath);
|
auto statusIconMap = DependencyManager::get<TextureCache>()->getImageTexture(iconMapPath);
|
||||||
addJob<DrawStatus>("DrawStatus", renderedOpaques, DrawStatus(statusIconMap));
|
addJob<DrawStatus>("DrawStatus", opaques, DrawStatus(statusIconMap));
|
||||||
_jobs.back().setEnabled(false);
|
|
||||||
_drawStatusJobIndex = (int)_jobs.size() - 1;
|
_drawStatusJobIndex = (int)_jobs.size() - 1;
|
||||||
|
enableJob(_drawStatusJobIndex, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
addJob<DrawOverlay3D>("DrawOverlay3D", shapePlumber);
|
addJob<DrawOverlay3D>("DrawOverlay3D", shapePlumber);
|
||||||
|
|
||||||
addJob<HitEffect>("HitEffect");
|
addJob<HitEffect>("HitEffect");
|
||||||
_jobs.back().setEnabled(false);
|
|
||||||
_drawHitEffectJobIndex = (int)_jobs.size() -1;
|
_drawHitEffectJobIndex = (int)_jobs.size() -1;
|
||||||
|
enableJob(_drawHitEffectJobIndex, false);
|
||||||
|
|
||||||
addJob<Blit>("Blit");
|
addJob<Blit>("Blit");
|
||||||
}
|
}
|
||||||
|
@ -168,26 +166,15 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we turn the deferred buffer debug on/off
|
|
||||||
setDrawDebugDeferredBuffer(renderContext->_deferredDebugMode);
|
setDrawDebugDeferredBuffer(renderContext->_deferredDebugMode);
|
||||||
|
|
||||||
// Make sure we turn the displayItemStatus on/off
|
|
||||||
setDrawItemStatus(renderContext->getDrawStatus());
|
setDrawItemStatus(renderContext->getDrawStatus());
|
||||||
|
|
||||||
// Make sure we display hit effect on screen, as desired from a script
|
|
||||||
setDrawHitEffect(renderContext->getDrawHitEffect());
|
setDrawHitEffect(renderContext->getDrawHitEffect());
|
||||||
|
|
||||||
|
|
||||||
// TODO: turn on/off AO through menu item
|
// TODO: turn on/off AO through menu item
|
||||||
setOcclusionStatus(renderContext->getOcclusionStatus());
|
setOcclusionStatus(renderContext->getOcclusionStatus());
|
||||||
|
|
||||||
setAntialiasingStatus(renderContext->getFxaaStatus());
|
setAntialiasingStatus(renderContext->getFxaaStatus());
|
||||||
|
|
||||||
setToneMappingExposure(renderContext->getTone().exposure);
|
setToneMappingExposure(renderContext->getTone().exposure);
|
||||||
setToneMappingToneCurve(renderContext->getTone().toneCurve);
|
setToneMappingToneCurve(renderContext->getTone().toneCurve);
|
||||||
|
|
||||||
renderContext->getArgs()->_context->syncCache();
|
|
||||||
|
|
||||||
for (auto job : _jobs) {
|
for (auto job : _jobs) {
|
||||||
job.run(sceneContext, renderContext);
|
job.run(sceneContext, renderContext);
|
||||||
}
|
}
|
||||||
|
@ -404,7 +391,7 @@ void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const
|
||||||
batch.setProjectionTransform(projMat);
|
batch.setProjectionTransform(projMat);
|
||||||
batch.setViewTransform(viewMat);
|
batch.setViewTransform(viewMat);
|
||||||
|
|
||||||
renderLights(sceneContext, renderContext, inItems);
|
renderItems(sceneContext, renderContext, inItems);
|
||||||
});
|
});
|
||||||
args->_batch = nullptr;
|
args->_batch = nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,41 +113,32 @@ public:
|
||||||
|
|
||||||
class RenderDeferredTask : public render::Task {
|
class RenderDeferredTask : public render::Task {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
RenderDeferredTask();
|
RenderDeferredTask();
|
||||||
|
|
||||||
int _drawDebugDeferredBufferIndex = -1;
|
int _drawDebugDeferredBufferIndex;
|
||||||
int _drawStatusJobIndex = -1;
|
int _drawStatusJobIndex;
|
||||||
int _drawHitEffectJobIndex = -1;
|
int _drawHitEffectJobIndex;
|
||||||
|
int _occlusionJobIndex;
|
||||||
|
int _antialiasingJobIndex;
|
||||||
|
int _toneMappingJobIndex;
|
||||||
|
|
||||||
void setDrawDebugDeferredBuffer(int draw) {
|
void setDrawDebugDeferredBuffer(int draw) { enableJob(_drawDebugDeferredBufferIndex, draw >= 0); }
|
||||||
if (_drawDebugDeferredBufferIndex >= 0) {
|
bool doDrawDebugDeferredBuffer() const { return getEnableJob(_drawDebugDeferredBufferIndex); }
|
||||||
_jobs[_drawDebugDeferredBufferIndex].setEnabled(draw >= 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool doDrawDebugDeferredBuffer() const { if (_drawDebugDeferredBufferIndex >= 0) { return _jobs[_drawDebugDeferredBufferIndex].isEnabled(); } else { return false; } }
|
|
||||||
|
|
||||||
void setDrawItemStatus(int draw) {
|
void setDrawItemStatus(int draw) { enableJob(_drawStatusJobIndex, draw > 0); }
|
||||||
if (_drawStatusJobIndex >= 0) {
|
bool doDrawItemStatus() const { return getEnableJob(_drawStatusJobIndex); }
|
||||||
_jobs[_drawStatusJobIndex].setEnabled(draw > 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool doDrawItemStatus() const { if (_drawStatusJobIndex >= 0) { return _jobs[_drawStatusJobIndex].isEnabled(); } else { return false; } }
|
|
||||||
|
|
||||||
void setDrawHitEffect(bool draw) { if (_drawHitEffectJobIndex >= 0) { _jobs[_drawHitEffectJobIndex].setEnabled(draw); } }
|
void setDrawHitEffect(bool draw) { enableJob(_drawHitEffectJobIndex, draw); }
|
||||||
bool doDrawHitEffect() const { if (_drawHitEffectJobIndex >=0) { return _jobs[_drawHitEffectJobIndex].isEnabled(); } else { return false; } }
|
bool doDrawHitEffect() const { return getEnableJob(_drawHitEffectJobIndex); }
|
||||||
|
|
||||||
int _occlusionJobIndex = -1;
|
|
||||||
|
|
||||||
void setOcclusionStatus(bool draw) { if (_occlusionJobIndex >= 0) { _jobs[_occlusionJobIndex].setEnabled(draw); } }
|
void setOcclusionStatus(bool draw) { enableJob(_occlusionJobIndex, draw); }
|
||||||
bool doOcclusionStatus() const { if (_occlusionJobIndex >= 0) { return _jobs[_occlusionJobIndex].isEnabled(); } else { return false; } }
|
bool doOcclusionStatus() const { return getEnableJob(_occlusionJobIndex); }
|
||||||
|
|
||||||
int _antialiasingJobIndex = -1;
|
|
||||||
|
|
||||||
void setAntialiasingStatus(bool draw) { if (_antialiasingJobIndex >= 0) { _jobs[_antialiasingJobIndex].setEnabled(draw); } }
|
void setAntialiasingStatus(bool draw) { enableJob(_antialiasingJobIndex, draw); }
|
||||||
bool doAntialiasingStatus() const { if (_antialiasingJobIndex >= 0) { return _jobs[_antialiasingJobIndex].isEnabled(); } else { return false; } }
|
bool doAntialiasingStatus() const { return getEnableJob(_antialiasingJobIndex); }
|
||||||
|
|
||||||
int _toneMappingJobIndex = -1;
|
|
||||||
|
|
||||||
void setToneMappingExposure(float exposure);
|
void setToneMappingExposure(float exposure);
|
||||||
float getToneMappingExposure() const;
|
float getToneMappingExposure() const;
|
||||||
|
@ -156,11 +147,6 @@ public:
|
||||||
int getToneMappingToneCurve() const;
|
int getToneMappingToneCurve() const;
|
||||||
|
|
||||||
virtual void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
|
virtual void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
|
||||||
|
|
||||||
|
|
||||||
gpu::Queries _timerQueries;
|
|
||||||
int _currentTimerQueryIndex = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // hifi_RenderDeferredTask_h
|
#endif // hifi_RenderDeferredTask_h
|
||||||
|
|
152
libraries/render-utils/src/RenderShadowTask.cpp
Normal file
152
libraries/render-utils/src/RenderShadowTask.cpp
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
//
|
||||||
|
// RenderShadowTask.cpp
|
||||||
|
// render-utils/src/
|
||||||
|
//
|
||||||
|
// Created by Zach Pomerantz on 1/7/2016.
|
||||||
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <gpu/Context.h>
|
||||||
|
|
||||||
|
#include <ViewFrustum.h>
|
||||||
|
|
||||||
|
#include "DeferredLightingEffect.h"
|
||||||
|
#include "FramebufferCache.h"
|
||||||
|
|
||||||
|
#include "RenderShadowTask.h"
|
||||||
|
|
||||||
|
#include "model_shadow_vert.h"
|
||||||
|
#include "skin_model_shadow_vert.h"
|
||||||
|
|
||||||
|
#include "model_shadow_frag.h"
|
||||||
|
#include "skin_model_shadow_frag.h"
|
||||||
|
|
||||||
|
using namespace render;
|
||||||
|
|
||||||
|
void RenderShadowMap::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext,
|
||||||
|
const render::ShapesIDsBounds& inShapes) {
|
||||||
|
assert(renderContext->getArgs());
|
||||||
|
assert(renderContext->getArgs()->_viewFrustum);
|
||||||
|
|
||||||
|
const auto& lightStage = DependencyManager::get<DeferredLightingEffect>()->getLightStage();
|
||||||
|
const auto globalLight = lightStage.lights[0];
|
||||||
|
const auto& shadow = globalLight->shadow;
|
||||||
|
const auto& fbo = shadow.framebuffer;
|
||||||
|
|
||||||
|
RenderArgs* args = renderContext->getArgs();
|
||||||
|
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||||
|
args->_batch = &batch;
|
||||||
|
|
||||||
|
glm::ivec4 viewport{0, 0, fbo->getWidth(), fbo->getHeight()};
|
||||||
|
batch.setViewportTransform(viewport);
|
||||||
|
batch.setStateScissorRect(viewport);
|
||||||
|
|
||||||
|
batch.setFramebuffer(fbo);
|
||||||
|
batch.clearFramebuffer(
|
||||||
|
gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_DEPTH,
|
||||||
|
vec4(vec3(1.0, 1.0, 1.0), 1.0), 1.0, 0, true);
|
||||||
|
|
||||||
|
batch.setProjectionTransform(shadow.getProjection());
|
||||||
|
batch.setViewTransform(shadow.getView());
|
||||||
|
|
||||||
|
auto shadowPipeline = _shapePlumber->pickPipeline(args, ShapeKey());
|
||||||
|
auto shadowSkinnedPipeline = _shapePlumber->pickPipeline(args, ShapeKey::Builder().withSkinned());
|
||||||
|
args->_pipeline = shadowPipeline;
|
||||||
|
batch.setPipeline(shadowPipeline->pipeline);
|
||||||
|
|
||||||
|
std::vector<ShapeKey> skinnedShapeKeys{};
|
||||||
|
for (auto items : inShapes) {
|
||||||
|
if (items.first.isSkinned()) {
|
||||||
|
skinnedShapeKeys.push_back(items.first);
|
||||||
|
} else {
|
||||||
|
renderItems(sceneContext, renderContext, items.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
args->_pipeline = shadowSkinnedPipeline;
|
||||||
|
batch.setPipeline(shadowSkinnedPipeline->pipeline);
|
||||||
|
for (const auto& key : skinnedShapeKeys) {
|
||||||
|
renderItems(sceneContext, renderContext, inShapes.at(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
args->_pipeline = nullptr;
|
||||||
|
args->_batch = nullptr;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderShadowTask::RenderShadowTask() : Task() {
|
||||||
|
// Prepare the ShapePipeline
|
||||||
|
ShapePlumberPointer shapePlumber = std::make_shared<ShapePlumber>();
|
||||||
|
{
|
||||||
|
auto state = std::make_shared<gpu::State>();
|
||||||
|
state->setCullMode(gpu::State::CULL_BACK);
|
||||||
|
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||||
|
|
||||||
|
auto modelVertex = gpu::Shader::createVertex(std::string(model_shadow_vert));
|
||||||
|
auto modelPixel = gpu::Shader::createPixel(std::string(model_shadow_frag));
|
||||||
|
gpu::ShaderPointer modelProgram = gpu::Shader::createProgram(modelVertex, modelPixel);
|
||||||
|
shapePlumber->addPipeline(
|
||||||
|
ShapeKey::Filter::Builder().withoutSkinned(),
|
||||||
|
modelProgram, state);
|
||||||
|
|
||||||
|
auto skinVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert));
|
||||||
|
auto skinPixel = gpu::Shader::createPixel(std::string(skin_model_shadow_frag));
|
||||||
|
gpu::ShaderPointer skinProgram = gpu::Shader::createProgram(skinVertex, skinPixel);
|
||||||
|
shapePlumber->addPipeline(
|
||||||
|
ShapeKey::Filter::Builder().withSkinned(),
|
||||||
|
skinProgram, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
// CPU: Fetch shadow-casting opaques
|
||||||
|
auto fetchedItems = addJob<FetchItems>("FetchShadowMap");
|
||||||
|
|
||||||
|
// CPU: Cull against KeyLight frustum (nearby viewing camera)
|
||||||
|
auto culledItems = addJob<CullItems<RenderDetails::SHADOW_ITEM>>("CullShadowMap", fetchedItems);
|
||||||
|
|
||||||
|
// CPU: Sort by pipeline
|
||||||
|
auto sortedShapes = addJob<PipelineSortShapes>("PipelineSortShadowSort", culledItems);
|
||||||
|
|
||||||
|
// CPU: Sort front to back
|
||||||
|
auto shadowShapes = addJob<DepthSortShapes>("DepthSortShadowMap", sortedShapes);
|
||||||
|
|
||||||
|
// GPU: Render to shadow map
|
||||||
|
addJob<RenderShadowMap>("RenderShadowMap", shadowShapes, shapePlumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderShadowTask::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||||
|
assert(sceneContext);
|
||||||
|
RenderArgs* args = renderContext->getArgs();
|
||||||
|
|
||||||
|
// sanity checks
|
||||||
|
if (!sceneContext->_scene || !args) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& lightStage = DependencyManager::get<DeferredLightingEffect>()->getLightStage();
|
||||||
|
const auto globalLight = lightStage.lights[0];
|
||||||
|
|
||||||
|
// If the global light is not set, bail
|
||||||
|
if (!globalLight) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewFrustum* viewFrustum = args->_viewFrustum;
|
||||||
|
|
||||||
|
auto nearClip = viewFrustum->getNearClip();
|
||||||
|
const int SHADOW_NEAR_DEPTH = -2;
|
||||||
|
const int SHADOW_FAR_DEPTH = 20;
|
||||||
|
globalLight->shadow.setKeylightFrustum(viewFrustum, nearClip + SHADOW_NEAR_DEPTH, nearClip + SHADOW_FAR_DEPTH);
|
||||||
|
|
||||||
|
// Set the keylight frustum
|
||||||
|
args->_viewFrustum = globalLight->shadow.getFrustum().get();
|
||||||
|
|
||||||
|
for (auto job : _jobs) {
|
||||||
|
job.run(sceneContext, renderContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the view frustum
|
||||||
|
args->_viewFrustum = viewFrustum;
|
||||||
|
};
|
41
libraries/render-utils/src/RenderShadowTask.h
Normal file
41
libraries/render-utils/src/RenderShadowTask.h
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
//
|
||||||
|
// RenderShadowTask.h
|
||||||
|
// render-utils/src/
|
||||||
|
//
|
||||||
|
// Created by Zach Pomerantz on 1/7/2016.
|
||||||
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_RenderShadowTask_h
|
||||||
|
#define hifi_RenderShadowTask_h
|
||||||
|
|
||||||
|
#include <gpu/Framebuffer.h>
|
||||||
|
#include <gpu/Pipeline.h>
|
||||||
|
|
||||||
|
#include <render/Scene.h>
|
||||||
|
#include <render/DrawTask.h>
|
||||||
|
|
||||||
|
class ViewFrustum;
|
||||||
|
|
||||||
|
class RenderShadowMap {
|
||||||
|
public:
|
||||||
|
RenderShadowMap(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {}
|
||||||
|
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext,
|
||||||
|
const render::ShapesIDsBounds& inShapes);
|
||||||
|
|
||||||
|
using JobModel = render::Task::Job::ModelI<RenderShadowMap, render::ShapesIDsBounds>;
|
||||||
|
protected:
|
||||||
|
render::ShapePlumberPointer _shapePlumber;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RenderShadowTask : public render::Task {
|
||||||
|
public:
|
||||||
|
RenderShadowTask();
|
||||||
|
|
||||||
|
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_RenderShadowTask_h
|
|
@ -14,34 +14,51 @@
|
||||||
// the shadow texture
|
// the shadow texture
|
||||||
uniform sampler2DShadow shadowMap;
|
uniform sampler2DShadow shadowMap;
|
||||||
|
|
||||||
struct EyePlanes {
|
struct ShadowTransform {
|
||||||
vec4 _S[1];
|
mat4 projection;
|
||||||
vec4 _T[1];
|
mat4 viewInverse;
|
||||||
vec4 _R[1];
|
|
||||||
vec4 _Q[1];
|
float bias;
|
||||||
|
float scale;
|
||||||
};
|
};
|
||||||
|
|
||||||
uniform eyePlanes {
|
uniform shadowTransformBuffer {
|
||||||
EyePlanes _eyePlanes;
|
ShadowTransform _shadowTransform;
|
||||||
};
|
};
|
||||||
|
|
||||||
EyePlanes getEyePlanes() {
|
mat4 getShadowViewInverse() {
|
||||||
return _eyePlanes;
|
return _shadowTransform.viewInverse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mat4 getShadowProjection() {
|
||||||
// Fetching it
|
return _shadowTransform.projection;
|
||||||
float fetchShadow(vec3 texcoord) {
|
|
||||||
return texture(shadowMap, texcoord);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// the distances to the cascade sections
|
float getShadowScale() {
|
||||||
uniform vec3 shadowDistances;
|
return _shadowTransform.scale;
|
||||||
|
}
|
||||||
|
|
||||||
// the inverse of the size of the shadow map
|
float getShadowBias() {
|
||||||
uniform float shadowScale;
|
return _shadowTransform.bias;
|
||||||
|
}
|
||||||
|
|
||||||
uniform mat4 shadowMatrices[4];
|
// Compute the texture coordinates from world coordinates
|
||||||
|
vec4 evalShadowTexcoord(vec4 position) {
|
||||||
|
mat4 biasMatrix = mat4(
|
||||||
|
0.5, 0.0, 0.0, 0.0,
|
||||||
|
0.0, 0.5, 0.0, 0.0,
|
||||||
|
0.0, 0.0, 0.5, 0.0,
|
||||||
|
0.5, 0.5, 0.5, 1.0);
|
||||||
|
float bias = -getShadowBias();
|
||||||
|
|
||||||
|
vec4 shadowCoord = biasMatrix * getShadowProjection() * getShadowViewInverse() * position;
|
||||||
|
return vec4(shadowCoord.xy, shadowCoord.z + bias, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sample the shadowMap with PCF (built-in)
|
||||||
|
float fetchShadow(vec3 shadowTexcoord) {
|
||||||
|
return texture(shadowMap, shadowTexcoord);
|
||||||
|
}
|
||||||
|
|
||||||
vec2 samples[8] = vec2[8](
|
vec2 samples[8] = vec2[8](
|
||||||
vec2(-2.0, -2.0),
|
vec2(-2.0, -2.0),
|
||||||
|
@ -54,80 +71,33 @@ vec2 samples[8] = vec2[8](
|
||||||
vec2(0.0, -1.0)
|
vec2(0.0, -1.0)
|
||||||
);
|
);
|
||||||
|
|
||||||
vec4 evalShadowTexcoord(vec4 position) {
|
float evalShadowAttenuationSampling(vec4 shadowTexcoord) {
|
||||||
// compute the corresponding texture coordinates
|
float shadowScale = getShadowScale();
|
||||||
EyePlanes eyePlanes = getEyePlanes();
|
|
||||||
vec3 shadowTexcoord = vec3(dot(eyePlanes._S[0], position), dot(eyePlanes._T[0], position), dot(eyePlanes._R[0], position));
|
|
||||||
return vec4(shadowTexcoord, 0.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec4 evalCascadedShadowTexcoord(vec4 position) {
|
|
||||||
EyePlanes eyePlanes = getEyePlanes();
|
|
||||||
|
|
||||||
// compute the index of the cascade to use and the corresponding texture coordinates
|
|
||||||
int shadowIndex = int(dot(step(vec3(position.z), shadowDistances), vec3(1.0, 1.0, 1.0)));
|
|
||||||
vec3 shadowTexcoord = vec3(
|
|
||||||
dot(eyePlanes._S[shadowIndex], position),
|
|
||||||
dot(eyePlanes._T[shadowIndex], position),
|
|
||||||
dot(eyePlanes._R[shadowIndex], position));
|
|
||||||
|
|
||||||
return vec4(shadowTexcoord, shadowIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
float evalShadowAttenuationPCF(vec4 shadowTexcoord) {
|
|
||||||
float radiusScale = (shadowTexcoord.w + 1.0);
|
|
||||||
float shadowAttenuation = (0.25 * (
|
float shadowAttenuation = (0.25 * (
|
||||||
fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[0], 0.0)) +
|
fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(samples[0], 0.0)) +
|
||||||
fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[1], 0.0)) +
|
fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(samples[1], 0.0)) +
|
||||||
fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[2], 0.0)) +
|
fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(samples[2], 0.0)) +
|
||||||
fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[3], 0.0))
|
fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(samples[3], 0.0))
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// Check for early bailing
|
||||||
if ((shadowAttenuation > 0) && (shadowAttenuation < 1.0)) {
|
if ((shadowAttenuation > 0) && (shadowAttenuation < 1.0)) {
|
||||||
radiusScale *= 0.5;
|
|
||||||
shadowAttenuation = 0.5 * shadowAttenuation + (0.125 * (
|
shadowAttenuation = 0.5 * shadowAttenuation + (0.125 * (
|
||||||
fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[4], 0.0)) +
|
fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(samples[4], 0.0)) +
|
||||||
fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[5], 0.0)) +
|
fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(samples[5], 0.0)) +
|
||||||
fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[6], 0.0)) +
|
fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(samples[6], 0.0)) +
|
||||||
fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[7], 0.0))
|
fetchShadow(shadowTexcoord.xyz + shadowScale * vec3(samples[7], 0.0))
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
return shadowAttenuation;
|
return shadowAttenuation;
|
||||||
}
|
}
|
||||||
|
|
||||||
float evalShadowAttenuationBasic(vec4 shadowTexcoord) {
|
float evalShadowAttenuation(vec4 position) {
|
||||||
float radiusScale = 0.5;
|
vec4 shadowTexcoord = evalShadowTexcoord(position);
|
||||||
float shadowAttenuation = (0.25 * (
|
|
||||||
fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[0], 0.0)) +
|
return evalShadowAttenuationSampling(shadowTexcoord);
|
||||||
fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[1], 0.0)) +
|
|
||||||
fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[2], 0.0)) +
|
|
||||||
fetchShadow(shadowTexcoord.xyz + radiusScale * shadowScale * vec3(samples[3], 0.0))
|
|
||||||
));
|
|
||||||
return shadowAttenuation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float evalShadowAttenuation(vec4 shadowTexcoord) {
|
|
||||||
return evalShadowAttenuationBasic(shadowTexcoord);
|
|
||||||
}
|
|
||||||
|
|
||||||
<!
|
|
||||||
vec3 debugShadowMap(float shadowAttenuation, vec4 shadowTexcoord) {
|
|
||||||
vec3 colorArray[4];
|
|
||||||
colorArray[0].xyz = vec3(1.0, 1.0, 1.0);
|
|
||||||
colorArray[1].xyz = vec3(1.0, 0.0, 0.0);
|
|
||||||
colorArray[2].xyz = vec3(0.0, 1.0, 0.0);
|
|
||||||
colorArray[3].xyz = vec3(0.0, 0.0, 1.0);
|
|
||||||
|
|
||||||
vec2 offsetArray[4];
|
|
||||||
offsetArray[0] = vec2(0.0, 0.0);
|
|
||||||
offsetArray[1] = vec2(0.5, 0.0);
|
|
||||||
offsetArray[2] = vec2(0.0, 0.5);
|
|
||||||
offsetArray[3] = vec2(0.5, 0.5);
|
|
||||||
|
|
||||||
return shadowAttenuation * colorArray[int(shadowTexcoord.w)];
|
|
||||||
// return shadowAttenuation * vec3(2.0*(shadowTexcoord.xy - offsetArray[int(shadowTexcoord.w)]), 0);
|
|
||||||
}
|
|
||||||
!>
|
|
||||||
|
|
||||||
<@endif@>
|
<@endif@>
|
||||||
|
|
|
@ -6,15 +6,13 @@
|
||||||
// fragment shader
|
// fragment shader
|
||||||
//
|
//
|
||||||
// Created by Andrzej Kapolka on 9/3/14.
|
// Created by Andrzej Kapolka on 9/3/14.
|
||||||
// Copyright 2014 High Fidelity, Inc.
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
//
|
//
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
// Everything about deferred buffer
|
|
||||||
<@include DeferredBuffer.slh@>
|
<@include DeferredBuffer.slh@>
|
||||||
|
|
||||||
<@include DeferredGlobalLight.slh@>
|
<@include DeferredGlobalLight.slh@>
|
||||||
|
|
||||||
<$declareEvalLightmappedColor()$>
|
<$declareEvalLightmappedColor()$>
|
||||||
|
@ -27,10 +25,12 @@ void main(void) {
|
||||||
DeferredTransform deferredTransform = getDeferredTransform();
|
DeferredTransform deferredTransform = getDeferredTransform();
|
||||||
DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0);
|
DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0);
|
||||||
|
|
||||||
|
float shadowAttenuation = 1.0;
|
||||||
|
|
||||||
if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) {
|
if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) {
|
||||||
vec3 color = evalLightmappedColor(
|
vec3 color = evalLightmappedColor(
|
||||||
deferredTransform.viewInverse,
|
deferredTransform.viewInverse,
|
||||||
1.0,
|
shadowAttenuation,
|
||||||
frag.normal,
|
frag.normal,
|
||||||
frag.diffuse,
|
frag.diffuse,
|
||||||
frag.specularVal.xyz);
|
frag.specularVal.xyz);
|
||||||
|
@ -38,7 +38,7 @@ void main(void) {
|
||||||
} else {
|
} else {
|
||||||
vec3 color = evalAmbientSphereGlobalColor(
|
vec3 color = evalAmbientSphereGlobalColor(
|
||||||
deferredTransform.viewInverse,
|
deferredTransform.viewInverse,
|
||||||
1.0,
|
shadowAttenuation,
|
||||||
frag.position.xyz,
|
frag.position.xyz,
|
||||||
frag.normal,
|
frag.normal,
|
||||||
frag.diffuse,
|
frag.diffuse,
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
<@include gpu/Config.slh@>
|
||||||
|
<$VERSION_HEADER$>
|
||||||
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
|
//
|
||||||
|
// directional_light_shadow.frag
|
||||||
|
// fragment shader
|
||||||
|
//
|
||||||
|
// Created by Zach Pomerantz on 1/18/2016.
|
||||||
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
<@include Shadow.slh@>
|
||||||
|
<@include DeferredBuffer.slh@>
|
||||||
|
<@include DeferredGlobalLight.slh@>
|
||||||
|
|
||||||
|
<$declareEvalLightmappedColor()$>
|
||||||
|
<$declareEvalAmbientSphereGlobalColor()$>
|
||||||
|
|
||||||
|
in vec2 _texCoord0;
|
||||||
|
out vec4 _fragColor;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
DeferredTransform deferredTransform = getDeferredTransform();
|
||||||
|
DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0);
|
||||||
|
|
||||||
|
vec4 worldPos = deferredTransform.viewInverse * vec4(frag.position.xyz, 1.0);
|
||||||
|
float shadowAttenuation = evalShadowAttenuation(worldPos);
|
||||||
|
|
||||||
|
if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) {
|
||||||
|
vec3 color = evalLightmappedColor(
|
||||||
|
deferredTransform.viewInverse,
|
||||||
|
shadowAttenuation,
|
||||||
|
frag.normal,
|
||||||
|
frag.diffuse,
|
||||||
|
frag.specularVal.xyz);
|
||||||
|
_fragColor = vec4(color, 1.0);
|
||||||
|
} else {
|
||||||
|
vec3 color = evalAmbientSphereGlobalColor(
|
||||||
|
deferredTransform.viewInverse,
|
||||||
|
shadowAttenuation,
|
||||||
|
frag.position.xyz,
|
||||||
|
frag.normal,
|
||||||
|
frag.diffuse,
|
||||||
|
frag.specular,
|
||||||
|
frag.gloss);
|
||||||
|
_fragColor = vec4(color, frag.normalVal.a);
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,15 +6,13 @@
|
||||||
// fragment shader
|
// fragment shader
|
||||||
//
|
//
|
||||||
// Created by Andrzej Kapolka on 9/3/14.
|
// Created by Andrzej Kapolka on 9/3/14.
|
||||||
// Copyright 2014 High Fidelity, Inc.
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
//
|
//
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
// Everything about deferred buffer
|
|
||||||
<@include DeferredBuffer.slh@>
|
<@include DeferredBuffer.slh@>
|
||||||
|
|
||||||
<@include DeferredGlobalLight.slh@>
|
<@include DeferredGlobalLight.slh@>
|
||||||
|
|
||||||
<$declareEvalLightmappedColor()$>
|
<$declareEvalLightmappedColor()$>
|
||||||
|
@ -27,11 +25,13 @@ void main(void) {
|
||||||
DeferredTransform deferredTransform = getDeferredTransform();
|
DeferredTransform deferredTransform = getDeferredTransform();
|
||||||
DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0);
|
DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0);
|
||||||
|
|
||||||
|
float shadowAttenuation = 1.0;
|
||||||
|
|
||||||
// Light mapped or not ?
|
// Light mapped or not ?
|
||||||
if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) {
|
if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) {
|
||||||
vec3 color = evalLightmappedColor(
|
vec3 color = evalLightmappedColor(
|
||||||
deferredTransform.viewInverse,
|
deferredTransform.viewInverse,
|
||||||
1.0,
|
shadowAttenuation,
|
||||||
frag.normal,
|
frag.normal,
|
||||||
frag.diffuse,
|
frag.diffuse,
|
||||||
frag.specularVal.xyz);
|
frag.specularVal.xyz);
|
||||||
|
@ -39,7 +39,7 @@ void main(void) {
|
||||||
} else {
|
} else {
|
||||||
vec3 color = evalAmbientGlobalColor(
|
vec3 color = evalAmbientGlobalColor(
|
||||||
deferredTransform.viewInverse,
|
deferredTransform.viewInverse,
|
||||||
1.0,
|
shadowAttenuation,
|
||||||
frag.position.xyz,
|
frag.position.xyz,
|
||||||
frag.normal,
|
frag.normal,
|
||||||
frag.diffuse,
|
frag.diffuse,
|
||||||
|
|
52
libraries/render-utils/src/directional_light_shadow.slf
Normal file
52
libraries/render-utils/src/directional_light_shadow.slf
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<@include gpu/Config.slh@>
|
||||||
|
<$VERSION_HEADER$>
|
||||||
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
|
//
|
||||||
|
// directional_light_shadow.frag
|
||||||
|
// fragment shader
|
||||||
|
//
|
||||||
|
// Created by Zach Pomerantz on 1/18/2016.
|
||||||
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
<@include Shadow.slh@>
|
||||||
|
<@include DeferredBuffer.slh@>
|
||||||
|
<@include DeferredGlobalLight.slh@>
|
||||||
|
|
||||||
|
<$declareEvalLightmappedColor()$>
|
||||||
|
<$declareEvalAmbientGlobalColor()$>
|
||||||
|
|
||||||
|
in vec2 _texCoord0;
|
||||||
|
out vec4 _fragColor;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
DeferredTransform deferredTransform = getDeferredTransform();
|
||||||
|
DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0);
|
||||||
|
|
||||||
|
vec4 worldPos = deferredTransform.viewInverse * vec4(frag.position.xyz, 1.0);
|
||||||
|
float shadowAttenuation = evalShadowAttenuation(worldPos);
|
||||||
|
|
||||||
|
// Light mapped or not ?
|
||||||
|
if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) {
|
||||||
|
vec3 color = evalLightmappedColor(
|
||||||
|
deferredTransform.viewInverse,
|
||||||
|
shadowAttenuation,
|
||||||
|
frag.normal,
|
||||||
|
frag.diffuse,
|
||||||
|
frag.specularVal.xyz);
|
||||||
|
_fragColor = vec4(color, 1.0);
|
||||||
|
} else {
|
||||||
|
vec3 color = evalAmbientGlobalColor(
|
||||||
|
deferredTransform.viewInverse,
|
||||||
|
shadowAttenuation,
|
||||||
|
frag.position.xyz,
|
||||||
|
frag.normal,
|
||||||
|
frag.diffuse,
|
||||||
|
frag.specular,
|
||||||
|
frag.gloss);
|
||||||
|
_fragColor = vec4(color, frag.normalVal.a);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,18 +3,16 @@
|
||||||
// Generated on <$_SCRIBE_DATE$>
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
//
|
//
|
||||||
// directional_light.frag
|
// directional_light.frag
|
||||||
<!// fragment shader
|
// fragment shader
|
||||||
//
|
//
|
||||||
// Created by Sam Gateau on 5/8/2015.
|
// Created by Sam Gateau on 5/8/2015.
|
||||||
// Copyright 2014 High Fidelity, Inc.
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
//
|
//
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//!>
|
//
|
||||||
|
|
||||||
// Everything about deferred buffer
|
|
||||||
<@include DeferredBuffer.slh@>
|
<@include DeferredBuffer.slh@>
|
||||||
|
|
||||||
<@include DeferredGlobalLight.slh@>
|
<@include DeferredGlobalLight.slh@>
|
||||||
|
|
||||||
<$declareEvalLightmappedColor()$>
|
<$declareEvalLightmappedColor()$>
|
||||||
|
@ -27,11 +25,13 @@ void main(void) {
|
||||||
DeferredTransform deferredTransform = getDeferredTransform();
|
DeferredTransform deferredTransform = getDeferredTransform();
|
||||||
DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0);
|
DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0);
|
||||||
|
|
||||||
|
float shadowAttenuation = 1.0;
|
||||||
|
|
||||||
// Light mapped or not ?
|
// Light mapped or not ?
|
||||||
if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) {
|
if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) {
|
||||||
vec3 color = evalLightmappedColor(
|
vec3 color = evalLightmappedColor(
|
||||||
deferredTransform.viewInverse,
|
deferredTransform.viewInverse,
|
||||||
1.0,
|
shadowAttenuation,
|
||||||
frag.normal,
|
frag.normal,
|
||||||
frag.diffuse,
|
frag.diffuse,
|
||||||
frag.specularVal.xyz);
|
frag.specularVal.xyz);
|
||||||
|
@ -39,7 +39,7 @@ void main(void) {
|
||||||
} else {
|
} else {
|
||||||
vec3 color = evalSkyboxGlobalColor(
|
vec3 color = evalSkyboxGlobalColor(
|
||||||
deferredTransform.viewInverse,
|
deferredTransform.viewInverse,
|
||||||
1.0,
|
shadowAttenuation,
|
||||||
frag.position.xyz,
|
frag.position.xyz,
|
||||||
frag.normal,
|
frag.normal,
|
||||||
frag.diffuse,
|
frag.diffuse,
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
<@include gpu/Config.slh@>
|
||||||
|
<$VERSION_HEADER$>
|
||||||
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
|
//
|
||||||
|
// directional_light_shadow.frag
|
||||||
|
// fragment shader
|
||||||
|
//
|
||||||
|
// Created by Zach Pomerantz on 1/18/2016.
|
||||||
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//!>
|
||||||
|
|
||||||
|
<@include Shadow.slh@>
|
||||||
|
<@include DeferredBuffer.slh@>
|
||||||
|
<@include DeferredGlobalLight.slh@>
|
||||||
|
|
||||||
|
<$declareEvalLightmappedColor()$>
|
||||||
|
<$declareEvalSkyboxGlobalColor()$>
|
||||||
|
|
||||||
|
in vec2 _texCoord0;
|
||||||
|
out vec4 _fragColor;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
DeferredTransform deferredTransform = getDeferredTransform();
|
||||||
|
DeferredFragment frag = unpackDeferredFragment(deferredTransform, _texCoord0);
|
||||||
|
|
||||||
|
vec4 worldPos = deferredTransform.viewInverse * vec4(frag.position.xyz, 1.0);
|
||||||
|
float shadowAttenuation = evalShadowAttenuation(worldPos);
|
||||||
|
|
||||||
|
// Light mapped or not ?
|
||||||
|
if ((frag.normalVal.a >= 0.45) && (frag.normalVal.a <= 0.55)) {
|
||||||
|
vec3 color = evalLightmappedColor(
|
||||||
|
deferredTransform.viewInverse,
|
||||||
|
shadowAttenuation,
|
||||||
|
frag.normal,
|
||||||
|
frag.diffuse,
|
||||||
|
frag.specularVal.xyz);
|
||||||
|
_fragColor = vec4(color, 1.0);
|
||||||
|
} else {
|
||||||
|
vec3 color = evalSkyboxGlobalColor(
|
||||||
|
deferredTransform.viewInverse,
|
||||||
|
shadowAttenuation,
|
||||||
|
frag.position.xyz,
|
||||||
|
frag.normal,
|
||||||
|
frag.diffuse,
|
||||||
|
frag.specular,
|
||||||
|
frag.gloss);
|
||||||
|
|
||||||
|
_fragColor = vec4(color, frag.normalVal.a);
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,9 +12,9 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
out vec4 _fragColor;
|
layout(location = 0) out vec4 _fragColor;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
// fixed color for now (we may eventually want to use texture alpha)
|
// stencil in solid color for debugging
|
||||||
_fragColor = vec4(1.0, 1.0, 1.0, 0.0);
|
_fragColor = vec4(0.0, 0.0, 1.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
20
libraries/render-utils/src/skin_model_shadow.slf
Normal file
20
libraries/render-utils/src/skin_model_shadow.slf
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<@include gpu/Config.slh@>
|
||||||
|
<$VERSION_HEADER$>
|
||||||
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
|
//
|
||||||
|
// model_shadow.frag
|
||||||
|
// fragment shader
|
||||||
|
//
|
||||||
|
// Created by Andrzej Kapolka on 3/24/14.
|
||||||
|
// Copyright 2013 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 _fragColor;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
// stencil in solid color for debugging
|
||||||
|
_fragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
||||||
|
}
|
|
@ -18,7 +18,6 @@
|
||||||
#include <ViewFrustum.h>
|
#include <ViewFrustum.h>
|
||||||
#include <gpu/Context.h>
|
#include <gpu/Context.h>
|
||||||
|
|
||||||
|
|
||||||
using namespace render;
|
using namespace render;
|
||||||
|
|
||||||
void render::cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) {
|
void render::cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) {
|
||||||
|
@ -62,27 +61,6 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont
|
||||||
renderDetails->_rendered += outItems.size();
|
renderDetails->_rendered += outItems.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FetchItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemIDsBounds& outItems) {
|
|
||||||
auto& scene = sceneContext->_scene;
|
|
||||||
|
|
||||||
outItems.clear();
|
|
||||||
|
|
||||||
const auto& bucket = scene->getMasterBucket();
|
|
||||||
const auto& items = bucket.find(_filter);
|
|
||||||
if (items != bucket.end()) {
|
|
||||||
outItems.reserve(items->second.size());
|
|
||||||
for (auto& id : items->second) {
|
|
||||||
auto& item = scene->getItem(id);
|
|
||||||
outItems.emplace_back(ItemIDAndBounds(id, item.getBound()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_probeNumItems) {
|
|
||||||
_probeNumItems(renderContext, (int)outItems.size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ItemBound {
|
struct ItemBound {
|
||||||
float _centerDepth = 0.0f;
|
float _centerDepth = 0.0f;
|
||||||
float _nearDepth = 0.0f;
|
float _nearDepth = 0.0f;
|
||||||
|
@ -146,14 +124,7 @@ void render::depthSortItems(const SceneContextPointer& sceneContext, const Rende
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void render::renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) {
|
||||||
void DepthSortItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) {
|
|
||||||
outItems.clear();
|
|
||||||
outItems.reserve(inItems.size());
|
|
||||||
depthSortItems(sceneContext, renderContext, _frontToBack, inItems, outItems);
|
|
||||||
}
|
|
||||||
|
|
||||||
void render::renderLights(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) {
|
|
||||||
auto& scene = sceneContext->_scene;
|
auto& scene = sceneContext->_scene;
|
||||||
RenderArgs* args = renderContext->getArgs();
|
RenderArgs* args = renderContext->getArgs();
|
||||||
|
|
||||||
|
@ -190,6 +161,30 @@ void render::renderShapes(const SceneContextPointer& sceneContext, const RenderC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FetchItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemIDsBounds& outItems) {
|
||||||
|
auto& scene = sceneContext->_scene;
|
||||||
|
|
||||||
|
outItems.clear();
|
||||||
|
|
||||||
|
const auto& bucket = scene->getMasterBucket();
|
||||||
|
const auto& items = bucket.find(_filter);
|
||||||
|
if (items != bucket.end()) {
|
||||||
|
outItems.reserve(items->second.size());
|
||||||
|
for (auto& id : items->second) {
|
||||||
|
auto& item = scene->getItem(id);
|
||||||
|
outItems.emplace_back(ItemIDAndBounds(id, item.getBound()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_probeNumItems) {
|
||||||
|
_probeNumItems(renderContext, (int)outItems.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DepthSortItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) {
|
||||||
|
depthSortItems(sceneContext, renderContext, _frontToBack, inItems, outItems);
|
||||||
|
}
|
||||||
|
|
||||||
void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||||
assert(renderContext->getArgs());
|
assert(renderContext->getArgs());
|
||||||
assert(renderContext->getArgs()->_viewFrustum);
|
assert(renderContext->getArgs()->_viewFrustum);
|
||||||
|
@ -214,7 +209,39 @@ void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContext
|
||||||
|
|
||||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||||
args->_batch = &batch;
|
args->_batch = &batch;
|
||||||
renderLights(sceneContext, renderContext, culledItems);
|
renderItems(sceneContext, renderContext, culledItems);
|
||||||
args->_batch = nullptr;
|
args->_batch = nullptr;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PipelineSortShapes::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ShapesIDsBounds& outShapes) {
|
||||||
|
auto& scene = sceneContext->_scene;
|
||||||
|
outShapes.clear();
|
||||||
|
|
||||||
|
for (const auto& item : inItems) {
|
||||||
|
auto key = scene->getItem(item.id).getShapeKey();
|
||||||
|
auto outItems = outShapes.find(key);
|
||||||
|
if (outItems == outShapes.end()) {
|
||||||
|
outItems = outShapes.insert(std::make_pair(key, ItemIDsBounds{})).first;
|
||||||
|
outItems->second.reserve(inItems.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
outItems->second.push_back(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& items : outShapes) {
|
||||||
|
items.second.shrink_to_fit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DepthSortShapes::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapesIDsBounds& inShapes, ShapesIDsBounds& outShapes) {
|
||||||
|
for (auto& pipeline : inShapes) {
|
||||||
|
auto& inItems = pipeline.second;
|
||||||
|
auto outItems = outShapes.find(pipeline.first);
|
||||||
|
if (outItems == outShapes.end()) {
|
||||||
|
outItems = outShapes.insert(std::make_pair(pipeline.first, ItemIDsBounds{})).first;
|
||||||
|
}
|
||||||
|
|
||||||
|
depthSortItems(sceneContext, renderContext, _frontToBack, inItems, outItems->second);
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,15 +19,15 @@
|
||||||
|
|
||||||
namespace render {
|
namespace render {
|
||||||
|
|
||||||
void cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outITems);
|
void cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems);
|
||||||
void depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemIDsBounds& inItems, ItemIDsBounds& outITems);
|
void depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemIDsBounds& inItems, ItemIDsBounds& outItems);
|
||||||
void renderLights(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems);
|
void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems);
|
||||||
void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1);
|
void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1);
|
||||||
|
|
||||||
|
|
||||||
class FetchItems {
|
class FetchItems {
|
||||||
public:
|
public:
|
||||||
typedef std::function<void (const RenderContextPointer& context, int count)> ProbeNumItems;
|
typedef std::function<void (const RenderContextPointer& context, int count)> ProbeNumItems;
|
||||||
|
FetchItems() {}
|
||||||
FetchItems(const ProbeNumItems& probe): _probeNumItems(probe) {}
|
FetchItems(const ProbeNumItems& probe): _probeNumItems(probe) {}
|
||||||
FetchItems(const ItemFilter& filter, const ProbeNumItems& probe): _filter(filter), _probeNumItems(probe) {}
|
FetchItems(const ItemFilter& filter, const ProbeNumItems& probe): _filter(filter), _probeNumItems(probe) {}
|
||||||
|
|
||||||
|
@ -35,7 +35,6 @@ public:
|
||||||
ProbeNumItems _probeNumItems;
|
ProbeNumItems _probeNumItems;
|
||||||
|
|
||||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemIDsBounds& outItems);
|
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemIDsBounds& outItems);
|
||||||
|
|
||||||
using JobModel = Task::Job::ModelO<FetchItems, ItemIDsBounds>;
|
using JobModel = Task::Job::ModelO<FetchItems, ItemIDsBounds>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -54,22 +53,34 @@ public:
|
||||||
|
|
||||||
class DepthSortItems {
|
class DepthSortItems {
|
||||||
public:
|
public:
|
||||||
bool _frontToBack = true;
|
bool _frontToBack;
|
||||||
|
|
||||||
DepthSortItems(bool frontToBack = true) : _frontToBack(frontToBack) {}
|
DepthSortItems(bool frontToBack = true) : _frontToBack(frontToBack) {}
|
||||||
|
|
||||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outITems);
|
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems);
|
||||||
|
|
||||||
using JobModel = Task::Job::ModelIO<DepthSortItems, ItemIDsBounds, ItemIDsBounds>;
|
using JobModel = Task::Job::ModelIO<DepthSortItems, ItemIDsBounds, ItemIDsBounds>;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DrawLight {
|
class DrawLight {
|
||||||
public:
|
public:
|
||||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
|
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
|
||||||
|
|
||||||
using JobModel = Task::Job::Model<DrawLight>;
|
using JobModel = Task::Job::Model<DrawLight>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PipelineSortShapes {
|
||||||
|
public:
|
||||||
|
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ShapesIDsBounds& outShapes);
|
||||||
|
using JobModel = Task::Job::ModelIO<PipelineSortShapes, ItemIDsBounds, ShapesIDsBounds>;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DepthSortShapes {
|
||||||
|
public:
|
||||||
|
bool _frontToBack;
|
||||||
|
DepthSortShapes(bool frontToBack = true) : _frontToBack(frontToBack) {}
|
||||||
|
|
||||||
|
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapesIDsBounds& inShapes, ShapesIDsBounds& outShapes);
|
||||||
|
using JobModel = Task::Job::ModelIO<DepthSortShapes, ShapesIDsBounds, ShapesIDsBounds>;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // hifi_render_DrawTask_h
|
#endif // hifi_render_DrawTask_h
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <gpu/Context.h>
|
||||||
|
|
||||||
#include "Engine.h"
|
#include "Engine.h"
|
||||||
|
|
||||||
using namespace render;
|
using namespace render;
|
||||||
|
@ -34,7 +36,9 @@ void Engine::addTask(const TaskPointer& task) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::run() {
|
void Engine::run() {
|
||||||
// TODO: Tasks will need to be specified such that their data can feed into each other
|
// Sync GPU state before beginning to render
|
||||||
|
_renderContext->getArgs()->_context->syncCache();
|
||||||
|
|
||||||
for (auto task : _tasks) {
|
for (auto task : _tasks) {
|
||||||
task->run(_sceneContext, _renderContext);
|
task->run(_sceneContext, _renderContext);
|
||||||
}
|
}
|
||||||
|
|
|
@ -432,7 +432,11 @@ public:
|
||||||
AABox bounds;
|
AABox bounds;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector< ItemIDAndBounds > ItemIDsBounds;
|
// A list of items to be passed between rendering jobs
|
||||||
|
using ItemIDsBounds = std::vector<ItemIDAndBounds>;
|
||||||
|
|
||||||
|
// A map of items by ShapeKey to optimize rendering pipeline assignments
|
||||||
|
using ShapesIDsBounds = std::unordered_map<ShapeKey, ItemIDsBounds, ShapeKey::Hash, ShapeKey::KeyEqual>;
|
||||||
|
|
||||||
|
|
||||||
// A map of ItemIDSets allowing to create bucket lists of items which are filtering correctly
|
// A map of ItemIDSets allowing to create bucket lists of items which are filtering correctly
|
||||||
|
|
|
@ -91,7 +91,9 @@ const ShapePipelinePointer ShapePlumber::pickPipeline(RenderArgs* args, const Ke
|
||||||
auto& batch = args->_batch;
|
auto& batch = args->_batch;
|
||||||
|
|
||||||
// Run the pipeline's BatchSetter on the passed in batch
|
// Run the pipeline's BatchSetter on the passed in batch
|
||||||
shapePipeline->batchSetter(*shapePipeline, *batch);
|
if (shapePipeline->batchSetter) {
|
||||||
|
shapePipeline->batchSetter(*shapePipeline, *batch);
|
||||||
|
}
|
||||||
|
|
||||||
// Setup the one pipeline (to rule them all)
|
// Setup the one pipeline (to rule them all)
|
||||||
batch->setPipeline(shapePipeline->pipeline);
|
batch->setPipeline(shapePipeline->pipeline);
|
||||||
|
|
|
@ -83,32 +83,32 @@ public:
|
||||||
|
|
||||||
Filter build() const { return Filter(_flags, _mask); }
|
Filter build() const { return Filter(_flags, _mask); }
|
||||||
|
|
||||||
Builder& withOpaque() { _flags.reset(TRANSLUCENT); _mask.set(TRANSLUCENT); return (*this); }
|
|
||||||
Builder& withTranslucent() { _flags.set(TRANSLUCENT); _mask.set(TRANSLUCENT); return (*this); }
|
Builder& withTranslucent() { _flags.set(TRANSLUCENT); _mask.set(TRANSLUCENT); return (*this); }
|
||||||
|
Builder& withOpaque() { _flags.reset(TRANSLUCENT); _mask.set(TRANSLUCENT); return (*this); }
|
||||||
|
|
||||||
Builder& withLightmap() { _flags.reset(LIGHTMAP); _mask.set(LIGHTMAP); return (*this); }
|
Builder& withLightmap() { _flags.set(LIGHTMAP); _mask.set(LIGHTMAP); return (*this); }
|
||||||
Builder& withoutLightmap() { _flags.set(LIGHTMAP); _mask.set(LIGHTMAP); return (*this); }
|
Builder& withoutLightmap() { _flags.reset(LIGHTMAP); _mask.set(LIGHTMAP); return (*this); }
|
||||||
|
|
||||||
Builder& withTangents() { _flags.reset(TANGENTS); _mask.set(TANGENTS); return (*this); }
|
Builder& withTangents() { _flags.set(TANGENTS); _mask.set(TANGENTS); return (*this); }
|
||||||
Builder& withoutTangents() { _flags.set(TANGENTS); _mask.set(TANGENTS); return (*this); }
|
Builder& withoutTangents() { _flags.reset(TANGENTS); _mask.set(TANGENTS); return (*this); }
|
||||||
|
|
||||||
Builder& withSpecular() { _flags.reset(SPECULAR); _mask.set(SPECULAR); return (*this); }
|
Builder& withSpecular() { _flags.set(SPECULAR); _mask.set(SPECULAR); return (*this); }
|
||||||
Builder& withoutSpecular() { _flags.set(SPECULAR); _mask.set(SPECULAR); return (*this); }
|
Builder& withoutSpecular() { _flags.reset(SPECULAR); _mask.set(SPECULAR); return (*this); }
|
||||||
|
|
||||||
Builder& withEmissive() { _flags.reset(EMISSIVE); _mask.set(EMISSIVE); return (*this); }
|
Builder& withEmissive() { _flags.set(EMISSIVE); _mask.set(EMISSIVE); return (*this); }
|
||||||
Builder& withoutEmissive() { _flags.set(EMISSIVE); _mask.set(EMISSIVE); return (*this); }
|
Builder& withoutEmissive() { _flags.reset(EMISSIVE); _mask.set(EMISSIVE); return (*this); }
|
||||||
|
|
||||||
Builder& withSkinned() { _flags.reset(SKINNED); _mask.set(SKINNED); return (*this); }
|
Builder& withSkinned() { _flags.set(SKINNED); _mask.set(SKINNED); return (*this); }
|
||||||
Builder& withoutSkinned() { _flags.set(SKINNED); _mask.set(SKINNED); return (*this); }
|
Builder& withoutSkinned() { _flags.reset(SKINNED); _mask.set(SKINNED); return (*this); }
|
||||||
|
|
||||||
Builder& withStereo() { _flags.reset(STEREO); _mask.set(STEREO); return (*this); }
|
Builder& withStereo() { _flags.set(STEREO); _mask.set(STEREO); return (*this); }
|
||||||
Builder& withoutStereo() { _flags.set(STEREO); _mask.set(STEREO); return (*this); }
|
Builder& withoutStereo() { _flags.reset(STEREO); _mask.set(STEREO); return (*this); }
|
||||||
|
|
||||||
Builder& withDepthOnly() { _flags.reset(DEPTH_ONLY); _mask.set(DEPTH_ONLY); return (*this); }
|
Builder& withDepthOnly() { _flags.set(DEPTH_ONLY); _mask.set(DEPTH_ONLY); return (*this); }
|
||||||
Builder& withoutDepthOnly() { _flags.set(DEPTH_ONLY); _mask.set(DEPTH_ONLY); return (*this); }
|
Builder& withoutDepthOnly() { _flags.reset(DEPTH_ONLY); _mask.set(DEPTH_ONLY); return (*this); }
|
||||||
|
|
||||||
Builder& withWireframe() { _flags.reset(WIREFRAME); _mask.set(WIREFRAME); return (*this); }
|
Builder& withWireframe() { _flags.set(WIREFRAME); _mask.set(WIREFRAME); return (*this); }
|
||||||
Builder& withoutWireframe() { _flags.set(WIREFRAME); _mask.set(WIREFRAME); return (*this); }
|
Builder& withoutWireframe() { _flags.reset(WIREFRAME); _mask.set(WIREFRAME); return (*this); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class Filter;
|
friend class Filter;
|
||||||
|
|
|
@ -207,12 +207,13 @@ public:
|
||||||
virtual ~Task() = default;
|
virtual ~Task() = default;
|
||||||
|
|
||||||
// Queue a new job to the task; returns the job's index
|
// Queue a new job to the task; returns the job's index
|
||||||
template <class T, class... A> size_t addJob(std::string name, A&&... args) {
|
template <class T, class... A> const Varying addJob(std::string name, A&&... args) {
|
||||||
_jobs.emplace_back(name, std::make_shared<typename T::JobModel>(std::forward<A>(args)...));
|
_jobs.emplace_back(name, std::make_shared<typename T::JobModel>(std::forward<A>(args)...));
|
||||||
return _jobs.size() - 1;
|
return _jobs.back().getOutput();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Job& getJob(size_t i) const { return _jobs.at(i); }
|
void enableJob(size_t jobIndex, bool enable = true) { _jobs.at(jobIndex).setEnabled(enable); }
|
||||||
|
bool getEnableJob(size_t jobIndex) const { return _jobs.at(jobIndex).isEnabled(); }
|
||||||
|
|
||||||
virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {}
|
virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ class RenderDetails {
|
||||||
public:
|
public:
|
||||||
enum Type {
|
enum Type {
|
||||||
OPAQUE_ITEM,
|
OPAQUE_ITEM,
|
||||||
|
SHADOW_ITEM,
|
||||||
TRANSLUCENT_ITEM,
|
TRANSLUCENT_ITEM,
|
||||||
OTHER_ITEM
|
OTHER_ITEM
|
||||||
};
|
};
|
||||||
|
@ -51,6 +52,7 @@ public:
|
||||||
int _trianglesRendered = 0;
|
int _trianglesRendered = 0;
|
||||||
|
|
||||||
Item _opaque;
|
Item _opaque;
|
||||||
|
Item _shadow;
|
||||||
Item _translucent;
|
Item _translucent;
|
||||||
Item _other;
|
Item _other;
|
||||||
|
|
||||||
|
@ -61,6 +63,9 @@ public:
|
||||||
case OPAQUE_ITEM:
|
case OPAQUE_ITEM:
|
||||||
_item = &_opaque;
|
_item = &_opaque;
|
||||||
break;
|
break;
|
||||||
|
case SHADOW_ITEM:
|
||||||
|
_item = &_shadow;
|
||||||
|
break;
|
||||||
case TRANSLUCENT_ITEM:
|
case TRANSLUCENT_ITEM:
|
||||||
_item = &_translucent;
|
_item = &_translucent;
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue