Bringing the Scattering type to the pixels and having a different shading during the lighting pass (for global right now)

This commit is contained in:
samcake 2016-06-20 17:58:35 -07:00
parent 72c362f7b0
commit 0c882832bf
24 changed files with 405 additions and 127 deletions

View file

@ -41,5 +41,5 @@ void main(void) {
vec3 yzDiffuseScaled = yzDiffuse.rgb * abs(worldNormal.x);
vec4 diffuse = vec4(xyDiffuseScaled + xzDiffuseScaled + yzDiffuseScaled, 1.0);
packDeferredFragment(_normal, 1.0, vec3(diffuse), DEFAULT_ROUGHNESS, DEFAULT_METALLIC, DEFAULT_EMISSIVE, DEFAULT_OCCLUSION);
packDeferredFragment(_normal, 1.0, vec3(diffuse), DEFAULT_ROUGHNESS, DEFAULT_METALLIC, DEFAULT_EMISSIVE, DEFAULT_OCCLUSION, DEFAULT_SCATTERING);
}

View file

@ -253,6 +253,10 @@ void FBXReader::consolidateFBXMaterials() {
}
}
if (material.name.contains("body_mat") || material.name.contains("skin")) {
material._material->setScattering(1.0);
}
if (material.opacity <= 0.0f) {
material._material->setOpacity(1.0f);
} else {

View file

@ -104,6 +104,13 @@ void Material::setMetallic(float metallic) {
_schemaBuffer.edit<Schema>()._metallic = metallic;
}
void Material::setScattering(float scattering) {
scattering = glm::clamp(scattering, 0.0f, 1.0f);
_key.setMetallic(scattering > 0.0f);
_schemaBuffer.edit<Schema>()._key = (uint32)_key._flags.to_ulong();
_schemaBuffer.edit<Schema>()._scattering = scattering;
}
void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textureMap) {
if (textureMap) {
_key.setMapChannel(channel, (true));

View file

@ -35,6 +35,7 @@ public:
OPACITY_VAL_BIT,
OPACITY_MASK_MAP_BIT, // Opacity Map and Opacity MASK map are mutually exclusive
OPACITY_TRANSLUCENT_MAP_BIT,
SCATTERING_VAL_BIT,
// THe map bits must be in the same sequence as the enum names for the map channels
EMISSIVE_MAP_BIT,
@ -44,6 +45,7 @@ public:
NORMAL_MAP_BIT,
OCCLUSION_MAP_BIT,
LIGHTMAP_MAP_BIT,
SCATTERING_MAP_BIT,
NUM_FLAGS,
};
@ -57,6 +59,7 @@ public:
NORMAL_MAP,
OCCLUSION_MAP,
LIGHTMAP_MAP,
SCATTERING_MAP,
NUM_MAP_CHANNELS,
};
@ -83,6 +86,8 @@ public:
Builder& withTranslucentFactor() { _flags.set(OPACITY_VAL_BIT); return (*this); }
Builder& withScattering() { _flags.set(SCATTERING_VAL_BIT); return (*this); }
Builder& withEmissiveMap() { _flags.set(EMISSIVE_MAP_BIT); return (*this); }
Builder& withAlbedoMap() { _flags.set(ALBEDO_MAP_BIT); return (*this); }
Builder& withMetallicMap() { _flags.set(METALLIC_MAP_BIT); return (*this); }
@ -94,6 +99,7 @@ public:
Builder& withNormalMap() { _flags.set(NORMAL_MAP_BIT); return (*this); }
Builder& withOcclusionMap() { _flags.set(OCCLUSION_MAP_BIT); return (*this); }
Builder& withLightmapMap() { _flags.set(LIGHTMAP_MAP_BIT); return (*this); }
Builder& withScatteringMap() { _flags.set(SCATTERING_MAP_BIT); return (*this); }
// Convenient standard keys that we will keep on using all over the place
static MaterialKey opaqueAlbedo() { return Builder().withAlbedo().build(); }
@ -135,7 +141,7 @@ public:
void setOpacityMaskMap(bool value) { _flags.set(OPACITY_MASK_MAP_BIT, value); }
bool isOpacityMaskMap() const { return _flags[OPACITY_MASK_MAP_BIT]; }
void setNormalMap(bool value) { _flags.set(NORMAL_MAP_BIT, value); }
bool isNormalMap() const { return _flags[NORMAL_MAP_BIT]; }
@ -145,6 +151,12 @@ public:
void setLightmapMap(bool value) { _flags.set(LIGHTMAP_MAP_BIT, value); }
bool isLightmapMap() const { return _flags[LIGHTMAP_MAP_BIT]; }
void setScattering(bool value) { _flags.set(SCATTERING_VAL_BIT, value); }
bool isScattering() const { return _flags[SCATTERING_VAL_BIT]; }
void setScatteringMap(bool value) { _flags.set(SCATTERING_MAP_BIT, value); }
bool isScatteringMap() const { return _flags[SCATTERING_MAP_BIT]; }
void setMapChannel(MapChannel channel, bool value) { _flags.set(EMISSIVE_MAP_BIT + channel, value); }
bool isMapChannel(MapChannel channel) const { return _flags[EMISSIVE_MAP_BIT + channel]; }
@ -218,6 +230,13 @@ public:
Builder& withoutLightmapMap() { _value.reset(MaterialKey::LIGHTMAP_MAP_BIT); _mask.set(MaterialKey::LIGHTMAP_MAP_BIT); return (*this); }
Builder& withLightmapMap() { _value.set(MaterialKey::LIGHTMAP_MAP_BIT); _mask.set(MaterialKey::LIGHTMAP_MAP_BIT); return (*this); }
Builder& withoutScattering() { _value.reset(MaterialKey::SCATTERING_VAL_BIT); _mask.set(MaterialKey::SCATTERING_VAL_BIT); return (*this); }
Builder& withScattering() { _value.set(MaterialKey::SCATTERING_VAL_BIT); _mask.set(MaterialKey::SCATTERING_VAL_BIT); return (*this); }
Builder& withoutScatteringMap() { _value.reset(MaterialKey::SCATTERING_MAP_BIT); _mask.set(MaterialKey::SCATTERING_MAP_BIT); return (*this); }
Builder& withScatteringMap() { _value.set(MaterialKey::SCATTERING_MAP_BIT); _mask.set(MaterialKey::SCATTERING_MAP_BIT); return (*this); }
// Convenient standard keys that we will keep on using all over the place
static MaterialFilter opaqueAlbedo() { return Builder().withAlbedo().withoutTranslucentFactor().build(); }
};
@ -275,6 +294,8 @@ public:
void setRoughness(float roughness);
float getRoughness() const { return _schemaBuffer.get<Schema>()._roughness; }
void setScattering(float scattering);
float getScattering() const { return _schemaBuffer.get<Schema>()._scattering; }
// Schema to access the attribute values of the material
class Schema {
@ -288,7 +309,9 @@ public:
glm::vec3 _fresnel{ 0.03f }; // Fresnel value for a default non metallic
float _metallic{ 0.0f }; // Not Metallic
glm::vec3 _spare{ 0.0f };
float _scattering{ 0.0f }; // Scattering info
glm::vec2 _spare{ 0.0f };
uint32_t _key{ 0 }; // a copy of the materialKey

View file

@ -15,7 +15,7 @@ struct Material {
vec4 _emissiveOpacity;
vec4 _albedoRoughness;
vec4 _fresnelMetallic;
vec4 _spareKey;
vec4 _scatteringSpare2Key;
};
uniform materialBuffer {
@ -37,7 +37,9 @@ float getMaterialMetallic(Material m) { return m._fresnelMetallic.a; }
float getMaterialShininess(Material m) { return 1.0 - getMaterialRoughness(m); }
int getMaterialKey(Material m) { return floatBitsToInt(m._spareKey.w); }
float getMaterialScattering(Material m) { return m._scatteringSpare2Key.x; }
int getMaterialKey(Material m) { return floatBitsToInt(m._scatteringSpare2Key.w); }
const int EMISSIVE_VAL_BIT = 0x00000001;
const int UNLIT_VAL_BIT = 0x00000002;
@ -47,14 +49,17 @@ const int GLOSSY_VAL_BIT = 0x00000010;
const int OPACITY_VAL_BIT = 0x00000020;
const int OPACITY_MASK_MAP_BIT = 0x00000040;
const int OPACITY_TRANSLUCENT_MAP_BIT = 0x00000080;
const int SCATTERING_VAL_BIT = 0x00000100;
const int EMISSIVE_MAP_BIT = 0x00000100;
const int ALBEDO_MAP_BIT = 0x00000200;
const int METALLIC_MAP_BIT = 0x00000400;
const int ROUGHNESS_MAP_BIT = 0x00000800;
const int NORMAL_MAP_BIT = 0x00001000;
const int OCCLUSION_MAP_BIT = 0x00002000;
const int LIGHTMAP_MAP_BIT = 0x00004000;
const int EMISSIVE_MAP_BIT = 0x00000200;
const int ALBEDO_MAP_BIT = 0x00000400;
const int METALLIC_MAP_BIT = 0x00000800;
const int ROUGHNESS_MAP_BIT = 0x00001000;
const int NORMAL_MAP_BIT = 0x00002000;
const int OCCLUSION_MAP_BIT = 0x00004000;
const int LIGHTMAP_MAP_BIT = 0x00008000;
const int SCATTERING_MAP_BIT = 0x00010000;
<@endif@>

View file

@ -111,6 +111,13 @@ static const std::string DEFAULT_LIGHTMAP_SHADER{
" }"
};
static const std::string DEFAULT_SCATTERING_SHADER{
"vec4 getFragmentColor() {"
" DeferredFragment frag = unpackDeferredFragmentNoPosition(uv);"
" return (frag.mode == FRAG_MODE_SCATTERING ? vec4(vec3(1.0), 1.0) : vec4(vec3(0.0), 1.0));"
" }"
};
static const std::string DEFAULT_DEPTH_SHADER {
"vec4 getFragmentColor() {"
" return vec4(vec3(texture(depthMap, uv).x), 1.0);"
@ -173,7 +180,7 @@ static const std::string DEFAULT_DIFFUSED_NORMAL_CURVATURE_SHADER{
" }"
};
static const std::string DEFAULT_SCATTERING_SHADER{
static const std::string DEFAULT_DEBUG_SCATTERING_SHADER{
"vec4 getFragmentColor() {"
" return vec4(pow(vec3(texture(scatteringMap, uv).xyz), vec3(1.0 / 2.2)), 1.0);"
// " return vec4(vec3(texture(scatteringMap, uv).xyz), 1.0);"
@ -239,6 +246,8 @@ std::string DebugDeferredBuffer::getShaderSourceCode(Mode mode, std::string cust
return DEFAULT_OCCLUSION_SHADER;
case LightmapMode:
return DEFAULT_LIGHTMAP_SHADER;
case ScatteringMode:
return DEFAULT_SCATTERING_SHADER;
case LightingMode:
return DEFAULT_LIGHTING_SHADER;
case ShadowMode:
@ -253,8 +262,8 @@ std::string DebugDeferredBuffer::getShaderSourceCode(Mode mode, std::string cust
return DEFAULT_DIFFUSED_CURVATURE_SHADER;
case DiffusedNormalCurvatureMode:
return DEFAULT_DIFFUSED_NORMAL_CURVATURE_SHADER;
case ScatteringMode:
return DEFAULT_SCATTERING_SHADER;
case ScatteringDebugMode:
return DEFAULT_DEBUG_SCATTERING_SHADER;
case AmbientOcclusionMode:
return DEFAULT_AMBIENT_OCCLUSION_SHADER;
case AmbientOcclusionBlurredMode:

View file

@ -57,6 +57,7 @@ protected:
UnlitMode,
OcclusionMode,
LightmapMode,
ScatteringMode,
LightingMode,
ShadowMode,
PyramidDepthMode,
@ -64,7 +65,7 @@ protected:
NormalCurvatureMode,
DiffusedCurvatureMode,
DiffusedNormalCurvatureMode,
ScatteringMode,
ScatteringDebugMode,
AmbientOcclusionMode,
AmbientOcclusionBlurredMode,
CustomMode // Needs to stay last

View file

@ -20,11 +20,16 @@ const float FRAG_PACK_LIGHTMAPPED_NON_METALLIC = 0.2;
const float FRAG_PACK_LIGHTMAPPED_METALLIC = 0.3;
const float FRAG_PACK_LIGHTMAPPED_RANGE_INV = 1.0 / (FRAG_PACK_LIGHTMAPPED_METALLIC - FRAG_PACK_LIGHTMAPPED_NON_METALLIC);
const float FRAG_PACK_UNLIT = 0.5;
const float FRAG_PACK_SCATTERING_NON_METALLIC = 0.4;
const float FRAG_PACK_SCATTERING_METALLIC = 0.5;
const float FRAG_PACK_SCATTERING_RANGE_INV = 1.0 / (FRAG_PACK_SCATTERING_METALLIC - FRAG_PACK_SCATTERING_NON_METALLIC);
const float FRAG_PACK_UNLIT = 0.6;
const int FRAG_MODE_UNLIT = 0;
const int FRAG_MODE_SHADED = 1;
const int FRAG_MODE_LIGHTMAPPED = 2;
const int FRAG_MODE_SCATTERING = 3;
void unpackModeMetallic(float rawValue, out int mode, out float metallic) {
if (rawValue <= FRAG_PACK_SHADED_METALLIC) {
@ -32,7 +37,10 @@ void unpackModeMetallic(float rawValue, out int mode, out float metallic) {
metallic = clamp((rawValue - FRAG_PACK_SHADED_NON_METALLIC) * FRAG_PACK_SHADED_RANGE_INV, 0.0, 1.0);
} else if (rawValue <= FRAG_PACK_LIGHTMAPPED_METALLIC) {
mode = FRAG_MODE_LIGHTMAPPED;
metallic = clamp((rawValue - FRAG_PACK_LIGHTMAPPED_NON_METALLIC) * FRAG_PACK_SHADED_RANGE_INV, 0.0, 1.0);
metallic = clamp((rawValue - FRAG_PACK_LIGHTMAPPED_NON_METALLIC) * FRAG_PACK_LIGHTMAPPED_RANGE_INV, 0.0, 1.0);
} else if (rawValue <= FRAG_PACK_SCATTERING_METALLIC) {
mode = FRAG_MODE_SCATTERING;
metallic = clamp((rawValue - FRAG_PACK_SCATTERING_NON_METALLIC) * FRAG_PACK_SCATTERING_RANGE_INV, 0.0, 1.0);
} else if (rawValue >= FRAG_PACK_UNLIT) {
mode = FRAG_MODE_UNLIT;
metallic = 0.0;
@ -47,6 +55,10 @@ float packLightmappedMetallic(float metallic) {
return mix(FRAG_PACK_LIGHTMAPPED_NON_METALLIC, FRAG_PACK_LIGHTMAPPED_METALLIC, metallic);
}
float packScatteringMetallic(float metallic) {
return mix(FRAG_PACK_SCATTERING_NON_METALLIC, FRAG_PACK_SCATTERING_METALLIC, metallic);
}
float packUnlit() {
return FRAG_PACK_UNLIT;
}

View file

@ -111,4 +111,24 @@ DeferredFragment unpackDeferredFragment(DeferredFrameTransform deferredTransform
}
<@func declareDeferredCurvature()@>
// the curvature texture
uniform sampler2D curvatureMap;
vec4 fetchCurvature(vec2 texcoord) {
return texture(curvatureMap, texcoord);
}
// the curvature texture
uniform sampler2D diffusedCurvatureMap;
vec4 fetchDiffusedCurvature(vec2 texcoord) {
return texture(diffusedCurvatureMap, texcoord);
}
<@endfunc@>
<@endif@>

View file

@ -30,13 +30,14 @@ const float DEFAULT_METALLIC = 0;
const vec3 DEFAULT_SPECULAR = vec3(0.1);
const vec3 DEFAULT_EMISSIVE = vec3(0.0);
const float DEFAULT_OCCLUSION = 1.0;
const float DEFAULT_SCATTERING = 0.0;
const vec3 DEFAULT_FRESNEL = DEFAULT_EMISSIVE;
void packDeferredFragment(vec3 normal, float alpha, vec3 albedo, float roughness, float metallic, vec3 emissive, float occlusion) {
void packDeferredFragment(vec3 normal, float alpha, vec3 albedo, float roughness, float metallic, vec3 emissive, float occlusion, float scattering) {
if (alpha != 1.0) {
discard;
}
_fragColor0 = vec4(albedo, packShadedMetallic(metallic));
_fragColor0 = vec4(albedo, ((scattering > 0.0) ? packScatteringMetallic(metallic) : packShadedMetallic(metallic)));
_fragColor1 = vec4(packNormal(normal), clamp(roughness, 0.0, 1.0));
_fragColor2 = vec4(emissive, occlusion);
}

View file

@ -152,6 +152,49 @@ vec3 evalLightmappedColor(mat4 invViewMat, float shadowAttenuation, float obscur
<@endfunc@>
<@func declareEvalSkyboxGlobalColorScattering()@>
<$declareDeferredCurvature()$>
<@include SubsurfaceScattering.slh@>
<$declareSubsurfaceScatteringResource()$>
vec3 evalSkyboxGlobalColorScattering(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, vec4 blurredCurvature, vec4 diffusedCurvature, float roughness) {
// prepareGlobalLight
// Transform directions to worldspace
vec3 fragNormal = vec3((normal));
vec3 fragEyeVector = vec3(invViewMat * vec4(-position, 0.0));
vec3 fragEyeDir = normalize(fragEyeVector);
// Get light
Light light = getLight();
vec3 fresnel = vec3(0.03); // Default Di-electric fresnel value
float metallic = 1.0;
vec3 fragLightDir = -normalize(getLightDirection(light));
vec3 bentNormalHigh = normalize( (blurredCurvature.xyz - 0.5f) * 2.0f );
vec3 bentNormalLow = normalize( (diffusedCurvature.xyz - 0.5f) * 2.0f );
float curvature = unpackCurvature(diffusedCurvature.w);
vec3 rS = bentNormalHigh;
vec3 bendFactorSpectrum = getBendFactor();
vec3 rN = normalize(mix(normal, bentNormalLow, bendFactorSpectrum.x));
vec3 gN = normalize(mix(bentNormalHigh, bentNormalLow, bendFactorSpectrum.y));
vec3 bN = normalize(mix(bentNormalHigh, bentNormalLow, bendFactorSpectrum.z));
vec3 NdotLSpectrum = vec3(dot(rN, fragLightDir), dot(gN, fragLightDir), dot(bN, fragLightDir));
// --> Look up the pre-integrated curvature-dependent BDRF textures
vec3 bdrf = fetchBRDFSpectrum(NdotLSpectrum, curvature);
return vec3(bdrf);
}
<@endfunc@>
<@func declareEvalGlobalLightingAlphaBlended()@>

View file

@ -41,13 +41,14 @@
using namespace render;
struct LightLocations {
int radius;
int ambientSphere;
int lightBufferUnit;
int sphereParam;
int coneParam;
int deferredFrameTransformBuffer;
int shadowTransformBuffer;
int radius{ -1 };
int ambientSphere{ -1 };
int lightBufferUnit{ -1 };
int sphereParam{ -1 };
int coneParam{ -1 };
int deferredFrameTransformBuffer{ -1 };
int subsurfaceScatteringParametersBuffer{ -1 };
int shadowTransformBuffer{ -1 };
};
enum DeferredShader_MapSlot {
@ -58,10 +59,14 @@ enum DeferredShader_MapSlot {
DEFERRED_BUFFER_OBSCURANCE_UNIT = 4,
SHADOW_MAP_UNIT = 5,
SKYBOX_MAP_UNIT = 6,
DEFERRED_BUFFER_CURVATURE_UNIT,
DEFERRED_BUFFER_DIFFUSED_CURVATURE_UNIT,
SCATTERING_LUT_UNIT,
};
enum DeferredShader_BufferSlot {
DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT = 2,
LIGHT_GPU_SLOT = 3,
DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT = 0,
SCATTERING_PARAMETERS_BUFFER_SLOT,
LIGHT_GPU_SLOT,
};
static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& program, LightLocationsPtr& locations);
@ -167,7 +172,13 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo
slotBindings.insert(gpu::Shader::Binding(std::string("shadowMap"), SHADOW_MAP_UNIT));
slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), SKYBOX_MAP_UNIT));
slotBindings.insert(gpu::Shader::Binding(std::string("curvatureMap"), DEFERRED_BUFFER_CURVATURE_UNIT));
slotBindings.insert(gpu::Shader::Binding(std::string("diffusedCurvatureMap"), DEFERRED_BUFFER_DIFFUSED_CURVATURE_UNIT));
slotBindings.insert(gpu::Shader::Binding(std::string("scatteringLUT"), SCATTERING_LUT_UNIT));
slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT));
slotBindings.insert(gpu::Shader::Binding(std::string("subsurfaceScatteringParametersBuffer"), SCATTERING_PARAMETERS_BUFFER_SLOT));
slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), LIGHT_GPU_SLOT));
gpu::Shader::makeProgram(*program, slotBindings);
@ -180,6 +191,7 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo
locations->lightBufferUnit = program->getBuffers().findLocation("lightBuffer");
locations->deferredFrameTransformBuffer = program->getBuffers().findLocation("deferredFrameTransformBuffer");
locations->subsurfaceScatteringParametersBuffer = program->getBuffers().findLocation("subsurfaceScatteringParametersBuffer");
locations->shadowTransformBuffer = program->getBuffers().findLocation("shadowTransformBuffer");
auto state = std::make_shared<gpu::State>();
@ -338,7 +350,7 @@ void PrepareDeferred::run(const SceneContextPointer& sceneContext, const RenderC
}
void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const DeferredFrameTransformPointer& frameTransform) {
void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const DeferredFrameTransformPointer& frameTransform, const SubsurfaceScatteringResourcePointer& subsurfaceScatteringResource) {
auto args = renderContext->args;
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
@ -372,59 +384,68 @@ void RenderDeferredSetup::run(const render::SceneContextPointer& sceneContext, c
// need to assign the white texture if ao is off
batch.setResourceTexture(DEFERRED_BUFFER_OBSCURANCE_UNIT, textureCache->getWhiteTexture());
}
assert(deferredLightingEffect->getLightStage().lights.size() > 0);
const auto& globalShadow = deferredLightingEffect->getLightStage().lights[0]->shadow;
// Bind the shadow buffer
batch.setResourceTexture(SHADOW_MAP_UNIT, globalShadow.map);
// The Deferred Frame Transform buffer
batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, frameTransform->getFrameTransformBuffer());
// Subsurface scattering specific
batch.setResourceTexture(DEFERRED_BUFFER_CURVATURE_UNIT, framebufferCache->getCurvatureTexture());
batch.setResourceTexture(DEFERRED_BUFFER_DIFFUSED_CURVATURE_UNIT, framebufferCache->getCurvatureTexture());
batch.setUniformBuffer(SCATTERING_PARAMETERS_BUFFER_SLOT, subsurfaceScatteringResource->getParametersBuffer());
batch.setResourceTexture(SCATTERING_LUT_UNIT, subsurfaceScatteringResource->getScatteringTable());
// Global directional light and ambient pass
{
auto& program = deferredLightingEffect->_shadowMapEnabled ? deferredLightingEffect->_directionalLightShadow : deferredLightingEffect->_directionalLight;
LightLocationsPtr locations = deferredLightingEffect->_shadowMapEnabled ? deferredLightingEffect->_directionalLightShadowLocations : deferredLightingEffect->_directionalLightLocations;
const auto& keyLight = deferredLightingEffect->_allocatedLights[deferredLightingEffect->_globalLights.front()];
// Setup the global directional pass pipeline
{
if (deferredLightingEffect->_shadowMapEnabled) {
if (keyLight->getAmbientMap()) {
program = deferredLightingEffect->_directionalSkyboxLightShadow;
locations = deferredLightingEffect->_directionalSkyboxLightShadowLocations;
} else {
program = deferredLightingEffect->_directionalAmbientSphereLightShadow;
locations = deferredLightingEffect->_directionalAmbientSphereLightShadowLocations;
}
} else {
if (keyLight->getAmbientMap()) {
program = deferredLightingEffect->_directionalSkyboxLight;
locations = deferredLightingEffect->_directionalSkyboxLightLocations;
} else {
program = deferredLightingEffect->_directionalAmbientSphereLight;
locations = deferredLightingEffect->_directionalAmbientSphereLightLocations;
}
}
if (locations->shadowTransformBuffer >= 0) {
batch.setUniformBuffer(locations->shadowTransformBuffer, globalShadow.getBuffer());
}
batch.setPipeline(program);
}
{ // Setup the global lighting
deferredLightingEffect->setupKeyLightBatch(batch, locations->lightBufferUnit, SKYBOX_MAP_UNIT);
}
batch.draw(gpu::TRIANGLE_STRIP, 4);
if (keyLight->getAmbientMap()) {
batch.setResourceTexture(SKYBOX_MAP_UNIT, nullptr);
assert(deferredLightingEffect->getLightStage().lights.size() > 0);
const auto& globalShadow = deferredLightingEffect->getLightStage().lights[0]->shadow;
// Bind the shadow buffer
batch.setResourceTexture(SHADOW_MAP_UNIT, globalShadow.map);
auto& program = deferredLightingEffect->_shadowMapEnabled ? deferredLightingEffect->_directionalLightShadow : deferredLightingEffect->_directionalLight;
LightLocationsPtr locations = deferredLightingEffect->_shadowMapEnabled ? deferredLightingEffect->_directionalLightShadowLocations : deferredLightingEffect->_directionalLightLocations;
const auto& keyLight = deferredLightingEffect->_allocatedLights[deferredLightingEffect->_globalLights.front()];
// Setup the global directional pass pipeline
{
if (deferredLightingEffect->_shadowMapEnabled) {
if (keyLight->getAmbientMap()) {
program = deferredLightingEffect->_directionalSkyboxLightShadow;
locations = deferredLightingEffect->_directionalSkyboxLightShadowLocations;
} else {
program = deferredLightingEffect->_directionalAmbientSphereLightShadow;
locations = deferredLightingEffect->_directionalAmbientSphereLightShadowLocations;
}
} else {
if (keyLight->getAmbientMap()) {
program = deferredLightingEffect->_directionalSkyboxLight;
locations = deferredLightingEffect->_directionalSkyboxLightLocations;
} else {
program = deferredLightingEffect->_directionalAmbientSphereLight;
locations = deferredLightingEffect->_directionalAmbientSphereLightLocations;
}
}
if (locations->shadowTransformBuffer >= 0) {
batch.setUniformBuffer(locations->shadowTransformBuffer, globalShadow.getBuffer());
}
batch.setPipeline(program);
}
{ // Setup the global lighting
deferredLightingEffect->setupKeyLightBatch(batch, locations->lightBufferUnit, SKYBOX_MAP_UNIT);
}
batch.draw(gpu::TRIANGLE_STRIP, 4);
if (keyLight->getAmbientMap()) {
batch.setResourceTexture(SKYBOX_MAP_UNIT, nullptr);
}
batch.setResourceTexture(SHADOW_MAP_UNIT, nullptr);
});
}
@ -562,9 +583,12 @@ void RenderDeferredCleanup::run(const render::SceneContextPointer& sceneContext,
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.setResourceTexture(DEFERRED_BUFFER_CURVATURE_UNIT, nullptr);
batch.setResourceTexture(DEFERRED_BUFFER_DIFFUSED_CURVATURE_UNIT, nullptr);
batch.setResourceTexture(SCATTERING_LUT_UNIT, nullptr);
batch.setUniformBuffer(SCATTERING_PARAMETERS_BUFFER_SLOT, nullptr);
batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, nullptr);
});
@ -582,7 +606,12 @@ void RenderDeferredCleanup::run(const render::SceneContextPointer& sceneContext,
void RenderDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const DeferredFrameTransformPointer& deferredTransform) {
setupJob.run(sceneContext, renderContext, deferredTransform);
if (!_subsurfaceScatteringResource) {
_subsurfaceScatteringResource = std::make_shared<SubsurfaceScatteringResource>();
_subsurfaceScatteringResource->generateScatteringTable(renderContext->args);
}
setupJob.run(sceneContext, renderContext, deferredTransform, _subsurfaceScatteringResource);
lightsJob.run(sceneContext, renderContext, deferredTransform);
cleanupJob.run(sceneContext, renderContext);

View file

@ -27,6 +27,8 @@
#include "LightStage.h"
#include "SubsurfaceScattering.h"
class RenderArgs;
struct LightLocations;
using LightLocationsPtr = std::shared_ptr<LightLocations>;
@ -111,9 +113,9 @@ public:
class RenderDeferredSetup {
public:
using JobModel = render::Job::ModelI<RenderDeferredSetup, DeferredFrameTransformPointer>;
// using JobModel = render::Job::ModelI<RenderDeferredSetup, DeferredFrameTransformPointer>;
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const DeferredFrameTransformPointer& frameTransform);
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const DeferredFrameTransformPointer& frameTransform, const SubsurfaceScatteringResourcePointer& subsurfaceScatteringResource);
};
class RenderDeferredLocals {
@ -140,6 +142,8 @@ public:
RenderDeferredSetup setupJob;
RenderDeferredLocals lightsJob;
RenderDeferredCleanup cleanupJob;
SubsurfaceScatteringResourcePointer _subsurfaceScatteringResource;
};
#endif // hifi_DeferredLightingEffect_h

View file

@ -38,26 +38,49 @@ enum ScatteringShaderMapSlots {
};
SubsurfaceScattering::SubsurfaceScattering() {
SubsurfaceScatteringResource::SubsurfaceScatteringResource() {
Parameters parameters;
_parametersBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Parameters), (const gpu::Byte*) &parameters));
}
void SubsurfaceScatteringResource::setBentNormalFactors(const glm::vec4& rgbsBentFactors) {
if (rgbsBentFactors != getBentNormalFactors()) {
_parametersBuffer.edit<Parameters>().normalBentInfo = rgbsBentFactors;
}
}
glm::vec4 SubsurfaceScatteringResource::getBentNormalFactors() const {
return _parametersBuffer.get<Parameters>().normalBentInfo;
}
void SubsurfaceScatteringResource::setCurvatureFactors(const glm::vec2& sbCurvatureFactors) {
if (sbCurvatureFactors != getCurvatureFactors()) {
_parametersBuffer.edit<Parameters>().curvatureInfo = sbCurvatureFactors;
}
}
glm::vec2 SubsurfaceScatteringResource::getCurvatureFactors() const {
return _parametersBuffer.get<Parameters>().curvatureInfo;
}
void SubsurfaceScatteringResource::generateScatteringTable(RenderArgs* args) {
if (!_scatteringTable) {
_scatteringTable = generatePreIntegratedScattering(args);
}
}
SubsurfaceScattering::SubsurfaceScattering() {
_scatteringResource = std::make_shared<SubsurfaceScatteringResource>();
}
void SubsurfaceScattering::configure(const Config& config) {
auto& params = _parametersBuffer.get<Parameters>();
glm::vec4 bentInfo(config.bentRed, config.bentGreen, config.bentBlue, config.bentScale);
_scatteringResource->setBentNormalFactors(bentInfo);
if (bentInfo != params.normalBentInfo) {
_parametersBuffer.edit<Parameters>().normalBentInfo = bentInfo;
}
if (config.curvatureOffset != params.curvatureInfo.x) {
_parametersBuffer.edit<Parameters>().curvatureInfo.x = config.curvatureOffset;
}
if (config.curvatureScale != params.curvatureInfo.y) {
_parametersBuffer.edit<Parameters>().curvatureInfo.y = config.curvatureScale;
}
glm::vec2 curvatureInfo(config.curvatureOffset, config.curvatureScale);
_scatteringResource->setCurvatureFactors(curvatureInfo);
_showLUT = config.showLUT;
}
@ -164,9 +187,8 @@ void SubsurfaceScattering::run(const render::SceneContextPointer& sceneContext,
RenderArgs* args = renderContext->args;
if (!_scatteringTable) {
_scatteringTable = SubsurfaceScattering::generatePreIntegratedScattering(args);
}
_scatteringResource->generateScatteringTable(args);
auto scatteringTable = _scatteringResource->getScatteringTable();
auto pipeline = getScatteringPipeline();
@ -194,14 +216,14 @@ void SubsurfaceScattering::run(const render::SceneContextPointer& sceneContext,
batch.setPipeline(pipeline);
batch.setUniformBuffer(ScatteringTask_FrameTransformSlot, frameTransform->getFrameTransformBuffer());
batch.setUniformBuffer(ScatteringTask_ParamSlot, _parametersBuffer);
batch.setUniformBuffer(ScatteringTask_ParamSlot, _scatteringResource->getParametersBuffer());
if (theLight->light) {
batch.setUniformBuffer(ScatteringTask_LightSlot, theLight->light->getSchemaBuffer());
if (theLight->light->getAmbientMap()) {
batch.setResourceTexture(ScatteringTask_IBLMapSlot, theLight->light->getAmbientMap());
}
}
batch.setResourceTexture(ScatteringTask_ScatteringTableSlot, _scatteringTable);
batch.setResourceTexture(ScatteringTask_ScatteringTableSlot, scatteringTable);
batch.setResourceTexture(ScatteringTask_CurvatureMapSlot, curvatureFramebuffer->getRenderBuffer(0));
batch.setResourceTexture(ScatteringTask_DiffusedCurvatureMapSlot, diffusedFramebuffer->getRenderBuffer(0));
batch.setResourceTexture(ScatteringTask_NormalMapSlot, framebufferCache->getDeferredNormalTexture());
@ -214,7 +236,7 @@ void SubsurfaceScattering::run(const render::SceneContextPointer& sceneContext,
auto viewportSize = std::min(args->_viewport.z, args->_viewport.w) >> 1;
batch.setViewportTransform(glm::ivec4(0, 0, viewportSize, viewportSize));
batch.setPipeline(getShowLUTPipeline());
batch.setResourceTexture(0, _scatteringTable);
batch.setResourceTexture(0, scatteringTable);
batch.draw(gpu::TRIANGLE_STRIP, 4);
}
});
@ -420,18 +442,15 @@ void diffuseProfile(gpu::TexturePointer& profile) {
profile->assignStoredMip(0, gpu::Element::COLOR_RGBA_32, bytes.size(), bytes.data());
}
gpu::TexturePointer SubsurfaceScatteringResource::generatePreIntegratedScattering(RenderArgs* args) {
gpu::TexturePointer SubsurfaceScattering::generatePreIntegratedScattering(RenderArgs* args) {
auto profileMap = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, 128, 1, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
diffuseProfile(profileMap);
const int WIDTH = 128;
const int HEIGHT = 128;
auto scatteringLUT = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, WIDTH, HEIGHT, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
diffuseScatter(scatteringLUT);
diffuseScatter(scatteringLUT);
//diffuseScatterGPU(profileMap, scatteringLUT, args);
return scatteringLUT;
}

View file

@ -17,6 +17,49 @@
#include "render/DrawTask.h"
#include "DeferredFrameTransform.h"
class SubsurfaceScatteringResource {
public:
using UniformBufferView = gpu::BufferView;
SubsurfaceScatteringResource();
void setBentNormalFactors(const glm::vec4& rgbsBentFactors);
glm::vec4 getBentNormalFactors() const;
void setCurvatureFactors(const glm::vec2& sbCurvatureFactors);
glm::vec2 getCurvatureFactors() const;
UniformBufferView getParametersBuffer() const { return _parametersBuffer; }
gpu::TexturePointer getScatteringTable() const { return _scatteringTable; }
void generateScatteringTable(RenderArgs* args);
static gpu::TexturePointer generatePreIntegratedScattering(RenderArgs* args);
protected:
// Class describing the uniform buffer with the transform info common to the AO shaders
// It s changing every frame
class Parameters {
public:
glm::vec4 normalBentInfo{ 1.5f, 0.8f, 0.3f, 1.5f };
glm::vec2 curvatureInfo{ 0.08f, 0.8f };
glm::vec2 spare{ 0.0f };
Parameters() {}
};
UniformBufferView _parametersBuffer;
gpu::TexturePointer _scatteringTable;
};
using SubsurfaceScatteringResourcePointer = std::shared_ptr<SubsurfaceScatteringResource>;
class SubsurfaceScatteringConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(float bentRed MEMBER bentRed NOTIFY dirty)
@ -57,24 +100,8 @@ public:
void configure(const Config& config);
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs, gpu::FramebufferPointer& scatteringFramebuffer);
static gpu::TexturePointer generatePreIntegratedScattering(RenderArgs* args);
private:
typedef gpu::BufferView UniformBufferView;
// Class describing the uniform buffer with all the parameters common to the AO shaders
class Parameters {
public:
glm::vec4 normalBentInfo { 0.0f };
glm::vec4 curvatureInfo{ 0.0f };
Parameters() {}
};
gpu::BufferView _parametersBuffer;
gpu::TexturePointer _scatteringTable;
SubsurfaceScatteringResourcePointer _scatteringResource;
bool updateScatteringFramebuffer(const gpu::FramebufferPointer& sourceFramebuffer, gpu::FramebufferPointer& scatteringFramebuffer);
gpu::FramebufferPointer _scatteringFramebuffer;

View file

@ -0,0 +1,45 @@
// Generated on <$_SCRIBE_DATE$>
//
// Created by Sam Gateau on 6/8/16.
// 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
//
<@func declareSubsurfaceScatteringResource()@>
uniform sampler2D scatteringLUT;
vec3 fetchBRDF(float LdotN, float curvature) {
return texture(scatteringLUT, vec2( LdotN * 0.5 + 0.5, curvature)).xyz;
}
vec3 fetchBRDFSpectrum(vec3 LdotNSpectrum, float curvature) {
return vec3(
fetchBRDF(LdotNSpectrum.r, curvature).r,
fetchBRDF(LdotNSpectrum.g, curvature).g,
fetchBRDF(LdotNSpectrum.b, curvature).b
);
}
// Subsurface Scattering parameters
struct ScatteringParameters {
vec4 normalBendInfo; // R, G, B, factor
vec4 curvatureInfo;// Offset, Scale
};
uniform subsurfaceScatteringParametersBuffer {
ScatteringParameters parameters;
};
vec3 getBendFactor() {
return parameters.normalBendInfo.xyz * parameters.normalBendInfo.w;
}
float unpackCurvature(float packedCurvature) {
return abs(packedCurvature * 2 - 1) * 0.5f * parameters.curvatureInfo.y + parameters.curvatureInfo.x;
}
<@endfunc@>

View file

@ -17,6 +17,7 @@
<$declareEvalLightmappedColor()$>
<$declareEvalSkyboxGlobalColor()$>
<$declareEvalSkyboxGlobalColorScattering()$>
in vec2 _texCoord0;
out vec4 _fragColor;
@ -39,6 +40,22 @@ void main(void) {
frag.diffuse,
frag.specularVal.xyz);
_fragColor = vec4(color, 1.0);
} else if (frag.mode == FRAG_MODE_SCATTERING) {
vec4 blurredCurvature = fetchCurvature(_texCoord0);
vec4 diffusedCurvature = fetchDiffusedCurvature(_texCoord0);
vec3 color = evalSkyboxGlobalColorScattering(
getViewInverse(),
shadowAttenuation,
frag.obscurance,
frag.position.xyz,
frag.normal,
frag.diffuse,
blurredCurvature,
diffusedCurvature,
frag.roughness);
_fragColor = vec4(color, 1.0);
} else {
vec3 color = evalSkyboxGlobalColor(
getViewInverse(),

View file

@ -45,6 +45,8 @@ void main(void) {
vec3 emissive = getMaterialEmissive(mat);
<$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;
float scattering = getMaterialScattering(mat);
packDeferredFragment(
normalize(_normal.xyz),
opacity,
@ -52,5 +54,6 @@ void main(void) {
roughness,
getMaterialMetallic(mat),
emissive,
occlusionTex);
occlusionTex,
scattering);
}

View file

@ -49,6 +49,8 @@ void main(void) {
vec3 viewNormal;
<$tangentToViewSpace(normalTex, _normal, _tangent, viewNormal)$>
float scattering = getMaterialScattering(mat);
packDeferredFragment(
viewNormal,
opacity,
@ -56,5 +58,6 @@ void main(void) {
roughness,
getMaterialMetallic(mat),
emissive,
occlusionTex);
occlusionTex,
scattering);
}

View file

@ -52,6 +52,7 @@ void main(void) {
float metallic = getMaterialMetallic(mat);
<$evalMaterialMetallic(metallicTex, metallic, matKey, metallic)$>;
float scattering = getMaterialScattering(mat);
packDeferredFragment(
normalize(viewNormal.xyz),
@ -60,5 +61,6 @@ void main(void) {
roughness,
metallic,
emissive,
occlusionTex);
occlusionTex,
scattering);
}

View file

@ -49,6 +49,8 @@ void main(void) {
float metallic = getMaterialMetallic(mat);
<$evalMaterialMetallic(metallicTex, metallic, matKey, metallic)$>;
float scattering = getMaterialScattering(mat);
packDeferredFragment(
normalize(_normal),
opacity,
@ -56,5 +58,6 @@ void main(void) {
roughness,
metallic,
emissive,
occlusionTex);
occlusionTex,
scattering);
}

View file

@ -54,6 +54,6 @@ void main(void) {
normal, 1.0, diffuse, max(0, 1.0 - shininess / 128.0), DEFAULT_METALLIC, specular, specular);
} else {
packDeferredFragment(
normal, 1.0, diffuse, max(0, 1.0 - shininess / 128.0), length(specular), DEFAULT_EMISSIVE, DEFAULT_OCCLUSION);
normal, 1.0, diffuse, max(0, 1.0 - shininess / 128.0), length(specular), DEFAULT_EMISSIVE, DEFAULT_OCCLUSION, DEFAULT_SCATTERING);
}
}

View file

@ -36,5 +36,6 @@ void main(void) {
DEFAULT_ROUGHNESS,
DEFAULT_METALLIC,
DEFAULT_EMISSIVE,
DEFAULT_OCCLUSION);
DEFAULT_OCCLUSION,
DEFAULT_SCATTERING);
}

View file

@ -24,5 +24,5 @@ void main(void) {
normalize(_normal.xyz),
1.0,
_color.rgb,
DEFAULT_ROUGHNESS, DEFAULT_METALLIC, DEFAULT_EMISSIVE, DEFAULT_OCCLUSION);
DEFAULT_ROUGHNESS, DEFAULT_METALLIC, DEFAULT_EMISSIVE, DEFAULT_OCCLUSION, DEFAULT_SCATTERING);
}