Custom shaders on sprites: What's the best approach?

Hey folks! I’m trying to render a large number of sprites to the screen using custom shaders, and I’m wondering how best to approach it. (OpenFL Next, by the way.)

The goal is at least 200-400 sprites arranged in a scene larger than the display resolution (user can pan to see other regions of the scene). The sprites will have custom shaders attached for lighting purposes, and ideally, be able to support arbitrary rotations. This is part of a larger HaxeFlixel game prototype, but I’m looking at OpenFL because it exposes more OpenGL (and particularly shader) features.

Here’s a screen of a scene I’m currently prototyping:

And here’s a pared-down code sample of how I got that effect:

It’s a combo of openfl-samples’s SimpleOpenGLView demo with some normal-mapping/lighting shaders from elsewhere, rendered beneath a HaxeFlixel camera. It’s pretty crude, however, and a performance hog. I’m sure I’m doing it “wrong,” but I’m unsure how to do it right. (Probably starting with not rendering each sprite per-frame with lots of overdraw.)

As I mention above, I’ve got something working that was derived from this demo. Since SimpleOpenGLView performs raw GL instructions, I was able to add my own vertex and fragment shaders, and pass the required uniforms, attributes, etc. into the renderer.

The down side here, however, is that it’s easy to do non-optimized (and non-cross-platform) stuff, since I’m bypassing OpenFL and HaxeFlixel rendering pipelines.

I think this is a similar approach to SimpleOpenGLView, above.

This approach was my initial attempt, and it was super easy to use. Just assign a shader to any sprite!

However, I soon discovered that the vertex shader this uses lacks some transform info (namely, the rotation of the sprite). At least, by default. I wasn’t sure if there was a way to override/modify that vertex shader to add this uniform (for normal-map TBN calcs).

BunnyMark seems to use a combo of Tilemap and TilemapLayer to send thousands (even tens of thousands!) of sprites around the screen. However, it seems to assume a zero rotation and no shader support.

HaxeFlixel Shaders
HaxeFlixel 4.0.0 also seems to have some shader support. However, this appears to be limited to those applied to a whole camera, not just certain sprites.

It’s possible that one or more of the above do what I’m thinking, and I just don’t realize it yet. Maybe I need to just render all my sprites to some textures, and then run shaders on those? Maybe layer some FlxCameras in HaxeFlixel?

I just wanted to ask some experts for their input on how they would approach this.

I’d like to Sprite.shader support improving soon. This will require more digging, but eventually this could work for something like this, perhaps?

I think the new “Tilemap” API is promising, I’m happy to hear if that seems a good direction? It’s obviously not finished, but per-tile effects could be an interesting feature.

I think Sprite.shader could do this, and it may even be possible already. I was having trouble figuring out how I could specify my own uniforms/etc. in the vertex shader so I could supply my own light position and sprite transform.

It’s possible Tilemap could do this, too, but I’m barely understanding how sprites render let alone fancier approaches :slight_smile:


Can you share your progress on this feature? Did you apply effects to sprite?

@hopewise, I’m unsure if you were asking me or singmajesty, but if it was me, I’m afraid I wasn’t able to make any more progress.

I believe you can use Sprite.filter = new ShaderFiler(class that extends openfl.display.Shader); on openfl 3.6.1 and lime 2.9.1 (work at least on cpp and flash target for what I know). I’m unsure of the implementation of the feature on openfl 4, last time I checked it didn’t worked.

You can see how it works, how you can build you own shader and how you can use uniform in this haxeflixel demo.

I’ll probably make soon a variation of Tilemap implementing a per Tile Shader using one or more global Shader for Tilemap (via Tilemap.filter) and shader attributes to activate or disable the shader for a specific Tile. So it will keep the one drawcall per texture process adding per Tile shader support. I think it’s feasible. Or maybe I can add uniform support for Tilemap but we will have much more drawcalls and it will also more difficult to code I guess.

Thanks Loudo, do you know how to use actuate on shaders to tween color for example? Also how to implement glowing filter using shaders? All resources I found talks about 3d, while I just need simple glowing effect for 2d sprites…

Maybe you can use Actuate onUpdate method. I don’t know how to make a glow effect with a shader, sorry.

Do you mean that I can’t change a parameter directly in a shader instance?