How to glow/highlight only selected faces on a mesh

Hi guys, need a little help here. This is my use case: I have a tiled terrain which has 1 material. User clicks a button signalling intention to place an object on terrain and visual should indicate available tiles for object placement. This is a fairly common use-case even in 2d or isometric games, cf, pics below.


My current implementation was to create multiple instances of a simple square disc with a yellow material and place them at selected coordinates. This informs the user where he can place objects on.

this.disc0 = BABYLON.MeshBuilder.CreateDisc("super disc0", {radius:1.4/2,tessellation: 4}, this.scene);
this.disc0.isPickable = false;
this.disc0.position.y = 999;
this.disc0.setMaterialByID("yellowmat_with_alpha");

Once the user action is completed/aborted, the instanced discs are disposed. The problem I’m facing is a perf hit when the scene has to create multiple such instances. In the pics above, the number of yellow tiles created eveytime the user initiates object placement is around 800. The fps takes a significant hit and I find perceptible lag navigating the canvas. Granted, this is an edge use case.

My question is: how can I highlight/glow selected faces on, say, a subdivide plane/sphere w/o taking a perf hit. I’ve tried glow: https://www.babylonjs-playground.com/#2Q4S2S#47 but this only works with multimaterials. I can’t seem to make it work with only submeshes and a single material. Any thoughts ?

Happy to submit a PR if needed, I see this as a fairly common use case for most game devs.

Glow relies on emissive values so maybe you could rely on an emissive texture and UVs ?

3 Likes

I’ve found the glow effect to be not terribly performative, I think it builds an additional scene for the overlay?
Maybe you could use the vertices of the picked facets to build your own separate cursor sort of mesh offset vertically?
Looks great btw.

2 Likes

Correct me if I’m wrong, but afaik its only possible to have multiple textures applied to individual UVs for meshes created with the MeshBuilder only ? If this isn’t true anymore, pls point me to the relevant doc, thks. Bjs development is a little hard to keep up with…

Well, I dunno. I mean, if just creating multiple mesh instances dropped the fps, I’m not sure that creating a separate mesh of picked facets will be faster. All I really need is a color overlay which is so simple to achieve in 2D but seems a lot of work in 3D. I managed to get glow to work with multimaterial on a sphere with no fps hit: https://www.babylonjs-playground.com/#2Q4S2S#48
Just gotta figure out a way to populate the submeshes array fast enuff every single mouse click/mouseover.

Hi, you could update the indices of a subdivided mesh to only render the faces you want, like in the example below where random squares are chosen:

https://playground.babylonjs.com/#ARL8SD

1 Like

that is a lot of draw calls, Maybe first merge all the meshes that are static?

Then what about a solid particle system to show the highlight squares? Or even a custom shader that changes the tiles color if placeable instead of creating new instances?

1 Like

@withADoveInOneHand, @Gijs: By popular demand, I modified Gijs’s PG: https://playground.babylonjs.com/#ARL8SD#1 and it works great with the skull. So, I injected similar codes into mine. And I got …

fps3

a predictably worst result. fps drop and a momentary freeze upon button click. Ignore the visuals, just look at the top right stats. I do have other processes (comms, realtime etc) running in a dev environment.

@Pryme8: highfive All excellent points and exactly the same tots I had. All the foliage are instances, I don’t think they can be merged. I do have to take a closer look at the number of draw calls. dunno if I have the time, since optimization is usually later in the dev cycle. Sps, submeshes, multimaterials are what I’m looking at right now. I MUST resolve this perf issue.

Will continue to update this thread as my tests go on. Thanks all for chiming in with your thoughts.

Oh yeah, 5000 meshes is way too many I think.

See what you can combine, like you said, multi materials could help with that.
Just take all the facets you can and throw them together in a single mesh. I’d want closer to 500 or less for sure.

You don’t want the meshes to have too many facets, but you also don’t want 5000 simple individual meshes; they are all iterated through every frame as far as I know.

1 Like

How good are you at custom shaders?

Maybe a CustomMaterial and then on your model buffers add a value for if they are buildable on or not.

then when you go into building mode you flip a Uniform on the CustomMaterial and all the meshes that have the buildable flag in their buffer have their Normals that point Up turn into yellow?

2 Likes

I made a custom texture that draws tiles, which can then be used as a projection texture on a modded SpotLight:

https://www.babylonjs-playground.com/#JC3Q3M#2

1 Like

@withADoveInOneHand the number of meshes is misleading, I think I have a couple of thousand of empties in it. Plus I have found a way that doesn’t require generating multiple meshes.

@Pryme8 Good idea but the terrain is using PBRCustomMaterial alr with normals from atlas.

@Gijs you are awesome ! But I found a method that doesn’t need spotlight projection.

My best result so far:

Ignore the visuals, just see the top right. Before, from the first post: stats were ~30fps, 3521 meshes and 113 drawcalls. With this, there is no fps hit, adds 1 mesh and some more draw calls. This is from multimaterials + submeshes. I think its good enuff. Will post a PG once I get the codes cleaned up and figure out which bjs resource model is best to demo this.

Cheers!

Maybe you could turn off occlusion somehow? I don’t know what an empty mesh is, I think it’s still iterating those every frame though so 90,000 unnecessary iterations every second.
Sounds like you are heading in the right direction though, could have a very nice engine on your hands.

1 Like

Found another even more efficient method than multimaterials and submeshes: https://www.babylonjs-playground.com/#NMU4ZM#12

@withADoveInOneHand: I’ll look at optimizations later. Engine is far from done, my todo will occupy me for another couple of yrs. :slight_smile:

Hope this thread inspires anyone with the same problem. Thanks everyone who chimed in, cheers!

5 Likes

Hi PL and others. My thought… is/was particles. I’ll assume that your terrain is flat. All your markers… are square, yes? So are the “quads” used for our standard particleSystem.

https://playground.babylonjs.com/#1PQT7P#28

BJS particleSystems (ps) allow easily-installable custom functions. You can see THREE of these custom functions… in lines 18-59. The first two are set core-default, but the third one… the update function… has been modified by me. Essentially, I turned off aging, color-changes, position-changing, and z-spin angle. Objective: After a particle is spawned, I want it to sit still, unchanged, and not age/fade/die.

In lines 86-88, THAT is how/where the three custom PS funcs… are/can-be installed.

The hope… here… was to use phaseLock’s “list of available grid-cells”… and my_startPositionFunction… to place each particle on phaselock’s terrain… all facing the sky.

But, I have some problems with billboarding, and I can’t fig how to make my particles non-alpha/transparent, yet. (I’m getting old… and I forget things that I once knew how to do).

The big issue… line 80… activate it… and it seems to kill the PS… somehow. AFTER I get billboardMode turned off… lines 121 and 122 SHOULD take-over the particle directions. AND/OR… I can re-activate line 86… getting full power over particle directions (aiming them all upwards). THEN… I or phaselock can do a complete re-code of my_startPositionFunction… one that ignores emitBox settings and randomizing, and instead… iterates (one particle per run) thru phaselock’s list of available lots, and places a particle of a certain size… on each available lot. :slight_smile:

It might be wise to use .manualEmitCount instead of .emitRate, and use .manualEmitCount = availableLots.length… so we don’t produce more particles than needed.

Anyway, I wanted to show the experiment, and ask core-folk if THEY think… .isBillboardBased (line 80) has a problem/bug. Activate it, and the particles seem to never emit, though I have not done any deep investigations, yet. They might be emitting… just invisible… or something.

Ok, that’s all I have… except… how about a ps with a customUpdate func… that causes sparkly particles… “sparticles”. Pretty! :slight_smile: https://www.babylonjs-playground.com/#1NXKLI#19 kbye.

1 Like

I still think a custom shader is going to be your most performant solution.

you could just copy and past a compiled version of the PBR fragment shader and manipulate it to accommodate the method I mentioned.

1 Like

@Wingnut particles were in my thoughts too, but now that I’ve used custom mesh, I will reserve particles for the game’s vfx. You are the particle expert, I will need you then! :smiley:

@Pryme8 Agreed, but I wanted to do more on the custom mesh. So I give you, custom mesh with custom material. Fragment shader adapted from bjs grid material. :))

no fps hit, rawr!!

7 Likes

Boom good job!

Gotta love it when you work things out.

1 Like

I want to try it now :smiley:

1 Like

Good job!

1 Like