Making an interactive star field

Hi @Modanung ,

Finally, I made one StaticModel for each star.
Each star is facing the center of the scene (I struggled few days for that!):


But, as you told me, billboard would be easier (in fact, the stars would be facing the camera the whole time!).
But does ray cast works on billboard?
It seems tha @cadaver tells it is possible:

Is there any sample for ray cast on a billboard?

Regards,

Did you manage to get it working with static models?

Should be exactly the same as raycast against any other drawable (for sure navigation, crowd navigation and decals samples use raycast).
And if You’d prefer to use static model instead of billboard, why use circles and not spheres with LOD (and maybe static model group)?

1 Like

About that…

Because I have in mind that a sphere is more CPU-consuming than a 12 edges trifan circle but I may be wrong…
I may draw thousands of stars (maybe 1,600 or up to 5,000, even 120,000 if I can) on a mobile phone. I really want to optimize my code.
This is why I made one .mdl with the whole stars in it at the begining.
This is why I prefer a circle to a sphere (but is it the right choice?).
The questions are:

  • are thousands of billboard items less CPU-consuming than thousands of StaticObject as @Modanung said: “you might as well use billboards instead of spheres for maximum performance”
  • is a circle less CPU-consuming than a sphere?
  • is a circle facing the center less CPU-consuming than a circle facing the camera (when the camera rotate)?
  • is a sphere less CPU-consuming than a circle facing the camere when the camera rotate?

I don’t really need LOD as all the stars are on a sphere at equal distance to the camera (Is LOD only for choosing an object depending on distance?).
The camera is in the center of the Scene and all the stars are at the same distance. To simulate the magnitude, I can use either the diameter of the circle (or the sphere) and the brightness of the color.
I was thinking about using a 18 edges trifan circle for Sirius (which is the brightest star), 12 edges for the 60 brightest stars and 8 edges for the others…

I could draw the stars, I haven’t tried Raycast already…

I actually wonder why you not just give it a try and fire a ray through you scene and see if it works :wink:

…looking at the code, BillboardSet implements its own ProcessRayQuery and it should work as intended,…(never used it though)

Use something like this:

and call it like this:

     auto* ui = GetSubsystem<UI>();
     IntVector2 pos = ui->GetCursorPosition();
    Vector3 hitpos; 
    Drawable* hitObj;
    if (RayCast(pos,1000000.0f,hitpos,hitObj)) {
      // do something with hitobj 
   }
1 Like

I don’t know how well would billboards perform with this numbers.
Assuming that camera is not static, spheres may be a better choice then circles, because You will have to rotate every circle to face the camera and probably You’ll loose performance gained from lower number of polys.
As for Your questions, the best way to find out which setup works best would be to simply compare them, especially that there is not so many options and it would take only few lines of code to switch between billboards, circles and spheres (keep in mind that there is static model group component).

Ever thought about quad with custom shader? You can do a lot of interesting things there.

Well, I tried a BillboardSet using this png image:


This is the result:

I guess (or I hope) the BillboradSet will offer a good performance.
But: how I use the transparency of the .png image?
Is it possible to get the billboard item at same size whatever the distance?
This is my code (sorry, C#):

        private void CreateBillboardSet(Scene scene)
        {
            var img = ResourceCache.GetImage("Images/glowingstar.png");
            var material = Material.FromImage(img);
            Node nodeBBS = scene.CreateChild();
            var bbs = nodeBBS.GetOrCreateComponent<BillboardSet>();
            bbs.NumBillboards = (uint)200;
            bbs.Sorted = true;
            bbs.Material = material;
            uint i = 0;
            i++; AddStarItem(bbs,i, -0.126f, 0.473f, -1.939f, -75.824f, 104.961f, 0.155f);
            i++; AddStarItem(bbs,i, -1.568f, -0.706f, 1.022f, 30.736f, 204.234f, 0.138f);
            i++; AddStarItem(bbs,i, -0.748f, -1.268f, -1.354f, -42.594f, 239.479f, 0.137f);
            i++; AddStarItem(bbs,i, 0.250f, -0.914f, 1.761f, 61.733f, 285.316f, 0.135f);
            i++; AddStarItem(bbs,i, 0.261f, 1.824f, 0.777f, 22.864f, 81.858f, 0.134f);
            //etc
            bbs.Commit();
        }

nearly done with that:

material.AlphaToCoverage= true;

stars are not glowing though…

Did you know you can browse the source of the engine? To find out the capabilities of a BillboardSet have a look at BillboardSet.h. There you will find:

void SetFixedScreenSize(bool enable);

To make your stars glow simply use an image of a glowing star, or add a bloom post-processing effect.

I am currently using a image of a glowing star.

I added useAlpha:true to the Material.FromImage(img, useAlpha:true) but it did not change the result. I wonder if the ResourceCache.GetImage() loads the alpha :thinking:

I tried bbs.FixedScreenSize = true; but that made all the stars disappear.

        private void CreateBillboardSet(Scene scene)
        {
      
            var img = ResourceCache.GetImage("Images/glowingstar.png"); //is alpha loaded?
            var material = Material.FromImage(img, useAlpha: true); // not enough :-(
                
            material.AlphaToCoverage= true;
            Node nodeBBS = scene.CreateChild();
            var bbs = nodeBBS.GetOrCreateComponent<BillboardSet>();
            
            bbs.NumBillboards = (uint)200;
            bbs.Sorted = true;
            bbs.Material = material;
            bbs.FixedScreenSize = true;
            uint i = 0;
            i++; AddStarItem(bbs,i, -0.126f, 0.473f, -1.939f, -75.824f, 104.961f, 0.155f);
            i++; AddStarItem(bbs,i, -1.568f, -0.706f, 1.022f, 30.736f, 204.234f, 0.138f);
            i++; AddStarItem(bbs,i, -0.748f, -1.268f, -1.354f, -42.594f, 239.479f, 0.137f);
            i++; AddStarItem(bbs,i, 0.250f, -0.914f, 1.761f, 61.733f, 285.316f, 0.135f);
            i++; AddStarItem(bbs,i, 0.261f, 1.824f, 0.777f, 22.864f, 81.858f, 0.134f);
            //I will write better code...
            bbs.Commit();
        }
        private void AddStarItem(BillboardSet bbs, uint i, Single x, Single y, Single z, Single r1, Single r2, Single radius)
        {
            var bbi = bbs.GetBillboardSafe(i-1);
            bbi.Position = new Vector3(x, y, -z);
            bbi.Size = 0.1f * Vector2.One;
            //bbi.Color = Color.White;
            bbi.Enabled = true;
        }

Have you tried a material that uses an alpha technique?

Well, I use a png image with alpha:


I use alpha when making the material from image and I set AlphaToCoverage to true.
What else should I do?

            var img = ResourceCache.GetImage("Images/glowingstar.png");
            var material = Material.FromImage(img, useAlpha: true);
            material.AlphaToCoverage= true;

If you save the image when you load it and then open that that should help you determine if it loaded the transparency. You could also print the material’s techniques to ensure it is actually one with alpha.

I looked at some pixels of the image img. It seems that Alpha is loaded:
(40,40) A=0 R=0 G=0 B=0
(120,120) A=0.302 R=1 G=1 B=1
(256,256) A=1 R=1 G=1 B=1
so the issue seems to be there:

var material = Material.FromImage(img, useAlpha: true);

Indeed the issue seems to be that you are not using Urho3D but UrhoSharp.

you are maybe right.
I have tried to set the ClearColor to blue:

viewPort.SetClearColor(Color.Blue);

and I added a green box inside my billboardset and here is the result:

Around the glowing stars, the alpha is zero and we can see the green box, but as soon the alpha is different from zero, the light does not come through…

I expect this is because FromImage with useAlpha set to true outputs a material using an alpha mask.

Well, this gives the same result:

            var material = Material.FromImage(img);//, useAlpha: true);
            material.AlphaToCoverage= true;

Anyway, I give up, the glowing effect will be for the next version.
@Modanung, @SirNate0, Thank you for your help.

That maybe a solution I will try later. Thank you.

I will try that next week, thank you.