Accessing a subrect of a texture using a UV map [GLSL]

Started by
5 comments, last by Servant of the Lord 5 years, 6 months ago

I have a texture I'm reading from like this:


vec4 diffuseFrag = texture2D(DiffuseMap, fDiffuseCoord);

Sometimes, for special effects, I'd actually like to do something this:


vec4 uvFrag = texture2D(UVMap, fUVCoord);
vec4 diffuseFrag = texture2D(DiffuseMap, uvFrag.rg);

...basically, I'm using a texture's Red and Green color channels to store the frag coordinates I want to read from DiffuseMap.

My probably is, both the UV map and the Diffuse map are spritesheets with multiple images in them. This means, I'm actually wanting uvFrag.rg's (0-1) texcoord to be multiplied against the *subportion* of the texture that all four vertices of my fDiffuseCoord are referring to.

Something like: 


vec4 uvFrag = texture2D(UVMap, fUVCoord).rg;

vec4 upperLeftOfSubrect = ...;
vec4 bottomRightOfSubrect = ...;

vec4 subrectSize = (bottomRightOfSubrect - upperLeftOfSubrect);
uvFrag = upperLeftOfSubrect + (uvFrag * range);

vec4 diffuseFrag = texture2D(DiffuseMap, uvFrag.rg);

 

Where my mind is going blank is, how can I get upperLeftOfSubrect / bottomRightOfSubrect, without bloating my vertex struct further with additional attributes?
It mentally trips me up that I'll have to copy upperLeftOfSubrect / bottomRightOfSubrect into all four of my vertices... and triply annoys me because I'm already passing them in as fDiffuseCoord (just spread between different vertices).

Is there a simple solution to this that I'm missing?

Advertisement

There might be something in instancing that would easily solve this, I've never used it as I'm usually aiming for hardware that doesn't support it, so others would have to answer whether instancing can help, as my knowledge on that is next to non-existent lol! :)

Other than that just some non-hardware instancing random ideas:

  1. Don't store the top left / bottom right in each vertex, can you store a single byte index to a uniform array with this info (that is assuming the hardware supports this, some older mobile can be finicky).
  2. Have an atlas for your UV map, instead of a straight map, that way you can reference different parts of the UV map which themselves map to different parts of the diffuse map atlas. This isn't ideal as you will probably be wasting UV map space, but might be feasible in some circumstances.
  3. Store the UV coord as larger values than 0-1, (e.g. 0-16 on each axis), mod this back to 1, and use the extra info as a lookup into a uniform array as in (1).

If you are using this in effect to do poor man's instancing, by having a single byte index in (1) you could also store other info relevant to the render and increase the 'bang for your buck'.

Also if your placement within the atlas is regular (i.e. on a grid) you could use the index directly as a lookup to location without needing a uniform array.

You may not need to store coords if all your sprites are the same size - all you need is a sprite index and calc the coords off of that. Sothis way you go from four numbers to one,

I'm not using instancing. I'm using this specifically to do a special-effect for enemy deaths (and enemies can be different sizes). I think I am just trying to cram too much stuff into one general purpose shader.

Because only one or two enemies are going to be dying on-screen at one time, I'll just use a separate shader and upload the subrect as a uniform.

Thank you both!

 

28 minutes ago, Servant of the Lord said:

Because only one or two enemies are going to be dying on-screen at one time, I'll just use a separate shader and upload the subrect as a uniform.

Doh! I must have assumed you were wanting to do this lots of times because of the packing into the vertex approach, forgetting the obvious solution lol! :) 

I got my effect working. Thanks gents! ?

https://twitter.com/JaminGrey/status/1053107844474646528

This topic is closed to new replies.

Advertisement