God Rays Effect

Tweet blitzmax glsl shaders code-archives
(Posted 2 years ago) RonTek

Port of Max3D's God Rays shader to OpenB3DMax

example code is wip. haaaaaaah..

BlitzMax Blitz3D God Rays Shader Light Scattering



uniform sampler2D colortex;
uniform sampler2D depthtex;

vec3 GodRaysColor = vec3(1.0, 1.0, 0.0);
uniform float GodRaysExposure;
uniform float GodRaysLightX;
uniform float GodRaysLightY;

const int NUM_SAMPLES = 100;

void main() {

  vec2 textCoo = gl_TexCoord[0].xy;
  vec2 lightPos = vec2(GodRaysLightX, GodRaysLightY);
  vec2 deltaTextCoord = (textCoo - lightPos) / float(NUM_SAMPLES);

  vec3 color = vec3(0.0);

  for (int i = 0; i < NUM_SAMPLES; i++) {
    textCoo -= deltaTextCoord;
    color += GodRaysColor * floor(texture2D(depthtex, textCoo).r);

  gl_FragColor = texture2D(colortex, gl_TexCoord[0].xy) + vec4(color / float(NUM_SAMPLES) * GodRaysExposure, 0.0);



' godrays.bmx
' postprocess effect - Light Scattering / God Rays


Framework Openb3dMax.B3dglgraphics
Import Brl.Random
?Not bmxng
Import Brl.Timer
Import Brl.TimerDefault

'Local width%=DesktopWidth(),height%=DesktopHeight()

Local width%=800,height%=600

Graphics3D width, height,0,2

SeedRnd MilliSecs()
ClearTextureFilters ' remove mipmap flag for postfx texture

Global camera:TCamera=CreateCamera()
CameraRange camera,0.5,1000.0 ' near must be closer than screen sprite to prevent clipping
CameraClsColor camera,64,128,255

Global postfx_cam:TCamera=CreateCamera() ' copy main camera
CameraRange postfx_cam,0.5,2000.0
CameraClsColor postfx_cam,64,128,255

HideEntity postfx_cam

AmbientLight 128,128,128

Local Light:TLight=CreateLight()
'Local lightYaw#=0,lightPitch#=0,lightRoll#
'TurnEntity Light,lightYaw,lightPitch,lightRoll
'PositionEntity Light,100,60,100
Local lightYaw#=45,lightPitch#=45,lightRoll#
TurnEntity Light,lightPitch,lightYaw,lightRoll
'PointEntity Light,Camera

Local brush:TBrush=CreateBrush()

Local lsprite:TSprite=CreateSprite()
EntityColor lsprite,255,255,255
'ScaleSprite lsprite,TParticleFunc.scalex,TParticleFunc.scaley
Local noisetex:TTexture=LoadTexture("../media/sunblue.tga",2)

'MoveEntity lsprite,-.5,-.5,0
EntityTexture lsprite,noisetex
'EntityFX lsprite,1+4+8+16
'UpdateNormals lsprite
EntityOrder lsprite,1

Local hx:Int=2.5,hy:Int=-2

HandleSprite lsprite,hx,hy


Local efx%=1,eblend%=2,etexenv%=2,multitexfactor#=0.5,ealpha#=1

'Local size:Int=256, vsize:Float=30, maxheight:Float=10
'Local terrain:TTerrain=LoadTerrain("../media/heightmap_256.BMP") ' path case-sensitive on Linux
'ScaleEntity terrain,1,(1*maxheight)/vsize,1 ' set height
'terrain.UpdateNormals() ' correct lighting

'PositionEntity terrain,-size/2,-10,size/2

Local terrain:TMesh=CreateCube()
ScaleEntity terrain,2000,1,2000
'MoveEntity terrain,0,-.5,0

' Texture terrain
Local grass_tex:TTexture=LoadTexture( "../media/terrain-1.jpg" )
EntityTexture terrain,grass_tex
ScaleTexture grass_tex,.01,.01

Local pivot:TPivot=CreatePivot()
PositionEntity pivot,0,0,0
Local anim_time:Float
Local anim_ent:TMesh=LoadAnimMesh("../media/zombie.b3d",pivot)
PositionEntity anim_ent,0,0,12
TurnEntity anim_ent,0,-90,0

Local cube:TMesh=LoadMesh("../media/castle1.b3d")
'ScaleMesh cube,4,2,4
PositionEntity cube,0,-5,0
ScaleEntity cube,.5,.5,.5
'Local cube_tex:TTexture=LoadTexture("../media/crate.bmp",1)
'EntityTexture cube,cube_tex
'TurnEntity cube,0,0,0

Global colortex:TTexture=CreateTexture(width,height,1+256)
ScaleTexture colortex,1.0,-1.0

Global depthtex:TTexture=CreateTexture(width,height,1+256)
ScaleTexture depthtex,1.0,-1.0

' in GL 2.0 render textures need attached before other textures (EntityTexture)
CameraToTex colortex,camera
DepthBufferToTex depthtex,camera
TGlobal.CheckFramebufferStatus(GL_FRAMEBUFFER_EXT) ' check for framebuffer errors

' screen sprite - by BlitzSupport
Global screensprite:TSprite=CreateSprite()
EntityOrder screensprite,-1
ScaleSprite screensprite,1.0,Float( GraphicsHeight() ) / GraphicsWidth() ' 0.75
MoveEntity screensprite,0,0,0.99 ' set z to 0.99 - instead of clamping uvs
EntityParent screensprite,camera

Global screensprite2:TSprite=CreateSprite()
ScaleSprite screensprite2,1.0,Float( GraphicsHeight() ) / GraphicsWidth() ' 0.75
EntityOrder screensprite2,-1
EntityParent screensprite2,camera
MoveEntity screensprite2,0,0,1.0 ' set z to 1.0
EntityTexture screensprite2,depthtex

PositionEntity camera,0,7,0 ' move camera now sprite is parented to it
MoveEntity camera,0,0,-25

Local shader:TShader=LoadShader("","../glsl/default.vert.glsl", "../glsl/godrays.frag.glsl")

Local GRExp:Float
Local GRLightX:Float
Local GRLightY:Float

ShaderTexture(shader,colortex,"colortex",0) ' Our render texture
ShaderTexture(shader,depthtex,"depthtex",1) ' 1 is depth texture

Local px#,py#

UseFloat(shader,"GodRaysExposure", GRExp)
UseFloat(shader,"GodRaysLightX", GRLightX)
UseFloat(shader,"GodRaysLightY", GRLightY)
ShadeEntity(screensprite, shader)

';ScaleTexture colortex,1.0,1.0

Global postprocess%=1
Local time#=0, framerate#=60.0, animspeed#=10
Local timer:TTimer=CreateTimer(framerate)
UseFloat(shader,"time",time) ' Time used to scroll the distortion map

' fps code
Local old_ms%=MilliSecs()
Local renders%, fps%

Local update% = 1

Local CamProj:String = "NO"

'HideEntity terrain;HideEntity cube

Local spx% = 0,spy% = 0,spz% = 5
Local grx# = 0.0, gry# = 0.0

'HideEntity lsprite

'PointEntity Light,camera


While Not KeyHit(KEY_ESCAPE)

    ' FX blending, alpha / nothing
    If KeyHit(KEY_N)
        efx=Not efx
        If efx

    'If KeyHit(KEY_TAB) Then toggle = Not toggle

    time=Float((TimerTicks(timer) / framerate) * animspeed)

    If KeyDown(KEY_MINUS) Then anim_time#=anim_time#-0.1
    If KeyDown(KEY_EQUALS) Then anim_time#=anim_time#+0.1

    If anim_time>20 Then anim_time=2
    TurnEntity pivot,0,1,0

    If KeyHit(KEY_SPACE) Then postprocess=Not postprocess

    ' control camera
    If KeyDown( KEY_RIGHT )=True Then TurnEntity Camera,0,-1,0
    If KeyDown( KEY_LEFT )=True Then TurnEntity Camera,0,1,0
    If KeyDown( KEY_DOWN )=True Then MoveEntity Camera,0,0,-2.5
    If KeyDown( KEY_UP )=True Then MoveEntity Camera,0,0,2.5
    End Rem
    If KeyDown( KEY_LEFT )
        TurnEntity camera,0,3,0
    Else If KeyDown( KEY_RIGHT )
        TurnEntity camera,0,-3,0

    If KeyDown( KEY_A )
        MoveEntity camera,0,0,3
    Else If KeyDown( KEY_Z )
        MoveEntity camera,0,0,-3

    If KeyDown( KEY_UP )
        TurnEntity camera,-3,0,0
    Else If KeyDown( KEY_DOWN )
        TurnEntity camera,3,0,0
    'End Rem

    PositionEntity postfx_cam,EntityX(camera),EntityY(camera),EntityZ(camera)
    RotateEntity postfx_cam,EntityPitch(camera),EntityYaw(camera),EntityRoll(camera)

    If KeyHit(KEY_Q) Then update=Not update

    Local cx#=EntityX(camera)
    Local cy#=EntityY(camera)
    Local cz#=EntityZ(camera)


    If KeyHit(KEY_T) Then spx = spx + 1
    If KeyHit(KEY_G) Then spy = spy + 1
    If KeyHit(KEY_B) Then spz = spz + 1
    If KeyHit(KEY_R) Then spx = spx - 1
    If KeyHit(KEY_F) Then spy = spy - 1
    If KeyHit(KEY_V) Then spz = spz - 1

    If KeyHit(KEY_3) Then hx = hx + .1
    If KeyHit(KEY_4) Then hx = hx - .1
    If KeyHit(KEY_W) Then hy = hy + .1
    If KeyHit(KEY_E) Then hy = hy - .1

    MoveEntity lsprite,spx,spy,spz

    Local sx#=EntityX(lsprite)
    Local sy#=EntityY(lsprite)
    Local sz#=EntityZ(lsprite)

    'grx = (grx*100)/100
    'gry = (gry*100)/100

    'PositionEntity lsprite,EntityX(Camera),EntityY(Camera), EntityZ(Camera)
    'MoveEntity lsprite,0,6,-10


    CameraProjMode camera,2
    CameraZoom camera,.1

        Local x#=ProjectedX(),y#=ProjectedY()
        px = x#
        y# = height - y#
        py = y#

        grx = px/(width/2)-1
        gry = py/(height/2)-1

        Local dx#=x#-512,dy#=y#-384
        Local d#=Sqr( dx*dx+dy*dy )/384.0
        If d>1 d=1
        GRExp = (1-d)*.5
        GRLightX = grx 'px# / width 'calculate percentage
        GRLightY = gry 'py# / height 'calculate percentage
        'px = 0
        'py = 0
    '   Local x#,y#,d#,dx#,dy#
    '   GRExp = 0
    '   GRLightX = 0
    '   GRLightY = 0

    CameraProjMode camera,1
    CameraZoom camera,1


    While update = 0
        'If KeyHit(KEY_TAB) Then toggle = Not toggle
        If KeyHit(KEY_SPACE) Then postprocess=Not postprocess
        If KeyHit(KEY_Q) Then update=Not update


    ' calculate fps
    If MilliSecs()-old_ms>=1000

    Text 0,20,"FPS: "+fps
    Text 0,40,"Space: postprocess = "+postprocess
    Text 0,60,"anim_time="+anim_time

    Text 0,80, GRLightX + " " + GRLightY
    Text 0,100, px + " " + py

    Text 0,120, grx + " " + gry

    'Text xx,yy,"Cube"

Function Update1Pass()

    If postprocess=0
        HideEntity postfx_cam
        ShowEntity camera
        HideEntity screensprite2
        HideEntity screensprite

    ElseIf postprocess=1
        HideEntity camera
        ShowEntity postfx_cam
        HideEntity screensprite2
        HideEntity screensprite

        CameraToTex colortex,postfx_cam

        HideEntity postfx_cam
        ShowEntity camera

        DepthBufferToTex depthtex,camera

        ShowEntity screensprite


End Function
(Posted 2 years ago) markcwm commented:

Wow, awesome! Thanks Ron!

So this is basically sunlight with proper light scattering (diffraction).

Here's a good GLSL 1.4 article https://medium.com/community-play-3d/god-rays-whats-that-5a67f26aeac2

(Posted 2 years ago) RonTek commented:

Thanks Mark! and yes it is. The shader code is actually good to go and I'm just having some issues with 3D to 2D spirte screen position. That's why on some angles the sprite to ray effect is off a bit. Nice article, actually that was one of the reference (Irrlicht shader?) if I recall when doing some changes with the port. I'll try to revisit that again next time. cheers.

(Posted 1 year ago) markcwm commented:

Hi Ron,

I've added this to openb3dmax.docs now (thanks again) but had to work on it adding some changes to the calculations, I dropped the sun height so the rays are visible at low angles, I stopped it shining brightly when turned away from the sun, I un-inverted ProjectedY as the rays seemed to be upside-down, and I put the sun on a pivot so it can be related to directional light, I still think there's something wrong with the rays angle but it's useable now.

(Posted 1 year ago) RonTek commented:

that's awesome Mark! I will try these new changes. Yes, it was really a wip and took some time figuring out, particularly converting the sun ray and direction.

Reply To Topic (minimum 10 characters)

Please log in to reply