Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Simple ? question about handling multiple textures  (Read 4677 times)

0 Members and 1 Guest are viewing this topic.

SpacedCowboy

  • Newbie
  • *
  • Posts: 16
    • View Profile
    • Email
Simple ? question about handling multiple textures
« on: December 02, 2021, 12:27:16 am »
I have a much-larger-than-the-screen map, on which is being tiled many layers of individually scaled textures. So for one of these scaled textures, it looks a little like the below (where the textures are actually drawn next to each other in the map, but that looks odd in ascii :)

┌──────────────────────────┐                                  
│                          │                                  
│                          │                                  
│      Map-sized mask      │─┐                                
│                          │ │                                
│                          │ │                                
└──────────────────────────┘ │                                
                             │                                
                             │     ┌──────────────────────────┐
┌───────────┐       Scaled   │     │┌ ─ ─   ┌ ─ ─    ┌ ─ ─    │
│           │      Texture   │     │     │       │        │   │
│Texture at │       ┌────┐   │     ││       │        │        │
│ full size │ ────▶ │    │ ──┴─▶   │ ─ ─ ┘   ─ ─ ┘    ─ ─ ┘   │
│           │       │    │         │           Map            │
└───────────┘       └────┘         └──────────────────────────┘                              
 

So I was reading up on how shaders work, since they're new to me. It seems I need two sets of co-ordinate space (one for the global mask, one for the scaled-down texture), so I'm passing in enough uniforms to work that out.

The shader code looks like:
uniform sampler2D texture;              // Scaled-down texture to tile over the map
uniform sampler2D mask;                 // Map-sized global mask
uniform float maskX;                    // x pixel of where to pull the mask data from
uniform float maskY;                    // y pixel of where to pull the mask data from
uniform float maskW;                    // total mask width in pixels
uniform float maskH;                    // total mask height in pixels
uniform float scaledW;                  // width of the scaled-down texture in pixels
uniform float scaledH;                  // height of the scaled-down texture in pixels

void main()
        {
        // lookup the pixel in the mask texture
        float mx        = maskX / maskW + gl_TexCoord[0].x * scaledW / maskW;
        float my        = maskY / maskH + gl_TexCoord[0].y * scaledH / maskH;
        vec4 maskPixel  = texture2D(mask, vec2(mx, my));
       
        // lookup the pixel in the drawing texture
        vec4 pixel = texture2D(texture, gl_TexCoord[0].xy);

        // set it to scaled:rgb, mask:alpha
        gl_FragColor = vec4(pixel.rgb, maskPixel.a);
        }
 

.. and the drawing code looks like:

        sf::Sprite scaledSprite;
        scaledSprite.setTexture(_scaled->getTexture());
       
        int x = 0;
        int y = 0;
        int w = scaledW;
        int h = scaledH;

        while (y < maskH)
                {
                h = (y + scaledH > maskH) ? maskH - y : scaledH;
                while (x < maskW)
                        {
                        w = (x + scaledW > maskW) ? maskW - x : scaledH;
                       
                        scaledSprite.setPosition(x, y);
                       
                        sf::Shader *shader = [[Shaders sharedInstance] paintWithMaskShader];
                        shader->setUniform("texture", sf::Shader::CurrentTexture);
                        shader->setUniform("mask", _mask->getTexture());
                        shader->setUniform("maskX", x);
                        shader->setUniform("maskY", y);
                        shader->setUniform("maskW", maskW);
                        shader->setUniform("maskH", maskH);
                        shader->setUniform("scaledW", scaledW);
                        shader->setUniform("scaledH", scaledH);
                        _result->draw(scaledSprite, shader);
                        x += w;
                        }
                x = 0;
                y += h;
                }
 

So basically just iterating over the map-sized RenderTexture '_result', using the shader to tile the scaled-down version of a texture, modulated by the corresponding area in the map-sized mask. the problem is that I'm not seeing the alpha value (supposed to come from the mask) work correctly, it's always the same value across the image.

I created a mask texture by calling clear(0,0,0,64) and then drawing a filled circle at (70,70) with colour (255,255,255,255). If I dump that texture to a file, it looks totally reasonable (see attached, scaled down) so when I apply it, I'd expect a circle of the drawn texture to be brighter than the surrounds, but they're all being set to alpha 0.25 (and if I change the (0,0,0,64) color to (0,0,0,128) it's drawn at intensity 0.5)

So, the shader is providing data, the texture is there, but it's not mapping in the correct alpha co-ordinates. I thought the texture co-ords were supposed to range from 0...1, so the calculation for the mask co-ords (based on the scaled-down texture being drawn) is:
  • Figure out the offset in the global map (mx = maskX / maskW) in 0...1 co-ords
  • Take the fraction across the scaled image, and multiply by the ratio (scaledWidth / maskWidth)
  • Add them together

The idea was to get 0...1 co-ords in the mask texture, but clearly I'm not doing that. Does anyone have any idea what I'm doing wrong ?

SpacedCowboy

  • Newbie
  • *
  • Posts: 16
    • View Profile
    • Email
Re: Simple ? question about handling multiple textures
« Reply #1 on: December 02, 2021, 02:41:22 am »
So I got this working in the end by changing the code around a bit. I now render a section of the global mask to an intermediate RenderTexture of the same size as the scaled-down texture.

There aren't any calculations to do wrt locating the global co-ordinate space in that instance, so it's relatively straightforward to get my global mask to tile correctly with the shrunk-down textures - at least once I'd figured out that the default render-state setting was add-alpha...

So now, with a shrunk-down texture I can render a global mask, and it looks like the attached :) I'm still a little curious as to where I was going wrong, but at least it's not a blocker any more :)