Texture Splatting


Suppose you have one mask, and 4 textures.

You want each texture to appear only within a certain altitude range (see array alt[5] in the code below).

You can have a 512X512 mask, and a smaller image say 128X128, it will be repeated (here 4 times).



C code

#include <stdio.h>
#include <stdlib.h>
#include "bitmap.h"

/*------------------------------------------------------------------------------
   get for percentage of color
------------------------------------------------------------------------------*/
float texture_factor(int h1, float h2, int step)
{
  float t = ((float)step - abs(h1 - (int)h2)) / (float)step;
  if     (t < 0.0f) t = 0.0f;
  else if(t > 1.0f) t = 1.0f;

  return t;
}

/*----------------------------------------------------------------------------*/
int main()
{
 //charge les images
 bitmap B[5];
        B[0].load("0.bmp"); // heightmap
        B[1].load("1.bmp");
        B[2].load("2.bmp");
        B[3].load("3.bmp");
        B[4].load("4.bmp");

 int width = B[0].getWidth();
 int height = B[0].getHeight();
 printf("width:%d height:%d\n", width, height);

 bitmap final;
        final.create(width,width);

 char n_channels = 3;
 unsigned char nbTextures = 4;

 int step = 256 / nbTextures;
 printf("step:%d\n", step);

 float texFactor;	// texture factor of each texture to blend
 int alt[5] = {0, 0, 85, 170, 256}; // took me time to get this one
 float red, green, blue; 	// final rgb at x,y

 // For each pixel
 for(unsigned short y=0; y<height; y++)
 {
    for(unsigned short x=0; x<width; x++)
    {
      //Get altitude from heightmap at x/z
      unsigned char r;
      B[0].getcolor(x,y, r,r,r); // r = g = b what a waste. 1 channel is enough

      red = green = blue = 0;
      for (unsigned char i=1; i<=nbTextures; i++) // For each texture to blend,
      {
        //if one of the images is smaller, repeat it
        int tx = x, ty = y; //where to read

        if (x >= B[i].getWidth())
        {
          unsigned short nx = (int)(x / B[i].getWidth());
          tx = x - (nx * B[i].getWidth());
          //tx = x - ((int)(x / B[i].getWidth()) * B[i].getWidth());
        }

        if (y >= B[i].getHeight())
        {
          unsigned short ny = (int)(y / B[i].getHeight());
          ty = y - (ny * B[i].getHeight());
        }

        // Read its rgb value ...
        unsigned char rx;
        unsigned char gx;
        unsigned char bx;
        B[i].getcolor(tx,ty, rx,gx,bx);

        // ... to determine texture factor of this texture depending on altitude
        texFactor = texture_factor(alt[i], r, step);

        //add to new RGB value for the pixel to be written
        red   += rx * texFactor;
        green += gx * texFactor;
        blue  += bx * texFactor;
      }

      // apply new pixel to final destination
      final.setcolor(x, y, (unsigned char)red, (unsigned char)green, (unsigned char)blue);
    }
 }

 final.save("final.bmp");

 return 0;
}