phoenix-firestorm/indra/newview/app_settings/shaders/class3/deferred/depthToShadowVolumeG.glsl

203 lines
5.7 KiB
GLSL

/**
* @file depthToShadowVolumeG.glsl
*
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, 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_geometry_shader4 : enable
#extension GL_ARB_texture_rectangle : enable
/*[EXTRA_CODE_HERE]*/
layout (triangles) in;
layout (triangle_strip, max_vertices = 128) out;
uniform sampler2DRect depthMap;
uniform mat4 shadowMatrix[6];
uniform vec4 lightpos;
VARYING vec2 vary_texcoord0;
out vec3 to_vec;
void cross_products(out vec4 ns[3], int a, int b, int c)
{
ns[0] = cross(gl_PositionIn[b].xyz - gl_PositionIn[a].xyz, gl_PositionIn[c].xyz - gl_PositionIn[a].xyz);
ns[1] = cross(gl_PositionIn[c].xyz - gl_PositionIn[b].xyz, gl_PositionIn[a].xyz - gl_PositionIn[b].xyz);
ns[2] = cross(gl_PositionIn[a].xyz - gl_PositionIn[c].xyz, gl_PositionIn[b].xyz - gl_PositionIn[c].xyz);
}
vec3 getLightDirection(vec4 lightpos, vec3 pos)
{
vec3 lightdir = lightpos.xyz - lightpos.w * pos;
return lightdir;
}
void emitTri(vec4 v[3])
{
gl_Position = proj_matrix * v[0];
EmitVertex();
gl_Position = proj_matrix * v[1];
EmitVertex();
gl_Position = proj_matrix * v[2];
EmitVertex();
EndPrimitive();
}
void emitQuad(vec4 v[4]
{
// Emit a quad as a triangle strip.
gl_Position = proj_matrix*v[0];
EmitVertex();
gl_Position = proj_matrix*v[1];
EmitVertex();
gl_Position = proj_matrix*v[2];
EmitVertex();
gl_Position = proj_matrix*v[3];
EmitVertex();
EndPrimitive();
}
void emitPrimitives(int layer)
{
int i = layer;
gl_Layer = i;
vec4 depth1 = vec4(texture2DRect(depthMap, tc0).rg, texture2DRect(depthMap, tc1).rg));
vec3 depth2 = vec4(texture2DRect(depthMap, tc2).rg, texture2DRect(depthMap, tc3).rg));
vec3 depth3 = vec4(texture2DRect(depthMap, tc4).rg, texture2DRect(depthMap, tc5).rg));
vec3 depth4 = vec4(texture2DRect(depthMap, tc6).rg, texture2DRect(depthMap, tc7).rg));
depth1 = min(depth1, depth2);
depth1 = min(depth1, depth3);
depth1 = min(depth1, depth4);
vec2 depth = min(depth1.xy, depth1.zw);
int side = sqrt(gl_VerticesIn);
for (int j = 0; j < side; j++)
{
for (int k = 0; k < side; ++k)
{
vec3 pos = gl_PositionIn[(j * side) + k].xyz;
vec4 v = shadowMatrix[i] * vec4(pos, 1.0);
gl_Position = v;
to_vec = pos - light_position.xyz * depth;
EmitVertex();
}
EndPrimitive();
}
vec3 norms[3]; // Normals
vec3 lightdir3]; // Directions toward light
vec4 v[4]; // Temporary vertices
vec4 or_pos[3] =
{ // Triangle oriented toward light source
gl_PositionIn[0],
gl_PositionIn[2],
gl_PositionIn[4]
};
// Compute normal at each vertex.
cross_products(n, 0, 2, 4);
// Compute direction from vertices to light.
lightdir[0] = getLightDirection(lightpos, gl_PositionIn[0].xyz);
lightdir[1] = getLightDirection(lightpos, gl_PositionIn[2].xyz);
lightdir[2] = getLightDirection(lightpos, gl_PositionIn[4].xyz);
// Check if the main triangle faces the light.
bool faces_light = true;
if (!(dot(ns[0],d[0]) > 0
|dot(ns[1],d[1]) > 0
|dot(ns[2],d[2]) > 0))
{
// Flip vertex winding order in or_pos.
or_pos[1] = gl_PositionIn[4];
or_pos[2] = gl_PositionIn[2];
faces_light = false;
}
// Near cap: simply render triangle.
emitTri(or_pos);
// Far cap: extrude positions to infinity.
v[0] =vec4(lightpos.w * or_pos[0].xyz - lightpos.xyz,0);
v[1] =vec4(lightpos.w * or_pos[2].xyz - lightpos.xyz,0);
v[2] =vec4(lightpos.w * or_pos[1].xyz - lightpos.xyz,0);
emitTri(v);
// Loop over all edges and extrude if needed.
for ( int i=0; i<3; i++ )
{
// Compute indices of neighbor triangle.
int v0 = i*2;
int nb = (i*2+1);
int v1 = (i*2+2) % 6;
cross_products(n, v0, nb, v1);
// Compute direction to light, again as above.
d[0] =lightpos.xyz-lightpos.w*gl_PositionIn[v0].xyz;
d[1] =lightpos.xyz-lightpos.w*gl_PositionIn[nb].xyz;
d[2] =lightpos.xyz-lightpos.w*gl_PositionIn[v1].xyz;
bool is_parallel = gl_PositionIn[nb].w < 1e-5;
// Extrude the edge if it does not have a
// neighbor, or if it's a possible silhouette.
if (is_parallel ||
( faces_light != (dot(ns[0],d[0])>0 ||
dot(ns[1],d[1])>0 ||
dot(ns[2],d[2])>0) ))
{
// Make sure sides are oriented correctly.
int i0 = faces_light ? v0 : v1;
int i1 = faces_light ? v1 : v0;
v[0] = gl_PositionIn[i0];
v[1] = vec4(lightpos.w*gl_PositionIn[i0].xyz - lightpos.xyz, 0);
v[2] = gl_PositionIn[i1];
v[3] = vec4(lightpos.w*gl_PositionIn[i1].xyz - lightpos.xyz, 0);
emitQuad(v);
}
}
}
void main()
{
// Output
emitPrimitives(0);
}