Skip to content

Instantly share code, notes, and snippets.

@Beherith
Created September 18, 2020 07:07
Show Gist options
  • Save Beherith/c2bfe6044d2ae5a50d21eeced3afae15 to your computer and use it in GitHub Desktop.
Save Beherith/c2bfe6044d2ae5a50d21eeced3afae15 to your computer and use it in GitHub Desktop.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
function widget:GetInfo()
return {
name = "Deferred rendering",
version = 3,
desc = "Collects and renders point and beam lights",
author = "beherith, aeonios",
date = "2015 Sept.",
license = "GPL V2",
layer = -99999990,
enabled = true
}
end
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
local glBeginEnd = gl.BeginEnd
local glBillboard = gl.Billboard
local glBlending = gl.Blending
local glCallList = gl.CallList
local glDeleteList = gl.DeleteList
local glClear = gl.Clear
local glColor = gl.Color
local glCreateList = gl.CreateList
local glCreateShader = gl.CreateShader
local glCreateTexture = gl.CreateTexture
local glDeleteShader = gl.DeleteShader
local glDeleteTexture = gl.DeleteTexture
local glDepthMask = gl.DepthMask
local glDepthTest = gl.DepthTest
local glGetShaderLog = gl.GetShaderLog
local glGetUniformLocation = gl.GetUniformLocation
local glGetViewSizes = gl.GetViewSizes
local glPopMatrix = gl.PopMatrix
local glPushMatrix = gl.PushMatrix
local glTexCoord = gl.TexCoord
local glTexture = gl.Texture
local glTexRect = gl.TexRect
local glRect = gl.Rect
local glRenderToTexture = gl.RenderToTexture
local glUniform = gl.Uniform
local glUniformInt = gl.UniformInt
local glUniformMatrix = gl.UniformMatrix
local glUseShader = gl.UseShader
local glVertex = gl.Vertex
local glTranslate = gl.Translate
local spEcho = Spring.Echo
local spGetCameraPosition = Spring.GetCameraPosition
local spWorldToScreenCoords = Spring.WorldToScreenCoords
local spGetGroundHeight = Spring.GetGroundHeight
local math_sqrt = math.sqrt
local math_min = math.min
local math_max = math.max
local glowImg = "LuaUI/Images/glow2.dds"
local beamGlowImg = ":n:LuaUI/Images/barglow-center.png"
local beamGlowEndImg = ":n:LuaUI/Images/barglow-edge.png"
local GLSLRenderer = true
local vsx, vsy
local ivsx = 1.0
local ivsy = 1.0
local screenratio = 1.0
-- dynamic light shaders
local depthPointShader = nil
local depthBeamShader = nil
-- shader uniforms
local lightposlocPoint = nil
local lightcolorlocPoint = nil
local lightparamslocPoint = nil
local uniformEyePosPoint
local uniformViewPrjInvPoint
local lightposlocBeam = nil
local lightpos2locBeam = nil
local lightcolorlocBeam = nil
local lightparamslocBeam = nil
local uniformEyePosBeam
local uniformViewPrjInvBeam
local LightDL = nil
--------------------------------------------------------------------------------
--Light falloff functions: http://gamedev.stackexchange.com/questions/56897/glsl-light-attenuation-color-and-intensity-formula
--------------------------------------------------------------------------------
local verbose = false
local function VerboseEcho(...)
if verbose then
Spring.Echo(...)
end
end
local collectionFunctions = {}
local collectionFunctionCount = 0
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
function widget:RecvLuaMsg(msg, playerID)
if msg:sub(1,18) == 'LobbyOverlayActive' then
chobbyInterface = (msg:sub(1,19) == 'LobbyOverlayActive1')
end
end
function widget:ViewResize()
vsx, vsy = gl.GetViewSizes()
ivsx = 1.0 / vsx --we can do /n here!
ivsy = 1.0 / vsy
if (Spring.GetMiniMapDualScreen() == 'left') then
vsx = vsx / 2
end
if (Spring.GetMiniMapDualScreen() == 'right') then
vsx = vsx / 2
end
screenratio = vsy / vsx --so we dont overdraw and only always draw a square
end
widget:ViewResize()
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
---------[[[NEW]]]-----------------
local luaShaderDir = "LuaUI/Widgets_BAR/Include/"
local vsSrc = [[
#version 150 compatibility
uniform mat4 viewMat;
uniform mat4 projMat;
out DataVS {
vec4 colAtt;
vec4 attrib0;
vec4 attrib1;
};
void main() {
gl_Position = gl_Vertex;
colAtt = gl_Color;
attrib0 = gl_Position;
attrib1 = gl_MultiTexCoord0;
}
]]
local gsSrc = [[
#version 150 compatibility
uniform mat4 viewMat;
uniform mat4 projMat;
//uniform int lightType;
layout (points) in;
layout (triangle_strip, max_vertices = 24) out;
#line 41
in DataVS {
vec4 colAtt;
vec4 attrib0;
vec4 attrib1;
} dataIn[];
out DataGS {
vec4 colAtt;
vec4 attrib0; //gl_Vertex
vec4 attrib1; //gl_MultiTexCoord0
};
// Z-; Z+ are bottom top planes of frustum
void GenericFrustum(mat4 worldMat, vec4 zMinModelCenterPos, vec4 zMaxModelCenterPos, float zMinRadius, float zMaxRadius) {
mat4 MVP = projMat * viewMat * worldMat;
vec4 frustumPoints[8] = vec4[](
//zMin (-- -+ +- ++)
MVP * (zMinModelCenterPos + vec4(-zMinRadius, -zMinRadius, 0.0, 0.0)),
MVP * (zMinModelCenterPos + vec4(-zMinRadius, zMinRadius, 0.0, 0.0)),
MVP * (zMinModelCenterPos + vec4( zMinRadius, -zMinRadius, 0.0, 0.0)),
MVP * (zMinModelCenterPos + vec4( zMinRadius, zMinRadius, 0.0, 0.0)),
//zMax (-- -+ +- ++)
MVP * (zMaxModelCenterPos + vec4(-zMaxRadius, -zMaxRadius, 0.0, 0.0)),
MVP * (zMaxModelCenterPos + vec4(-zMaxRadius, zMaxRadius, 0.0, 0.0)),
MVP * (zMaxModelCenterPos + vec4( zMaxRadius, -zMaxRadius, 0.0, 0.0)),
MVP * (zMaxModelCenterPos + vec4( zMaxRadius, zMaxRadius, 0.0, 0.0))
);
#define MyEmitVertex(idx) \
{ \
gl_Position = frustumPoints[idx]; \
colAtt = dataIn[0].colAtt; \
attrib0 = dataIn[0].attrib0; \
attrib1 = dataIn[0].attrib1; \
EmitVertex(); \
}
// Z-
MyEmitVertex(3);
MyEmitVertex(1);
MyEmitVertex(2);
MyEmitVertex(0);
EndPrimitive();
// Z+
MyEmitVertex(4);
MyEmitVertex(5);
MyEmitVertex(6);
MyEmitVertex(7);
EndPrimitive();
// X-
MyEmitVertex(0);
MyEmitVertex(1);
MyEmitVertex(4);
MyEmitVertex(5);
EndPrimitive();
// X+
MyEmitVertex(3);
MyEmitVertex(2);
MyEmitVertex(7);
MyEmitVertex(6);
EndPrimitive();
// Y-
MyEmitVertex(0);
MyEmitVertex(4);
MyEmitVertex(2);
MyEmitVertex(6);
EndPrimitive();
// Y+
MyEmitVertex(7);
MyEmitVertex(5);
MyEmitVertex(3);
MyEmitVertex(1);
EndPrimitive();
}
void GetSphereBoundingShape(mat4 worldMat, vec4 modelCenterPos, float r) {
vec4 zMinModelCenterPos = modelCenterPos; zMinModelCenterPos.z -= r;
vec4 zMaxModelCenterPos = modelCenterPos; zMaxModelCenterPos.z += r;
GenericFrustum(worldMat, zMinModelCenterPos, zMaxModelCenterPos, r, r);
}
void GetBeamBoundingShape(mat4 worldMat, vec4 modelBeamStartPos, vec4 modelBeamEndPos, float r0, float r1) {
GenericFrustum(worldMat, modelBeamStartPos, modelBeamEndPos, r0, r1);
}
void GetConeBoundingShape(mat4 worldMat, vec4 modelBeamStartPos, float r, float phi) {
vec4 modelBeamEndPos = modelBeamStartPos; modelBeamEndPos.z += r;
float rFar = r * tan(0.5 * phi);
GenericFrustum(worldMat, modelBeamStartPos, modelBeamEndPos, 0.0, rFar);
}
mat4 GetDirectionMatrix(vec3 dirNorm) {
const vec3 up = vec3(0, 1, 0);
vec3 zaxis = dirNorm;
vec3 xaxis = normalize(cross(zaxis, up));
xaxis = isnan(xaxis.x) ? vec3(1, 0, 0) : xaxis;
vec3 yaxis = cross(xaxis, zaxis);
return mat4(
vec4(xaxis.x, yaxis.x, zaxis.x, 0.0),
vec4(xaxis.y, yaxis.y, zaxis.y, 0.0),
vec4(xaxis.z, yaxis.z, zaxis.z, 0.0),
vec4(0.0, 0.0, 0.0, 1.0)
);
}
mat4 GetTranslationMatrix(vec3 xyz) {
mat4 trlMat = mat4(1.0);
trlMat[3] = vec4(xyz, 1.0);
return trlMat;
}
void main() {
vec3 pos0 = gl_in[0].gl_Position.xyz;
float r0 = gl_in[0].gl_Position.w;
vec3 pos1 = dataIn[0].attrib0.xyz;
float r1 = dataIn[0].attrib0.w;
const vec4 startModelPos = vec4(0.0, 0.0, 0.0, 1.0);
//if (dataIn[0].attrib1.a == 0) { // omni-dir light
if (1.0>0.0) { // omni-dir light
mat4 rotMat = GetDirectionMatrix(vec3(0, 1, 0));
mat4 trlMat = GetTranslationMatrix(pos0);
mat4 worldMat = trlMat * rotMat;
GetSphereBoundingShape(worldMat, startModelPos, r0);
}
else if (dataIn[0].attrib1.a < 0) { // beam light
vec4 dirLen = vec4(pos1 - pos0, 0.0);
dirLen.w = length(dirLen.xyz);
dirLen.xyz /= dirLen.w;
vec4 endModelPos = vec4(0.0, 0.0, dirLen.w, 1.0);
mat4 rotMat = GetDirectionMatrix(dirLen.xyz);
mat4 trlMat = GetTranslationMatrix(pos0);
mat4 worldMat = trlMat * rotMat;
GetBeamBoundingShape(worldMat, startModelPos, endModelPos, r0, r1);
}
else if (dataIn[0].attrib1.a > 0) { // //cone light
mat4 rotMat = GetDirectionMatrix(normalize(pos1));
mat4 trlMat = GetTranslationMatrix(pos0);
mat4 worldMat = trlMat * rotMat;
GetConeBoundingShape(worldMat, startModelPos, r0, r1);
}
}
]]
local fsSrc = [[
#version 150 compatibility
//uniform int lightType;
uniform vec2 viewPortSize;
uniform sampler2D modelnormals;
uniform sampler2D modeldepths;
uniform sampler2D mapnormals;
uniform sampler2D mapdepths;
uniform sampler2D modelExtra;
uniform mat4 viewProjectionInv;
uniform vec3 eyePos;
in DataGS {
vec4 colAtt; //color.rgb, falloff
vec4 attrib0; //gl_vertex, worldpos.xyz, radius
vec4 attrib1; //gl_MultiTexCoord0,
//for point lights this is ==0
//for beam lights: pos2.xyz, >-1
//for cone lights its: dir.xyz, angle
};
#define LIGHTCOLOR colAtt.rgb
#define FALLOFF colAtt.a
#define LIGHTPOS attrib0.xyz
#define LIGHTRADIUS attrib0.a
#define BEAMPOS attrib1.xyz
#define CONEDIR attrib1.xyz
#define CONEANGLE attrib1.a
#define LIGHTTYPE attrib1.a
#define CLIP_CONTROL 1 //TODO
float attenuate(float dist, float radius) {
// float raw = constant-linear * dist / radius - squared * dist * dist / (radius * radius);
// float att = clamp(raw, 0.0, 0.5);
float raw = 0.7 - 0.3 * dist / radius - FALLOFF * dist * dist / (radius * radius);
float att = clamp(raw, 0.0, 1.0);
return (att * att);
}
void main() {
vec2 uv = gl_FragCoord.xy / viewPortSize;
//gl_FragColor = !gl_FrontFacing ? vec4(colAtt.rgb, 1.0) : vec4(vec3(1.0), 1.0);
gl_FragColor = vec4(colAtt.rgb, 1.0);
gl_FragColor = vec4(uv, 0.0, 1.0);
float mapDepth = texture2D( mapdepths, uv).x;
float mdlDepth = texture2D(modeldepths, uv).x;
#if (CLIP_CONTROL == 1)
vec4 mappos4 = vec4( vec3(uv * 2.0 - 1.0, mapDepth), 1.0);
vec4 modelpos4 = vec4( vec3(uv * 2.0 - 1.0, mdlDepth), 1.0);
#else
vec4 mappos4 = vec4( vec3(uv, mapDepth) * 2.0 - 1.0, 1.0);
vec4 modelpos4 = vec4( vec3(uv, mdlDepth) * 2.0 - 1.0, 1.0);
#endif
vec4 map_normals4 = texture2D(mapnormals , uv) * 2.0 - 1.0;
vec4 model_normals4 = texture2D(modelnormals, uv) * 2.0 - 1.0;
vec4 model_extra4 = texture2D(modelExtra , uv) * 2.0 - 1.0;
float specularHighlight = 1.0; // default specular factor, for models it should be read
float model_lighting_multiplier = 1.0; //models recieve additional lighting, looks better.
float specularExponent = 10.0; //default specular power, for models it should be different TODO
if ((mappos4.z - modelpos4.z) > 0.0) {
// this means we are processing a model fragment, not a map fragment
if (model_extra4.a > 0.5) {
map_normals4 = model_normals4;
mappos4 = modelpos4;
model_lighting_multiplier = 1.5;
specularHighlight = specularHighlight + 2.0 * model_extra4.g;
}
}
mappos4 = viewProjectionInv * mappos4;
mappos4.xyz = mappos4.xyz / mappos4.w;
vec3 light_direction = normalize(LIGHTPOS - mappos4.xyz);;
float dist_light_here = dot(LIGHTPOS - mappos4.xyz, light_direction);
float cosphi = 0;
if (LIGHTTYPE <= -1) { // BEAM LIGHT
//distance( Point P, Segment P0:P1 ) http://geomalgorithms.com/a02-_lines.html
vec3 v = BEAMPOS - LIGHTPOS;
vec3 w = mappos4.xyz - LIGHTPOS;
float c1 = dot(v, w);
float c2 = dot(v, v);
if (c1 <= 0.0){
w = LIGHTPOS;
} else if (c2 < c1) {
w = BEAMPOS.xyz;
} else {
w = LIGHTPOS + (c1 / c2) * v;
}
v = mappos4.xyz;
light_direction = normalize(w.xyz - v.xyz);
dist_light_here = dot(w - v, light_direction);
cosphi = max(0.0, dot(normalize(map_normals4.xyz), light_direction));
}
else if(LIGHTTYPE > 0){ // CONE Light
//https://www.tomdalling.com/blog/modern-opengl/08-even-more-lighting-directional-lights-spotlights-multiple-lights/
vec3 coneDirection = normalize(CONEDIR);
float spotlightfactor = dot(coneDirection,light_direction);
if (spotlightfactor < CONEANGLE) spotlightfactor = 0;
cosphi = spotlightfactor * max(0.0, dot(normalize(map_normals4.xyz), light_direction));
}
else{ // POINT LIGHT
cosphi = max(0.0, dot(normalize(map_normals4.xyz), light_direction));
}
float attenuation = attenuate(dist_light_here, LIGHTRADIUS);
vec3 viewDirection = normalize(vec3(eyePos - mappos4.xyz));
// light source on the wrong side?
if (dot(map_normals4.xyz, light_direction) > 0.02) {
vec3 reflection = reflect(-1.0 * light_direction, map_normals4.xyz);
float glossiness = dot(reflection, viewDirection);
float highlight = pow(max(0.0, glossiness), 8.0);
specularHighlight *= (0.5 * highlight);
} else {
specularHighlight = 0.0;
}
//OK, our blending func is the following: Rr=Lr*Dr+1*Dr
float lightalpha = cosphi * attenuation + attenuation * specularHighlight;
//dont light underwater:
lightalpha = clamp(lightalpha, 0.0, lightalpha * ((mappos4.y + 50.0) * (0.02)));
gl_FragColor = vec4(LIGHTCOLOR * lightalpha * model_lighting_multiplier, 1.0);
//gl_FragColor.g = 1.0;
//gl_FragColor.r = cosphi;
//gl_FragColor.b = fract(dist_light_here*0.01);
gl_FragColor.r = uv.x;
gl_FragColor.g = uv.y;
//gl_FragColor.r = fract(mappos4.x * 0.001);
//gl_FragColor.g = fract(mappos4.y * 0.001);
//gl_FragColor.b = fract(mappos4.z * 0.001);
gl_FragColor.r = fract(mappos4.x * 0.01);
gl_FragColor.g = fract(mappos4.y * 0.01);
gl_FragColor.b = fract(mappos4.z * 0.01);
//gl_FragColor.xyz = vec3(map_normals4.xyz);
//#define DEBUG
#ifdef DEBUG
gl_FragColor = vec4(map_normals4.xyz, 1.0); //world normals debugging
gl_FragColor = vec4(fract(modelpos4.z * 0.01),sign(mappos4.z - modelpos4.z), 0.0, 1.0); //world pos debugging, very useful
if (length(LIGHTCOLOR * lightalpha * model_lighting_multiplier) < (1.0 / 256.0)){ //shows light boudaries
gl_FragColor=vec4(vec3(0.5, 0.0, 0.5), 0.0);
}
#endif
}
]]
-----------------------------------------------------------------
-- Global Variables
-----------------------------------------------------------------
local glBlending = gl.Blending
local glTexture = gl.Texture
local LuaShader = VFS.Include(luaShaderDir.."LuaShader.lua")
local vsx, vsy, vpx, vpy
local lightShader
local dlPoint, dlBeam, dlCone
-------[[[OLD]]]--------------------
local vertSrc = [[
void main(void)
{
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = gl_Vertex;
}
]]
local fragSrc = [[
//This code authored by Peter Sarkozy aka Beherith (mysterme@gmail.com )
//License is GPL V2
// old version with calced normals is 67 fps for 10 beamers full screen at 1440p
// new version with buffered normals is 88 fps for 10 beamers full screen at 1440p
//#define DEBUG
#define LIGHTRADIUS lightpos.w
uniform sampler2D modelnormals;
uniform sampler2D modeldepths;
uniform sampler2D mapnormals;
uniform sampler2D mapdepths;
uniform sampler2D modelExtra;
uniform vec3 eyePos;
uniform vec4 lightpos;
#if (BEAM_LIGHT == 1)
uniform vec4 lightpos2;
#endif
uniform vec4 lightcolor;
uniform mat4 viewProjectionInv;
float attenuate(float dist, float radius) {
// float raw = constant-linear * dist / radius - squared * dist * dist / (radius * radius);
// float att = clamp(raw, 0.0, 0.5);
float raw = 0.7 - 0.3 * dist / radius - lightcolor.a * dist * dist / (radius * radius);
float att = clamp(raw, 0.0, 1.0);
return (att * att);
}
void main(void)
{
float mapDepth = texture2D( mapdepths, gl_TexCoord[0].st).x;
float mdlDepth = texture2D(modeldepths, gl_TexCoord[0].st).x;
#if (CLIP_CONTROL == 1)
vec4 mappos4 = vec4( vec3(gl_TexCoord[0].st * 2.0 - 1.0, mapDepth), 1.0);
vec4 modelpos4 = vec4( vec3(gl_TexCoord[0].st * 2.0 - 1.0, mdlDepth), 1.0);
#else
vec4 mappos4 = vec4( vec3(gl_TexCoord[0].st, mapDepth) * 2.0 - 1.0, 1.0);
vec4 modelpos4 = vec4( vec3(gl_TexCoord[0].st, mdlDepth) * 2.0 - 1.0, 1.0);
#endif
vec4 map_normals4 = texture2D(mapnormals , gl_TexCoord[0].st) * 2.0 - 1.0;
vec4 model_normals4 = texture2D(modelnormals, gl_TexCoord[0].st) * 2.0 - 1.0;
vec4 model_extra4 = texture2D(modelExtra , gl_TexCoord[0].st) * 2.0 - 1.0;
float specularHighlight = 1.0;
float model_lighting_multiplier = 1.0; //models recieve additional lighting, looks better.
if ((mappos4.z - modelpos4.z) > 0.0) {
// this means we are processing a model fragment, not a map fragment
if (model_extra4.a > 0.5) {
map_normals4 = model_normals4;
mappos4 = modelpos4;
model_lighting_multiplier = 1.5;
specularHighlight = specularHighlight + 2.0 * model_extra4.g;
}
}
mappos4 = viewProjectionInv * mappos4;
mappos4.xyz = mappos4.xyz / mappos4.w;
vec3 light_direction;
#if (BEAM_LIGHT == 0)
light_direction = normalize(lightpos.xyz - mappos4.xyz);
float dist_light_here = dot(lightpos.xyz - mappos4.xyz, light_direction);
float cosphi = max(0.0, dot(normalize(map_normals4.xyz), light_direction));
float attenuation = attenuate(dist_light_here, LIGHTRADIUS);
#else
/*distance( Point P, Segment P0:P1 ) // http://geomalgorithms.com/a02-_lines.html
{
v = P1 - P0
w = P - P0
if ( (c1 = w dot v) <= 0 ) // before P0
return d(P, P0)
if ( (c2 = v dot v) <= c1 ) // after P1
return d(P, P1)
b = c1 / c2
Pb = P0 + bv
return d(P, Pb)
}
*/
vec3 v = lightpos2.xyz - lightpos.xyz;
vec3 w = mappos4.xyz - lightpos.xyz;
float c1 = dot(v, w);
float c2 = dot(v, v);
if (c1 <= 0.0){
v = mappos4.xyz;
w = lightpos.xyz;
} else if (c2 < c1) {
v = mappos4.xyz;
w = lightpos2.xyz;
} else {
w = lightpos.xyz + (c1 / c2) * v;
v = mappos4.xyz;
}
light_direction = normalize(w.xyz - v.xyz);
float dist_light_here = dot(w - v, light_direction);
float cosphi = max(0.0, dot(normalize(map_normals4.xyz), light_direction));
// float attenuation = max(0.0, (1.0 * LIGHT_CONSTANT - LIGHT_SQUARED * (dist_light_here * dist_light_here) / (LIGHTRADIUS * LIGHTRADIUS) - LIGHT_LINEAR * (dist_light_here) / (LIGHTRADIUS)));
float attenuation = attenuate(dist_light_here, LIGHTRADIUS);
#endif
vec3 viewDirection = normalize(vec3(eyePos - mappos4.xyz));
// light source on the wrong side?
if (dot(map_normals4.xyz, light_direction) > 0.02) {
vec3 reflection = reflect(-1.0 * light_direction, map_normals4.xyz);
float glossiness = dot(reflection, viewDirection);
float highlight = pow(max(0.0, glossiness), 8.0);
specularHighlight *= (0.5 * highlight);
} else {
specularHighlight = 0.0;
}
//OK, our blending func is the following: Rr=Lr*Dr+1*Dr
float lightalpha = cosphi * attenuation + attenuation * specularHighlight;
//dont light underwater:
lightalpha = clamp(lightalpha, 0.0, lightalpha * ((mappos4.y + 50.0) * (0.02)));
gl_FragColor = vec4(lightcolor.rgb * lightalpha * model_lighting_multiplier, 1.0);
gl_FragColor.r = 1.0;
#ifdef DEBUG
gl_FragColor = vec4(map_normals4.xyz, 1.0); //world normals debugging
gl_FragColor = vec4(fract(modelpos4.z * 0.01),sign(mappos4.z - modelpos4.z), 0.0, 1.0); //world pos debugging, very useful
if (length(lightcolor.rgb * lightalpha * model_lighting_multiplier) < (1.0 / 256.0)){ //shows light boudaries
gl_FragColor=vec4(vec3(0.5, 0.0, 0.5), 0.0);
}
#endif
}
]]
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
local function DeferredLighting_RegisterFunction(func)
collectionFunctionCount = collectionFunctionCount + 1
collectionFunctions[collectionFunctionCount] = func
return collectionFunctionCount
end
local function DeferredLighting_UnRegisterFunction(functionID)
collectionFunctions[functionID] = nil
end
local function PrepareLightDisplayLists()
if dlPoint then
gl.DeleteList(dlPoint)
dlPoint = nil
end
if dlBeam then
gl.DeleteList(dlBeam)
dlBeam = nil
end
if dlCone then
gl.DeleteList(dlCone)
dlCone = nil
end
dlBeam = gl.CreateList( function() --800, 130, 2700
gl.BeginEnd(GL.POINTS, function ()
gl.Color(0, 1, 0, 1) --green, unit fallofffactor
gl.Vertex(1000, 250, 1000, 250)
gl.MultiTexCoord(0, 1000, 250 , 2000, -2.0) --
end)
end)
dlPoint = gl.CreateList( function()
gl.BeginEnd(GL.POINTS, function ()
gl.Color(1, 0, 1, 1) --blue, unit fallofffactor
gl.Vertex(2000, 150, 1000, 150)
gl.MultiTexCoord(0, 0, 0 , 0, 0) --
gl.Color(0, 1, 0, 1) --green, unit fallofffactor
gl.Vertex(3000, 250, 1000, 250)
gl.MultiTexCoord(0, 0, 0 , 0, 0) --
end)
end)
dlCone = gl.CreateList( function()
gl.BeginEnd(GL.POINTS, function ()
gl.Color(1, 1, 0, 1) --yellow, unit fallofffactor
gl.Vertex(4000, 250, 1000, 250)
gl.MultiTexCoord(0, 200, 250 , 1600, 1.0) --
end)
end)
end
function widget:Initialize()
local vsx, vsy, vpx, vpy = Spring.GetViewGeometry()
widget:ViewResize()
------[[[NEW]]-----
lightShader = LuaShader({
vertex = vsSrc,
geometry = gsSrc,
fragment = fsSrc,
uniformFloat = {
viewPortSize = {vsx, vsy},
eyePos = {0,0,0},
},
}, "Light Volume Shader2")
lightShader:Initialize()
PrepareLightDisplayLists()
if (glCreateShader == nil) then
Spring.Echo('Deferred Rendering requires shader support!')
widgetHandler:RemoveWidget(self)
return
end
Spring.SetConfigInt("AllowDeferredMapRendering", 1)
Spring.SetConfigInt("AllowDeferredModelRendering", 1)
if (Spring.GetConfigString("AllowDeferredMapRendering") == '0' or Spring.GetConfigString("AllowDeferredModelRendering") == '0') then
Spring.Echo('Deferred Rendering (gfx_deferred_rendering.lua) requires AllowDeferredMapRendering and AllowDeferredModelRendering to be enabled in springsettings.cfg!')
widgetHandler:RemoveWidget(self)
return
end
if ((not forceNonGLSL) and Spring.GetMiniMapDualScreen() ~= 'left') then --FIXME dualscreen
if (not glCreateShader) then
spEcho("gfx_deferred_rendering.lua: Shaders not found, removing self.")
GLSLRenderer = false
widgetHandler:RemoveWidget(self)
return
else
depthPointShader = depthPointShader or glCreateShader({
defines = {
"#version 150 compatibility\n",
"#define BEAM_LIGHT 0\n",
"#define CLIP_CONTROL " .. (Platform ~= nil and Platform.glSupportClipSpaceControl and 1 or 0) .. "\n"
},
vertex = vertSrc,
fragment = fragSrc,
uniformInt = {
modelnormals = 0,
modeldepths = 1,
mapnormals = 2,
mapdepths = 3,
modelExtra = 4,
},
})
if (not depthPointShader) then
spEcho(glGetShaderLog())
spEcho("gfx_deferred_rendering.lua: Bad depth point shader, removing self.")
GLSLRenderer = false
widgetHandler:RemoveWidget(self)
return
else
lightposlocPoint = glGetUniformLocation(depthPointShader, "lightpos")
lightcolorlocPoint = glGetUniformLocation(depthPointShader, "lightcolor")
uniformEyePosPoint = glGetUniformLocation(depthPointShader, 'eyePos')
uniformViewPrjInvPoint = glGetUniformLocation(depthPointShader, 'viewProjectionInv')
end
--fragSrc = "#define BEAM_LIGHT \n" .. fragSrc
depthBeamShader = depthBeamShader or glCreateShader({
defines = {
"#version 150 compatibility\n",
"#define BEAM_LIGHT 1\n",
"#define CLIP_CONTROL " .. (Platform ~= nil and Platform.glSupportClipSpaceControl and 1 or 0) .. "\n"
},
vertex = vertSrc,
fragment = fragSrc,
uniformInt = {
modelnormals = 0,
modeldepths = 1,
mapnormals = 2,
mapdepths = 3,
modelExtra = 4,
},
})
if (not depthBeamShader) then
spEcho(glGetShaderLog())
spEcho("gfx_deferred_rendering.lua: Bad depth beam shader, removing self.")
GLSLRenderer = false
widgetHandler:RemoveWidget(self)
return
else
lightposlocBeam = glGetUniformLocation(depthBeamShader, 'lightpos')
lightpos2locBeam = glGetUniformLocation(depthBeamShader, 'lightpos2')
lightcolorlocBeam = glGetUniformLocation(depthBeamShader, 'lightcolor')
uniformEyePosBeam = glGetUniformLocation(depthBeamShader, 'eyePos')
uniformViewPrjInvBeam = glGetUniformLocation(depthBeamShader, 'viewProjectionInv')
end
WG.DeferredLighting_RegisterFunction = DeferredLighting_RegisterFunction
WG.DeferredLighting_UnRegisterFunction = DeferredLighting_UnRegisterFunction
end
screenratio = vsy / vsx --so we dont overdraw and only always draw a square
else
GLSLRenderer = false
end
end
function widget:Shutdown()
if (GLSLRenderer) then
if (glDeleteShader) then
glDeleteShader(depthPointShader)
glDeleteShader(depthBeamShader)
end
end
end
local drawarea = 0
local function DrawLightType(lights, lightsCount, lighttype) -- point = 0 beam = 1
--Spring.Echo('Camera FOV = ', Spring.GetCameraFOV()) -- default TA cam fov = 45
--set uniforms:
local cpx, cpy, cpz = spGetCameraPosition()
if lighttype == 0 then --point
glUseShader(depthPointShader)
glUniform(uniformEyePosPoint, cpx, cpy, cpz)
glUniformMatrix(uniformViewPrjInvPoint, "viewprojectioninverse")
else --beam
glUseShader(depthBeamShader)
glUniform(uniformEyePosBeam, cpx, cpy, cpz)
glUniformMatrix(uniformViewPrjInvBeam, "viewprojectioninverse")
end
glTexture(0, "$model_gbuffer_normtex")
glTexture(1, "$model_gbuffer_zvaltex")
glTexture(2, "$map_gbuffer_normtex")
glTexture(3, "$map_gbuffer_zvaltex")
glTexture(4, "$model_gbuffer_spectex")
local cx, cy, cz = spGetCameraPosition()
for i = 1, lightsCount do
local light = lights[i]
local param = light.param
if verbose then
VerboseEcho('gfx_deferred_rendering.lua: Light being drawn:', i)
Spring.Utilities.TableEcho(light)
end
if lighttype == 0 then -- point
local lightradius = param.radius
local falloffsquared = param.falloffsquared or 1.0
--Spring.Echo("Drawlighttype position = ", light.px, light.py, light.pz)
local groundheight = math_max(0, spGetGroundHeight(light.px, light.pz))
local sx, sy, sz = spWorldToScreenCoords(light.px, groundheight, light.pz) -- returns x, y, z, where x and y are screen pixels, and z is z buffer depth.
sx = sx/vsx
sy = sy/vsy --since FOV is static in the Y direction, the Y ratio is the correct one
--local dist_sq = (light.px-cx)^2 + (groundheight-cy)^2 + (light.pz-cz)^2
local dist_sq = (light.px-cx)^2 + (groundheight-cy)^2 + (light.pz-cz)^2
local ratio = lightradius / math_sqrt(dist_sq) * 1.5
glUniform(lightposlocPoint, light.px, light.py, light.pz, param.radius) --in world space
glUniform(lightcolorlocPoint, param.r * light.colMult, param.g * light.colMult, param.b * light.colMult, falloffsquared)
local tx1 = (sx-0.5)*2-ratio*screenratio
local ty1 = (sy-0.5)*2-ratio
local tx2 = (sx-0.5)*2+ratio*screenratio
local ty2 = (sy-0.5)*2+ratio
drawarea = drawarea + ( math_min( 1 , tx2)- math_max(-1 , tx1)) * (math_min( 1 , ty2) - math_max(-1 , ty1))*0.25
--PtaQ uncomment this if you want to debug:
--Spring.Echo(string.format("sx=%.4f sy = %.4f dist_sq=%.1f ratio = %.4f, {%.4f : %.4f}-{%.4f : %.4f}",sx,sy,dist_sq,ratio,tx1,ty1,tx2,ty2))
glTexRect(
math_max(-1 , tx1),
math_max(-1 , ty1),
math_min( 1 , tx2),
math_min( 1 , ty2),
math_max( 0 , sx - 0.5*ratio*screenratio),
math_max( 0 , sy - 0.5*ratio),
math_min( 1 , sx + 0.5*ratio*screenratio),
math_min( 1 , sy + 0.5*ratio)
) -- screen size goes from -1, -1 to 1, 1; uvs go from 0, 0 to 1, 1
end
if lighttype == 1 then -- beam
local lightradius = 0
local falloffsquared = param.falloffsquared or 1.0
local px = light.px+light.dx*0.5
local py = light.py+light.dy*0.5
local pz = light.pz+light.dz*0.5
local lightradius = param.radius + math_sqrt(light.dx*light.dx + light.dy*light.dy + light.dz*light.dz)*0.5
VerboseEcho("Drawlighttype position = ", light.px, light.py, light.pz)
local sx, sy, sz = spWorldToScreenCoords(px, py, pz) -- returns x, y, z, where x and y are screen pixels, and z is z buffer depth.
sx = sx/vsx
sy = sy/vsy --since FOV is static in the Y direction, the Y ratio is the correct one
local dist_sq = (px-cx)^2 + (py-cy)^2 + (pz-cz)^2
local ratio = lightradius / math_sqrt(dist_sq)
ratio = ratio*2
glUniform(lightposlocBeam, light.px, light.py, light.pz, param.radius) --in world space
glUniform(lightpos2locBeam, light.px+light.dx, light.py+light.dy+24, light.pz+light.dz, param.radius) --in world space, the magic constant of +24 in the Y pos is needed because of our beam distance calculator function in GLSL
glUniform(lightcolorlocBeam, param.r * light.colMult, param.g * light.colMult, param.b * light.colMult, falloffsquared)
--TODO: use gl.Shape instead, to avoid overdraw
local tx1 = (sx-0.5)*2-ratio*screenratio
local ty1 = (sy-0.5)*2-ratio
local tx2 = (sx-0.5)*2+ratio*screenratio
local ty2 = (sy-0.5)*2+ratio
drawarea = drawarea + ( math_min( 1 , tx2)- math_max(-1 , tx1)) * (math_min( 1 , ty2) - math_max(-1 , ty1))*0.25
glTexRect(
math_max(-1 , tx1),
math_max(-1 , ty1),
math_min( 1 , tx2),
math_min( 1 , ty2),
math_max( 0 , sx - 0.5*ratio*screenratio),
math_max( 0 , sy - 0.5*ratio),
math_min( 1 , sx + 0.5*ratio*screenratio),
math_min( 1 , sy + 0.5*ratio)
) -- screen size goes from -1, -1 to 1, 1; uvs go from 0, 0 to 1, 1
end
end
glUseShader(0)
glTexture(0, false)
glTexture(1, false)
glTexture(2, false)
glTexture(3, false)
glTexture(4, false)
end
local function renderToTextureFunc(tex, s, t)
glTexture(tex)
glTexRect(-1 * s, -1 * t, 1 * s, 1 * t)
glTexture(false)
end
local function mglRenderToTexture(FBOTex, tex, s, t)
glRenderToTexture(FBOTex, renderToTextureFunc, tex, s, t)
end
local beamLights = {}
local beamLightCount = 0
local pointLights = {}
local pointLightCount = 0
function widget:Update()
beamLights = {}
beamLightCount = 0
pointLights = {}
pointLightCount = 0
for i = 1, collectionFunctionCount do
if collectionFunctions[i] then
beamLights, beamLightCount, pointLights, pointLightCount = collectionFunctions[i](beamLights, beamLightCount, pointLights, pointLightCount)
end
end
end
-- adding a glow to Cannon projectiles
--[[
function widget:DrawWorld()
local lights = pointLights
glBlending(GL.SRC_ALPHA, GL.ONE)
gl.Texture(glowImg)
local size = 1
for i = 1, pointLightCount do
local light = lights[i]
local param = light.param
if param.gib == nil and param.type == "Cannon" then
size = param.glowradius * 0.44
gl.PushMatrix()
local colorMultiplier = 1 / math_max(param.r, param.g, param.b)
gl.Color(param.r*colorMultiplier, param.g*colorMultiplier, param.b*colorMultiplier, 0.015 + (size/4000))
gl.Translate(light.px, light.py, light.pz)
gl.Billboard(true)
gl.TexRect(-(size/2), -(size/2), (size/2), (size/2))
gl.PopMatrix()
end
end
gl.Billboard(false)
gl.Texture(false)
glBlending(GL.SRC_ALPHA, GL.ONE_MINUS_SRC_ALPHA)
end
]]--
local GL_KEEP = 0x1E00
local GL_ZERO = 0x0000
local GL_INCR = 0x1E02
local GL_INCR_WRAP = 0x8507
local GL_DECR_WRAP = 0x8508
local function LightVolumePass1()
gl.StencilTest(true)
gl.Culling(GL.BACK)
gl.ColorMask(false, false, false, false)
gl.DepthTest(GL.LEQUAL)
gl.StencilOp(GL_ZERO, GL_INCR, GL_ZERO)
gl.StencilFunc(GL.ALWAYS, 0, 0xFF)
if dlPoint then
--lightShader:SetUniformIntAlways("lightType", 0)
gl.CallList(dlPoint)
end
if dlBeam then
--lightShader:SetUniformIntAlways("lightType", 1)
gl.CallList(dlBeam)
end
if dlCone then
--lightShader:SetUniformIntAlways("lightType", 2)
gl.CallList(dlCone)
end
if LightDL then
--lightShader:SetUniformIntAlways("lightType", 2)
gl.CallList(LightDL)
end
end
local function LightVolumePass2()
gl.Culling(GL.FRONT)
gl.ColorMask(true, true, true, true)
gl.DepthTest(GL.GEQUAL)
gl.StencilOp(GL_ZERO, GL_ZERO, GL_ZERO)
gl.StencilFunc(GL.EQUAL, 0, 0xFF)
glBlending(GL.SRC_ALPHA, GL.ONE)
glTexture(0, "$model_gbuffer_normtex")
glTexture(1, "$model_gbuffer_zvaltex")
glTexture(2, "$map_gbuffer_normtex")
glTexture(3, "$map_gbuffer_zvaltex")
glTexture(4, "$model_gbuffer_spectex")
if dlPoint then
--lightShader:SetUniformIntAlways("lightType", 0)
gl.CallList(dlPoint)
end
if dlBeam then
--lightShader:SetUniformIntAlways("lightType", 1)
gl.CallList(dlBeam)
end
if dlCone then
--lightShader:SetUniformIntAlways("lightType", 2)
gl.CallList(dlCone)
end
if LightDL then
--lightShader:SetUniformIntAlways("lightType", 2)
gl.CallList(LightDL)
end
--Spring.Echo("Drawing",dlPoint,dlBeam,dlCone,LightDL)
--cleanup
gl.StencilTest(false)
gl.DepthTest(GL.LEQUAL)
gl.Culling(false)
glTexture(0, false)
glTexture(1, false)
glTexture(2, false)
glTexture(3, false)
glTexture(4, false)
glBlending(GL.SRC_ALPHA, GL.ONE_MINUS_SRC_ALPHA)
end
function widget:DrawWorld()
lightShader:ActivateWith( function ()
lightShader:SetUniformMatrix("viewMat", "camera")
lightShader:SetUniformMatrix("projMat", "projection")
lightShader:SetUniformMatrix("viewProjectionInv","viewprojectioninverse") -- TODO GET THE FUCKING INVERSE OF THIS SHIT!
local cpx, cpy, cpz = spGetCameraPosition()
lightShader:SetUniformAlways("eyePos", cpx, cpy, cpz)
--LightVolumePass1()
LightVolumePass2()
--LightVolumePassSimple()
--LightVolumePassDebug()
--LightVolumePass1B()
--LightVolumePass2B()
end)
end
function widget:DrawScreenEffects()
if not (GLSLRenderer) then
Spring.Echo('Removing deferred rendering widget: failed to use GLSL shader')
widgetHandler:RemoveWidget(self)
return
end
drawarea = 0
--glBlending(GL.DST_COLOR, GL.ONE) -- Set add blending mode
glBlending(GL.SRC_ALPHA, GL.ONE)
if beamLightCount > 0 then
--DrawLightType(beamLights, beamLightCount, 1)
end
--glBlending(GL.ONE_MINUS_SRC_COLOR, GL.ONE)
if pointLightCount > 0 then
--DrawLightType(pointLights, pointLightCount, 0)
end
if drawarea> 0.01 then
Spring.Echo(string.format("Total Draw Area for dynamic lights = %.3f, beams=%d, points=%d, cones=%d",drawarea,beamLightCount,pointLightCount,0))
end
drawarea = 0
glBlending(GL.SRC_ALPHA, GL.ONE_MINUS_SRC_ALPHA)
end
function widget:Update()
CreateLightDisplayList()
end
function CreateLightDisplayList()
if not (GLSLRenderer) then
Spring.Echo('Removing deferred rendering widget: failed to use GLSL shader')
widgetHandler:RemoveWidget(self)
return
end
if LightDL then
glDeleteList(LightDL)
LightDL = nil
end
local allLights = pointLights
local allLightsCount = pointLightCount
for i = 1, beamLightCount do
allLights[i+allLightsCount] = beamLights[i]
allLightsCount = allLightsCount + 1
end
for i = 1, beamLightCount do
allLights[i+allLightsCount] = beamLights[i]
allLightsCount = allLightsCount + 1
end
LightDL = glCreateList( function()
gl.BeginEnd(GL.POINTS, function()
local light_index = 0
--gl.Color(0, -1, 1, 1) -- R, G, B, fallofffactor
--gl.MultiTexCoord(i, 2738, 140, 4519, 32)
--for point lights this is ==0
--for beam lights: pos2.xyz, >-1
--for cone lights its: dir.xyz, angle
--gl.Vertex(2556, 140, 4753, 40) -- index of point, lightpos.xyz, light radius
for i = 1, allLightsCount do
local light = allLights[i]
local param = light.param
local falloffsquared = param.falloffsquared or 1.0
gl.Color(
param.r * light.colMult,
param.g * light.colMult,
param.b * light.colMult,
falloffsquared)
if light.beam then
gl.MultiTexCoord(light_index,light.dx,light.dy, light.dz, -2.0)
elseif light.cone then
gl.MultiTexCoord(light_index,light.dx,light.dy, light.dz, 0.3)
else
gl.MultiTexCoord(light_index,0,0,0,0)
end
light_index = light_index + 1
gl.Vertex(light.px, light.py, light.pz, param.radius)
end
end )
end )
end
---TODO: 2020 september 17
-- 1. fix light collection functions, do not separate beams
-- 2. Decide wether to drawworld or drawscreeneffects
-- 3. Decide wether all particles should contribute - is dlist creation worse than gl.vertex?
-- 4. build up dlist of all lights
-- 5. readd glow to cannon projectiles
-- 6. pass eyepos and projMatinv to fragment shader
-- 7. check light radii for sanity
-- a. luaify attenuate function for worst case
-- 8. premultiply light intensity with light color
-- 9. pass linear falloff to fragment shader
-- 10. add a function to each lightdef, that runs per sim frame
-- a. should allow removal of self
-- b. can a function operate on the table that it was included in?
-- 11. prevent flickering lights from non-sim flickering
-- 12. what is clip control and do we need it?
---TODO: 2020 september 17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment