Entity Amount Visible

Blitz3D Forums/Blitz3D Beginners Area/Entity Amount Visible

Rob the Great(Posted 2011) [#1]
Hey all, I have a question.

I'm done designing my own sun flare system, and it's beautiful except that I'm having some slow down issues when I check to see if there is an object blocking the camera's view of the sun. I can do a single EntityVisiable(camera,sun) without a problem, but what I'm trying to do is check and see how much of the sun is visible (e.g. only the upper half) and adjust flare alpha values based on that. Otherwise, there is visible flare on/off snapping that looks horrible.

My system to do so involves creating a pivot and gradually moving the pivot from the bottom edge of the sun to the top edge and stopping when the pivot can see the camera. In other words, pseudo might look like:
Local piv = CreatePivot()
Local toppiv = CreatePivot()
PositionEntity piv,EntityX(sun),EntityY(sun) - 100,EntityZ(sun)
PositionEntity toppiv,EntityX(sun),EntityY(sun) + 100,EntityZ(sun)
Local visible# = 0.0
While Not visible
   PointEntity piv,toppiv
   MoveEntity piv,0,1,0
   If EntityVisible(camera,piv)
      visible# = EntityDistance(piv,toppiv)
   EndIf
Wend
Return visible# ;with additional math to make it in the range of 0-1

You can see how this is a very poor system regarding speed, even if I increase the amount of movement per loop.

Is there a better approach or a library to do this kind of thing? Basically, I just want to know how much of a given entity is visible to the camera, but this may not be possible under normal situations.

EDIT: I should note that I'm only using this for the level and knowing when the sun sets. Characters, trees, objects, ect. are not checked in this routine.

Last edited 2011


Kryzon(Posted 2011) [#2]
It's a matter of testing methods until you find the most performant one.
Here's another way:

- Create a camera with a small viewport. Attach it to your main game camera. This small viewport should have the same ratio as your screen so you're looking at the same content, but smaller so it's faster to sample it (something in the order of 32 x 18 when on a 16:9 screen).
- Create a brush that's a flat magenta (255,0,255. It's a perfect, rare color you almost never get to see in the middle of a game), and another brush that's flat black.

- Every frame, color the sun with the magenta brush. Color all other object's with the black brush.
- Disable the game camera, enable the small-viewported camera. Renderworld and use CopyRect to paste the backbuffer to a 32 x 18 image.
- Hide all objects except the sun. Renderworld.
- Run a loop that samples the backbuffer (which contains the entire sun, with all objects hidden), and count how many magenta pixels there are. In this same loop sample the grabbed image (which contains the sun potentialy occluded by any object) and count how many magenta pixels there are as well.
- Compare the two amount of magenta pixels: Scene_With_Objects / Float(Scene_With_Just_Sun).
- The result is your flare strength. If the sun is occluded by any object, it should have a low amount of magenta pixels in the 'scene with objects' and potentially a high amount of magenta pixels in the 'scene with just the sun'. This would give a floating value between 0.0 ~ 1.0.
"Potentially", because the sun can be at the screen corner and have few magenta pixels anyway, but then the flares will still be colored correctly.
Just be careful not to divide by zero in case the sun is off-screen. In this situation, use a hardcoded value of '1' for the divisor or even better - don't render the small viewports and go through this process at all.

- Restore each object's visibility* and original material. Disable the small-viewport camera and enable the game camera.
- Render the game screen.

* You can speed things up by parenting everything except the sun to a single, "root" pivot and just hiding the pivot.

Last edited 2011


Rob the Great(Posted 2011) [#3]
Wow, I definitely like this approach. I knew EntityVisible was slow, but glancing over this, this looks brilliant. Let me try it out and see how it works. It's got to beat the 40 some millisecs my function was taking.


Kryzon(Posted 2011) [#4]
Hi Rob. I just realized you can further optimize this.

No other object in your game is likely to be magenta, so you can skip the loop that colors all other objects with black.
You can save a few cycles by just coloring the sun back and forth and checking for its visible pixels.
Objects will still occlude it regardless if they're black or not.

Last edited 2011


Rob the Great(Posted 2011) [#5]
Too late. I've already got a system set from your example. Waiting on youtube, stay tuned.


Kryzon(Posted 2011) [#6]
Haha =D
Looking forward to.


Rob the Great(Posted 2011) [#7]
Alright, here's the verdict. My function was clocking in somewhere between 5-40 millisecs in certain situations. Sometimes it would run great, other times it would really slow the game down.

Implementing your method, the time taken to perform all of the sunflare calculations is unmeasurable (< 1 millisecond), and here's a youtube video clip to show the final result. I'm still going to touch up the effect (it's a little snappy, easily fixed), and then I'm moving on to something else.

If you want a code sample, I can provide what I have, but it's not able to run by itself since I'm using types and other things not related to this topic. If you want it, let me know and I'll post the function that did what you were talking about.

Thanks for the help!

Youtube link:
http://www.youtube.com/watch?v=0MwWRblmeic


Kryzon(Posted 2011) [#8]
Wow, you got a sweet engine going on! you should make a formal post in the Blitz Showcase.
Did you make all the graphics? what are you using for the sky?

I agree it might be a little snappy - I'd attribute this to the size of the buffer. A bigger buffer should have a smoother variance.

Oh, the method is not mine. Who thought of this method were the engineers at nVidia, and it has been implemented in hardware so with modern GPUs it's really fast.
It's called "Occlusion Query", such that you render an object, turn on the feature, then render the occluders and ask the GPU how many pixels pass (i.e: are visible).
This way you can tell if an object is visible when being inside the camera's view while having potential stuff covering it completely.


Rob the Great(Posted 2011) [#9]
Huh, I'm surprised I've never heard of this technique before.


Did you make all the graphics?


Ha! I wish. The character models (link, gorons, ect.) are a rip from Twilight Princess, and I just converted the 3ds files into b3d files. My character modelling is about as good as an average second grader's painting.

I did, however, have to animate everything. The models did not come with animation, and that was a b**** to do. It's still not even done yet.

For the sky, I'm using a custom particle system for individual clouds. They are just cloud sprites using the additive blend mode (I just recently discovered this, I love it), all parented to a pivot which is positioned at the camera's location and rotates on its own axis for wind. There is a skybox behind the particle clouds, but it varies based upon the time of day, the weather the program randomly chooses, and the wind. To be technical, there's actually three skyboxes: The first is for daylight clouds or a blue sky (depending on weather), the second and third are being drawn behind the first and are used for dawn/dusk. When dawn/dusk approaches, the first day skybox changes its alpha until it's visible/invisible (based on dawn or dusk). During night, the alpha of the dusk skybox will then decrease, revealing yet another particle system for stars. They are simple sprites (white dot on a black background), and since the night sky is black, there's no need to have an alpha channel or an additive blend mode. The stars twinkle at night, the music changes with the scene, and it's set up where it's easy to adjust how quickly the hours pass in the game. It sounds complex, but it's really not that bad.

Just to avoid confusion, I'm using artificial sprites (found it in the archives somewhere), not Blitz's native sprites. Those had a lot of problems in my game.