From a378a6eccb8105227595ebc3a8ff7aa51840f810 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 3 Oct 2016 18:28:44 -0700 Subject: [PATCH] separate the rendering of the light outline from the main rendering and introduce a way to support both platform --- .../src/DeferredLightingEffect.cpp | 11 ++ .../render-utils/src/DeferredLightingEffect.h | 2 + .../render-utils/src/LightClusterGrid.slh | 19 ++- libraries/render-utils/src/LightPoint.slh | 21 +++ libraries/render-utils/src/LightSpot.slh | 22 +++ libraries/render-utils/src/LightingModel.h | 3 +- .../src/local_lights_drawOutline.slf | 153 ++++++++++++++++++ 7 files changed, 221 insertions(+), 10 deletions(-) create mode 100644 libraries/render-utils/src/local_lights_drawOutline.slf diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index ace969563e..084ec0e746 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -36,6 +36,7 @@ #include "directional_skybox_light_shadow_frag.h" #include "local_lights_shading_frag.h" +#include "local_lights_drawOutline_frag.h" #include "point_light_frag.h" #include "spot_light_frag.h" @@ -103,6 +104,7 @@ void DeferredLightingEffect::init() { _directionalSkyboxLightShadowLocations = std::make_shared(); _localLightLocations = std::make_shared(); + _localLightOutlineLocations = std::make_shared(); _pointLightLocations = std::make_shared(); _spotLightLocations = std::make_shared(); @@ -115,6 +117,7 @@ void DeferredLightingEffect::init() { loadLightProgram(deferred_light_vert, directional_skybox_light_shadow_frag, false, _directionalSkyboxLightShadow, _directionalSkyboxLightShadowLocations); loadLightProgram(deferred_light_vert, local_lights_shading_frag, true, _localLight, _localLightLocations); + loadLightProgram(deferred_light_vert, local_lights_drawOutline_frag, true, _localLightOutline, _localLightOutlineLocations); loadLightVolumeProgram(deferred_light_point_vert, no_light_frag, false, _pointLightBack, _pointLightLocations); loadLightVolumeProgram(deferred_light_point_vert, no_light_frag, true, _pointLightFront, _pointLightLocations); @@ -795,6 +798,14 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext, batch._glUniform4fv(deferredLightingEffect->_localLightLocations->texcoordFrameTransform, 1, reinterpret_cast(&textureFrameTransform)); batch.draw(gpu::TRIANGLE_STRIP, 4); + + // Draw outline as well ? + if (lightingModel->isShowLightContourEnabled()) { + batch.setPipeline(deferredLightingEffect->_localLightOutline); + batch._glUniform4fv(deferredLightingEffect->_localLightOutlineLocations->texcoordFrameTransform, 1, reinterpret_cast(&textureFrameTransform)); + + batch.draw(gpu::TRIANGLE_STRIP, 4); + } } } } diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 9462dbcc4e..d2b8dd42b2 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -90,6 +90,7 @@ private: gpu::PipelinePointer _directionalLightShadow; gpu::PipelinePointer _localLight; + gpu::PipelinePointer _localLightOutline; gpu::PipelinePointer _pointLightBack; gpu::PipelinePointer _pointLightFront; @@ -105,6 +106,7 @@ private: LightLocationsPtr _directionalLightShadowLocations; LightLocationsPtr _localLightLocations; + LightLocationsPtr _localLightOutlineLocations; LightLocationsPtr _pointLightLocations; LightLocationsPtr _spotLightLocations; diff --git a/libraries/render-utils/src/LightClusterGrid.slh b/libraries/render-utils/src/LightClusterGrid.slh index efb38f621e..80203ef49b 100644 --- a/libraries/render-utils/src/LightClusterGrid.slh +++ b/libraries/render-utils/src/LightClusterGrid.slh @@ -49,20 +49,24 @@ float projection_getFar(mat4 projection) { <@if GLPROFILE == MAC_GL @> #define GRID_NUM_ELEMENTS 4096 +#define GRID_INDEX_TYPE ivec4 +#define GRID_FETCH_BUFFER(i) i / 4][i % 4 <@else@> #define GRID_NUM_ELEMENTS 16384 +#define GRID_INDEX_TYPE int +#define GRID_FETCH_BUFFER(i) i <@endif@> uniform clusterGridBuffer { - int _clusterGridTable[GRID_NUM_ELEMENTS]; + GRID_INDEX_TYPE _clusterGridTable[GRID_NUM_ELEMENTS]; }; uniform clusterContentBuffer { - int _clusterGridContent[GRID_NUM_ELEMENTS]; + GRID_INDEX_TYPE _clusterGridContent[GRID_NUM_ELEMENTS]; }; ivec3 clusterGrid_getCluster(int index) { - int clusterDesc = _clusterGridTable[index]; + int clusterDesc = _clusterGridTable[GRID_FETCH_BUFFER(index)]; int numPointLights = 0xFF & (clusterDesc >> 16); int numSpotLights = 0xFF & (clusterDesc >> 24); int contentOffset = 0xFFFF & (clusterDesc); @@ -70,12 +74,11 @@ ivec3 clusterGrid_getCluster(int index) { } int clusterGrid_getClusterLightId(int index, int offset) { - int arrayElement = offset + index; - int element = _clusterGridContent[arrayElement]; + int elementIndex = offset + index; + int element = _clusterGridContent[GRID_FETCH_BUFFER(elementIndex)]; return element; -// int element = _clusterGridContent[arrayElement >> 1]; - -// return (((arrayElement & 0x00000001) == 1) ? (element >> 16) : element) & 0x0000FFFF; + //int element = _clusterGridContent[GRID_FETCH_BUFFER(elementIndex)]; + // return (((elementIndex & 0x00000001) == 1) ? (element >> 16) : element) & 0x0000FFFF; } <@endif@> diff --git a/libraries/render-utils/src/LightPoint.slh b/libraries/render-utils/src/LightPoint.slh index 5160396e8a..431731ec18 100644 --- a/libraries/render-utils/src/LightPoint.slh +++ b/libraries/render-utils/src/LightPoint.slh @@ -50,3 +50,24 @@ void evalLightingPoint(out vec3 diffuse, out vec3 specular, Light light, <@endfunc@> +<@func declareDrawPointOutline()@> + +bool evalLightPointEdge(out vec3 color, Light light, vec4 fragLightDirLen, vec3 fragEyeDir) { + // Allright we re valid in the volume + float fragLightDistance = fragLightDirLen.w; + vec3 fragLightDir = fragLightDirLen.xyz; + + // Show edges + float edge = abs(2.0 * ((lightVolume_getRadius(light.volume) - fragLightDistance) / (0.1)) - 1.0); + if (edge < 1) { + float edgeCoord = exp2(-8.0*edge*edge); + color = vec3(edgeCoord * edgeCoord * getLightColor(light)); + } + + return (edge < 1); +} + +<@endfunc@> + + + diff --git a/libraries/render-utils/src/LightSpot.slh b/libraries/render-utils/src/LightSpot.slh index a3be944494..6ce21f8823 100644 --- a/libraries/render-utils/src/LightSpot.slh +++ b/libraries/render-utils/src/LightSpot.slh @@ -54,4 +54,26 @@ void evalLightingSpot(out vec3 diffuse, out vec3 specular, Light light, <@endfunc@> +<@func declareDrawSpotOutline()@> + +bool evalLightSpotEdge(out vec3 color, Light light, vec4 fragLightDirLen, float cosSpotAngle, vec3 fragEyeDir) { + // Allright we re valid in the volume + float fragLightDistance = fragLightDirLen.w; + vec3 fragLightDir = fragLightDirLen.xyz; + + // Show edges + float edgeDistR = (lightVolume_getRadius(light.volume) - fragLightDistance); + float edgeDistS = dot(fragLightDistance * vec2(cosSpotAngle, sqrt(1.0 - cosSpotAngle * cosSpotAngle)), -lightVolume_getSpotOutsideNormal2(light.volume)); + float edgeDist = min(edgeDistR, edgeDistS); + float edge = abs(2.0 * (edgeDist / (0.1)) - 1.0); + if (edge < 1) { + float edgeCoord = exp2(-8.0*edge*edge); + color = vec3(edgeCoord * edgeCoord * getLightColor(light)); + } + + return (edge < 1); +} + +<@endfunc@> + diff --git a/libraries/render-utils/src/LightingModel.h b/libraries/render-utils/src/LightingModel.h index 5bb0e621a4..8f3ee9b7d6 100644 --- a/libraries/render-utils/src/LightingModel.h +++ b/libraries/render-utils/src/LightingModel.h @@ -143,8 +143,7 @@ public: bool enablePointLight{ true }; bool enableSpotLight{ true }; - // bool showLightContour { false }; // false by default - bool showLightContour { true }; // false by default + bool showLightContour { false }; // false by default signals: void dirty(); diff --git a/libraries/render-utils/src/local_lights_drawOutline.slf b/libraries/render-utils/src/local_lights_drawOutline.slf new file mode 100644 index 0000000000..3aa210a241 --- /dev/null +++ b/libraries/render-utils/src/local_lights_drawOutline.slf @@ -0,0 +1,153 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// local_lights_drawOutline.frag +// fragment shader +// +// Created by Sam Gateau on 9/6/2016. +// 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 +// + +// Everything about deferred buffer +<@include DeferredBufferRead.slh@> + +<$declareDeferredCurvature()$> + +// Everything about light +<@include model/Light.slh@> +<$declareLightBuffer(128)$> +<@include LightingModel.slh@> + + +<@include LightPoint.slh@> +<$declareDrawPointOutline()$> +<@include LightSpot.slh@> +<$declareDrawSpotOutline()$> + +<@include LightClusterGrid.slh@> + + + +in vec2 _texCoord0; +out vec4 _fragColor; + +void main(void) { + + // Grab the fragment data from the uv + vec2 texCoord = _texCoord0.st; + + vec4 fragPosition = unpackDeferredPositionFromZeye(texCoord); + DeferredFragment frag = unpackDeferredFragmentNoPosition(texCoord); + + if (frag.mode == FRAG_MODE_UNLIT) { + discard; + } + + frag.position = fragPosition; + + + // Frag pos in world + mat4 invViewMat = getViewInverse(); + vec4 fragPos = invViewMat * fragPosition; + + // From frag world pos find the cluster + vec4 clusterEyePos = frustumGrid_worldToEye(fragPos); + ivec3 clusterPos = frustumGrid_eyeToClusterPos(clusterEyePos.xyz); + + ivec3 cluster = clusterGrid_getCluster(frustumGrid_clusterToIndex(clusterPos)); + int numLights = cluster.x + cluster.y; + if (numLights <= 0) { + discard; + } + int lightClusterOffset = cluster.z; + + ivec3 dims = frustumGrid.dims.xyz; + if (clusterPos.x < 0 || clusterPos.x >= dims.x) { + discard; + } + + if (clusterPos.y < 0 || clusterPos.y >= dims.y) { + discard; + } + if (clusterPos.z < 0 || clusterPos.z > dims.z) { + discard; + } + + // Frag to eye vec + vec4 fragEyeVector = invViewMat * vec4(-frag.position.xyz, 0.0); + vec3 fragEyeDir = normalize(fragEyeVector.xyz); + + int numLightTouching = 0; + for (int i = 0; i < cluster.x; i++) { + // Need the light now + int theLightIndex = clusterGrid_getClusterLightId(i, lightClusterOffset); + Light light = getLight(theLightIndex); + + // Clip againgst the light volume and Make the Light vector going from fragment to light center in world space + vec4 fragLightVecLen2; + vec4 fragLightDirLen; + + if (!lightVolume_clipFragToLightVolumePoint(light.volume, fragPos.xyz, fragLightVecLen2)) { + continue; + } + + // Allright we re in the light sphere volume + fragLightDirLen.w = length(fragLightVecLen2.xyz); + fragLightDirLen.xyz = fragLightVecLen2.xyz / fragLightDirLen.w; + if (dot(frag.normal, fragLightDirLen.xyz) < 0.0) { + continue; + } + + numLightTouching++; + + // Allright we re valid in the volume + float fragLightDistance = fragLightDirLen.w; + vec3 fragLightDir = fragLightDirLen.xyz; + + vec3 color = vec3(0.0); + if (evalLightPointEdge(color, light, fragLightDirLen, fragEyeDir)) { + _fragColor.rgb += color; + } + } + + for (int i = cluster.x; i < numLights; i++) { + // Need the light now + int theLightIndex = clusterGrid_getClusterLightId(i, lightClusterOffset); + Light light = getLight(theLightIndex); + + // Clip againgst the light volume and Make the Light vector going from fragment to light center in world space + vec4 fragLightVecLen2; + vec4 fragLightDirLen; + float cosSpotAngle; + + if (!lightVolume_clipFragToLightVolumePoint(light.volume, fragPos.xyz, fragLightVecLen2)) { + continue; + } + + // Allright we re in the light sphere volume + fragLightDirLen.w = length(fragLightVecLen2.xyz); + fragLightDirLen.xyz = fragLightVecLen2.xyz / fragLightDirLen.w; + if (dot(frag.normal, fragLightDirLen.xyz) < 0.0) { + continue; + } + + // Check spot + if (!lightVolume_clipFragToLightVolumeSpotSide(light.volume, fragLightDirLen, cosSpotAngle)) { + continue; + } + + numLightTouching++; + + vec3 color = vec3(0.0); + + if (evalLightSpotEdge(color, light, fragLightDirLen, cosSpotAngle, fragEyeDir)) { + _fragColor.rgb += color; + } + } + +} +