–
Deferred shading & Fancy effects
VIDEO :
http://youtu.be/4nEV3nK7INs
[color=green]WORKING
- deferred shading : point and directional lights in view space, phong equation, bounding volumes for lights,
- doesn’t rely on autoshader,
- custom g-buffers shader for normal maps,
- FXAA : Fast Approximate Anti-Aliasing,
- depth of field bokeh : one-pass effect based on Martins Upitis code,
- bleach bypass : b&w merged with color to enhance contrasts and desaturate colors,
- bloom,
- vignetting.
[color=darkblue]TODO
- material specular information written in g-buffer,
- linear depth buffer,
- try other light models,
- working shadows,
- sprite-based bokeh dof,
- fxaa last version,
- anamorphic lens flare,
- transparency,
- HDR tonemaping,
- speed.
[color=red]PROBLEMS
- projection of shadows in the light bounding volumes
- change texture format
CODE INCOMING !
–
Hello all,
here a simple deferred shading system, only point lights atm, more to come.
You need panda buildbot version.
The panda app :
#####################################################
## DEFERRED LIGHTING - POINT LIGHT IN VIEW SPACE ##
#####################################################
### Imports ###
from panda3d.core import *
loadPrcFileData('', 'show-buffers 0')
from direct.showbase.ShowBase import ShowBase
from panda3d.egg import *
from direct.filter.FilterManager import *
from pandac.PandaModules import Vec3
from math import pi,sin,cos
import random
### Class constants ###
LIGHTS_NUMBER = 15
### Class Application ###
class Application(ShowBase):
### Constructor ###
def __init__(self):
ShowBase.__init__(self)
self.setup_scene()
taskMgr.add(self.update,"update")
#disable mouse#
base.disableMouse()
### Function setup ###
def setup_scene(self):
### Camera setup ###
self.light_cam = self.makeCamera(self.win)
self.light_cam.reparentTo(self.cam)
scene_mask = BitMask32(1)
light_mask = BitMask32(2)
self.cam.node().setCameraMask(scene_mask)
self.light_cam.node().setCameraMask(light_mask)
base.camera.setPos(0,-200,115)
self.camera.setP(-30)
self.cam.node().getDisplayRegion(0).setSort(1)
self.light_cam.node().getDisplayRegion(0).setSort(2)
self.win.setSort(3)
self.light_cam.node().getDisplayRegion(0).setClearColor(Vec4(.0, .0, .0, 1))
self.light_cam.node().getDisplayRegion(0).setClearColorActive(1)
### Scene creation ###
self.scene = render.attachNewNode("scene")
self.scene.hide(light_mask)
self.scene.setShaderAuto()
#create spheres
for i in range(10):
angleDegrees = i * 36
angleRadians = angleDegrees * (pi / 180.0)
sphere = loader.loadModel("test")
sphere.setPos( sin(angleRadians)*40,cos(angleRadians)*40,0)
sphere.setScale(10)
sphere.reparentTo(self.scene)
sphere.setAttrib(ShadeModelAttrib.make(ShadeModelAttrib.MSmooth))
#create floor
cm = CardMaker("floor")
cm.setFrame(-100, 100, -100, 100)
plane = render.attachNewNode(cm.generate())
plane.setP(270)
plane.setZ(-10)
plane.reparentTo(self.scene)
self.lights = []
self.bulbs = []
self.abs = []
self.ords = []
### Buffers creation ###
self.gbuffer_man = FilterManager(self.win, self.cam)
depth = Texture()
albedo = Texture()
normal = Texture()
self.gbuffer_man.renderSceneInto(colortex = albedo, depthtex = depth, auxtex = normal,auxbits = AuxBitplaneAttrib.ABOAuxNormal)
### Lights creation ###
for i in range(LIGHTS_NUMBER):
#light geometry
light = loader.loadModel("misc/sphere")
light.setPos(random.uniform(-40,40),random.uniform(-40,40),random.uniform(0,15))
light.setColor(random.uniform(0,1),random.uniform(0,1),random.uniform(0,1))
light.setScale(100)
light.reparentTo(render)
light.setAttrib(DepthTestAttrib.make(RenderAttrib.MLess))
light.setAttrib(CullFaceAttrib.make(CullFaceAttrib.MCullClockwise))
#self.light.setAttrib(CullFaceAttrib.make(CullFaceAttrib.MCullCounterClockwise)
light.setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.MAdd, ColorBlendAttrib.OOne, ColorBlendAttrib.OOne))
light.setAttrib(DepthWriteAttrib.make(DepthWriteAttrib.MOff))
#light shader
light.setShader(loader.loadShader("def_light.cg"))
light.setShaderInput("albedo", albedo)
light.setShaderInput("depth", depth)
light.setShaderInput("normal", normal)
light.setShaderInput("Kd", Vec3(1,1,1))
light.setShaderInput("Ks",Vec3(.8,.8,.8))
light.setShaderInput("att_params",Vec3(0.1,0.2,0.003))
light.setShaderInput("light_radius", light.getScale())
light.setShaderInput("camera",base.camera)
self.abs.append(light.getX())
self.ords.append(light.getY())
bulb = loader.loadModel("sphere")
bulb.reparentTo(render)
bulb.setPos(light.getPos())
bulb.setColorScale(light.getColor())
bulb.hide(light_mask)
light.hide(scene_mask)
self.bulbs.append(bulb)
self.lights.append(light)
### Update per frame ###
def update(self,task):
for i in range(LIGHTS_NUMBER):
self.lights[i].setZ(self.lights[i].getZ()+ sin(task.time)/20)
self.bulbs[i].setZ(self.bulbs[i].getZ()+ sin(task.time)/20)
angleDegrees = task.time * 6.0
angleRadians = angleDegrees * (pi / 180.0)
self.lights[i].setPos(self.abs[i] * sin(angleRadians), self.ords[i] * cos(angleRadians), 3)
self.bulbs[i].setPos(self.abs[i] * sin(angleRadians), self.ords[i] * cos(angleRadians), 3)
return task.cont
application = Application()
application.run()
The point light shader :
//Cg
void vshader(
float4 vtx_position : POSITION,
out float4 l_position : POSITION,
out float4 l_pos : TEXCOORD0,
uniform float4x4 mat_modelproj)
{
l_position = mul(mat_modelproj, vtx_position);
l_pos = l_position;
}
void fshader(
float4 l_position : TEXCOORD0,
float4 l_normal : TEXCOORD1,
uniform sampler2D k_albedo : TEXUNIT0, // color map
uniform sampler2D k_depth : TEXUNIT1, // depth map
uniform sampler2D k_normal : TEXUNIT2, // normal map
uniform float4 texpad_albedo,
uniform float4 texpad_normal,
uniform float4 texpad_depth,
uniform float4 attr_color,
uniform float3 att_params, // attenuation parameters
uniform float3 light_radius,
uniform float4 vspos_camera, // position of camera in view space
uniform float3 Kd, // diffuse coef.
uniform float3 Ks, // specular coef.
uniform float4 vspos_model, // position of model in view space
uniform float4x4 trans_clip_to_view,
out float4 o_color0 : COLOR0)
{
////////////////////////////////////////////
// DEFERRED POINT LIGHT IN VIEW SPACE //
////////////////////////////////////////////
// fragment position in clip space
l_position.xy /= l_position.w;
// textures input
float2 texcoords = float2(l_position.xy) * texpad_normal.xy + texpad_normal.xy;
float4 albedo = tex2D(k_albedo, texcoords);
float4 normal = tex2D(k_normal, texcoords);
float4 depth = tex2D(k_depth, texcoords);
// point illuminated
float4 P;
P.xy = l_position.xy;
P.z = depth;
P.w = 1;
P = mul(trans_clip_to_view, P);
P /= P.w*2;
// normal
float3 N;
N = normal;
N.xyz = N.xyz - float3(0.5,0.5,0.5);
N.xyz = 2 * N.xyz;
N = normalize(N);
// light vector
float3 L = (vspos_model - P);
// ray length
float l = length(L);
// light attenuation
float constant_att = att_params.x;
float linear_att = att_params.y;
float quadra_att = att_params.z;
float attenuation = 1.0f / (constant_att + linear_att*l + quadra_att*l*l);
// normalize light vector
L = normalize(L);
// compute diffuse light
float diffuseLight = max(dot(L, N),0);
float3 diffuse = diffuseLight * albedo * attr_color;
// compute specular term
float3 V = normalize(vspos_camera - P);
float3 H = normalize(L + V);
float specularLight = pow(max(dot(N, H), 0), 180);
if (diffuseLight <= 0) specularLight = 0;
float3 specular = Ks * attr_color * specularLight* albedo;
// output
o_color0.xyz = attenuation * diffuse + specular ;
o_color0.w = 1;
}
Feel free to discuss, there may be errors or bad comments.