I have a simple pixel shader that replaces one color with another. Before calling the shader, I have to set two parameters. One parameter is the color to replace the second parameter is the color to replace it with. Works fine for a single sprite. Let’s say I’m drawing four sprites. Three of the sprites I want to replace blue with pink. One of the sprites I want to replace black with gray. This will not work. Below is the pseudo code. Is it possible to do what I’m trying?
spritebatch.begin setting effect and SpriteSortMode.BackToFront
effect.parameter.setvalue of blue.
effect.parameter.setvalue of pink.
draw sprite1
effect.parameter.setvalue of blue.
effect.parameter.setvalue of pink
draw sprite2
effect.parameter.setvalue of black.
effect.parameter.setvalue of gray.
draw sprite3
effect.parameter.setvalue of blue.
effect.parameter.setvalue of pink.
draw sprite4
spritebatch.end
I can do what I need if I do a bunch of spritebatch begin and end. I’m trying to avoid that because in future because I may draw a lot more sprites and I need the sprites sorted by the layer.
I believe the problem is that using SpriteSortMode.BackToFront results in deferral of the actual drawing until spriteBatch.End() is called, so the effect will apply to all sprites at once using whatever its parameters were last set to.
Try setting the SpriteSortMode to Immediate. That should cause each sprite to draw immediately when Draw() is called. The downside is that sorting is ignored. You’ll have to manually sort by calling Draw in the desired order.
Also, if you know you’re going to have multiple sprites with the same effect values, it might be more efficient to group them into their own SpriteBatches and use a deferred SpriteSortMode, only changing the parameters of the effect once before drawing the group.
So you need per instance data for your sprites. Instance data for sprites usually goes into the vertex buffer. The standard SpriteBatch vertex buffer format only has vertex position, texture coordinate and color. Unless you create a custom sprite solution, you’re stuck with those.
Color is the only field you could potentially use for your porpuse. Doing color replacement sounds like you wouldn’t need the standard sprite color. That only gives you one color though, while you need two. You could work around that by encoding two color indices instead of an actual color. In the shader you then use those indices to lookup the actual color from a color array. This assumes that you only need a limited number of colors.
Those are now hardcoded in the shader, later you could upload this array from the CPU.
2.) Encode the color indices into the sprite color
Lets say we want to replace green with blue, we have to put index 1 (green) and index 2 (blue) into the sprite color, then draw the sprite using that color.
Color spriteCol = new Color(1, 2, 0); // third value doesn't matter, we don't need it
spriteBatch.Draw(texture, pos, spriteCol);
3.) Extracat indices in pixel shader and lookup color values
int sourceIndex = (int)(input.Color.r * 255);
int destinationIndex = (int)(input.Color.g * 255);
float3 sourceColor = Colors[sourceIndex];
float3 destinationColor = Colors[destinationIndex];