2
votes

I would like to create a texture to apply to a Torus like the following:

enter image description here

And this is the code I've just started to write:

void initMyProceduralTexture() {
  GLubyte image[64][64][3];
  int i,  j, c, r, g, b;

  glGenTextures( 1, &textureName[NUM_TEXTURES - 1] );
  glBindTexture(GL_TEXTURE_2D, textureName[NUM_TEXTURES - 1]);

  for(i=0;i<64;i++) {
    for(j=0;j<64;j++) {
        float a = floor(i * 8.0);
        float b = floor(j * 8.0);
        if (fmod(a,b) > 0.5 ) {
            image[i][j][0]= (GLubyte) 255.0;
            image[i][j][1]= (GLubyte) 127.5;
            image[i][j][2]= (GLubyte) 127.5;
        }
        else {
            image[i][j][0]= (GLubyte) 153.0;
            image[i][j][1]= (GLubyte) 153.0;
            image[i][j][2]= (GLubyte) 255.0;
        }
    }

  }

glTexImage2D(GL_TEXTURE_2D,0,3,64,64,0,GL_RGB,GL_UNSIGNED_BYTE, image);
...

But I don't know how to distinguish blue parts from red ones and how to set that image matrix. I have looked to this site and that's why I've set that scale to 8.0... can you help please? This is what I get with that code: enter image description here

1
But I don't know how to distinguish blue parts from red ones - can you reword that? I've no idea what this means. I think the fmod equation looks fishy as well, but maybe there's some magic in it.Bartek Banachewicz
Sorry...I mean that I don't know when and how to draw a blue rectangle and how and when to draw the red one...Simply, I don't know what to write inside the image matrix :(SagittariusA
You know how (the code you posted does that). If anything, you don't know when.Bartek Banachewicz
I think it doesn't work beacuse I don't get the result I posted in that picture...I get something strangeerSagittariusA
I've just added another picture...SagittariusA

1 Answers

2
votes

Since the textures are typically squares sized power-of-two * power-of-two, you can divide them into n sub-squares on each end, where n is a power-of-two as well. This will guarantee smooth wrapping of the texture.

Any other number can cause problems, because the number won't be divisible by it (the factorisation of 2n only has 2s in it), and either it will end with a part of a square, or the squares that you'll put in the texture won't have perfectly equal sizes.

1D example

Let's take a 1D texture first. The index in a loop is going to vary from 1 to, for example, 64. We only need to divide that number by the desired number of segments to get the number of pixels we want in one segment:

int texSize = 64;
const int desiredSegmentCount = 8;
int segmentSize = texSize / desiredSegmentCount; // 8

Now, when iterating, we can obtain the number of segment by taking the index divided by segment size:

for (int i = 0; i < texSize; ++i) {
    const int segmentNum = i / segmentSize;
}

And once we have the segment number, it's easy to assess whether it's odd or even by doing segmentNum % 2 (optionally adding == 0 for clarity).

Hence, the full loop would look like:

for (int i = 0; i < texSize; ++i) {
    const int segmentNum = i / segmentSize;
    const bool isEven = (segmentNum % 2) == 0;

    if (isEven) {
        // output red pixel
    } else {
       // output blue pixel
    }
}

Expansion to 2D

When we add another dimension, it gets only slightly more complicated. We can still assume that sizes are gonna be numbers, because we deal with squares only. The loop needs to loop across another dimension though:

for (int i = 0; i < texSize; ++i) {
    for (int j = 0; j < texSize; ++j) {
        const int segmentNum = i / segmentSize;
        const bool isEven = (segmentNum % 2) == 0;
    
        if (isEven) {
            // output red pixel
        } else {
           // output blue pixel
        }
    }
}

This should produce a striped texture. Now we need to add actual dependency on the row, as well as on the column.

The condition for "if" becomes a truth table:

     | odd  | even        j
-----|------------------
odd  | blue | red
even | red  | blue

i

That's something you should immediately recognize as a XOR operation, which for booleans actually is the same as (!=) operator. Now the code below should be perfectly clear:

for (int i = 0; i < texSize; ++i) {
    for (int j = 0; j < texSize; ++j) {
        const int segmentNumI = i / segmentSize;
        const int segmentNumJ = j / segmentSize;

        const bool isEvenI = (segmentNumI % 2) == 0;
        const bool isEvenJ = (segmentNumJ % 2) == 0;

        const bool redPixel = isEvenI != isEvenJ;
    
        if (redPixel) {
            // output red pixel
        } else {
           // output blue pixel
        }
    }
}