[Solved] Per Object Glow

Blitz3D Forums/Blitz3D Programming/[Solved] Per Object Glow

RustyKristi(Posted 2016) [#1]
I'm trying to do a per object glow. I found some code that does the whole scene but I just needed per object to focus on it. Is there a workaround or somebody already done this, w/o the use of userlibs?


RemiD(Posted 2016) [#2]
Yes,

either with several meshes with each one being scaled up a little more and alpha a little less (=more transparent) (tried, looks ok)

or

with a textured quad and several textures, each one for a different view angle (8 or 16 depending on the shape), the texture being a render of the shape in fullbright, and blurred. (never tried, but i have seen it in Rune)

or

with several flat rectangle mesh which go outside the shape (along its major edges) and the near vertices are of the same color of the thing color and alpha 1.0 and the far vertices are of the same color of the thing color and alpha 0.0 (tried, looks ok, i have seen it in Tecno the base)

Full screen glow is really slow if you want a pixel precise glow with an offset around each shape (not like the blur using 8quads with an offset around the screen...)


RustyKristi(Posted 2016) [#3]
thanks RemiD. Can you post some simple examples? I find the first method to be quite easy btw, great idea!


RustyKristi(Posted 2016) [#4]
Ok tried the first one and there's a blurring issue if you got more details on your texture. It will do but would like to try other methods.


Bobysait(Posted 2016) [#5]
Use a full screen glow method with a small trick :

- 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

It can be achieved by a simple "Type"

Type TNonGlowingMeshes
   Field Entity
   Field Material
End Type

use the type to register entities that glow wont affect


And that's a small sample of how you can do it
Unoptimized, and it's just a prototype (so, it's not really good to integrate -> should be like a library with small function calls etc ...)


it requires 2 renderworld and 1 copyrect


Bobysait(Posted 2016) [#6]
ps : as mentionned in the comment (in the code), you can remove the Fullbright FX and use some shininess

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

It will make glow from specularity on the non glowing meshes.



(code updated with single surface, but curiously, more quads makes the demo slower, while more quad meshes doesn't)



RemiD(Posted 2016) [#7]
@RustyKristi>>for method1 there is an example in the code archives, see : http://www.blitzbasic.com/codearcs/codearcs.php?code=391


@Bobysait>>the problem wih fullscreen glow (do a small render of fulldbright colored shapes (and the others shapes colored in black), then blur this render, then display it on a screen mesh over the scene) is that the glow is not precise and i have found that it produces flickering of the glow when a shape is too small... And if you do a bigger render, it is slower... And a glow on a big texture (1024*1024) is too slow anyway...


Bobysait(Posted 2016) [#8]

(do a small render of fulldbright colored shapes (and the others shapes colored in black), then blur this render, then display it on a screen mesh over the scene)



mmm ... maybe you should just try the code above then.
What I mentioned as "Glow pass" is not a "bad glow pass", it's just a "nice real glow pass".
While what you describe is a ugly way to make glow.

- On my routine, there is no real blur applied because there is no need for it, and no artifact or fickering with smaller or farther objects.
The bluring effect doesn't stretch the pixels (like what gaussian or other standard algorithm would do)
It's more accurate and looks way much nicer.
- The render is not a "small render", it actually renders at the full resolution.
- The glowing objetcs are not rendered fullbright, they are just rendered normally.

------------------

The principle is not to render in a special way the glowing objects, but to disable the "not-glowing" objects.
So, all objects are rendered black and glowing objects are rendered with their standard brushes. Then, render the scene again with all objects painted with their original brushes
Once you apply the blend in light mode, what it does is "Add" the pixel to the screen.
So, a black pixel just does not add any light, while a "normal" pixel will highlight the pixel above.

As the mesh that receives the blended texture is composed of several quads with alpha, all offseted (by one or two pixels), it adds smaller amount of light around each pixels that was not black.

So, the final render is just like a fullscreen per pixel effect, neat and accurate.


RemiD(Posted 2016) [#9]
Yes what i described is what sswift suggested (i have a demo somewhere...) and i have not found that it produces a precise glow and there is some flickering when the glowing shapes are too small (those which are far away.



As the mesh that receives the blended texture is composed of several quads with alpha, all offseted (by one or two pixels), it adds smaller amount of light around each pixels that was not black.


that's a good idea, i will take a look at your code. Thanks

You also posted this example a while ago : http://www.blitzbasic.com/Community/posts.php?topic=105815 (#4)
maybe RustyKristi wants to take a look...


RemiD(Posted 2016) [#10]
@Bobysait>>i am still trying to understand what you are doing in your code but this just gave me another idea for a per shape glow effect, but i am not sure if this is doable (fast enough)

The idea would be to render the scene with normal width height (for example 1024*768), with the non glowing shapes colored in black (or with no light and ambientlight 0,0,0) and the glowing shapes colored in their color and fullbright, and then analyze the resulting image, and for each colored pixel (which corresponds to a part of a glowing shape) create a small quad with a size slightly bigger than the pixel (so this would be the glow radius)
All quads would be merged to one mesh one surface which would then be drawn (blendmode add) on top of the screen mesh + screen texture (with the image of the render with the shapes with their normal colors)
The slow step would be to analyze the pixels of the image of the render (1024*768=786432pixels!!!)


RemiD(Posted 2016) [#11]
@Bobysait>>i think i understand your code now, but it is still not pixel precise glow... since when you scale up a screen mesh + screen texture (or in your example play with the uv to stretch the texture), the glow will not be uniform around the shape... one or two sides will glow more depending on where it is rendered on the screen...

But nice example anyway.


RemiD(Posted 2016) [#12]
simpified version of your code (replaced the nonglowmesh customtype by entityfx 0 or 1 + hideentity(light) + ambientlight(0,0,0))



Bobysait(Posted 2016) [#13]

but it is still not pixel precise glow... since [...]



It is.
It just need to be set with the optimal values ( -> 1.0/GraphicsWidth() for the offset)
Thoose two variables :
Local qi# = Float(i)/GraphicsWidth()
Local qj# = Float(j)/GraphicsHeight()
This will use an offset of one pixel.

Then, I don't know what you're looking for, but maybe it's not glow.

Finally, I don't play with the UV (in the sample, I just used du and dv on qi and qj just for convenience because it was a good factor for good result and good perfs)
Then, where I use the UVs, it's just that I set them to fit the texture area that contains the viewport of the camera rendered :
-> because a texture is power of 2 size, a 800*600 will create a 1024*1024 texture, but the camera rendered will export on the 800*600 area, so it does not cover the whole texture.
-> So I set the UV to fit the {800/1024, 600/1024} texture coords
Once done, I don't need to touch it anymore.

The only tweaking is about the offset and the alpha (to modify the power of the glow, and the dispersion)

More dispersion will create "glares" and at this moment it won't be pixel precise, but if you use "1.0/GraphicsWidth()" as offset, you'll have quads that are offseted by one pixel.
More quads = more glow radius = more smooth = more resources (lower fps)
or you can just use the dispersion to cover a larger radius (but you'll see the quads)

If you need very accurate and large radius, there is a cost.
But, as mentionned, I really doubt you'll find a better way to acheive this effect without a drastic fps cost.


RemiD(Posted 2016) [#14]
Yes i know, there is nothing ideal in this world :)


RemiD(Posted 2016) [#15]
Another problem with the blendmode "add" is that sometimes the resulting glow is not of the same color than the shape color (because, as i understand it, too many "added" pixels become white pixels)


RemiD(Posted 2016) [#16]
Your method is quite good compared to the sswift method. There is no flickering even with far away small shapes. Good.


Bobysait(Posted 2016) [#17]

Another problem with the blendmode "add" is that sometimes the resulting glow is not of the same color than the shape color (because, as i understand it, too many "added" pixels become white pixels)


At the same time, this is what glow is supposed to do.
So, seriously, I don't know what you're looking for, but maybe it's not glow, but just something like an highlighted outline ?


RemiD(Posted 2016) [#18]
Since you probably know how directx manages stuff behind the scene, what happens if several meshes have the same entityorder, (for example quads) how is the final color of a pixel calculated since the shapes have the same zorder ?
For example, let's say 2quads with the same entityorder and with blendmode "add"


Bobysait(Posted 2016) [#19]
if entityorder is set, it disables the depth test, so all faces are drawn the first to the last, no matter what.

Then, if you have two quads with same order, they are rendered the last on top of the first (render the first, then render the last = the last appear front of the previous one. exactly Like 2D drawing)

It depends on the creation time.


RemiD(Posted 2016) [#20]
Oh so the creation order of meshes is considered ? Like the creation order of surfaces in a mesh ? I remember some discussions to prevent zorder artifacts was to create a surface before another depending on if it is more inside or outside a mesh (related to the camera).


Bobysait(Posted 2016) [#21]
Yep, but there are cases where it doesn't matter.
(like the code I posted above)

For entities with blending modes, they are mixed with special equation
-> blend add adds the pixels, so no matter the order 0+1+2+3 = 0+3+1+2 = 2+1+3+0
-> blend shade is a multiplication -> 1*2*3 = 2*1*3 etc ...

it only matters for solid or alpha blend. (actually, it's essentially with alpha that the problem occures, with or without entityorder, the alpha meshes disable the z buffer (because the z buffer only store a single value, it's a choice to make when you program the rendering, and blitz3d choose to disable it -> which is not a bad choise, because others methods are actually worse))


RemiD(Posted 2016) [#22]
removed because of an error in this old ugly code


RemiD(Posted 2016) [#23]
... (nothing interesting, i was just confused :P)


Bobysait(Posted 2016) [#24]
nope, it's a static offset between two layers.
it's the offset that quantify the dispersion.
-> set it to 1.0/GraphicsWidth() to get a "pixel perfect" effect and lower glow radius.


RemiD(Posted 2016) [#25]
Oh ok, thanks for the clarification.


Yue(Posted 2016) [#26]



RustyKristi(Posted 2016) [#27]
Wow, I did not know it will end up this long of a discussion! Anyway, thanks RemiD and Bobysait.

I will try all posted methods here. awesome.


RemiD(Posted 2016) [#28]
Here is the old glow demo with the sswift blur method :
http://expirebox.com/download/34503ac9e9bf6d7a971e99866858462d.html


RemiD(Posted 2016) [#29]
Why not use a combination of geometric glow and a screen mesh + blurred screen texture with blendmode add ?

It would allow to have a precise glow around the shape but also to have a blured glow.

This can be done by using the example Rob (or I) posted and FastExt blur, however the FastExt lib does not work well with the last version of Blitz3d...


RustyKristi(Posted 2016) [#30]
I think I should go for the one that is easiest and won't affect much performance, but looks like it's all good for here. appreciate the help, thanks again.


RemiD(Posted 2016) [#31]
Oh ! I just had another idea :
Similar to the geometric glow, but instead of using several scaled up shapes with decreasing alpha, use several flipped scaled up shapes with decreasing alpha.
Also don't use the blendmode "add" but use the blendmode "alpha/default"
Also set all geometric glow shapes to fullbright.
Also you need a screen mesh + a screen texture with blendmode "alpha/default"

In the mainloop :
hide the light(s)
set ambientlight to 0,0,0
set camera cls color to 0,0,0
hide the screen mesh
render the scene (all "normal" shapes will be black, all fullbright shapes (the geometric glow shapes) will be colored and fullbright
copyrect the result to the screen texture
fast blur the texture (with fastext blur ?)
show the light(s)
set the ambientlight to its initial color
set the camera cls color to its initial color
hide the geometric glow shapes (facultative)
show the screen mesh
render the scene

This should produce a glow which is of the color of the shape (from opaque color to transparent color) instead of the white saturation produced by the blendmode "add"


Bobysait(Posted 2016) [#32]
1 - If it worked it would only produce some darkish blur (not glow)
2 - It won't work at all.

Add blend removes the black parts because it doesn't add the color.
alpha will mixe the black color with the scene.
The result will be darkened and probably dirty blured.

But !
Anyway, whatever I can think or anticipate, if you have an idea, don't expose it, try it then post the result
You already have the requested structur to make the minor changes on this topic


RemiD(Posted 2016) [#33]
@Bobysait>>sometimes i appreciate when others post their methods (in words, not necessarily in code), if the method is senseful and will most likely work, why not, so here was my post.

But i understand your concern about the blending of colored pixels and black pixels so maybe a workaround would be to have a progressive decrease of the alpha of each bigger shape but between 1.0 and 0.5 so that the resulting pixels stay colored enough ? I don't know and i don't want to try now...


RemiD(Posted 2016) [#34]
2 ways to reduce the brightness (white pixels of the blendmode "add") in the example (#22) is to color the shape with a color between 0 and 128 (instead of 0 and 255)
and also to set the alpha of each between 0.5 and 0 instead of 1.0 and 0.


RemiD(Posted 2016) [#35]
Here is an attempt to use the 3rd method described in post#2

the glowing shape is a square (2 triangles)


Rick Nasher(Posted 2016) [#36]
This would serve nicely as a button on an elevator or something.


RustyKristi(Posted 2016) [#37]
Yes this looks nice RemiD! Can you post the actual code?


Bobysait(Posted 2016) [#38]
@Rick Nasher : For a button, you'd probably better use an alpha texture with the glowing effect on it (on a fixed sprite or something similar), as it's a simple purpose it would not require several copies of the polygons and it would prevent the counter-part : there is a big chance your alpha polygons will be intersecting with the wall the button will be on.

But I must admit it's a very nice blue.


Kryzon(Posted 2016) [#39]
Doom 3 uses something similar, a dynamic mesh that is changed based on the camera position:
https://simonschreibt.de/gat/doom-3-volumetric-glow/


RemiD(Posted 2016) [#40]

there is a big chance your alpha polygons will be intersecting with the wall the button will be on


@Bobysait>>i made sure to have each "glow part" not intersecting with each other or with the square mesh (with an offset of 0.001 between each near vertices) (it is also easier to set the alpha value if the vertices have a precise position, in this case, the vertices at the bottom near the edges of the square are alpha 1.0 and all others vertices far from the edges of the square are alpha 0)

If you play the game TECNO the base (made with Blitz3d) you will see this method used on almost all lightsources/luminous things, this method and the method of scaling up the shape and decreasing its alpha are really fast compared to having to render the whole scene twice. Even if it looks slightly different...


RemiD(Posted 2016) [#41]
@Kryzon>>very nice method, similar to what i have done, but my example is not "dynamic". Thanks for the link!


Bobysait(Posted 2016) [#42]

Even if it looks slightly different


"slightly"
I would say, "even if it does not look the same at all"

Well, if it's just for single buttons, and limited geometries, I guess this trick can do the job.
But depending on how many object need to be "glowed", this trick could easily be lower than rendering twice, as you multiply geometries to get the result.


RemiD(Posted 2016) [#43]
The doom3 method is way better because the glow is uniform around the flat shape and there are less triangles and consequently less alpha, i have to think about how to reproduce this effect, it should be doable...


RustyKristi(Posted 2016) [#44]
Wow nice. I hope we can see some example code and demo :D

I have seen a lot of awesome B3D stuff digging the archives and thread that has some shader equivalent so I think this is possible.


Bobysait(Posted 2016) [#45]
The doom3 method probably uses a lots of picking to generate the mesh on the fly. What you'd win in polygon rendering (GPU) would probably be lost in CPU time. But if there is not too many objects to "project" and the pickable scene is not too complex, maybe it can be fast enough.


RemiD(Posted 2016) [#46]
Test with another flat shape (a symbol) with only an "outglow" :


imo it looks better with an "outglow" + an "outlineglow" (like with the square shape)

also the cool thing is that if you model the "outglow" in a certain way, you can then scale it up/down along the "outaxis" (in this case upward) and it will look as if the intensity is increased/decreased.


Rick Nasher(Posted 2016) [#47]
Interesting. You seem to become the glow/illuminated objects expert here.


RemiD(Posted 2016) [#48]
@Rick>>thanks but i don't like the term "expert", i would prefer the term experimenter if you don't mind ;)


RemiD(Posted 2016) [#49]
new experiment/result inspired by the volumetric glow by Rob with some improvements to have the glow shape with only one surface and some tweaks with the colors/alpha to make it looks less white/more colored :


there is still one improvement that i want to add :
instead of scalingup each glow shape, i want to push the vertices (using the vertices normals) so that there is the same offset all around the shape. Not sure if this doable without producing deformations of the shape, i will see...


RemiD(Posted 2016) [#50]
no... it only works if the shape is shaped in a way that the scaled up bigger shape will have all its edges outside of the smaller shape. Hence the superiority of per pixel glow...


Bobysait(Posted 2016) [#51]
Don't scale using the normal but using the vector relative to the center of the object.
V.Vector = Vertex-Center
L# = V.Length() + Extend#
NewVertexPosition = Vertex +  V.Normalized() * L


It won't be homogenous but it will work for any convex shapes


RemiD(Posted 2016) [#52]
I think that's what scalemesh already does but from the origine of the shape, so if i set the origine at the center of the shape, then scalemesh probably repositions the vertices using a similar formula.


Bobysait(Posted 2016) [#53]
ScaleMesh resizes from the 0,0,0 coordinates. (it's not always the center, it's only the "bouding center" for blitz primitive, but for ex, a cube that you PositionMesh 0,1,0 will have a center at 0,1,0, while ScaleMesh will still use the 0,0,0 point (local to the entity, of course, it's not a global position) )

The job behind scalemesh :
- Create a transformation matrix (that is just an identity matrix multiplied by a vector which holds the 3 scale factors)
- applies the matrix to each vertex.
(and finally, recomputes the internal mesh stuff like bounding box/sphere)

So, in the end, it looks almost the same, except the center is not always the one that fit better for a scaling.
But anyway, the goal of my previous post is just to say :
- Don't use the vertex normals, they won't do the job for unweld meshes (and will only work for meshes with normals "polyshed" like using UpdateNormals), while an expand along the distance of the vertex to an arbitrary point will work better (for convex meshes !)


RemiD(Posted 2016) [#54]

Don't use the vertex normals, they won't do the job for unweld meshes


yes i understand what you mean, but in my previous procedures, i first determined which vertices were at the same position before calculating the new position and repositionning them, and the new position was calculated by adding the n vectors from the n vertices sharing the same position, so it did not matter, there were no offset. But ok !


RemiD(Posted 2016) [#55]
Experiment/result with the procedure to push vertices around the shape using the normals (instead of scalingup the shape) :

(the glow offset is bigger around some parts than around others parts and i think this is because the surface uses a smoothinggroup which adds more vertices to the surface so that the lighting/shading looks a certain way. And this procedure adds an offset for each vertex and the others vertices at the same position, so if several vertices are at the same position the offset is added multiple times...)


RustyKristi(Posted 2016) [#56]
cool RemiD! any code to actually try?


RemiD(Posted 2016) [#57]
By exporting the mesh/surface without taking into account the smoothinggroups, the mesh is welded (it has only one vertex at each position), then the glow is more uniform, with the same offset all around the shape :


and since a fullbright mesh/surface is not lighted/shaded, it can be welded without problems (it also has the advantage to have less vertices per shape/glow)

Great ! :D


RemiD(Posted 2016) [#58]

any code to actually try?


I have just explained what i have done, so if you try, i am sure that you can reproduce it ;)

Maybe later, i want to finish a demo with my own special graphics effects...


RemiD(Posted 2016) [#59]
Final version (tweaked the color of the shape and of the color of the glow layers so that they blend well) :

this is what a nice glow should look like imo.

i have to admit that the render in post #57 looks nice too, but this is not really glow since the shape must be of a brighter color than the glow...


RemiD(Posted 2016) [#60]
I was wondering if my "pushverticesofsurface" procedure would work if the shape has its origine not at its center, in theory, yes, in practice, yes :

the offset between each glow layer is uniform all around the shape, good ! :)
i will try with others weird shapes and if it works well, i will share it.
in any case, the shape needs to be welded (only one vertex at each position, and so not take into account smoothinggroups, Fragmotion can help you to export this way (when you export in b3d, tick the "exclude normals" option))


RemiD(Posted 2016) [#61]
I wonder if there is a way to have only some parts of the shape glow...
For example, color some vertices of the shape in the material (non glowing) color and some vertices in the glowing color
like this :

and use the alpha property of each vertex of the glow layers to be able to have a glow coming out only from some parts of the shape.
Tricky but may work...


RustyKristi(Posted 2016) [#62]
Looks nice.


RemiD(Posted 2016) [#63]
Before i post the procedure, i would appreciate if you can share a few weird 3d shapes (with less than 32000/9 tris), so that i can debug/improve it if necessary. Thanks


RustyKristi(Posted 2016) [#64]
sure, I found a couple on github

https://github.com/OpenGLInsights/OpenGLInsightsCode/raw/master/Chapter%2026%20Indexing%20Multiple%20Vertex%20Arrays/article/suzanne.obj

https://github.com/OpenGLInsights/OpenGLInsightsCode/blob/master/Chapter%2026%20Indexing%20Multiple%20Vertex%20Arrays/article/bunny.obj

Just click download on the right side button


RemiD(Posted 2016) [#65]
Thanks, i also found some in the Blitz3d samples folders (good to keep in mind!)


RustyKristi(Posted 2016) [#66]
nice


Kryzon(Posted 2016) [#67]
This 2003 demo uses shaders and HDR rendering to get some impressive effects:

http://web.archive.org/web/20090223060038/http://www.daionet.gr.jp/~masa/rthdribl

Linked to web archive because the actual website seems broken.


RemiD(Posted 2016) [#68]
With a complex shape (like a humanoid), we can really see the difference between using a welded surface and a notwelded surface :
with a welded surface (=no smoothing groups, only one vertex at each position)


with a notwelded surface (=smoothing groups, several vertices may be at the same position to improve lighting/shading)


with a well modeled welded surface, it seems to work well even if the shape is complex. Good !