0
votes

I'm creating a 2D tile based tactical rpg using OpenGL using C++ and I'm having difficulties with layering my tiles/quads. I want to to able to put say a tree textured quad, the image is of the tree with a surrounding transparent alpha layer, on top of an opaque grass textured quad. I need to have the tree appear on top of the grass with the grass showing through the alpha layer of the tree image.

So far I've been messing with glDisable(GL_DEPTH_TEST), glEnable(GL_BLEND), andglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) but with no luck so far. I end up with a tree on a black background, instead of the grass tile. Could someone point me in the right direction?

Below is my render function and initialize function which are probably most relevant.

void View::initialize() {
  updateProjection(window);
  glDisable(GL_DEPTH_TEST);
  glClearColor(0.0, 0.0, 0.0, 1.0);
  camera = new Camera(Vector3(-1, -3, 25), Vector3(-1, -3, 0), Vector3(0, 1, 0));
  loadImages();
  initShaders();

  //needed for transparency?
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}

void View::render(World* worldTemp)
{
  Matrix4 mvpMatrix, viewMatrix, modelMatrix;
  Matrix4 XAxisRotationMatrix, YAxisRotationMatrix, ZAxisRotationMatrix;

  input->handleInput(camera, worldTemp->getPlayer());

  worldTemp->timerTick();
  worldTemp->clearFog();

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);            // Clear Screen and Depth Buffer

  XAxisRotationMatrix = Matrix4::IDENTITY;
  YAxisRotationMatrix = Matrix4::IDENTITY;
  ZAxisRotationMatrix = Matrix4::IDENTITY;
  XAxisRotationMatrix.rotate(Vector3(1.0, 0.0, 0.0), XAxisRotationAngle);
  YAxisRotationMatrix.rotate(Vector3(0.0, 1.0, 0.0), YAxisRotationAngle);
  ZAxisRotationMatrix.rotate(Vector3(0.0, 0.0, 1.0), ZAxisRotationAngle);

  viewMatrix = camera->getViewMatrix();

  modelMatrix = translationMatrix(Vector3(-4, 2, 0));
  mvpMatrix = projectionMatrix * viewMatrix * modelMatrix;

  //Spit out the map
  for (int i = 0; i < 100; i++){
      for (int j = 0; j < 100; j++){
          for (int t = 0; t < 5; t++){
              if (worldTemp->getTile(i, j)->isOccupied() == true) {
                  if (worldTemp->getTile(i, j)->getOccupyingEntityIndexed(t)->getFog()){
                    worldTemp->getTile(i, j)->getOccupyingEntityIndexed(t)->getEntityQuad()->render_self(mvpMatrix, true);
                  }
                  else{
                    worldTemp->getTile(i, j)->getOccupyingEntityIndexed(t)->getEntityQuad()->render_self(mvpMatrix);
                  }
              }
          }
      }
  }

  //Place the player
  worldTemp->getPlayer()->getEntityQuad()->render_self(mvpMatrix);
  renderEnemies();

  glutSwapBuffers(); //works with GL_DOUBLE. use glFlush(); instead, if using GL_SINGLE
}
1
Are you sure that your tree texture actually has an alpha component with the correct transparency? And then, the trees would have to be rendered last. My answer here explains various transparency rendering options in some detail: stackoverflow.com/a/23283256/3530129.Reto Koradi

1 Answers

0
votes

Basically, in 2d games layering done via ordering of render calls. If you want layer A on top of layer B, you should render layer B first and then layer A.

blend function that you're using should depend on texture format of images. There are two common formats for alpha:

  1. Pre-multiplied alpha

  2. Straight alpha

    More info about this: https://developer.nvidia.com/content/alpha-blending-pre-or-not-pre

opengl es2 premultiplied vs straight alpha + blending

glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); is for premultiplied alpha, and it should work well if you use colors as is. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); is for straight alpha.