Download

Any ideas for optimizing "bullet hell" 2d projectiles in UDK? Particles, quads

Hey guys, this is somewhat related to my old thread about creating the lightest type of Actor possible.

The original setup for doing 2d sprite bullets was that each bullet is an Actor with a ParticleSystemComponent.
The reasoning there was that Actors are easy to manipulate, and SpriteComponent doesn’t do alpha blending and cannot rotate.

This lags quite a bit when you get up to about 500-600 bullets in a complex scene, so I’ve decided to try rewriting the entire setup, making it so I don’t use an Actor for each projectile, but instead have a single Actor and a fast pool of reusable components.

Here’s what I’ve tried just for preliminary testing with a single “Bullet Manager” actor that spawns 1000 components of various types, testing each type separately.

  • ParticleSystemComponent lags quite a bit on its own, I get something like a x2 performance boost at best when all the components are linked to a single Actor, there is still strong lag just from the particles being present
  • DrawQuadComponent while promising seems to not render anything, even if rotated and unhidden
  • StaticMeshComponent is unfortunately very laggy, even with lighting and shadows disabled and a 2 triangle quad mesh, performing worse than ParticleSystemComponent does, and I haven’t found a way to activate instancing for it

Overall it doesn’t look so great but I’m open to ideas, am especially curious why StaticMeshComponent performs so poorly, and if maybe ParticleSystemComponent could be used to manage more than one bullet like I do now.
Any ideas or thoughts are very welcome.

function Init()
{
	local int i;	
	SetCollision(false, false, true);
	SetPhysics(PHYS_None);

	for(i=0; i<1000; i++)
	{
		part4 = new(self) class'DrawQuadComponent';
		part4.Texture = Texture2D'variator.bullet18';
		part4.SetDepthPriorityGroup(SDPG_Foreground);
		part4.sethidden(false);
		part4.setrotation(rot(25000,25000,10));
		part4.setscale(0.5f);
		AttachComponent(part4);

		part = new(self) class'ParticleSystemComponent';	
		part.SetTemplate(ParticleSystem'variator.effects.EnemyBullet4');
		part.SetDepthPriorityGroup(SDPG_Foreground);			
		part.MaxLightEnvironmentPooledReuses = 10000;
		AttachComponent(part);
		
		part2 = new(self) class'StaticMeshComponent';	
		part2.SetStaticMesh(StaticMesh'EditorMeshes.TexPropPlane');
		part2.SetActorCollision(false, false);
		part2.bCastDynamicShadow = false;
		part2.CastShadow = false;		
		part2.bAcceptsDynamicDominantLightShadows = false;
		part2.setrotation(rot(16384,16384,16384));
		AttachComponent(part2);
	}
}

you could also use static mesh components. Oh sorry i see that you are. i be interesed in trying to come up with something, as long as it better then what we are running now.

Edit Are you doing this in the ship game you are making?

Yeah, I am looking at static mesh components right now the most.
I am curious if they can be instanced without too much trouble, and also if there’s more ways to make them more performant, I didn’t think 1000-1500 separate quads would have such a performance impact.

And yep it’s for the shoot 'em up.

we used the way udk was doing theirs with added stuff to that to get what we were after. which was the projectile code using a static mesh as the seen actor flying in the air with lods. closer to you better looking the static mesh is.

Example what we did at like say 0 to 50 feet in front of you we have solid round ball. Out at 50 to 250 it not so round, 250 out its a square box( 6 sides )only.

Oh I know about LOD, it shouldn’t be a factor with these quads, they’re just 2 polygons. Maybe lighting or shadows could be a factor if I missed out on disabling something.

If you haven’t tried it yet, you should use the Gameplay Profiler tool to figure out what the game is spending so much time on.

Yes, i would do this before going too deep on a custom implementation. Actors can be very lightweight providing you disable certain features on them. They are after all simply descendants of objects. I have 100’s of thousands on my map at any one time.

It is usually ticking, physics, and (in network games) replication that cause performance cost.

Yes, i would do as @Nathaniel3W suggests before going too deep on a custom implementation. Actors can be very lightweight providing you disable certain features on them. They are after all simply descendants of objects. I have 100’s of thousands on my map at any one time.

It is usually ticking, physics, and (in network games) replication that cause performance cost.

@ciox which has better performance a 1000 particles or a 1000 static meshs?

Are you after something like this?
https://www.youtube.com/watch?v=h6VwfQlvr3k