Per Object Glow


👉 BlitzCoder will be building a new platform and other plans to preserve and continue the Blitz legacy.

To be able to achieve this goal, we need your support by becoming a Patreon Paid Member 👈

 

Tweet blitz3d code-archives effects tutorials
BlitzCoder

Per Object Glow, using a full screen glow method with a small trick.

It can be achieved by a simple "Type". The demo source is using single surface, but curiously, more quads makes the demo slower, while more quad meshes doesn't. You can remove the Fullbright FX and use some shininess.

Author: Bobysait

How It Works:

  • create a fullbright black material (Fx=1+8 -> fullbright + fog disabled)

On your render loop :

  • apply the black material to all objects except the one you want to be glow
  • make your glow pass
  • re-apply materials to the objects
  • Renderworld
  • draw your glow pass on top of the renderworld

Updates:

  • Added simpified version of code (replaced the nonglowmesh customtype by entityfx 0 or 1 + hideentity(light) + ambientlight(0,0,0)) by RemiD (see last code sample below)

Image

Image

Type TNonGlowMesh
Field Mesh
Field Material
End Type

; easier function to set a new "non-glow" mesh
Function NewNonGlowMesh(entity)
; only meshes based entity (mesh, terrain, plane, sprite)
Select EntityClass(entity)
Case "Mesh", "Terrain", "Sprite", "Plane"
Default : Return
End Select

Local ngm.TNonGlowMesh = New TNonGlowMesh
ngm\Mesh = entity
ngm\Material = GetEntityBrush(entity)
End Function

Graphics3D 800,600,0,2
SetBuffer BackBuffer()

; sunset lighting

AmbientLight 0,0,0
Local light1 = CreateLight (2) ; blue sky light
MoveEntity (light1, 0,20000,0)
LightColor (light1, 050,140,255)
LightRange (light1, 30000)

Local light2 = CreateLight (2) ; yellow sunset light
MoveEntity (light2, -20000,500,2000)
LightColor (light2, 255,140,050)
LightRange (light2, 40000)

; backlighting (light from above -> simulate fake sky refraction from the ground)
Local light3 = CreateLight (2) ; blueish backlight
MoveEntity (light3, 0,-30000,0)
LightColor (light3, 000,040,050)
LightRange (light3, 50000)

; small fps system ( player->head->camera )
Local player = CreatePivot ()
Local head = CreatePivot (player)
Local cam = CreateCamera (head)
PositionEntity (player, 0,2,0)
CameraClsColor (cam, 230,150,145)

; scene
; a plane for the floor
Local ground = CreatePlane (6)
EntityColor (ground, 30,80,10)
; the ground does not glow
NewNonGlowMesh (ground)

; some entities to show
Local mesh
For n = 1 To 50
; random primitive
Select Rand(1,3)
Case 1 : mesh = CreateCube()
Case 2 : mesh = CreateSphere(Rand(10,20))
Case 3 : mesh = CreateCylinder(Rand(12,24), 1)
End Select

; randomize position, size and color
MoveEntity mesh, Rnd(-50,50), Rnd(1,2), Rnd(-50,50)
TurnEntity mesh, Rnd(-15,15), Rnd(360), Rnd(-15,15)
ScaleEntity mesh, Rnd(1,2), Rnd(1,2), Rnd(1,2)
EntityColor mesh, Rnd(160,255),Rnd(160,255),Rnd(160,255)
EntityShininess mesh, 0.4

; approximate one other 3 meshes is glowing
Select Rand(1,10)
Case 1,2,3 ; glowing meshes -> do nothing
EntityColor mesh, Rnd(160,255)*.4,Rnd(160,255)*.4,500

Default ; else non-glowing mesh -> register them
NewNonGlowMesh mesh
End Select
Next

; A black material
Local BLACK = CreateBrush(0,0,0)
BrushFX BLACK, 8 ; you can also set the fx to "0" To enable glowing specularity
BrushShininess BLACK, .5

; the glow texture
Local GLOW_Tex_L = CreateTexture(GraphicsWidth(), GraphicsHeight())
; real size (texture are power of 2 size)
Local Glow_W = TextureWidth(GLOW_Tex_L)
Local Glow_H = TextureHeight(GLOW_Tex_L)
Local FX_Screen_Ratio#= Float(GraphicsHeight())/GraphicsWidth()

; ratio of the texture vs graphics size
Local FX_Quad_du# = Float(GraphicsWidth())/Glow_W
Local FX_Quad_dv# = Float(GraphicsHeight())/Glow_H

; quads to render the texture
Local FX_GLOW_POWER#= 0.2
Local FX_GLOW_COUNT%= 5

Local FX_Quad_A# = FX_GLOW_POWER / Sqr(FX_GLOW_COUNT*FX_GLOW_COUNT*2);
Local FX_Quad_Div# = 1.0 / Sqr(FX_GLOW_COUNT*FX_GLOW_COUNT*2)
Local FX_Quad_Offset#= 6.0/GraphicsWidth()
Local FX_Quad_si# = 2.0
Local FX_Quad_sj# = 2.0*FX_Screen_Ratio

; -> all quads are attached to a single pivot (for easier Hide/Show and transformations)
Local FX_Quad = CreateMesh (cam)
PositionEntity (FX_Quad, 0,0,2) ; position at Z=2 -> no need to set a specific camera near range
; scale the pivot so the quads will preserve the graphics ratio
HideEntity (FX_Quad)
EntityOrder (FX_Quad, -1000) ; render the quad on top of any meshes rendered
EntityFX (FX_Quad, 1+2+8+32) ; disable lighting and fog on the quads
EntityTexture (FX_Quad, GLOW_Tex_L)
EntityBlend (FX_Quad, 3) ; LIGHT Blend -> mandatory if you want glowing highlights (else it will just make some blur)

Local FX_Surf = CreateSurface (FX_Quad)

; you can create more quads to get a smoother result (here I used 49 quads with low alpha)
; all the stuff below can be replaced by a single surface will all triangles on it.
; this is just for demonstration, so I used quads, faster to code (lazzy me ? maybe)
For j = -FX_GLOW_COUNT To FX_GLOW_COUNT
For i = -FX_GLOW_COUNT To FX_GLOW_COUNT
; offset the quads
Local qi# = Float(i)*FX_Quad_Offset/FX_Quad_du
Local qj# = Float(j)*FX_Quad_Offset/FX_Quad_dv
; set as transparent mesh (the farther from center, the less visible)
; the glow surface
Local qa# = FX_Quad_A * (1.0 - Sqr(i*i+j*j) * FX_Quad_Div)
If qa>0.01
Local v0 = AddVertex (FX_Surf, -FX_Quad_si+qi, FX_Quad_sj+qj, 0, 0,0)
AddVertex (FX_Surf, FX_Quad_si+qi, FX_Quad_sj+qj, 0, FX_Quad_du,0) ; UVs are offseted to fit the real part of the texture rendered
AddVertex (FX_Surf, FX_Quad_si+qi,-FX_Quad_sj+qj, 0, FX_Quad_du,FX_Quad_dv)
AddVertex (FX_Surf, -FX_Quad_si+qi,-FX_Quad_sj+qj, 0, 0,FX_Quad_dv)
VertexColor (FX_Surf, v0 , 255,255,255, qa)
VertexColor (FX_Surf, v0+1, 255,255,255, qa)
VertexColor (FX_Surf, v0+2, 255,255,255, qa)
VertexColor (FX_Surf, v0+3, 255,255,255, qa)
AddTriangle (FX_Surf, v0,v0+1,v0+2)
AddTriangle (FX_Surf, v0,v0+2,v0+3)
EndIf
Next
Next

; reset mouse speeds just before the loop to prevent random rotation on first loop if you press the mouse button.
MouseXSpeed()
MouseYSpeed()

Repeat

Local msx# = MouseXSpeed()
Local msy# = MouseYSpeed()

; ZQSD or Arrows -> Replce the Key_L "30" by the QWERTY value, it's set on an AZERTY keyboard
Local Key_L = (KeyDown(203) Or KeyDown(30))>0
Local Key_R = (KeyDown(205) Or KeyDown(32))>0
Local Key_U = (KeyDown(200) Or KeyDown(17))>0
Local Key_D = (KeyDown(208) Or KeyDown(31))>0

; on left mouse down -> rotate the player
If MouseDown(1)
TurnEntity player, 0, -msx,0
TurnEntity head, msy,0,0
EndIf

; move the player with ZQSD/Arrows
MoveEntity player, Float(Key_R-Key_L)*1, 0, Float(Key_U-Key_D)*1.5

; -------------------------------------------------
; - The Glow part -
; -------------------------------------------------
; use the black material to mask non glowing meshes
Local ent.TNonGlowMesh
For ent = Each TNonGlowMesh
PaintEntity ent\Mesh,BLACK
Next
; remove the background color (so it's full black -> for this demo, we don't want the background to be glowing)
CameraClsColor cam, 0,0,0

; hide the glow quad
HideEntity FX_Quad

; render the scene and copy the result to the glow texture
RenderWorld()
CopyRect 0,0,GraphicsWidth(), GraphicsHeight(), 0,0, BackBuffer(), TextureBuffer(GLOW_Tex_L)

; restore materials and reset background
For ent = Each TNonGlowMesh
PaintEntity ent\Mesh,ent\Material
Next
CameraClsColor cam, 230,150,145

; show the glow quads
ShowEntity FX_Quad
; -------------------------------------------------

; finally render the scene.
; it will mix the "normal" with the glow quads
RenderWorld()

Flip 1

Until KeyDown(1)
End

Version 2.0

Graphics3D 800,600,32,2
SetBuffer BackBuffer()

dlight = CreateLight(1)
LightColor(dlight,255,255,255)
PositionEntity(dlight,-1000,1000,-1000,True)
RotateEntity(dlight,45,-45,0,True)

AmbientLight 064,064,064

; small fps system ( player->head->camera )
Local player = CreatePivot ()
Local head = CreatePivot (player)
Local cam = CreateCamera (head)
PositionEntity (player, 0,1.65,0)
CameraRange(cam,0.1,100)
CameraClsColor (cam, 128,128,255)

; scene
; a plane for the floor
Local ground = CreateCube()
ScaleMesh(ground,1000.0,0.1/2,1000.0)
PositionMesh(ground,0,-0.1/2,0)
EntityColor (ground, 000,096,000)
EntityFX(ground,0)

; some entities to show
Local mesh
For n = 1 To 100
; random primitive
Select Rand(1,3)
Case 1 : mesh = CreateCube()
Case 2 : mesh = CreateSphere(16)
Case 3 : mesh = CreateCylinder(16)
End Select

; randomize position, size and color
Scale# = Rnd(0.1,1.0)
ScaleMesh mesh, Scale/2, Scale/2, Scale/2
EntityColor mesh, Rnd(025,255),Rnd(025,255),Rnd(025,255)
MoveEntity mesh, Rnd(-50,50), Scale/2, Rnd(-50,50)
TurnEntity mesh, Rnd(-15,15), Rnd(-180,180), Rnd(-15,15)

;EntityShininess mesh, 0.4

; approximate one other 3 meshes is glowing
Select Rand(1,2)
Case 1 ; glowing meshes -> do nothing
;EntityColor mesh, Rand(025,255),Rand(025,255),Rand(025,255)
EntityFX(mesh,1)
Case 2
EntityFX(mesh,0)
End Select
Next

; the glow texture
Local GLOW_Tex_L = CreateTexture(GraphicsWidth(), GraphicsHeight())
; real size (texture are power of 2 size)
Local Glow_W = TextureWidth(GLOW_Tex_L)
Local Glow_H = TextureHeight(GLOW_Tex_L)
Local FX_Screen_Ratio#= Float(GraphicsHeight())/GraphicsWidth()

; ratio of the texture vs graphics size
Local FX_Quad_du# = Float(GraphicsWidth())/Glow_W
Local FX_Quad_dv# = Float(GraphicsHeight())/Glow_H

; quads to render the texture
Local FX_GLOW_POWER#= 0.5
Local FX_GLOW_COUNT%= 3

Local FX_Quad_A# = FX_GLOW_POWER / Sqr(FX_GLOW_COUNT*FX_GLOW_COUNT*2);
Local FX_Quad_Div# = 1.0 / Sqr(FX_GLOW_COUNT*FX_GLOW_COUNT*2)
Local FX_Quad_Offset#= 6.0/GraphicsWidth()
Local FX_Quad_si# = 2.0
Local FX_Quad_sj# = 2.0*FX_Screen_Ratio

; -> all quads are attached to a single pivot (for easier Hide/Show and transformations)
Local FX_Quad = CreateMesh (cam)
PositionEntity (FX_Quad, 0,0,2) ; position at Z=2 -> no need to set a specific camera near range
; scale the pivot so the quads will preserve the graphics ratio
HideEntity (FX_Quad)
EntityOrder (FX_Quad, -1000) ; render the quad on top of any meshes rendered
EntityFX (FX_Quad, 1+2+8+32) ; disable lighting and fog on the quads
EntityTexture (FX_Quad, GLOW_Tex_L)
EntityBlend (FX_Quad, 3) ; LIGHT Blend -> mandatory if you want glowing highlights (else it will just make some blur)

Local FX_Surf = CreateSurface (FX_Quad)

; you can create more quads to get a smoother result (here I used 49 quads with low alpha)
; all the stuff below can be replaced by a single surface will all triangles on it.
; this is just for demonstration, so I used quads, faster to code (lazzy me ? maybe)
For j = -FX_GLOW_COUNT To FX_GLOW_COUNT
For i = -FX_GLOW_COUNT To FX_GLOW_COUNT
; offset the quads
Local qi# = Float(i)*FX_Quad_Offset/FX_Quad_du
Local qj# = Float(j)*FX_Quad_Offset/FX_Quad_dv
; set as transparent mesh (the farther from center, the less visible)
; the glow surface
Local qa# = FX_Quad_A * (1.0 - Sqr(i*i+j*j) * FX_Quad_Div)
If qa>0.01
Local v0 = AddVertex (FX_Surf, -FX_Quad_si+qi, FX_Quad_sj+qj, 0, 0,0)
AddVertex (FX_Surf, FX_Quad_si+qi, FX_Quad_sj+qj, 0, FX_Quad_du,0) ; UVs are offseted to fit the real part of the texture rendered
AddVertex (FX_Surf, FX_Quad_si+qi,-FX_Quad_sj+qj, 0, FX_Quad_du,FX_Quad_dv)
AddVertex (FX_Surf, -FX_Quad_si+qi,-FX_Quad_sj+qj, 0, 0,FX_Quad_dv)
VertexColor (FX_Surf, v0 , 255,255,255, qa)
VertexColor (FX_Surf, v0+1, 255,255,255, qa)
VertexColor (FX_Surf, v0+2, 255,255,255, qa)
VertexColor (FX_Surf, v0+3, 255,255,255, qa)
AddTriangle (FX_Surf, v0,v0+1,v0+2)
AddTriangle (FX_Surf, v0,v0+2,v0+3)
EndIf
Next
Next

; reset mouse speeds just before the loop to prevent random rotation on first loop if you press the mouse button.
MouseXSpeed()
MouseYSpeed()

Repeat

Local msx# = MouseXSpeed()
Local msy# = MouseYSpeed()
MoveMouse(GraphicsWidth()/2,GraphicsHeight()/2)
; ZQSD or Arrows -> Replce the Key_L "30" by the QWERTY value, it's set on an AZERTY keyboard
Local Key_L = (KeyDown(203) Or KeyDown(30))>0
Local Key_R = (KeyDown(205) Or KeyDown(32))>0
Local Key_U = (KeyDown(200) Or KeyDown(17))>0
Local Key_D = (KeyDown(208) Or KeyDown(31))>0

; on left mouse down -> rotate the player

TurnEntity player, 0, -msx,0
TurnEntity head, msy,0,0
If MouseDown(1)=1
MoveEntity(player,0,0,0.15)
Else If MouseDown(2)=1
MoveEntity(player,0,0,-0.15)
EndIf

; -------------------------------------------------
; - The Glow part -
; -------------------------------------------------

HideEntity(dlight)
AmbientLight(0,0,0)
CameraClsColor cam, 0,0,0

; hide the glow quad
HideEntity FX_Quad

; render the scene and copy the result to the glow texture
RenderWorld()
CopyRect 0,0,GraphicsWidth(), GraphicsHeight(), 0,0, BackBuffer(), TextureBuffer(GLOW_Tex_L)

; restore materials and reset background
ShowEntity(dlight)
AmbientLight(064,064,064)
CameraClsColor (cam, 128,128,255)

; show the glow quads
ShowEntity FX_Quad
; -------------------------------------------------

; finally render the scene.
; it will mix the "normal" with the glow quads
RenderWorld()

Flip True

Until KeyDown(1)
End
RemiD commented:

i remmember this one

i have created a more precise version with 8 offsets.

i will post an example, someday, when i find it

BlitzCoder commented:

i remmember this one

cheers RemiD. both techniques are really great and each has some practical use for it.

i have created a more precise version with 8 offsets.
i will post an example, someday, when i find it

that's awesome and looking forward to it.

speaking of which or perhaps something related, how would you apply this to a sun (directlight) but have rays intersecting with objects in front of and near the camera? like volumetric lighting or god rays.

I am trying to replicate how FastExt does it. To start with, I was thinking along the lines of a parented entity/sprite to a camera like what you do on a skybox.

Image

RemiD commented:

how would you apply this to a sun (directlight) but have rays intersecting with objects in front of and near the camera? like volumetric lighting or god rays.
I am trying to replicate how FastExt does it. To start with, I was thinking along the lines of a parented entity/sprite to a camera like what you do on a skybox.

Fredborg made a demo about this effect.

the idea was to have a subdivided quad parented to the camera, have its vertices colored with the sun color, and use linepicks from the sun to each vertex, and set the vertices alphas accordingly (if a light ray can reach a vertex, alpha 0.5, if a light ray can't reach a vertex, alpha 0)
with blendmode add or multiply2...

something like that...

BlitzCoder commented:

Fredborg made a demo about this effect.

I thought this was the JSL demo, but it's just a bloom effect.

Do you still have the discussion link or perhaps some demo/sources?

the idea was to have a subdivided quad parented to the camera, have its vertices colored with the sun color, and use linepicks from the sun to each vertex, and set the vertices alphas accordingly (if a light ray can reach a vertex, alpha 0.5, if a light ray can't reach a vertex, alpha 0)
with blendmode add or multiply2...
something like that...

Thanks! basically I got the overall idea, but still curious how those colored streaks gets generated if vertices will only be used. What's the decent size of the quad subdivision?

Looking at how fastext does it below, it seems to be drawing a sprite as I don't see any vertices when debugging it in wireframe mode.

I also see the concept is basically the same on most parts.

    CameraProject Camera, EntityX(Light,1), EntityY(Light,1), EntityZ(Light,1)
    If ProjectedZ()>0 Then
        TFormVector 0, 0, 1, Camera, Light
        pitch# =  Abs(Sin(VectorPitch (TFormedX(), TFormedY(), TFormedZ())))   :   pitch = pitch*pitch
        yaw# = Abs(Sin(VectorYaw (TFormedX(), TFormedY(), TFormedZ())))   :   yaw = yaw*yaw
        alpha# = (1.0 - pitch) * (1.0 - yaw)
        x# = ProjectedX()/Float(GraphicsWidth())
        y# = ProjectedY()/Float(GraphicsHeight())
        CustomPostprocessRays x, y, 115, 0.8 * alpha, 4, 4, 3, 180, 240, 255        ; <<< Customize Rays postprocess FX
        RaysFX = FE_Rays ; Enable God Rays
    Else
        RaysFX = 0 ; light not in camera
    EndIf

    RenderPostprocess RaysFX
RemiD commented:

your answer is in the name of the command 'RenderPostprocess RaysFX', Fastext is like a hacking of blitz3d to add some functionalities / effects. so you won't see everything which is going on outside of Blitz3d.

concerning the part of the code that you mention, it is checking the orientation of the camera related to the sun (is facing or is away), before doing the Rays effects.

I thought this was the JSL demo, but it's just a bloom effect.

yes it is this demo, not it is not bloom

maybe a big sprite shown only when the camera is looking at the sun and drawn on top of all the environment ?

BlitzCoder commented:

maybe a big sprite shown only when the camera is looking at the sun and drawn on top of all the environment ?

yes, I was also thinking of this at first, but to complete the effect and make it work there should be intersecting, occluded and dispersing rays of at least objects that are near the camera/player.

yes it is this demo, not it is not bloom

it does look like a bloom, with 1 pass and only affecting the skybox or perhaps a dummy sprite in place or relative to light position/location.

I will post a screenshot if I can find a demo copy.

I think the first concept that you mentioned with fredborg is the best and fastest way so far. I just can't picture how the quad would look like in action.

RemiD commented:

Sun:
The sun flare, is a quad with additive blending rendered in front of everything else.

here : https://mojolabs.nz/posts.php?topic=43068 (#40)

i also remember a similar sun blinding effect by bobysait, but no idea where to find it.

also there is a sun blinding effect in the code example Blitz3D\samples\AGore\GrassDemo

BlitzCoder commented:

Ah yes, sunflare effects! I did see a lot of cool demos and with that sample in blitz3d. I also know a great asset/resource that will greatly improve that effect, will post a demo soon as I find them.

I did seem to notice that the fastext godrays might be using a combination of sunflare because when you are facing on the side, there is this light sprite clipped and still present and this may be coded on purpose.

Actually, I had a eureka moment earlier testing out and still using glow. It does seem to work particularly using per object glow, but this will be better if the glow is more amplified and fine tuned, perhaps some dithering/blurring of the artifacts.

Although these are similar in concept, I have started a new thread here since now the topic is about Volumetric Lighting or God Rays which might have other or better solutions including the one you mentioned about subdivided quads with vertex alphas

Reply To Topic (minimum 10 characters)

Please log in to reply