Cg Tutorial Part 12

Don't mind the mess!

We're currently in the process of migrating the Panda3D Manual to a new service. This is a temporary layout in the meantime.

Top
Python C++

This page is not in the table of contents.

Cg Tutorial Part 12: Per pixel lighting with multiple point lights and attenuation

#Lesson 12
 
"""
Instead of only one light, we added here two another lights.
"""

 
import sys
import math
 
import direct.directbase.DirectStart
from direct.interval.LerpInterval import LerpFunc
from panda3d.core import PointLight
 
base.setBackgroundColor(0.0, 0.0, 0.2)
base.disableMouse()
 
base.camLens.setNearFar(1.0, 50.0)
base.camLens.setFov(45.0)
 
camera.setPos(0.0, -20.0, 10.0)
camera.lookAt(0.0, 0.0, 0.0)
 
root = render.attachNewNode("Root")
 
lights = []
 
for i in range(3):
light = render.attachNewNode("Light")
modelLight = loader.loadModel("misc/Pointlight.egg.pz")
modelLight.reparentTo(light)
lights += [ light ]
 
modelCube = loader.loadModel("cube.egg")
 
cubes = []
for x in [-3.0, 0.0, 3.0]:
cube = modelCube.copyTo(root)
cube.setPos(x, 0.0, 0.0)
cubes += [ cube ]
 
shader = loader.loadShader("lesson12.sha")
for cube in cubes:
cube.setShader(shader)
for i in range(len(lights)):
cube.setShaderInput("light" + str(i), lights[i])
 
base.accept("escape", sys.exit)
base.accept("o", base.oobe)
 
def animate(t):
radius = 4.3
angle = math.radians(t)
x = math.cos(angle) * radius
y = math.sin(angle) * radius
z = math.sin(angle) * radius
lights[0].setPos(x, y, z)
lights[1].setPos(y, x, 0.0)
lights[2].setPos(z, 0.0, x)
 
def intervalStartPauseResume(i):
if i.isStopped():
i.start()
elif i.isPaused():
i.resume()
else:
i.pause()
 
interval = LerpFunc(animate, 10.0, 0.0, 360.0)
 
base.accept("i", intervalStartPauseResume, [interval])
 
def move(x, y, z):
root.setX(root.getX() + x)
root.setY(root.getY() + y)
root.setZ(root.getZ() + z)
 
base.accept("d", move, [1.0, 0.0, 0.0])
base.accept("a", move, [-1.0, 0.0, 0.0])
base.accept("w", move, [0.0, 1.0, 0.0])
base.accept("s", move, [0.0, -1.0, 0.0])
base.accept("e", move, [0.0, 0.0, 1.0])
base.accept("q", move, [0.0, 0.0, -1.0])
 
run()
//Cg
/* lesson12.sha */

/*
Cg does not offers lot of high level constructs like classes in C++. It is more
like C. Functions are therefore possible, and are used in this example.
*/

/*
Like in the previous shader we do all our work in the pixel shader, therefore we
do not have to add anything to our vertex shader.
*/
void vshader(
    uniform float4x4 mat_modelproj,
    in float4 vtx_position : POSITION,
    in float3 vtx_normal : NORMAL,
    in float4 vtx_color : COLOR,
    out float4 l_color : COLOR,
    out float3 l_myposition : TEXCOORD0,
    out float3 l_mynormal : TEXCOORD1,
    out float4 l_position : POSITION)
{
    l_position = mul(mat_modelproj, vtx_position);

    l_myposition = vtx_position.xyz;
    l_mynormal = normalize(vtx_normal);

    l_color = vtx_color;
}

float lit(float3 lightposition, float3 modelposition, float3 normal)
{
    float3 direction = lightposition - modelposition;
    float distance = length(direction);
    float diffuse = saturate(dot(normalize(normal), normalize(direction)));
    /*
    Normally you would define the following constants in Python source and pass
    them this shader. We are a bit lazy here and hard code them in this
    function.
    */
    float a = 0.0;
    float b = 0.0;
    float c = 1.0;
    /*
    DIRTY
    If you like to achieve the same results as the fixed function pipeline you
    should add a saturate here. But I think, that it looks quite nice, if you
    get extremely bright spots when a light source is near a face, even is the
    face is dark.
    */
    float attenuation = 1.0 / (a + b * distance + c * distance * distance);
    return attenuation * diffuse;
}

/*
Because we have extended the lighting equations in a separate function, the
fragment shader looks clean. It would be simple to add more lights. The only
limits here is that every GPU only supports a limited number of uniforms and
shader instructions. So you maybe cannot add hundreds of lights, besides that it
takes an endless amount of time to do per pixel lighting with hundred lights.
*/
void fshader(
    uniform float4 mspos_light0,
    uniform float4 mspos_light1,
    uniform float4 mspos_light2,
    in float3 l_myposition : TEXCOORD0,
    in float3 l_mynormal : TEXCOORD1,
    in float4 l_color : COLOR,
    out float4 o_color : COLOR)
{
    float brightness = 0.0;

    brightness += lit(mspos_light0.xyz, l_myposition, l_mynormal);
    brightness += lit(mspos_light1.xyz, l_myposition, l_mynormal);
    brightness += lit(mspos_light2.xyz, l_myposition, l_mynormal);

    o_color = l_color * brightness;
}

Top