Learning to use buffers/deferred rendering

Thanks to Craig in the IRC room last light I discovered I need to use buffers/deferred rendering for my latest attempt at an atmosphere scattering shader (suddenly all this talk of multiple rendering passes make sense!). I’ve gone over the firefly, advanced glow, and distortion samples, but I still am getting

error C5102: output semantic attribute "COLOR" has too big of a numeric index (2)

for my COLOR2 line. Any advice/tips/link would be most welcome.

Code

from pandac.PandaModules import loadPrcFileData

loadPrcFileData( '', 'frame-rate-meter-scale 0.035' )
loadPrcFileData( '', 'frame-rate-meter-side-margin 0.1' )
loadPrcFileData( '', 'show-frame-rate-meter 1' )
loadPrcFileData( '', 'window-title Atmosphere Demo' )
loadPrcFileData('', "sync-video 0")
loadPrcFileData('', "basic-shaders-only #f")

from direct.directbase.DirectStart import *

from direct.showbase.DirectObject import DirectObject 
from panda3d.core import FrameBufferProperties, WindowProperties, BitMask32
from panda3d.core import GraphicsPipe,GraphicsOutput
from panda3d.core import Shader, Vec3, Vec4
from panda3d.core import Texture, TextureStage,  TexGenAttrib
# Import light!
from panda3d.core import PointLight
import math

light = render.attachNewNode( PointLight( "sunPointLight" ) )
light.setPos(10000,0,0)
render.setLight( light )

earth = loader.loadModel("planet_sphere")
earth.reparentTo(render)

atmo = loader.loadModel("atmo")
atmo.reparentTo(earth)
atmo.setScale(-1.025)

outerRadius = abs((earth.getScale().getX() * atmo.getScale().getX()))
scale = 1/(outerRadius - earth.getScale().getX())
atmo.setShaderInput("fOuterRadius", outerRadius)
atmo.setShaderInput("fInnerRadius", earth.getScale().getX())
atmo.setShaderInput("fOuterRadius2", outerRadius * outerRadius)
atmo.setShaderInput("fInnerRadius2", earth.getScale().getX() * earth.getScale().getX())

atmo.setShaderInput("fKr4PI", 0.0025 * 4 * 3.14159)
atmo.setShaderInput("fKm4PI", 0.0015 * 4 * 3.14159)

atmo.setShaderInput("fScale", scale)
atmo.setShaderInput("fScaleDepth", 0.25)
atmo.setShaderInput("fScaleOverScaleDepth", scale/0.5)

atmo.setShaderInput("fSamples", 2.0)
atmo.setShaderInput("nSamples", 2)

# These do sunsets and sky colors
ESun = 15.0
atmo.setShaderInput("fKrESun", 0.0025 * ESun)
atmo.setShaderInput("fKmESun", 0.0015 * ESun)
# Color of sun
atmo.setShaderInput("v3InvWavelength", 1.0 / math.pow(0.650, 4), 
                                  1.0 / math.pow(0.570, 4), 
                                  1.0 / math.pow(0.475, 4))
                                  
atmo.setShaderInput("v3CameraPos", base.camera.getPos().getX(),
        base.camera.getPos().getY(), 
        base.camera.getPos().getZ())
lightv = light.getPos()
atmo.setShaderInput("v3LightDir", lightv.getX()*-1, 
        lightv.getY()*-1, 
        lightv.getZ()*-1)
atmo.setShaderInput("v3LightPos", light.getPos().getX(), 
        light.getPos().getY(), 
        light.getPos().getZ())
        
atmo.setShaderInput("fCameraHeight", base.camera.getPos().length())
atmo.setShaderInput("fCameraHeight2", base.camera.getPos().length()*2)

atmoShader = Shader.load("shader5.cg")
atmo.setShader(atmoShader)

from direct.task import Task
 
# This task runs for two seconds, then prints done
def exampleTask(task):
    atmo.setShaderInput("v3CameraPos", base.camera.getPos().getX(),
        base.camera.getPos().getY(), 
        base.camera.getPos().getZ())
    atmo.setShaderInput("fCameraHeight", base.camera.getPos().length())
    atmo.setShaderInput("fCameraHeight2", base.camera.getPos().length()*2)
    return task.cont

taskMgr.add(exampleTask, 'MyTaskName')
run()

And the shader (which I know will need further fixing to make it work with panda)

//Cg
// http://stainlessbeer.weebly.com/planets-9-atmospheric-scattering.html
#include "Common.cg"
float g =-0.90f;
float g2 = 0.81f;
float fExposure =2;
 
float scale(float fCos, float4 fScaleDepth)
{
    float x = 1.0 - fCos;  
    return fScaleDepth.x * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
}
 
void vshader(float4 vtx_position:POSITION,
    uniform float4 k_v3LightPos,          // The light's current position
    in uniform float4 k_v3CameraPos,         // The camera's current position
    in uniform float4 k_v3LightDir,          // Direction vector to the light source
    in uniform float4 k_v3InvWavelength,     // 1 / pow(wavelength, 4) for RGB
    in uniform float4 k_fCameraHeight,        // The camera's current height
    in uniform float4 k_fCameraHeight2,       // fCameraHeight^2
    in uniform float4 k_fOuterRadius,         // The outer (atmosphere) radius
    in uniform float4 k_fOuterRadius2,        // fOuterRadius^2
    in uniform float4 k_fInnerRadius,         // The inner (planetary) radius
    in uniform float4 k_fInnerRadius2,        // fInnerRadius^2
    in uniform float4 k_fKrESun,              // Kr * ESun
    in uniform float4 k_fKmESun,              // Km * ESun
    in uniform float4 k_fKr4PI,               // Kr * 4 * PI
    in uniform float4 k_fKm4PI,               // Km * 4 * PI
    in uniform float4 k_fScale,               // 1 / (fOuterRadius - fInnerRadius)
    in uniform float4 k_fScaleOverScaleDepth, // fScale / fScaleDepth
    in uniform float4 k_fScaleDepth,          // The scale depth (i.e. the altitude at which the atmosphere's average density is found)
    in uniform float4 k_fSamples,
    in uniform float4 k_nSamples,
    uniform float4x4 mat_modelproj,
    out float4 l_position : POSITION,
    out float4 l_color0   : COLOR0,
    out float4 l_color1   : COLOR1,
    out float3 l_v3Direction: TEXCOORD0 )
{
    float3 v3Pos = vtx_position.xyz;
    float3 v3Ray = v3Pos - k_v3CameraPos.xyz;
    float fFar = length(v3Ray);
 
    v3Ray /= fFar;
 
    // Calculate the closest intersection of the ray with the outer atmosphere 
    // (which is the near point of the ray passing through the atmosphere)
    
    float B = 2.0 * dot(k_v3CameraPos.xyz, v3Ray);
    float C = k_fCameraHeight2.x - k_fOuterRadius2.x;
    float fDet = max(0.0, B*B - 4.0 * C);
    float fNear = 0.5 * (-B - sqrt(fDet));
     
    // Calculate the ray's start and end positions in the atmosphere,
    // then calculate its scattering offset
 
    float3 v3Start = k_v3CameraPos.xyz + v3Ray * fNear;
    fFar -= fNear;
 
    // Initialize the scattering loop variables
    float fSampleLength = fFar / k_fSamples.x;
    float fScaledLength = fSampleLength * k_fScale.x;
    float3 v3SampleRay = v3Ray * fSampleLength;
    float3 v3SamplePoint = v3Start + (v3SampleRay * 0.5);
    
    float fHeight = length(v3SamplePoint);
    float fStartAngle = dot(v3Ray, v3Start) / k_fOuterRadius.x;
    float fStartDepth = exp(-1.0 / k_fScaleDepth.x);
    float fStartOffset = fStartDepth * scale(fStartAngle, k_fScaleDepth);
    
    // Now loop through the sample points
 
    float3 v3FrontColor = float3(0.0, 0.0, 0.0);
    //for(float i=0; i<k_fSamples.x; i++)
    for(int i=0; i<2; i++)  
    {
        float fHeight = length(v3SamplePoint);
        float fDepth = exp(k_fScaleOverScaleDepth.x * (k_fInnerRadius.x-fHeight.x));
        float fLightAngle = dot(k_v3LightPos.xyz, v3SamplePoint) / fHeight;
        float fCameraAngle = dot(v3Ray, v3SamplePoint) / fHeight;
        float fScatter = (fStartOffset + fDepth * (scale(fLightAngle, k_fScaleDepth) - scale(fCameraAngle, k_fScaleDepth)));
        float3 v3Attenuate = exp(-fScatter *(k_v3InvWavelength.xyz * k_fKr4PI.x + k_fKm4PI.x));
        v3FrontColor += v3Attenuate * (fDepth * fScaledLength);
        v3SamplePoint += v3SampleRay;
    }
    l_color1.rgb=v3FrontColor*k_fKmESun.x;
    
    l_color0.rgb = v3FrontColor.xyz * k_v3InvWavelength.xyz * k_fKrESun.x;
 
    l_position=mul(mat_modelproj, vtx_position);
    
    l_v3Direction =k_v3CameraPos.xyz - v3Pos;
}
 
void fshader(in float4 l_position : POSITION,
    in float4 l_color0   : COLOR0,
    in float4 l_color1   : COLOR1,
    in float3 l_v3Direction : TEXCOORD0 ,
 
    uniform float4 k_v3LightPos,
    out float4 o_color:COLOR)
{
 
    float fCos = dot(k_v3LightPos, l_v3Direction) / length(l_v3Direction);
    float fRayleighPhase = 0.75 * (1.0 + fCos*fCos);
    float fMiePhase= 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos*fCos) / pow(1.0 + g2 - 2.0*g*fCos, 1.5);
    float4 col=(fRayleighPhase * l_color0) + (fMiePhase * l_color1);
    col.a=col.b;
    o_color = 1 - exp(-fExposure * col);
}   

Panda3D doesn’t support CgFX shaders at the moment. We will likely support CgFX shaders in Panda 2.0.

I think I converted the shader to cg (updated in op), but now I am back to my original problem: error C5102: output semantic attribute “COLOR” has too big of a numeric index (2) and stumped how to proceed.

Try using a different semantic, instead of COLOR#, for passing data between the vertex and fragment shader.

Had I looked at the origional cg shaders I would of noticed to do that!

Well, I made it a little further than I ever have before, although there is a long way to go to get this perdy!

Uploaded with ImageShack.us