Materials on Instanced Static Meshes - Starfields

I posted a question on answerhub about an issue I’m having with rotations on my instanced static meshes. First of all, instanced static mesh is a lot to type so I’m going to call it ISM from here on. There’s a lot of stuff I don’t understand so was hoping to spark a conversation here.

I’m basically spawning a starfield (a volume of dots) and I want to be able to fly through it. I want the stars to always face the camera. So far I’ve tried the following:

Billboards
Pros:

  • Can set size in screen space so they stay the same size regardless of distance to camera
  • They always face the camera

Cons:

  • Draw calls

ISM
Pros

  • 1 draw call

Cons

  • Can’t easily make them face the camera
  • Need to use camera depth fade to prevent them from getting too close to camera

The first thing people seem to recommend is having the ISM rotate to face the camera every frame. In my opinion I may as well go back to billboards instead of this, the draw call is probably less expensive in terms of CPU than the tick and rotation calculation AND I’d get rid of the need to use depth fade in the process. I’d be happy to be proven wrong here.

Doing it in the material
Another alternative I’ve been experimenting with is performing the rotation in the material via the node:
43d311db136f215d8d6d4cd368389a5f28eececd.jpeg
Which incidentally looks like someone forgot to take some test code out of.

The TLDR version of this question is: How do I get the world space location of an ISM from within a shader? The goal is to rotate it using its world space location as the pivot to face the camera.

I am not much of a shader programmer. I searched the documentation and source for this node for a long time and just realized that I need to double click it to open it up. I’m trying to use this to make the ISM materials apply the rotation to face the camera using world offset. The problem I’m having is that the ISMs feel like their positions are reported in a local space offset from the original instance. I see in InstancedStaticMesh.cpp that you can specify


bWorldSpace 

when you call


GetInstanceTransform()

. But I don’t know how the actor position is queried from within a shader.

If anyone can shed some light here I’d really appreciate it.

I’ve detailed some of my work on stars and nebulas.

Nice blogpost :wink:

Just a note on ISM: If you are targeting mobile, non-Metal phones, it will do a draw call per instance as the hardware has no support, so we emulate it.

Good to know. What does UE4 use to do instancing? I thought that static/dynamic batching was compatible with all GPUs, but I’m not an engine programmer :slight_smile:

On mobile, non-Metal gpu’s (so Android & older iOS devices) it will set some shader constants, then do a draw call per instance, which is expensive; on Metal & PC/Mac/Console, it will issue one draw call for all the instances.

Out of interest, why not do this in a Particle System inside an Initial Location module? Or are you spawning them at specific points based on some maths?

Each Emitter is One Draw Call, and you still have the same control you seem to have in that blueprint (including Seed functionality). The sprites also face the camera on their own auto-magically. Definitely cheaper than doing all of that in a Blueprint.