Finally clean the lighting pass for global and local lights, split it into global and locals and make it work with the stereo single drawcall

This commit is contained in:
samcake 2016-06-17 17:19:49 -07:00
parent e2a3d1a750
commit 37a6d29406
10 changed files with 226 additions and 474 deletions

View file

@ -75,7 +75,7 @@ bool StereoDisplayPlugin::internalActivate() {
_container->removeMenu(FRAMERATE);
_screen = qApp->primaryScreen();
_container->setFullscreen(_screen);
// _container->setFullscreen(_screen);
return Parent::internalActivate();
}

View file

@ -91,6 +91,9 @@ const Backend::TransformCamera& Backend::TransformCamera::recomputeDerived(const
Mat4 viewUntranslated = _view;
viewUntranslated[3] = Vec4(0.0f, 0.0f, 0.0f, 1.0f);
_projectionViewUntranslated = _projection * viewUntranslated;
_stereoInfo = Vec4(0.0f);
return *this;
}
@ -104,7 +107,9 @@ Backend::TransformCamera Backend::TransformCamera::getEyeCamera(int eye, const S
}
result._projection = _stereo._eyeProjections[eye];
result.recomputeDerived(offsetTransform);
result._stereoInfo = Vec4(1.0f, (float) eye, 0.0f, 0.0f);
return result;
}

View file

@ -104,6 +104,7 @@ public:
Mat4 _projection;
mutable Mat4 _projectionInverse;
Vec4 _viewport; // Public value is int but float in the shader to stay in floats for all the transform computations.
mutable Vec4 _stereoInfo;
const Backend::TransformCamera& recomputeDerived(const Transform& xformView) const;
TransformCamera getEyeCamera(int eye, const StereoState& stereo, const Transform& xformView) const;

View file

@ -18,6 +18,7 @@ struct TransformCamera {
mat4 _projection;
mat4 _projectionInverse;
vec4 _viewport;
vec4 _stereoInfo;
};
layout(std140) uniform transformCameraBuffer {
@ -31,6 +32,16 @@ TransformCamera getTransformCamera() {
vec3 getEyeWorldPos() {
return _camera._viewInverse[3].xyz;
}
bool cam_isStereo() {
return _camera._stereoInfo.x > 0.0;
}
float cam_getStereoSide() {
return _camera._stereoInfo.y;
}
<@endfunc@>

View file

@ -44,7 +44,7 @@ struct LightLocations {
int radius;
int ambientSphere;
int lightBufferUnit;
int texcoordMat;
int sphereParam;
int coneParam;
int deferredFrameTransformBuffer;
int shadowTransformBuffer;
@ -139,323 +139,6 @@ void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radiu
}
}
void DeferredLightingEffect::render(const render::RenderContextPointer& renderContext, const DeferredFrameTransformPointer& frameTransform) {
auto args = renderContext->args;
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
// Framebuffer copy operations cannot function as multipass stereo operations.
batch.enableStereo(false);
// perform deferred lighting, rendering to free fbo
auto framebufferCache = DependencyManager::get<FramebufferCache>();
auto textureCache = DependencyManager::get<TextureCache>();
QSize framebufferSize = framebufferCache->getFrameBufferSize();
// binding the first framebuffer
auto lightingFBO = framebufferCache->getLightingFramebuffer();
batch.setFramebuffer(lightingFBO);
batch.setViewportTransform(args->_viewport);
batch.setStateScissorRect(args->_viewport);
// Bind the G-Buffer surfaces
batch.setResourceTexture(DEFERRED_BUFFER_COLOR_UNIT, framebufferCache->getDeferredColorTexture());
batch.setResourceTexture(DEFERRED_BUFFER_NORMAL_UNIT, framebufferCache->getDeferredNormalTexture());
batch.setResourceTexture(DEFERRED_BUFFER_EMISSIVE_UNIT, framebufferCache->getDeferredSpecularTexture());
batch.setResourceTexture(DEFERRED_BUFFER_DEPTH_UNIT, framebufferCache->getPrimaryDepthTexture());
// FIXME: Different render modes should have different tasks
if (args->_renderMode == RenderArgs::DEFAULT_RENDER_MODE && _ambientOcclusionEnabled) {
batch.setResourceTexture(DEFERRED_BUFFER_OBSCURANCE_UNIT, framebufferCache->getOcclusionTexture());
} else {
// need to assign the white texture if ao is off
batch.setResourceTexture(DEFERRED_BUFFER_OBSCURANCE_UNIT, textureCache->getWhiteTexture());
}
assert(_lightStage.lights.size() > 0);
const auto& globalShadow = _lightStage.lights[0]->shadow;
// Bind the shadow buffer
batch.setResourceTexture(SHADOW_MAP_UNIT, globalShadow.map);
// 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;
float sMin = args->_viewport.x / (float)framebufferSize.width();
float sWidth = args->_viewport.z / (float)framebufferSize.width();
float tMin = args->_viewport.y / (float)framebufferSize.height();
float tHeight = args->_viewport.w / (float)framebufferSize.height();
// The view frustum is the mono frustum base
auto viewFrustum = args->getViewFrustum();
// Eval the mono projection
mat4 monoProjMat;
viewFrustum.evalProjectionMatrix(monoProjMat);
// The mono view transform
Transform monoViewTransform;
viewFrustum.evalViewTransform(monoViewTransform);
// THe mono view matrix coming from the mono view transform
glm::mat4 monoViewMat;
monoViewTransform.getMatrix(monoViewMat);
// Running in stero ?
bool isStereo = args->_context->isStereo();
int numPasses = 1;
mat4 projMats[2];
Transform viewTransforms[2];
ivec4 viewports[2];
vec4 clipQuad[2];
vec2 screenBottomLeftCorners[2];
vec2 screenTopRightCorners[2];
vec4 fetchTexcoordRects[2];
auto geometryCache = DependencyManager::get<GeometryCache>();
if (isStereo) {
numPasses = 2;
mat4 eyeViews[2];
args->_context->getStereoProjections(projMats);
args->_context->getStereoViews(eyeViews);
float halfWidth = 0.5f * sWidth;
for (int i = 0; i < numPasses; i++) {
// In stereo, the 2 sides are layout side by side in the mono viewport and their width is half
int sideWidth = monoViewport.z >> 1;
viewports[i] = ivec4(monoViewport.x + (i * sideWidth), monoViewport.y, sideWidth, monoViewport.w);
auto sideViewMat = monoViewMat * glm::inverse(eyeViews[i]);
// viewTransforms[i].evalFromRawMatrix(sideViewMat);
viewTransforms[i] = monoViewTransform;
viewTransforms[i].postTranslate(-glm::vec3((eyeViews[i][3])));// evalFromRawMatrix(sideViewMat);
clipQuad[i] = glm::vec4(sMin + i * halfWidth, tMin, halfWidth, tHeight);
screenBottomLeftCorners[i] = glm::vec2(-1.0f + i * 1.0f, -1.0f);
screenTopRightCorners[i] = glm::vec2(i * 1.0f, 1.0f);
fetchTexcoordRects[i] = glm::vec4(sMin + i * halfWidth, tMin, halfWidth, tHeight);
}
} else {
viewports[0] = monoViewport;
projMats[0] = monoProjMat;
viewTransforms[0] = monoViewTransform;
clipQuad[0] = glm::vec4(sMin, tMin, sWidth, tHeight);
screenBottomLeftCorners[0] = glm::vec2(-1.0f, -1.0f);
screenTopRightCorners[0] = glm::vec2(1.0f, 1.0f);
fetchTexcoordRects[0] = glm::vec4(sMin, tMin, sWidth, tHeight);
}
auto eyePoint = viewFrustum.getPosition();
float nearRadius = glm::distance(eyePoint, viewFrustum.getNearTopLeft());
batch.setUniformBuffer(_directionalLightLocations->deferredFrameTransformBuffer, frameTransform->getFrameTransformBuffer());
for (int side = 0; side < numPasses; side++) {
// Render in this side's viewport
batch.setViewportTransform(viewports[side]);
batch.setStateScissorRect(viewports[side]);
glm::vec2 topLeft(-1.0f, -1.0f);
glm::vec2 bottomRight(1.0f, 1.0f);
glm::vec2 texCoordTopLeft(clipQuad[side].x, clipQuad[side].y);
glm::vec2 texCoordBottomRight(clipQuad[side].x + clipQuad[side].z, clipQuad[side].y + clipQuad[side].w);
// First Global directional light and ambient pass
{
auto& program = _shadowMapEnabled ? _directionalLightShadow : _directionalLight;
LightLocationsPtr locations = _shadowMapEnabled ? _directionalLightShadowLocations : _directionalLightLocations;
const auto& keyLight = _allocatedLights[_globalLights.front()];
// Setup the global directional pass pipeline
{
if (_shadowMapEnabled) {
if (keyLight->getAmbientMap()) {
program = _directionalSkyboxLightShadow;
locations = _directionalSkyboxLightShadowLocations;
} else {
program = _directionalAmbientSphereLightShadow;
locations = _directionalAmbientSphereLightShadowLocations;
}
} else {
if (keyLight->getAmbientMap()) {
program = _directionalSkyboxLight;
locations = _directionalSkyboxLightLocations;
} else {
program = _directionalAmbientSphereLight;
locations = _directionalAmbientSphereLightLocations;
}
}
if (locations->shadowTransformBuffer >= 0) {
batch.setUniformBuffer(locations->shadowTransformBuffer, globalShadow.getBuffer());
}
batch.setPipeline(program);
}
{ // Setup the global lighting
setupKeyLightBatch(batch, locations->lightBufferUnit, SKYBOX_MAP_UNIT);
}
{
batch.setModelTransform(Transform());
batch.setProjectionTransform(glm::mat4());
batch.setViewTransform(Transform());
glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f);
geometryCache->renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, color);
}
if (keyLight->getAmbientMap()) {
batch.setResourceTexture(SKYBOX_MAP_UNIT, nullptr);
}
}
auto texcoordMat = glm::mat4();
/* texcoordMat[0] = glm::vec4(sWidth / 2.0f, 0.0f, 0.0f, sMin + sWidth / 2.0f);
texcoordMat[1] = glm::vec4(0.0f, tHeight / 2.0f, 0.0f, tMin + tHeight / 2.0f);
*/ texcoordMat[0] = glm::vec4(fetchTexcoordRects[side].z / 2.0f, 0.0f, 0.0f, fetchTexcoordRects[side].x + fetchTexcoordRects[side].z / 2.0f);
texcoordMat[1] = glm::vec4(0.0f, fetchTexcoordRects[side].w / 2.0f, 0.0f, fetchTexcoordRects[side].y + fetchTexcoordRects[side].w / 2.0f);
texcoordMat[2] = glm::vec4(0.0f, 0.0f, 1.0f, 0.0f);
texcoordMat[3] = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f);
// enlarge the scales slightly to account for tesselation
const float SCALE_EXPANSION = 0.05f;
batch.setProjectionTransform(projMats[side]);
batch.setViewTransform(viewTransforms[side]);
// Splat Point lights
if (!_pointLights.empty()) {
batch.setPipeline(_pointLight);
batch._glUniformMatrix4fv(_pointLightLocations->texcoordMat, 1, false, reinterpret_cast< const float* >(&texcoordMat));
for (auto lightID : _pointLights) {
auto& light = _allocatedLights[lightID];
// IN DEBUG: light->setShowContour(true);
batch.setUniformBuffer(_pointLightLocations->lightBufferUnit, light->getSchemaBuffer());
float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION);
// TODO: We shouldn;t have to do that test and use a different volume geometry for when inside the vlight volume,
// we should be able to draw thre same geometry use DepthClamp but for unknown reason it's s not working...
if (glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius) {
Transform model;
model.setTranslation(glm::vec3(0.0f, 0.0f, -1.0f));
batch.setModelTransform(model);
batch.setViewTransform(Transform());
batch.setProjectionTransform(glm::mat4());
glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f);
DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, color);
batch.setProjectionTransform(projMats[side]);
batch.setViewTransform(viewTransforms[side]);
} else {
Transform model;
model.setTranslation(glm::vec3(light->getPosition().x, light->getPosition().y, light->getPosition().z));
batch.setModelTransform(model.postScale(expandedRadius));
batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
geometryCache->renderSphere(batch);
}
}
}
// Splat spot lights
if (!_spotLights.empty()) {
batch.setPipeline(_spotLight);
batch._glUniformMatrix4fv(_spotLightLocations->texcoordMat, 1, false, reinterpret_cast< const float* >(&texcoordMat));
for (auto lightID : _spotLights) {
auto light = _allocatedLights[lightID];
// IN DEBUG: light->setShowContour(true);
batch.setUniformBuffer(_spotLightLocations->lightBufferUnit, light->getSchemaBuffer());
auto eyeLightPos = eyePoint - light->getPosition();
auto eyeHalfPlaneDistance = glm::dot(eyeLightPos, light->getDirection());
const float TANGENT_LENGTH_SCALE = 0.666f;
glm::vec4 coneParam(light->getSpotAngleCosSin(), TANGENT_LENGTH_SCALE * tanf(0.5f * light->getSpotAngle()), 1.0f);
float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION);
// TODO: We shouldn;t have to do that test and use a different volume geometry for when inside the vlight volume,
// we should be able to draw thre same geometry use DepthClamp but for unknown reason it's s not working...
const float OVER_CONSERVATIVE_SCALE = 1.1f;
if ((eyeHalfPlaneDistance > -nearRadius) &&
(glm::distance(eyePoint, glm::vec3(light->getPosition())) < (expandedRadius * OVER_CONSERVATIVE_SCALE) + nearRadius)) {
coneParam.w = 0.0f;
batch._glUniform4fv(_spotLightLocations->coneParam, 1, reinterpret_cast< const float* >(&coneParam));
Transform model;
model.setTranslation(glm::vec3(0.0f, 0.0f, -1.0f));
batch.setModelTransform(model);
batch.setViewTransform(Transform());
batch.setProjectionTransform(glm::mat4());
glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f);
DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, color);
batch.setProjectionTransform( projMats[side]);
batch.setViewTransform(viewTransforms[side]);
} else {
light->setShowContour(false);
coneParam.w = 1.0f;
batch._glUniform4fv(_spotLightLocations->coneParam, 1, reinterpret_cast< const float* >(&coneParam));
Transform model;
model.setTranslation(light->getPosition());
model.postRotate(light->getOrientation());
model.postScale(glm::vec3(expandedRadius, expandedRadius, expandedRadius));
batch.setModelTransform(model);
auto mesh = getSpotLightMesh();
batch.setIndexBuffer(mesh->getIndexBuffer());
batch.setInputBuffer(0, mesh->getVertexBuffer());
batch.setInputFormat(mesh->getVertexFormat());
{
auto& part = mesh->getPartBuffer().get<model::Mesh::Part>(0);
batch.drawIndexed(model::Mesh::topologyToPrimitive(part._topology), part._numIndices, part._startIndex);
}
}
}
}
}
// Probably not necessary in the long run because the gpu layer would unbound this texture if used as render target
batch.setResourceTexture(DEFERRED_BUFFER_COLOR_UNIT, nullptr);
batch.setResourceTexture(DEFERRED_BUFFER_NORMAL_UNIT, nullptr);
batch.setResourceTexture(DEFERRED_BUFFER_EMISSIVE_UNIT, nullptr);
batch.setResourceTexture(DEFERRED_BUFFER_DEPTH_UNIT, nullptr);
batch.setResourceTexture(DEFERRED_BUFFER_OBSCURANCE_UNIT, nullptr);
batch.setResourceTexture(SHADOW_MAP_UNIT, nullptr);
batch.setResourceTexture(SKYBOX_MAP_UNIT, nullptr);
// batch.setUniformBuffer(_directionalLightLocations->deferredTransformBuffer, nullptr);
batch.setUniformBuffer(_directionalLightLocations->deferredFrameTransformBuffer, nullptr);
});
// End of the Lighting pass
if (!_pointLights.empty()) {
_pointLights.clear();
}
if (!_spotLights.empty()) {
_spotLights.clear();
}
}
void DeferredLightingEffect::setupKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int skyboxCubemapUnit) {
PerformanceTimer perfTimer("DLE->setupBatch()");
auto keyLight = _allocatedLights[_globalLights.front()];
@ -492,7 +175,7 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo
locations->radius = program->getUniforms().findLocation("radius");
locations->ambientSphere = program->getUniforms().findLocation("ambientSphere.L00");
locations->texcoordMat = program->getUniforms().findLocation("texcoordMat");
locations->sphereParam = program->getUniforms().findLocation("sphereParam");
locations->coneParam = program->getUniforms().findLocation("coneParam");
locations->lightBufferUnit = program->getBuffers().findLocation("lightBuffer");
@ -667,9 +350,7 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c
auto framebufferCache = DependencyManager::get<FramebufferCache>();
auto textureCache = DependencyManager::get<TextureCache>();
auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>();
QSize framebufferSize = framebufferCache->getFrameBufferSize();
// binding the first framebuffer
auto lightingFBO = framebufferCache->getLightingFramebuffer();
batch.setFramebuffer(lightingFBO);
@ -697,99 +378,11 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c
// Bind the shadow buffer
batch.setResourceTexture(SHADOW_MAP_UNIT, globalShadow.map);
// 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;
float sMin = args->_viewport.x / (float)framebufferSize.width();
float sWidth = args->_viewport.z / (float)framebufferSize.width();
float tMin = args->_viewport.y / (float)framebufferSize.height();
float tHeight = args->_viewport.w / (float)framebufferSize.height();
// The view frustum is the mono frustum base
auto viewFrustum = args->getViewFrustum();
// Eval the mono projection
mat4 monoProjMat;
viewFrustum.evalProjectionMatrix(monoProjMat);
// The mono view transform
Transform monoViewTransform;
viewFrustum.evalViewTransform(monoViewTransform);
// THe mono view matrix coming from the mono view transform
glm::mat4 monoViewMat;
monoViewTransform.getMatrix(monoViewMat);
// Running in stero ?
bool isStereo = args->_context->isStereo();
int numPasses = 1;
mat4 projMats[2];
Transform viewTransforms[2];
ivec4 viewports[2];
vec4 clipQuad[2];
vec2 screenBottomLeftCorners[2];
vec2 screenTopRightCorners[2];
vec4 fetchTexcoordRects[2];
auto geometryCache = DependencyManager::get<GeometryCache>();
if (isStereo) {
numPasses = 2;
mat4 eyeViews[2];
args->_context->getStereoProjections(projMats);
args->_context->getStereoViews(eyeViews);
float halfWidth = 0.5f * sWidth;
for (int i = 0; i < numPasses; i++) {
// In stereo, the 2 sides are layout side by side in the mono viewport and their width is half
int sideWidth = monoViewport.z >> 1;
viewports[i] = ivec4(monoViewport.x + (i * sideWidth), monoViewport.y, sideWidth, monoViewport.w);
auto sideViewMat = monoViewMat * glm::inverse(eyeViews[i]);
// viewTransforms[i].evalFromRawMatrix(sideViewMat);
viewTransforms[i] = monoViewTransform;
viewTransforms[i].postTranslate(-glm::vec3((eyeViews[i][3])));// evalFromRawMatrix(sideViewMat);
clipQuad[i] = glm::vec4(sMin + i * halfWidth, tMin, halfWidth, tHeight);
screenBottomLeftCorners[i] = glm::vec2(-1.0f + i * 1.0f, -1.0f);
screenTopRightCorners[i] = glm::vec2(i * 1.0f, 1.0f);
fetchTexcoordRects[i] = glm::vec4(sMin + i * halfWidth, tMin, halfWidth, tHeight);
}
} else {
viewports[0] = monoViewport;
projMats[0] = monoProjMat;
viewTransforms[0] = monoViewTransform;
clipQuad[0] = glm::vec4(sMin, tMin, sWidth, tHeight);
screenBottomLeftCorners[0] = glm::vec2(-1.0f, -1.0f);
screenTopRightCorners[0] = glm::vec2(1.0f, 1.0f);
fetchTexcoordRects[0] = glm::vec4(sMin, tMin, sWidth, tHeight);
}
auto eyePoint = viewFrustum.getPosition();
float nearRadius = glm::distance(eyePoint, viewFrustum.getNearTopLeft());
batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, frameTransform->getFrameTransformBuffer());
// Render in this side's viewport
// batch.setViewportTransform(viewports[side]);
// batch.setStateScissorRect(viewports[side]);
int side = 0;
glm::vec2 topLeft(-1.0f, -1.0f);
glm::vec2 bottomRight(1.0f, 1.0f);
glm::vec2 texCoordTopLeft(clipQuad[side].x, clipQuad[side].y);
glm::vec2 texCoordBottomRight(clipQuad[side].x + clipQuad[side].z, clipQuad[side].y + clipQuad[side].w);
// First Global directional light and ambient pass
// Global directional light and ambient pass
{
auto& program = deferredLightingEffect->_shadowMapEnabled ? deferredLightingEffect->_directionalLightShadow : deferredLightingEffect->_directionalLight;
LightLocationsPtr locations = deferredLightingEffect->_shadowMapEnabled ? deferredLightingEffect->_directionalLightShadowLocations : deferredLightingEffect->_directionalLightLocations;
@ -825,16 +418,8 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c
deferredLightingEffect->setupKeyLightBatch(batch, locations->lightBufferUnit, SKYBOX_MAP_UNIT);
}
{
batch.setModelTransform(Transform());
batch.setProjectionTransform(glm::mat4());
batch.setViewTransform(Transform());
glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f);
//geometryCache->renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, color);
batch.draw(gpu::TRIANGLE_STRIP, 4);
}
batch.draw(gpu::TRIANGLE_STRIP, 4);
if (keyLight->getAmbientMap()) {
batch.setResourceTexture(SKYBOX_MAP_UNIT, nullptr);
}
@ -844,17 +429,128 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c
}
void RenderDeferredGlobal::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const DeferredFrameTransformPointer& frameTransform) {
void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const DeferredFrameTransformPointer& frameTransform) {
auto args = renderContext->args;
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
});
}
void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const DeferredFrameTransformPointer& frameTransform) {
// 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;
// The view frustum is the mono frustum base
auto viewFrustum = args->getViewFrustum();
// Eval the mono projection
mat4 monoProjMat;
viewFrustum.evalProjectionMatrix(monoProjMat);
// The mono view transform
Transform monoViewTransform;
viewFrustum.evalViewTransform(monoViewTransform);
// THe mono view matrix coming from the mono view transform
glm::mat4 monoViewMat;
monoViewTransform.getMatrix(monoViewMat);
auto geometryCache = DependencyManager::get<GeometryCache>();
auto eyePoint = viewFrustum.getPosition();
float nearRadius = glm::distance(eyePoint, viewFrustum.getNearTopLeft());
float nearClip = 1.01f * viewFrustum.getNearClip();
auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>();
// Render in this side's viewport
batch.setViewportTransform(monoViewport);
batch.setStateScissorRect(monoViewport);
// enlarge the scales slightly to account for tesselation
const float SCALE_EXPANSION = 0.05f;
batch.setProjectionTransform(monoProjMat);
batch.setViewTransform(monoViewTransform);
// Splat Point lights
if (!deferredLightingEffect->_pointLights.empty()) {
// POint light pipeline
batch.setPipeline(deferredLightingEffect->_pointLight);
for (auto lightID : deferredLightingEffect->_pointLights) {
auto& light = deferredLightingEffect->_allocatedLights[lightID];
// IN DEBUG: light->setShowContour(true);
batch.setUniformBuffer(deferredLightingEffect->_pointLightLocations->lightBufferUnit, light->getSchemaBuffer());
float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION);
glm::vec4 sphereParam(expandedRadius, 0.0f, 0.0f, 1.0f);
// TODO: We shouldn;t have to do that test and use a different volume geometry for when inside the vlight volume,
// we should be able to draw thre same geometry use DepthClamp but for unknown reason it's s not working...
if (glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius) {
sphereParam.w = 0.0f;
batch._glUniform4fv(deferredLightingEffect->_pointLightLocations->sphereParam, 1, reinterpret_cast< const float* >(&sphereParam));
batch.draw(gpu::TRIANGLE_STRIP, 4);
} else {
sphereParam.w = 1.0f;
batch._glUniform4fv(deferredLightingEffect->_pointLightLocations->sphereParam, 1, reinterpret_cast< const float* >(&sphereParam));
Transform model;
model.setTranslation(glm::vec3(light->getPosition().x, light->getPosition().y, light->getPosition().z));
batch.setModelTransform(model.postScale(expandedRadius));
batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
geometryCache->renderSphere(batch);
}
}
}
// Splat spot lights
if (!deferredLightingEffect->_spotLights.empty()) {
// Spot light pipeline
batch.setPipeline(deferredLightingEffect->_spotLight);
// Spot mesh
auto mesh = deferredLightingEffect->getSpotLightMesh();
batch.setIndexBuffer(mesh->getIndexBuffer());
batch.setInputBuffer(0, mesh->getVertexBuffer());
batch.setInputFormat(mesh->getVertexFormat());
auto& conePart = mesh->getPartBuffer().get<model::Mesh::Part>(0);
for (auto lightID : deferredLightingEffect->_spotLights) {
auto light = deferredLightingEffect->_allocatedLights[lightID];
// IN DEBUG:
light->setShowContour(true);
batch.setUniformBuffer(deferredLightingEffect->_spotLightLocations->lightBufferUnit, light->getSchemaBuffer());
auto eyeLightPos = eyePoint - light->getPosition();
auto eyeHalfPlaneDistance = glm::dot(eyeLightPos, light->getDirection());
const float TANGENT_LENGTH_SCALE = 0.666f;
glm::vec4 coneParam(light->getSpotAngleCosSin(), TANGENT_LENGTH_SCALE * tanf(0.5f * light->getSpotAngle()), 1.0f);
float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION);
// TODO: We shouldn;t have to do that test and use a different volume geometry for when inside the vlight volume,
// we should be able to draw thre same geometry use DepthClamp but for unknown reason it's s not working...
const float OVER_CONSERVATIVE_SCALE = 1.1f;
if ((eyeHalfPlaneDistance > -nearRadius) &&
(glm::distance(eyePoint, glm::vec3(light->getPosition())) < (expandedRadius * OVER_CONSERVATIVE_SCALE) + nearRadius)) {
coneParam.w = 0.0f;
batch._glUniform4fv(deferredLightingEffect->_spotLightLocations->coneParam, 1, reinterpret_cast< const float* >(&coneParam));
batch.draw(gpu::TRIANGLE_STRIP, 4);
} else {
coneParam.w = 1.0f;
batch._glUniform4fv(deferredLightingEffect->_spotLightLocations->coneParam, 1, reinterpret_cast< const float* >(&coneParam));
Transform model;
model.setTranslation(light->getPosition());
model.postRotate(light->getOrientation());
model.postScale(glm::vec3(expandedRadius, expandedRadius, expandedRadius));
batch.setModelTransform(model);
batch.drawIndexed(model::Mesh::topologyToPrimitive(conePart._topology), conePart._numIndices, conePart._startIndex);
}
}
}
});
}
void RenderDeferredCleanup::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) {
@ -886,9 +582,8 @@ void RenderDeferredCleanup::run(const render::SceneContextPointer& sceneContext,
void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const DeferredFrameTransformPointer& deferredTransform) {
// DependencyManager::get<DeferredLightingEffect>()->render(renderContext, deferredTransform);
setupJob.run(sceneContext, renderContext, deferredTransform);
lightsJob.run(sceneContext, renderContext, deferredTransform);
cleanupJob.run(sceneContext, renderContext);
}

View file

@ -30,7 +30,8 @@
class RenderArgs;
struct LightLocations;
using LightLocationsPtr = std::shared_ptr<LightLocations>;
/// Handles deferred lighting for the bits that require it (voxels...)
// THis is where we currently accumulate the local lights, let s change that sooner than later
class DeferredLightingEffect : public Dependency {
SINGLETON_DEPENDENCY
@ -46,8 +47,6 @@ public:
float intensity = 0.5f, float falloffRadius = 0.01f,
const glm::quat& orientation = glm::quat(), float exponent = 0.0f, float cutoff = PI);
void render(const render::RenderContextPointer& renderContext, const DeferredFrameTransformPointer& frameTransform);
void setupKeyLightBatch(gpu::Batch& batch, int lightBufferUnit, int skyboxCubemapUnit);
// update global lighting
@ -99,7 +98,6 @@ private:
std::vector<int> _spotLights;
friend class RenderDeferredSetup;
friend class RenderDeferredGlobal;
friend class RenderDeferredLocals;
friend class RenderDeferredCleanup;
};
@ -118,13 +116,6 @@ public:
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const DeferredFrameTransformPointer& frameTransform);
};
class RenderDeferredGlobal {
public:
using JobModel = render::Job::ModelI<RenderDeferredGlobal, DeferredFrameTransformPointer>;
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const DeferredFrameTransformPointer& frameTransform);
};
class RenderDeferredLocals {
public:
using JobModel = render::Job::ModelI<RenderDeferredLocals, DeferredFrameTransformPointer>;
@ -147,7 +138,7 @@ public:
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const DeferredFrameTransformPointer& frameTransform);
RenderDeferredSetup setupJob;
RenderDeferredLocals lightsJob;
RenderDeferredCleanup cleanupJob;
};

View file

@ -5,18 +5,26 @@
// deferred_light.vert
// vertex shader
//
// Created by Andrzej Kapolka on 9/18/14.
// Created by Sam Gateau on 6/16/16.
// Copyright 2014 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/Inputs.slh@>
out vec2 _texCoord0;
void main(void) {
_texCoord0 = inTexCoord0.st;
gl_Position = inPosition;
const float depth = 1.0;
const vec4 UNIT_QUAD[4] = vec4[4](
vec4(-1.0, -1.0, depth, 1.0),
vec4(1.0, -1.0, depth, 1.0),
vec4(-1.0, 1.0, depth, 1.0),
vec4(1.0, 1.0, depth, 1.0)
);
vec4 pos = UNIT_QUAD[gl_VertexID];
_texCoord0 = (pos.xy + 1) * 0.5;
gl_Position = pos;
}

View file

@ -5,7 +5,7 @@
// deferred_light_limited.vert
// vertex shader
//
// Created by Andrzej Kapolka on 9/19/14.
// Created by Sam Gateau on 6/16/16.
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
@ -18,17 +18,39 @@
<$declareStandardTransform()$>
uniform mat4 texcoordMat;
uniform vec4 sphereParam;
out vec4 _texCoord0;
void main(void) {
// standard transform
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
<$transformModelToClipPos(cam, obj, inPosition, gl_Position)$>;
if (sphereParam.w != 0.0) {
vec4 projected = gl_Position / gl_Position.w;
_texCoord0 = vec4(dot(projected, texcoordMat[0]) * gl_Position.w,
dot(projected, texcoordMat[1]) * gl_Position.w, 0.0, gl_Position.w);
// standard transform
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
<$transformModelToClipPos(cam, obj, inPosition, gl_Position)$>;
vec4 projected = gl_Position / gl_Position.w;
projected.xy = (projected.xy + 1.0) * 0.5;
if (cam_isStereo()) {
projected.x = 0.5 * (projected.x + cam_getStereoSide());
}
_texCoord0 = vec4(projected.xy, 0.0, 1.0) * gl_Position.w;
} else {
const float depth = -1.0; //Draw at near plane
const vec4 UNIT_QUAD[4] = vec4[4](
vec4(-1.0, -1.0, depth, 1.0),
vec4(1.0, -1.0, depth, 1.0),
vec4(-1.0, 1.0, depth, 1.0),
vec4(1.0, 1.0, depth, 1.0)
);
vec4 pos = UNIT_QUAD[gl_VertexID];
_texCoord0 = vec4((pos.xy + 1) * 0.5, 0.0, 1.0);
if (cam_isStereo()) {
_texCoord0.x = 0.5 * (_texCoord0.x + cam_getStereoSide());
}
gl_Position = pos;
}
}

View file

@ -18,7 +18,6 @@
<$declareStandardTransform()$>
uniform mat4 texcoordMat;
uniform vec4 coneParam;
out vec4 _texCoord0;
@ -38,14 +37,34 @@ void main(void) {
} else {
coneVertex.z = 0.0;
}
// standard transform
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
<$transformModelToClipPos(cam, obj, coneVertex, gl_Position)$>;
vec4 projected = gl_Position / gl_Position.w;
projected.xy = (projected.xy + 1.0) * 0.5;
if (cam_isStereo()) {
projected.x = 0.5 * (projected.x + cam_getStereoSide());
}
_texCoord0 = vec4(projected.xy, 0.0, 1.0) * gl_Position.w;
} else {
const float depth = -1.0; //Draw at near plane
const vec4 UNIT_QUAD[4] = vec4[4](
vec4(-1.0, -1.0, depth, 1.0),
vec4(1.0, -1.0, depth, 1.0),
vec4(-1.0, 1.0, depth, 1.0),
vec4(1.0, 1.0, depth, 1.0)
);
vec4 pos = UNIT_QUAD[gl_VertexID];
_texCoord0 = vec4((pos.xy + 1) * 0.5, 0.0, 1.0);
if (cam_isStereo()) {
_texCoord0.x = 0.5 * (_texCoord0.x + cam_getStereoSide());
}
gl_Position = pos;
}
// standard transform
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
<$transformModelToClipPos(cam, obj, coneVertex, gl_Position)$>;
vec4 projected = gl_Position / gl_Position.w;
_texCoord0 = vec4(dot(projected, texcoordMat[0]) * gl_Position.w,
dot(projected, texcoordMat[1]) * gl_Position.w, 0.0, gl_Position.w);
}

View file

@ -19,7 +19,7 @@
#include <render/ShapePipeline.h>
#include <render/Context.h>
#define DEFERRED_LIGHTING
//#define DEFERRED_LIGHTING
class TestWindow : public QWindow {
protected: