SL-17286 Reflection probe alpha/fullbright support.
parent
02fb1bd610
commit
3564b24e2a
|
|
@ -58,6 +58,7 @@ public:
|
|||
S32 mIndexedTextureChannels;
|
||||
bool disableTextureIndex;
|
||||
bool hasAlphaMask;
|
||||
bool hasReflectionProbes = false;
|
||||
bool attachNothing;
|
||||
|
||||
// char numLights;
|
||||
|
|
|
|||
|
|
@ -218,6 +218,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
|
|||
}
|
||||
}
|
||||
|
||||
if (features->hasReflectionProbes)
|
||||
{
|
||||
if (!shader->attachFragmentObject("deferred/reflectionProbeF.glsl"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (features->hasAmbientOcclusion)
|
||||
{
|
||||
if (!shader->attachFragmentObject("deferred/aoUtil.glsl"))
|
||||
|
|
|
|||
|
|
@ -35,10 +35,11 @@ out vec4 frag_color;
|
|||
uniform sampler2D diffuseMap;
|
||||
#endif
|
||||
|
||||
|
||||
VARYING vec4 vertex_color;
|
||||
VARYING vec2 vary_texcoord0;
|
||||
VARYING vec3 vary_texcoord1;
|
||||
VARYING vec4 vary_position;
|
||||
VARYING vec3 vary_position;
|
||||
|
||||
uniform samplerCube environmentMap;
|
||||
|
||||
|
|
@ -54,6 +55,14 @@ void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, ou
|
|||
vec3 linear_to_srgb(vec3 c);
|
||||
vec3 srgb_to_linear(vec3 c);
|
||||
|
||||
#ifdef HAS_REFLECTION_PROBES
|
||||
// reflection probe interface
|
||||
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyEnv,
|
||||
vec3 pos, vec3 norm, float glossiness, float envIntensity);
|
||||
void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm);
|
||||
void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity);
|
||||
#endif
|
||||
|
||||
// See:
|
||||
// class1\deferred\fullbrightShinyF.glsl
|
||||
// class1\lighting\lightFullbrightShinyF.glsl
|
||||
|
|
@ -70,21 +79,29 @@ void main()
|
|||
// SL-9632 HUDs are affected by Atmosphere
|
||||
if (no_atmo == 0)
|
||||
{
|
||||
vec3 sunlit;
|
||||
vec3 amblit;
|
||||
vec3 additive;
|
||||
vec3 atten;
|
||||
vec3 pos = vary_position.xyz/vary_position.w;
|
||||
vec3 sunlit;
|
||||
vec3 amblit;
|
||||
vec3 additive;
|
||||
vec3 atten;
|
||||
vec3 pos = vary_position;
|
||||
calcAtmosphericVars(pos.xyz, vec3(0), 1.0, sunlit, amblit, additive, atten, false);
|
||||
|
||||
calcAtmosphericVars(pos.xyz, vec3(0), 1.0, sunlit, amblit, additive, atten, false);
|
||||
|
||||
vec3 envColor = textureCube(environmentMap, vary_texcoord1.xyz).rgb;
|
||||
float env_intensity = vertex_color.a;
|
||||
|
||||
//color.rgb = srgb_to_linear(color.rgb);
|
||||
color.rgb = mix(color.rgb, envColor.rgb, env_intensity);
|
||||
color.rgb = fullbrightAtmosTransportFrag(color.rgb, additive, atten);
|
||||
color.rgb = fullbrightScaleSoftClip(color.rgb);
|
||||
float env_intensity = vertex_color.a;
|
||||
#ifndef HAS_REFLECTION_PROBES
|
||||
vec3 envColor = textureCube(environmentMap, vary_texcoord1.xyz).rgb;
|
||||
color.rgb = mix(color.rgb, envColor.rgb, env_intensity);
|
||||
#else
|
||||
vec3 ambenv;
|
||||
vec3 glossenv;
|
||||
vec3 legacyenv;
|
||||
vec3 norm = normalize(vary_texcoord1.xyz);
|
||||
vec4 spec = vec4(0,0,0,0);
|
||||
sampleReflectionProbes(ambenv, glossenv, legacyenv, pos.xyz, norm.xyz, spec.a, env_intensity);
|
||||
legacyenv *= 1.5; // fudge brighter
|
||||
applyLegacyEnv(color.rgb, legacyenv, spec, pos, norm, env_intensity);
|
||||
#endif
|
||||
color.rgb = fullbrightAtmosTransportFrag(color.rgb, additive, atten);
|
||||
color.rgb = fullbrightScaleSoftClip(color.rgb);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -98,7 +115,6 @@ void main()
|
|||
*/
|
||||
|
||||
color.a = 1.0;
|
||||
|
||||
//color.rgb = linear_to_srgb(color.rgb);
|
||||
|
||||
frag_color = color;
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ ATTRIBUTE vec2 texcoord0;
|
|||
VARYING vec4 vertex_color;
|
||||
VARYING vec2 vary_texcoord0;
|
||||
VARYING vec3 vary_texcoord1;
|
||||
VARYING vec4 vary_position;
|
||||
VARYING vec3 vary_position;
|
||||
|
||||
#ifdef HAS_SKIN
|
||||
mat4 getObjectSkinnedTransform();
|
||||
|
|
@ -61,17 +61,23 @@ void main()
|
|||
mat4 mat = getObjectSkinnedTransform();
|
||||
mat = modelview_matrix * mat;
|
||||
vec4 pos = mat * vert;
|
||||
vary_position = gl_Position = projection_matrix * pos;
|
||||
gl_Position = projection_matrix * pos;
|
||||
vec3 norm = normalize((mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz);
|
||||
#else
|
||||
vec4 pos = (modelview_matrix * vert);
|
||||
vary_position = gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
|
||||
gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
|
||||
vec3 norm = normalize(normal_matrix * normal);
|
||||
#endif
|
||||
vec3 ref = reflect(pos.xyz, -norm);
|
||||
|
||||
vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
|
||||
vary_position = pos.xyz;
|
||||
vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
|
||||
|
||||
#ifndef HAS_REFLECTION_PROBES
|
||||
vec3 ref = reflect(pos.xyz, -norm);
|
||||
vary_texcoord1 = transpose(normal_matrix) * ref.xyz;
|
||||
#else
|
||||
vary_texcoord1 = norm;
|
||||
#endif
|
||||
|
||||
calcAtmospherics(pos.xyz);
|
||||
|
||||
|
|
|
|||
|
|
@ -64,6 +64,13 @@ out vec4 frag_color;
|
|||
float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen);
|
||||
#endif
|
||||
|
||||
#ifdef HAS_REFLECTION_PROBES
|
||||
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv,
|
||||
vec3 pos, vec3 norm, float glossiness, float envIntensity);
|
||||
void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm);
|
||||
void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity);
|
||||
#endif
|
||||
|
||||
uniform samplerCube environmentMap;
|
||||
uniform sampler2D lightFunc;
|
||||
|
||||
|
|
@ -322,6 +329,16 @@ void main()
|
|||
// lighting from the sun stays sharp
|
||||
float da = clamp(dot(normalize(norm.xyz), light_dir.xyz), 0.0, 1.0);
|
||||
da = pow(da, 1.0 / 1.3);
|
||||
vec3 sun_contrib = min(da, shadow) * sunlit;
|
||||
|
||||
#ifdef HAS_REFLECTION_PROBES
|
||||
vec3 ambenv;
|
||||
vec3 glossenv;
|
||||
vec3 legacyenv;
|
||||
sampleReflectionProbes(ambenv, glossenv, legacyenv, pos.xyz, norm.xyz, spec.a, envIntensity);
|
||||
amblit = max(ambenv, amblit);
|
||||
color.rgb = amblit;
|
||||
#else
|
||||
|
||||
color = amblit;
|
||||
|
||||
|
|
@ -333,9 +350,8 @@ void main()
|
|||
ambient *= ambient;
|
||||
ambient = (1.0 - ambient);
|
||||
|
||||
vec3 sun_contrib = min(da, shadow) * sunlit;
|
||||
|
||||
color *= ambient;
|
||||
#endif
|
||||
|
||||
color += sun_contrib;
|
||||
|
||||
|
|
@ -345,35 +361,6 @@ void main()
|
|||
|
||||
if (spec.a > 0.0) // specular reflection
|
||||
{
|
||||
/* // Reverting this specular calculation to previous 'dumbshiny' version - DJH 6/17/2020
|
||||
// Preserving the refactored version as a comment for potential reconsideration,
|
||||
// overriding the general rule to avoid pollutiong the source with commented code.
|
||||
//
|
||||
// If you're reading this in 2021+, feel free to obliterate.
|
||||
|
||||
vec3 npos = -normalize(pos.xyz);
|
||||
|
||||
//vec3 ref = dot(pos+lv, norm);
|
||||
vec3 h = normalize(light_dir.xyz + npos);
|
||||
float nh = dot(norm.xyz, h);
|
||||
float nv = dot(norm.xyz, npos);
|
||||
float vh = dot(npos, h);
|
||||
float sa = nh;
|
||||
float fres = pow(1 - dot(h, npos), 5)*0.4 + 0.5;
|
||||
|
||||
float gtdenom = 2 * nh;
|
||||
float gt = max(0, min(gtdenom * nv / vh, gtdenom * da / vh));
|
||||
|
||||
if (nh > 0.0)
|
||||
{
|
||||
float scol = fres*texture2D(lightFunc, vec2(nh, spec.a)).r*gt / (nh*da);
|
||||
vec3 sp = sun_contrib*scol / 6.0f;
|
||||
sp = clamp(sp, vec3(0), vec3(1));
|
||||
bloom = dot(sp, sp) / 4.0;
|
||||
color += sp * spec.rgb;
|
||||
}
|
||||
*/
|
||||
|
||||
float sa = dot(refnormpersp, sun_dir.xyz);
|
||||
vec3 dumbshiny = sunlit * shadow * (texture2D(lightFunc, vec2(sa, spec.a)).r);
|
||||
|
||||
|
|
@ -385,10 +372,24 @@ void main()
|
|||
glare = max(glare, spec_contrib.b);
|
||||
|
||||
color += spec_contrib;
|
||||
|
||||
#ifdef HAS_REFLECTION_PROBES
|
||||
applyGlossEnv(color, glossenv, spec, pos.xyz, norm.xyz);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
color = mix(color.rgb, diffcol.rgb, diffuse.a);
|
||||
|
||||
#ifdef HAS_REFLECTION_PROBES
|
||||
if (envIntensity > 0.0)
|
||||
{ // add environmentmap
|
||||
//fudge darker
|
||||
legacyenv *= 0.5*diffuse.a+0.5;
|
||||
|
||||
applyLegacyEnv(color, legacyenv, spec, pos.xyz, norm.xyz, envIntensity);
|
||||
}
|
||||
#else
|
||||
if (envIntensity > 0.0)
|
||||
{
|
||||
//add environmentmap
|
||||
|
|
@ -403,6 +404,7 @@ void main()
|
|||
cur_glare *= envIntensity*4.0;
|
||||
glare += cur_glare;
|
||||
}
|
||||
#endif
|
||||
|
||||
color = atmosFragLighting(color, additive, atten);
|
||||
color = scaleSoftClipFrag(color);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* @file class1/deferred/reflectionProbeF.glsl
|
||||
*
|
||||
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2022, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
// fallback stub -- will be used if actual reflection probe shader failed to load (output pink so it's obvious)
|
||||
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv,
|
||||
vec3 pos, vec3 norm, float glossiness, float envIntensity)
|
||||
{
|
||||
ambenv = vec3(1,0,1);
|
||||
glossenv = vec3(1,0,1);
|
||||
legacyenv = vec3(1,0,1);
|
||||
}
|
||||
|
||||
void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm)
|
||||
{
|
||||
color = vec3(1,0,1);
|
||||
}
|
||||
|
||||
void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity)
|
||||
{
|
||||
color = vec3(1,0,1);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,476 @@
|
|||
/**
|
||||
* @file class2/deferred/reflectionProbeF.glsl
|
||||
*
|
||||
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2022, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#extension GL_ARB_shader_texture_lod : enable
|
||||
|
||||
#define FLT_MAX 3.402823466e+38
|
||||
|
||||
#define REFMAP_COUNT 256
|
||||
#define REF_SAMPLE_COUNT 64 //maximum number of samples to consider
|
||||
|
||||
uniform samplerCubeArray reflectionProbes;
|
||||
|
||||
layout (std140, binding = 1) uniform ReflectionProbes
|
||||
{
|
||||
// list of OBBs for user override probes
|
||||
// box is a set of 3 planes outward facing planes and the depth of the box along that plane
|
||||
// for each box refBox[i]...
|
||||
/// box[0..2] - plane 0 .. 2 in [A,B,C,D] notation
|
||||
// box[3][0..2] - plane thickness
|
||||
mat4 refBox[REFMAP_COUNT];
|
||||
// list of bounding spheres for reflection probes sorted by distance to camera (closest first)
|
||||
vec4 refSphere[REFMAP_COUNT];
|
||||
// index of cube map in reflectionProbes for a corresponding reflection probe
|
||||
// e.g. cube map channel of refSphere[2] is stored in refIndex[2]
|
||||
// refIndex.x - cubemap channel in reflectionProbes
|
||||
// refIndex.y - index in refNeighbor of neighbor list (index is ivec4 index, not int index)
|
||||
// refIndex.z - number of neighbors
|
||||
// refIndex.w - priority, if negative, this probe has a box influence
|
||||
ivec4 refIndex[REFMAP_COUNT];
|
||||
|
||||
// neighbor list data (refSphere indices, not cubemap array layer)
|
||||
ivec4 refNeighbor[1024];
|
||||
|
||||
// number of reflection probes present in refSphere
|
||||
int refmapCount;
|
||||
|
||||
// intensity of ambient light from reflection probes
|
||||
float reflectionAmbiance;
|
||||
};
|
||||
|
||||
// Inputs
|
||||
uniform mat3 env_mat;
|
||||
|
||||
// list of probeIndexes shader will actually use after "getRefIndex" is called
|
||||
// (stores refIndex/refSphere indices, NOT rerflectionProbes layer)
|
||||
int probeIndex[REF_SAMPLE_COUNT];
|
||||
|
||||
// number of probes stored in probeIndex
|
||||
int probeInfluences = 0;
|
||||
|
||||
bool isAbove(vec3 pos, vec4 plane)
|
||||
{
|
||||
return (dot(plane.xyz, pos) + plane.w) > 0;
|
||||
}
|
||||
|
||||
// return true if probe at index i influences position pos
|
||||
bool shouldSampleProbe(int i, vec3 pos)
|
||||
{
|
||||
if (refIndex[i].w < 0)
|
||||
{
|
||||
vec4 v = refBox[i] * vec4(pos, 1.0);
|
||||
if (abs(v.x) > 1 ||
|
||||
abs(v.y) > 1 ||
|
||||
abs(v.z) > 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vec3 delta = pos.xyz - refSphere[i].xyz;
|
||||
float d = dot(delta, delta);
|
||||
float r2 = refSphere[i].w;
|
||||
r2 *= r2;
|
||||
|
||||
if (d > r2)
|
||||
{ //outside bounding sphere
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// call before sampleRef
|
||||
// populate "probeIndex" with N probe indices that influence pos where N is REF_SAMPLE_COUNT
|
||||
// overall algorithm --
|
||||
void preProbeSample(vec3 pos)
|
||||
{
|
||||
// TODO: make some sort of structure that reduces the number of distance checks
|
||||
|
||||
for (int i = 0; i < refmapCount; ++i)
|
||||
{
|
||||
// found an influencing probe
|
||||
if (shouldSampleProbe(i, pos))
|
||||
{
|
||||
probeIndex[probeInfluences] = i;
|
||||
++probeInfluences;
|
||||
|
||||
int neighborIdx = refIndex[i].y;
|
||||
if (neighborIdx != -1)
|
||||
{
|
||||
int neighborCount = min(refIndex[i].z, REF_SAMPLE_COUNT-1);
|
||||
|
||||
int count = 0;
|
||||
while (count < neighborCount)
|
||||
{
|
||||
// check up to REF_SAMPLE_COUNT-1 neighbors (neighborIdx is ivec4 index)
|
||||
|
||||
int idx = refNeighbor[neighborIdx].x;
|
||||
if (shouldSampleProbe(idx, pos))
|
||||
{
|
||||
probeIndex[probeInfluences++] = idx;
|
||||
if (probeInfluences == REF_SAMPLE_COUNT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
if (count == neighborCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
idx = refNeighbor[neighborIdx].y;
|
||||
if (shouldSampleProbe(idx, pos))
|
||||
{
|
||||
probeIndex[probeInfluences++] = idx;
|
||||
if (probeInfluences == REF_SAMPLE_COUNT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
if (count == neighborCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
idx = refNeighbor[neighborIdx].z;
|
||||
if (shouldSampleProbe(idx, pos))
|
||||
{
|
||||
probeIndex[probeInfluences++] = idx;
|
||||
if (probeInfluences == REF_SAMPLE_COUNT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
if (count == neighborCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
idx = refNeighbor[neighborIdx].w;
|
||||
if (shouldSampleProbe(idx, pos))
|
||||
{
|
||||
probeIndex[probeInfluences++] = idx;
|
||||
if (probeInfluences == REF_SAMPLE_COUNT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
if (count == neighborCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
++neighborIdx;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// from https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection
|
||||
|
||||
// original reference implementation:
|
||||
/*
|
||||
bool intersect(const Ray &ray) const
|
||||
{
|
||||
float t0, t1; // solutions for t if the ray intersects
|
||||
#if 0
|
||||
// geometric solution
|
||||
Vec3f L = center - orig;
|
||||
float tca = L.dotProduct(dir);
|
||||
// if (tca < 0) return false;
|
||||
float d2 = L.dotProduct(L) - tca * tca;
|
||||
if (d2 > radius2) return false;
|
||||
float thc = sqrt(radius2 - d2);
|
||||
t0 = tca - thc;
|
||||
t1 = tca + thc;
|
||||
#else
|
||||
// analytic solution
|
||||
Vec3f L = orig - center;
|
||||
float a = dir.dotProduct(dir);
|
||||
float b = 2 * dir.dotProduct(L);
|
||||
float c = L.dotProduct(L) - radius2;
|
||||
if (!solveQuadratic(a, b, c, t0, t1)) return false;
|
||||
#endif
|
||||
if (t0 > t1) std::swap(t0, t1);
|
||||
|
||||
if (t0 < 0) {
|
||||
t0 = t1; // if t0 is negative, let's use t1 instead
|
||||
if (t0 < 0) return false; // both t0 and t1 are negative
|
||||
}
|
||||
|
||||
t = t0;
|
||||
|
||||
return true;
|
||||
} */
|
||||
|
||||
// adapted -- assume that origin is inside sphere, return distance from origin to edge of sphere
|
||||
vec3 sphereIntersect(vec3 origin, vec3 dir, vec3 center, float radius2)
|
||||
{
|
||||
float t0, t1; // solutions for t if the ray intersects
|
||||
|
||||
vec3 L = center - origin;
|
||||
float tca = dot(L,dir);
|
||||
|
||||
float d2 = dot(L,L) - tca * tca;
|
||||
|
||||
float thc = sqrt(radius2 - d2);
|
||||
t0 = tca - thc;
|
||||
t1 = tca + thc;
|
||||
|
||||
vec3 v = origin + dir * t1;
|
||||
return v;
|
||||
}
|
||||
|
||||
// from https://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/
|
||||
/*
|
||||
vec3 DirectionWS = normalize(PositionWS - CameraWS);
|
||||
vec3 ReflDirectionWS = reflect(DirectionWS, NormalWS);
|
||||
|
||||
// Intersection with OBB convertto unit box space
|
||||
// Transform in local unit parallax cube space (scaled and rotated)
|
||||
vec3 RayLS = MulMatrix( float(3x3)WorldToLocal, ReflDirectionWS);
|
||||
vec3 PositionLS = MulMatrix( WorldToLocal, PositionWS);
|
||||
|
||||
vec3 Unitary = vec3(1.0f, 1.0f, 1.0f);
|
||||
vec3 FirstPlaneIntersect = (Unitary - PositionLS) / RayLS;
|
||||
vec3 SecondPlaneIntersect = (-Unitary - PositionLS) / RayLS;
|
||||
vec3 FurthestPlane = max(FirstPlaneIntersect, SecondPlaneIntersect);
|
||||
float Distance = min(FurthestPlane.x, min(FurthestPlane.y, FurthestPlane.z));
|
||||
|
||||
// Use Distance in WS directly to recover intersection
|
||||
vec3 IntersectPositionWS = PositionWS + ReflDirectionWS * Distance;
|
||||
vec3 ReflDirectionWS = IntersectPositionWS - CubemapPositionWS;
|
||||
|
||||
return texCUBE(envMap, ReflDirectionWS);
|
||||
*/
|
||||
|
||||
// get point of intersection with given probe's box influence volume
|
||||
// origin - ray origin in clip space
|
||||
// dir - ray direction in clip space
|
||||
// i - probe index in refBox/refSphere
|
||||
vec3 boxIntersect(vec3 origin, vec3 dir, int i)
|
||||
{
|
||||
// Intersection with OBB convertto unit box space
|
||||
// Transform in local unit parallax cube space (scaled and rotated)
|
||||
mat4 clipToLocal = refBox[i];
|
||||
|
||||
vec3 RayLS = mat3(clipToLocal) * dir;
|
||||
vec3 PositionLS = (clipToLocal * vec4(origin, 1.0)).xyz;
|
||||
|
||||
vec3 Unitary = vec3(1.0f, 1.0f, 1.0f);
|
||||
vec3 FirstPlaneIntersect = (Unitary - PositionLS) / RayLS;
|
||||
vec3 SecondPlaneIntersect = (-Unitary - PositionLS) / RayLS;
|
||||
vec3 FurthestPlane = max(FirstPlaneIntersect, SecondPlaneIntersect);
|
||||
float Distance = min(FurthestPlane.x, min(FurthestPlane.y, FurthestPlane.z));
|
||||
|
||||
// Use Distance in CS directly to recover intersection
|
||||
vec3 IntersectPositionCS = origin + dir * Distance;
|
||||
|
||||
return IntersectPositionCS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Tap a sphere based reflection probe
|
||||
// pos - position of pixel
|
||||
// dir - pixel normal
|
||||
// lod - which mip to bias towards (lower is higher res, sharper reflections)
|
||||
// c - center of probe
|
||||
// r2 - radius of probe squared
|
||||
// i - index of probe
|
||||
// vi - point at which reflection vector struck the influence volume, in clip space
|
||||
vec3 tapRefMap(vec3 pos, vec3 dir, float lod, vec3 c, float r2, int i)
|
||||
{
|
||||
//lod = max(lod, 1);
|
||||
// parallax adjustment
|
||||
|
||||
vec3 v;
|
||||
if (refIndex[i].w < 0)
|
||||
{
|
||||
v = boxIntersect(pos, dir, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
v = sphereIntersect(pos, dir, c, r2);
|
||||
}
|
||||
|
||||
v -= c;
|
||||
v = env_mat * v;
|
||||
{
|
||||
float min_lod = textureQueryLod(reflectionProbes,v).y; // lower is higher res
|
||||
return textureLod(reflectionProbes, vec4(v.xyz, refIndex[i].x), max(min_lod, lod)).rgb;
|
||||
//return texture(reflectionProbes, vec4(v.xyz, refIndex[i].x)).rgb;
|
||||
}
|
||||
}
|
||||
|
||||
vec3 sampleProbes(vec3 pos, vec3 dir, float lod)
|
||||
{
|
||||
float wsum = 0.0;
|
||||
vec3 col = vec3(0,0,0);
|
||||
float vd2 = dot(pos,pos); // view distance squared
|
||||
|
||||
for (int idx = 0; idx < probeInfluences; ++idx)
|
||||
{
|
||||
int i = probeIndex[idx];
|
||||
float r = refSphere[i].w; // radius of sphere volume
|
||||
float p = float(abs(refIndex[i].w)); // priority
|
||||
float rr = r*r; // radius squred
|
||||
float r1 = r * 0.1; // 75% of radius (outer sphere to start interpolating down)
|
||||
vec3 delta = pos.xyz-refSphere[i].xyz;
|
||||
float d2 = dot(delta,delta);
|
||||
float r2 = r1*r1;
|
||||
|
||||
{
|
||||
vec3 refcol = tapRefMap(pos, dir, lod, refSphere[i].xyz, rr, i);
|
||||
|
||||
float w = 1.0/d2;
|
||||
|
||||
float atten = 1.0-max(d2-r2, 0.0)/(rr-r2);
|
||||
w *= atten;
|
||||
w *= p; // boost weight based on priority
|
||||
col += refcol*w;
|
||||
|
||||
wsum += w;
|
||||
}
|
||||
}
|
||||
|
||||
if (probeInfluences <= 1)
|
||||
{ //edge-of-scene probe or no probe influence, mix in with embiggened version of probes closest to camera
|
||||
for (int idx = 0; idx < 8; ++idx)
|
||||
{
|
||||
if (refIndex[idx].w < 0)
|
||||
{ // don't fallback to box probes, they are *very* specific
|
||||
continue;
|
||||
}
|
||||
int i = idx;
|
||||
vec3 delta = pos.xyz-refSphere[i].xyz;
|
||||
float d2 = dot(delta,delta);
|
||||
|
||||
{
|
||||
vec3 refcol = tapRefMap(pos, dir, lod, refSphere[i].xyz, d2, i);
|
||||
|
||||
float w = 1.0/d2;
|
||||
w *= w;
|
||||
col += refcol*w;
|
||||
wsum += w;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wsum > 0.0)
|
||||
{
|
||||
col *= 1.0/wsum;
|
||||
}
|
||||
|
||||
return col;
|
||||
}
|
||||
|
||||
vec3 sampleProbeAmbient(vec3 pos, vec3 dir, float lod)
|
||||
{
|
||||
vec3 col = sampleProbes(pos, dir, lod);
|
||||
|
||||
//desaturate
|
||||
vec3 hcol = col *0.5;
|
||||
|
||||
col *= 2.0;
|
||||
col = vec3(
|
||||
col.r + hcol.g + hcol.b,
|
||||
col.g + hcol.r + hcol.b,
|
||||
col.b + hcol.r + hcol.g
|
||||
);
|
||||
|
||||
col *= 0.333333;
|
||||
|
||||
return col*reflectionAmbiance;
|
||||
|
||||
}
|
||||
|
||||
// brighten a color so that at least one component is 1
|
||||
vec3 brighten(vec3 c)
|
||||
{
|
||||
float m = max(max(c.r, c.g), c.b);
|
||||
|
||||
if (m == 0)
|
||||
{
|
||||
return vec3(1,1,1);
|
||||
}
|
||||
|
||||
return c * 1.0/m;
|
||||
}
|
||||
|
||||
|
||||
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv,
|
||||
vec3 pos, vec3 norm, float glossiness, float envIntensity)
|
||||
{
|
||||
// TODO - don't hard code lods
|
||||
float reflection_lods = 8;
|
||||
preProbeSample(pos);
|
||||
|
||||
vec3 refnormpersp = reflect(pos.xyz, norm.xyz);
|
||||
|
||||
ambenv = sampleProbeAmbient(pos, norm, reflection_lods-1);
|
||||
|
||||
if (glossiness > 0.0)
|
||||
{
|
||||
float lod = (1.0-glossiness)*reflection_lods;
|
||||
glossenv = sampleProbes(pos, normalize(refnormpersp), lod);
|
||||
}
|
||||
|
||||
if (envIntensity > 0.0)
|
||||
{
|
||||
legacyenv = sampleProbes(pos, normalize(refnormpersp), 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm)
|
||||
{
|
||||
glossenv *= 0.35; // fudge darker
|
||||
float fresnel = 1.0+dot(normalize(pos.xyz), norm.xyz);
|
||||
float minf = spec.a * 0.1;
|
||||
fresnel = fresnel * (1.0-minf) + minf;
|
||||
glossenv *= spec.rgb*min(fresnel, 1.0);
|
||||
color.rgb += glossenv;
|
||||
}
|
||||
|
||||
void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity)
|
||||
{
|
||||
vec3 reflected_color = legacyenv; //*0.5; //fudge darker
|
||||
vec3 lookAt = normalize(pos);
|
||||
float fresnel = 1.0+dot(lookAt, norm.xyz);
|
||||
fresnel *= fresnel;
|
||||
fresnel = min(fresnel+envIntensity, 1.0);
|
||||
reflected_color *= (envIntensity*fresnel)*brighten(spec.rgb);
|
||||
color = mix(color.rgb, reflected_color, envIntensity);
|
||||
}
|
||||
|
|
@ -42,38 +42,8 @@ uniform sampler2DRect specularRect;
|
|||
uniform sampler2DRect normalMap;
|
||||
uniform sampler2DRect lightMap;
|
||||
uniform sampler2DRect depthMap;
|
||||
uniform samplerCube environmentMap;
|
||||
uniform samplerCubeArray reflectionProbes;
|
||||
uniform sampler2D lightFunc;
|
||||
|
||||
layout (std140, binding = 1) uniform ReflectionProbes
|
||||
{
|
||||
// list of OBBs for user override probes
|
||||
// box is a set of 3 planes outward facing planes and the depth of the box along that plane
|
||||
// for each box refBox[i]...
|
||||
/// box[0..2] - plane 0 .. 2 in [A,B,C,D] notation
|
||||
// box[3][0..2] - plane thickness
|
||||
mat4 refBox[REFMAP_COUNT];
|
||||
// list of bounding spheres for reflection probes sorted by distance to camera (closest first)
|
||||
vec4 refSphere[REFMAP_COUNT];
|
||||
// index of cube map in reflectionProbes for a corresponding reflection probe
|
||||
// e.g. cube map channel of refSphere[2] is stored in refIndex[2]
|
||||
// refIndex.x - cubemap channel in reflectionProbes
|
||||
// refIndex.y - index in refNeighbor of neighbor list (index is ivec4 index, not int index)
|
||||
// refIndex.z - number of neighbors
|
||||
// refIndex.w - priority, if negative, this probe has a box influence
|
||||
ivec4 refIndex[REFMAP_COUNT];
|
||||
|
||||
// neighbor list data (refSphere indices, not cubemap array layer)
|
||||
ivec4 refNeighbor[1024];
|
||||
|
||||
// number of reflection probes present in refSphere
|
||||
int refmapCount;
|
||||
|
||||
// intensity of ambient light from reflection probes
|
||||
float reflectionAmbiance;
|
||||
};
|
||||
|
||||
uniform float blur_size;
|
||||
uniform float blur_fidelity;
|
||||
|
||||
|
|
@ -98,6 +68,12 @@ vec3 scaleSoftClipFrag(vec3 l);
|
|||
vec3 fullbrightAtmosTransportFrag(vec3 light, vec3 additive, vec3 atten);
|
||||
vec3 fullbrightScaleSoftClip(vec3 light);
|
||||
|
||||
// reflection probe interface
|
||||
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyEnv,
|
||||
vec3 pos, vec3 norm, float glossiness, float envIntensity);
|
||||
void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm);
|
||||
void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity);
|
||||
|
||||
vec3 linear_to_srgb(vec3 c);
|
||||
vec3 srgb_to_linear(vec3 c);
|
||||
|
||||
|
|
@ -105,376 +81,8 @@ vec3 srgb_to_linear(vec3 c);
|
|||
vec4 applyWaterFogView(vec3 pos, vec4 color);
|
||||
#endif
|
||||
|
||||
// list of probeIndexes shader will actually use after "getRefIndex" is called
|
||||
// (stores refIndex/refSphere indices, NOT rerflectionProbes layer)
|
||||
int probeIndex[REF_SAMPLE_COUNT];
|
||||
|
||||
// number of probes stored in probeIndex
|
||||
int probeInfluences = 0;
|
||||
|
||||
bool isAbove(vec3 pos, vec4 plane)
|
||||
{
|
||||
return (dot(plane.xyz, pos) + plane.w) > 0;
|
||||
}
|
||||
|
||||
// return true if probe at index i influences position pos
|
||||
bool shouldSampleProbe(int i, vec3 pos)
|
||||
{
|
||||
if (refIndex[i].w < 0)
|
||||
{
|
||||
vec4 v = refBox[i] * vec4(pos, 1.0);
|
||||
if (abs(v.x) > 1 ||
|
||||
abs(v.y) > 1 ||
|
||||
abs(v.z) > 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vec3 delta = pos.xyz - refSphere[i].xyz;
|
||||
float d = dot(delta, delta);
|
||||
float r2 = refSphere[i].w;
|
||||
r2 *= r2;
|
||||
|
||||
if (d > r2)
|
||||
{ //outside bounding sphere
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// populate "probeIndex" with N probe indices that influence pos where N is REF_SAMPLE_COUNT
|
||||
// overall algorithm --
|
||||
void getRefIndex(vec3 pos)
|
||||
{
|
||||
// TODO: make some sort of structure that reduces the number of distance checks
|
||||
|
||||
for (int i = 0; i < refmapCount; ++i)
|
||||
{
|
||||
// found an influencing probe
|
||||
if (shouldSampleProbe(i, pos))
|
||||
{
|
||||
probeIndex[probeInfluences] = i;
|
||||
++probeInfluences;
|
||||
|
||||
int neighborIdx = refIndex[i].y;
|
||||
if (neighborIdx != -1)
|
||||
{
|
||||
int neighborCount = min(refIndex[i].z, REF_SAMPLE_COUNT-1);
|
||||
|
||||
int count = 0;
|
||||
while (count < neighborCount)
|
||||
{
|
||||
// check up to REF_SAMPLE_COUNT-1 neighbors (neighborIdx is ivec4 index)
|
||||
|
||||
int idx = refNeighbor[neighborIdx].x;
|
||||
if (shouldSampleProbe(idx, pos))
|
||||
{
|
||||
probeIndex[probeInfluences++] = idx;
|
||||
if (probeInfluences == REF_SAMPLE_COUNT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
if (count == neighborCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
idx = refNeighbor[neighborIdx].y;
|
||||
if (shouldSampleProbe(idx, pos))
|
||||
{
|
||||
probeIndex[probeInfluences++] = idx;
|
||||
if (probeInfluences == REF_SAMPLE_COUNT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
if (count == neighborCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
idx = refNeighbor[neighborIdx].z;
|
||||
if (shouldSampleProbe(idx, pos))
|
||||
{
|
||||
probeIndex[probeInfluences++] = idx;
|
||||
if (probeInfluences == REF_SAMPLE_COUNT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
if (count == neighborCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
idx = refNeighbor[neighborIdx].w;
|
||||
if (shouldSampleProbe(idx, pos))
|
||||
{
|
||||
probeIndex[probeInfluences++] = idx;
|
||||
if (probeInfluences == REF_SAMPLE_COUNT)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
if (count == neighborCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
++neighborIdx;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// from https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection
|
||||
|
||||
// original reference implementation:
|
||||
/*
|
||||
bool intersect(const Ray &ray) const
|
||||
{
|
||||
float t0, t1; // solutions for t if the ray intersects
|
||||
#if 0
|
||||
// geometric solution
|
||||
Vec3f L = center - orig;
|
||||
float tca = L.dotProduct(dir);
|
||||
// if (tca < 0) return false;
|
||||
float d2 = L.dotProduct(L) - tca * tca;
|
||||
if (d2 > radius2) return false;
|
||||
float thc = sqrt(radius2 - d2);
|
||||
t0 = tca - thc;
|
||||
t1 = tca + thc;
|
||||
#else
|
||||
// analytic solution
|
||||
Vec3f L = orig - center;
|
||||
float a = dir.dotProduct(dir);
|
||||
float b = 2 * dir.dotProduct(L);
|
||||
float c = L.dotProduct(L) - radius2;
|
||||
if (!solveQuadratic(a, b, c, t0, t1)) return false;
|
||||
#endif
|
||||
if (t0 > t1) std::swap(t0, t1);
|
||||
|
||||
if (t0 < 0) {
|
||||
t0 = t1; // if t0 is negative, let's use t1 instead
|
||||
if (t0 < 0) return false; // both t0 and t1 are negative
|
||||
}
|
||||
|
||||
t = t0;
|
||||
|
||||
return true;
|
||||
} */
|
||||
|
||||
// adapted -- assume that origin is inside sphere, return distance from origin to edge of sphere
|
||||
vec3 sphereIntersect(vec3 origin, vec3 dir, vec3 center, float radius2)
|
||||
{
|
||||
float t0, t1; // solutions for t if the ray intersects
|
||||
|
||||
vec3 L = center - origin;
|
||||
float tca = dot(L,dir);
|
||||
|
||||
float d2 = dot(L,L) - tca * tca;
|
||||
|
||||
float thc = sqrt(radius2 - d2);
|
||||
t0 = tca - thc;
|
||||
t1 = tca + thc;
|
||||
|
||||
vec3 v = origin + dir * t1;
|
||||
return v;
|
||||
}
|
||||
|
||||
// from https://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/
|
||||
/*
|
||||
vec3 DirectionWS = normalize(PositionWS - CameraWS);
|
||||
vec3 ReflDirectionWS = reflect(DirectionWS, NormalWS);
|
||||
|
||||
// Intersection with OBB convertto unit box space
|
||||
// Transform in local unit parallax cube space (scaled and rotated)
|
||||
vec3 RayLS = MulMatrix( float(3x3)WorldToLocal, ReflDirectionWS);
|
||||
vec3 PositionLS = MulMatrix( WorldToLocal, PositionWS);
|
||||
|
||||
vec3 Unitary = vec3(1.0f, 1.0f, 1.0f);
|
||||
vec3 FirstPlaneIntersect = (Unitary - PositionLS) / RayLS;
|
||||
vec3 SecondPlaneIntersect = (-Unitary - PositionLS) / RayLS;
|
||||
vec3 FurthestPlane = max(FirstPlaneIntersect, SecondPlaneIntersect);
|
||||
float Distance = min(FurthestPlane.x, min(FurthestPlane.y, FurthestPlane.z));
|
||||
|
||||
// Use Distance in WS directly to recover intersection
|
||||
vec3 IntersectPositionWS = PositionWS + ReflDirectionWS * Distance;
|
||||
vec3 ReflDirectionWS = IntersectPositionWS - CubemapPositionWS;
|
||||
|
||||
return texCUBE(envMap, ReflDirectionWS);
|
||||
*/
|
||||
|
||||
// get point of intersection with given probe's box influence volume
|
||||
// origin - ray origin in clip space
|
||||
// dir - ray direction in clip space
|
||||
// i - probe index in refBox/refSphere
|
||||
vec3 boxIntersect(vec3 origin, vec3 dir, int i)
|
||||
{
|
||||
// Intersection with OBB convertto unit box space
|
||||
// Transform in local unit parallax cube space (scaled and rotated)
|
||||
mat4 clipToLocal = refBox[i];
|
||||
|
||||
vec3 RayLS = mat3(clipToLocal) * dir;
|
||||
vec3 PositionLS = (clipToLocal * vec4(origin, 1.0)).xyz;
|
||||
|
||||
vec3 Unitary = vec3(1.0f, 1.0f, 1.0f);
|
||||
vec3 FirstPlaneIntersect = (Unitary - PositionLS) / RayLS;
|
||||
vec3 SecondPlaneIntersect = (-Unitary - PositionLS) / RayLS;
|
||||
vec3 FurthestPlane = max(FirstPlaneIntersect, SecondPlaneIntersect);
|
||||
float Distance = min(FurthestPlane.x, min(FurthestPlane.y, FurthestPlane.z));
|
||||
|
||||
// Use Distance in CS directly to recover intersection
|
||||
vec3 IntersectPositionCS = origin + dir * Distance;
|
||||
|
||||
return IntersectPositionCS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Tap a sphere based reflection probe
|
||||
// pos - position of pixel
|
||||
// dir - pixel normal
|
||||
// lod - which mip to bias towards (lower is higher res, sharper reflections)
|
||||
// c - center of probe
|
||||
// r2 - radius of probe squared
|
||||
// i - index of probe
|
||||
// vi - point at which reflection vector struck the influence volume, in clip space
|
||||
vec3 tapRefMap(vec3 pos, vec3 dir, float lod, vec3 c, float r2, int i)
|
||||
{
|
||||
//lod = max(lod, 1);
|
||||
// parallax adjustment
|
||||
|
||||
vec3 v;
|
||||
if (refIndex[i].w < 0)
|
||||
{
|
||||
v = boxIntersect(pos, dir, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
v = sphereIntersect(pos, dir, c, r2);
|
||||
}
|
||||
|
||||
v -= c;
|
||||
v = env_mat * v;
|
||||
{
|
||||
float min_lod = textureQueryLod(reflectionProbes,v).y; // lower is higher res
|
||||
return textureLod(reflectionProbes, vec4(v.xyz, refIndex[i].x), max(min_lod, lod)).rgb;
|
||||
//return texture(reflectionProbes, vec4(v.xyz, refIndex[i].x)).rgb;
|
||||
}
|
||||
}
|
||||
|
||||
vec3 sampleRefMap(vec3 pos, vec3 dir, float lod)
|
||||
{
|
||||
float wsum = 0.0;
|
||||
vec3 col = vec3(0,0,0);
|
||||
float vd2 = dot(pos,pos); // view distance squared
|
||||
|
||||
for (int idx = 0; idx < probeInfluences; ++idx)
|
||||
{
|
||||
int i = probeIndex[idx];
|
||||
float r = refSphere[i].w; // radius of sphere volume
|
||||
float p = float(abs(refIndex[i].w)); // priority
|
||||
float rr = r*r; // radius squred
|
||||
float r1 = r * 0.1; // 75% of radius (outer sphere to start interpolating down)
|
||||
vec3 delta = pos.xyz-refSphere[i].xyz;
|
||||
float d2 = dot(delta,delta);
|
||||
float r2 = r1*r1;
|
||||
|
||||
{
|
||||
vec3 refcol = tapRefMap(pos, dir, lod, refSphere[i].xyz, rr, i);
|
||||
|
||||
float w = 1.0/d2;
|
||||
|
||||
float atten = 1.0-max(d2-r2, 0.0)/(rr-r2);
|
||||
w *= atten;
|
||||
w *= p; // boost weight based on priority
|
||||
col += refcol*w;
|
||||
|
||||
wsum += w;
|
||||
}
|
||||
}
|
||||
|
||||
if (probeInfluences <= 1)
|
||||
{ //edge-of-scene probe or no probe influence, mix in with embiggened version of probes closest to camera
|
||||
for (int idx = 0; idx < 8; ++idx)
|
||||
{
|
||||
if (refIndex[idx].w < 0)
|
||||
{ // don't fallback to box probes, they are *very* specific
|
||||
continue;
|
||||
}
|
||||
int i = idx;
|
||||
vec3 delta = pos.xyz-refSphere[i].xyz;
|
||||
float d2 = dot(delta,delta);
|
||||
|
||||
{
|
||||
vec3 refcol = tapRefMap(pos, dir, lod, refSphere[i].xyz, d2, i);
|
||||
|
||||
float w = 1.0/d2;
|
||||
w *= w;
|
||||
col += refcol*w;
|
||||
wsum += w;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wsum > 0.0)
|
||||
{
|
||||
col *= 1.0/wsum;
|
||||
}
|
||||
|
||||
return col;
|
||||
}
|
||||
|
||||
vec3 sampleAmbient(vec3 pos, vec3 dir, float lod)
|
||||
{
|
||||
vec3 col = sampleRefMap(pos, dir, lod);
|
||||
|
||||
//desaturate
|
||||
vec3 hcol = col *0.5;
|
||||
|
||||
col *= 2.0;
|
||||
col = vec3(
|
||||
col.r + hcol.g + hcol.b,
|
||||
col.g + hcol.r + hcol.b,
|
||||
col.b + hcol.r + hcol.g
|
||||
);
|
||||
|
||||
col *= 0.333333;
|
||||
|
||||
return col*reflectionAmbiance;
|
||||
|
||||
}
|
||||
|
||||
// brighten a color so that at least one component is 1
|
||||
vec3 brighten(vec3 c)
|
||||
{
|
||||
float m = max(max(c.r, c.g), c.b);
|
||||
|
||||
if (m == 0)
|
||||
{
|
||||
return vec3(1,1,1);
|
||||
}
|
||||
|
||||
return c * 1.0/m;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
float reflection_lods = 8; // TODO -- base this on resolution of reflection map instead of hard coding
|
||||
|
||||
vec2 tc = vary_fragcoord.xy;
|
||||
float depth = texture2DRect(depthMap, tc.xy).r;
|
||||
vec4 pos = getPositionWithDepth(tc, depth);
|
||||
|
|
@ -504,13 +112,15 @@ void main()
|
|||
vec3 additive;
|
||||
vec3 atten;
|
||||
|
||||
getRefIndex(pos.xyz);
|
||||
|
||||
calcAtmosphericVars(pos.xyz, light_dir, ambocc, sunlit, amblit, additive, atten, true);
|
||||
|
||||
//vec3 amb_vec = env_mat * norm.xyz;
|
||||
|
||||
vec3 ambenv = sampleAmbient(pos.xyz, norm.xyz, reflection_lods-1);
|
||||
vec3 ambenv;
|
||||
vec3 glossenv;
|
||||
vec3 legacyenv;
|
||||
sampleReflectionProbes(ambenv, glossenv, legacyenv, pos.xyz, norm.xyz, spec.a, envIntensity);
|
||||
|
||||
amblit = max(ambenv, amblit);
|
||||
color.rgb = amblit*ambocc;
|
||||
|
||||
|
|
@ -527,7 +137,6 @@ void main()
|
|||
|
||||
vec3 refnormpersp = reflect(pos.xyz, norm.xyz);
|
||||
|
||||
vec3 env_vec = env_mat * refnormpersp;
|
||||
if (spec.a > 0.0) // specular reflection
|
||||
{
|
||||
float sa = dot(normalize(refnormpersp), light_dir.xyz);
|
||||
|
|
@ -539,27 +148,16 @@ void main()
|
|||
color.rgb += spec_contrib;
|
||||
|
||||
// add reflection map - EXPERIMENTAL WORK IN PROGRESS
|
||||
|
||||
float lod = (1.0-spec.a)*reflection_lods;
|
||||
vec3 reflected_color = sampleRefMap(pos.xyz, normalize(refnormpersp), lod);
|
||||
reflected_color *= 0.35; // fudge darker
|
||||
float fresnel = 1.0+dot(normalize(pos.xyz), norm.xyz);
|
||||
float minf = spec.a * 0.1;
|
||||
fresnel = fresnel * (1.0-minf) + minf;
|
||||
reflected_color *= spec.rgb*min(fresnel, 1.0);
|
||||
color.rgb += reflected_color;
|
||||
applyGlossEnv(color, glossenv, spec, pos.xyz, norm.xyz);
|
||||
}
|
||||
|
||||
color.rgb = mix(color.rgb, diffuse.rgb, diffuse.a);
|
||||
|
||||
if (envIntensity > 0.0)
|
||||
{ // add environmentmap
|
||||
vec3 reflected_color = sampleRefMap(pos.xyz, normalize(refnormpersp), 0.0)*0.5; //fudge darker
|
||||
float fresnel = 1.0+dot(normalize(pos.xyz), norm.xyz);
|
||||
fresnel *= fresnel;
|
||||
fresnel = min(fresnel+envIntensity, 1.0);
|
||||
reflected_color *= (envIntensity*fresnel)*brighten(spec.rgb);
|
||||
color = mix(color.rgb, reflected_color, envIntensity);
|
||||
//fudge darker
|
||||
legacyenv *= 0.5*diffuse.a+0.5;;
|
||||
applyLegacyEnv(color, legacyenv, spec, pos.xyz, norm.xyz, envIntensity);
|
||||
}
|
||||
|
||||
if (norm.w < 0.5)
|
||||
|
|
@ -577,6 +175,8 @@ void main()
|
|||
// convert to linear as fullscreen lights need to sum in linear colorspace
|
||||
// and will be gamma (re)corrected downstream...
|
||||
//color = vec3(ambocc);
|
||||
//color = ambenv;
|
||||
//color = ambenv;
|
||||
//color.b = diffuse.a;
|
||||
frag_color.rgb = srgb_to_linear(color.rgb);
|
||||
frag_color.a = bloom;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -460,6 +460,11 @@ void LLDrawPoolBump::beginFullbrightShiny()
|
|||
LLVector4 vec4(vec, gShinyOrigin.mV[3]);
|
||||
shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV);
|
||||
|
||||
if (shader->mFeatures.hasReflectionProbes)
|
||||
{
|
||||
gPipeline.bindReflectionProbes(*shader);
|
||||
}
|
||||
|
||||
// Make sure that texture coord generation happens for tex unit 1, as that's the one we use for
|
||||
// the cube map in the one pass shiny shaders
|
||||
gGL.getTexUnit(1)->disable();
|
||||
|
|
@ -520,6 +525,10 @@ void LLDrawPoolBump::endFullbrightShiny()
|
|||
if( cube_map )
|
||||
{
|
||||
cube_map->disable();
|
||||
if (shader->mFeatures.hasReflectionProbes)
|
||||
{
|
||||
gPipeline.unbindReflectionProbes(*shader);
|
||||
}
|
||||
shader->unbind();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -506,6 +506,8 @@ void LLReflectionMapManager::setUniforms()
|
|||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
|
||||
|
||||
// TODO -- avoid repacking UBO unnecessarily
|
||||
|
||||
// structure for packing uniform buffer object
|
||||
// see class2/deferred/softenLightF.glsl
|
||||
struct ReflectionProbeData
|
||||
|
|
|
|||
|
|
@ -977,6 +977,7 @@ BOOL LLViewerShaderMgr::loadBasicShaders()
|
|||
index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/deferredUtil.glsl", 1) );
|
||||
index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/shadowUtil.glsl", 1) );
|
||||
index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/aoUtil.glsl", 1) );
|
||||
index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/reflectionProbeF.glsl", llmax(mShaderLevel[SHADER_DEFERRED], 1)) );
|
||||
index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) );
|
||||
index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightAlphaMaskNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) );
|
||||
index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightFullbrightNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) );
|
||||
|
|
@ -1503,6 +1504,12 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
|
|||
gDeferredMaterialProgram[i].mFeatures.hasGamma = true;
|
||||
gDeferredMaterialProgram[i].mFeatures.hasShadows = use_sun_shadow;
|
||||
|
||||
if (mShaderLevel[SHADER_DEFERRED] > 1)
|
||||
{
|
||||
gDeferredMaterialProgram[i].mFeatures.hasReflectionProbes = true;
|
||||
gDeferredMaterialProgram[i].addPermutation("HAS_REFLECTION_PROBES", "1");
|
||||
}
|
||||
|
||||
if (has_skin)
|
||||
{
|
||||
gDeferredMaterialProgram[i].addPermutation("HAS_SKIN", "1");
|
||||
|
|
@ -2202,6 +2209,11 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
|
|||
gDeferredFullbrightShinyProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB));
|
||||
gDeferredFullbrightShinyProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB));
|
||||
gDeferredFullbrightShinyProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
|
||||
if (gDeferredFullbrightShinyProgram.mShaderLevel >= 2) // TODO : make this a 3 when reflection probes are restricted to class 3
|
||||
{
|
||||
gDeferredFullbrightShinyProgram.addPermutation("HAS_REFLECTION_PROBES", "1");
|
||||
gDeferredFullbrightShinyProgram.mFeatures.hasReflectionProbes = true;
|
||||
}
|
||||
success = make_rigged_variant(gDeferredFullbrightShinyProgram, gDeferredSkinnedFullbrightShinyProgram);
|
||||
success = success && gDeferredFullbrightShinyProgram.createShader(NULL, NULL);
|
||||
llassert(success);
|
||||
|
|
@ -2274,6 +2286,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
|
|||
gDeferredSoftenProgram.mFeatures.hasGamma = true;
|
||||
gDeferredSoftenProgram.mFeatures.isDeferred = true;
|
||||
gDeferredSoftenProgram.mFeatures.hasShadows = use_sun_shadow;
|
||||
gDeferredSoftenProgram.mFeatures.hasReflectionProbes = true;
|
||||
|
||||
gDeferredSoftenProgram.clearPermutations();
|
||||
gDeferredSoftenProgram.mShaderFiles.push_back(make_pair("deferred/softenLightV.glsl", GL_VERTEX_SHADER_ARB));
|
||||
|
|
@ -2324,6 +2337,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
|
|||
gDeferredSoftenWaterProgram.mFeatures.hasGamma = true;
|
||||
gDeferredSoftenWaterProgram.mFeatures.isDeferred = true;
|
||||
gDeferredSoftenWaterProgram.mFeatures.hasShadows = use_sun_shadow;
|
||||
gDeferredSoftenWaterProgram.mFeatures.hasReflectionProbes = true;
|
||||
|
||||
if (ambient_kill)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8208,30 +8208,16 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_
|
|||
|
||||
stop_glerror();
|
||||
|
||||
bool setup_env_mat = false;
|
||||
channel = shader.enableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
|
||||
if (channel > -1)
|
||||
{
|
||||
LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
|
||||
if (cube_map)
|
||||
{
|
||||
setup_env_mat = true;
|
||||
cube_map->enable(channel);
|
||||
cube_map->bind();
|
||||
}
|
||||
}
|
||||
|
||||
channel = shader.enableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP_ARRAY);
|
||||
if (channel > -1 && mReflectionMapManager.mTexture.notNull())
|
||||
{
|
||||
// see comments in class2/deferred/softenLightF.glsl for what these uniforms mean
|
||||
mReflectionMapManager.mTexture->bind(channel);
|
||||
mReflectionMapManager.setUniforms();
|
||||
setup_env_mat = true;
|
||||
}
|
||||
|
||||
if (setup_env_mat)
|
||||
{
|
||||
F32* m = gGLModelView;
|
||||
|
||||
F32 mat[] = { m[0], m[1], m[2],
|
||||
|
|
@ -8239,8 +8225,10 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_
|
|||
m[8], m[9], m[10] };
|
||||
|
||||
shader.uniformMatrix3fv(LLShaderMgr::DEFERRED_ENV_MAT, 1, TRUE, mat);
|
||||
}
|
||||
}
|
||||
|
||||
bindReflectionProbes(shader);
|
||||
|
||||
if (gAtmosphere)
|
||||
{
|
||||
// bind precomputed textures necessary for calculating sun and sky luminance
|
||||
|
|
@ -9163,7 +9151,35 @@ void LLPipeline::unbindDeferredShader(LLGLSLShader &shader)
|
|||
}
|
||||
}
|
||||
|
||||
channel = shader.disableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP);
|
||||
unbindReflectionProbes(shader);
|
||||
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
gGL.getTexUnit(0)->activate();
|
||||
shader.unbind();
|
||||
}
|
||||
|
||||
void LLPipeline::bindReflectionProbes(LLGLSLShader& shader)
|
||||
{
|
||||
S32 channel = shader.enableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP_ARRAY);
|
||||
if (channel > -1 && mReflectionMapManager.mTexture.notNull())
|
||||
{
|
||||
// see comments in class2/deferred/softenLightF.glsl for what these uniforms mean
|
||||
mReflectionMapManager.mTexture->bind(channel);
|
||||
mReflectionMapManager.setUniforms();
|
||||
|
||||
F32* m = gGLModelView;
|
||||
|
||||
F32 mat[] = { m[0], m[1], m[2],
|
||||
m[4], m[5], m[6],
|
||||
m[8], m[9], m[10] };
|
||||
|
||||
shader.uniformMatrix3fv(LLShaderMgr::DEFERRED_ENV_MAT, 1, TRUE, mat);
|
||||
}
|
||||
}
|
||||
|
||||
void LLPipeline::unbindReflectionProbes(LLGLSLShader& shader)
|
||||
{
|
||||
S32 channel = shader.disableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP);
|
||||
if (channel > -1 && mReflectionMapManager.mTexture.notNull())
|
||||
{
|
||||
mReflectionMapManager.mTexture->unbind();
|
||||
|
|
@ -9172,12 +9188,9 @@ void LLPipeline::unbindDeferredShader(LLGLSLShader &shader)
|
|||
gGL.getTexUnit(channel)->enable(LLTexUnit::TT_TEXTURE);
|
||||
}
|
||||
}
|
||||
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
gGL.getTexUnit(0)->activate();
|
||||
shader.unbind();
|
||||
}
|
||||
|
||||
|
||||
inline float sgn(float a)
|
||||
{
|
||||
if (a > 0.0F) return (1.0F);
|
||||
|
|
|
|||
|
|
@ -294,6 +294,10 @@ public:
|
|||
void setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep);
|
||||
|
||||
void unbindDeferredShader(LLGLSLShader& shader);
|
||||
|
||||
void bindReflectionProbes(LLGLSLShader& shader);
|
||||
void unbindReflectionProbes(LLGLSLShader& shader);
|
||||
|
||||
void renderDeferredLighting(LLRenderTarget* light_target);
|
||||
void postDeferredGammaCorrect(LLRenderTarget* screen_target);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue