tim
tim

Reputation: 319

Android OpengGL Multiple Textures not displaying

I have successfully displayed a Cube with the same texture on all 6 sides (e.g a crate) but I am now trying to make a skybox (6 different textures 1 for each side). The skybox is only displaying white on all sides. each texture works on the crate cube so the textures are fine (i think.) Here is my code and some screen shots.

TexturedCube class (the one for a crate etc)

package com.dissertation.dnativeapp;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLUtils;
import android.util.Log;
/*
 * A cube with texture. 
 * Define the vertices for only one representative face.
 * Render the cube by translating and rotating the face.
 */
public class TexturedCube {
    private static final String TAG = "texcube";
   private FloatBuffer vertexBuffer; // Buffer for vertex-array
   private FloatBuffer texBuffer;    // Buffer for texture-coords-array (NEW)

   private float[] vertices = { // Vertices for a face
      -1.0f, -1.0f, 0.0f,  // 0. left-bottom-front
       1.0f, -1.0f, 0.0f,  // 1. right-bottom-front
      -1.0f,  1.0f, 0.0f,  // 2. left-top-front
       1.0f,  1.0f, 0.0f   // 3. right-top-front
   };

   float[] texCoords = { // Texture coords for the above face (NEW)
      0.0f, 1.0f,  // A. left-bottom (NEW)
      1.0f, 1.0f,  // B. right-bottom (NEW)
      0.0f, 0.0f,  // C. left-top (NEW)
      1.0f, 0.0f   // D. right-top (NEW)
   };
   int[] textureIDs = new int[1];   // Array for 1 texture-ID (NEW)

   // Constructor - Set up the buffers
   public TexturedCube() {
      // Setup vertex-array buffer. Vertices in float. An float has 4 bytes
      ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
      vbb.order(ByteOrder.nativeOrder()); // Use native byte order
      vertexBuffer = vbb.asFloatBuffer(); // Convert from byte to float
      vertexBuffer.put(vertices);         // Copy data into buffer
      vertexBuffer.position(0);           // Rewind

      // Setup texture-coords-array buffer, in float. An float has 4 bytes (NEW)
      ByteBuffer tbb = ByteBuffer.allocateDirect(texCoords.length * 4);
      tbb.order(ByteOrder.nativeOrder());
      texBuffer = tbb.asFloatBuffer();
      texBuffer.put(texCoords);
      texBuffer.position(0);
   }

   // Draw the shape
   public void draw(GL10 gl) {
      gl.glFrontFace(GL10.GL_CCW);    // Front face in counter-clockwise orientation
      gl.glEnable(GL10.GL_CULL_FACE); // Enable cull face
      gl.glCullFace(GL10.GL_BACK);    // Cull the back face (don't display) 

      gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
      gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
      gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);  // Enable texture-coords-array (NEW)
      gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, texBuffer); // Define texture-coords buffer (NEW)

      // front
      gl.glPushMatrix();
      gl.glTranslatef(0.0f, 0.0f, 1.0f);
      gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
      gl.glPopMatrix();

      // left
      gl.glPushMatrix();
      gl.glRotatef(270.0f, 0.0f, 1.0f, 0.0f);
      gl.glTranslatef(0.0f, 0.0f, 1.0f);
      gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
      gl.glPopMatrix();

      // back
      gl.glPushMatrix();
      gl.glRotatef(180.0f, 0.0f, 1.0f, 0.0f);
      gl.glTranslatef(0.0f, 0.0f, 1.0f);
      gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
      gl.glPopMatrix();

      // right
      gl.glPushMatrix();
      gl.glRotatef(90.0f, 0.0f, 1.0f, 0.0f);
      gl.glTranslatef(0.0f, 0.0f, 1.0f);
      gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
      gl.glPopMatrix();

      // top
      gl.glPushMatrix();
      gl.glRotatef(270.0f, 1.0f, 0.0f, 0.0f);
      gl.glTranslatef(0.0f, 0.0f, 1.0f);
      gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
      gl.glPopMatrix();

      // bottom
      gl.glPushMatrix();
      gl.glRotatef(90.0f, 1.0f, 0.0f, 0.0f);
      gl.glTranslatef(0.0f, 0.0f, 1.0f);
      gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
      gl.glPopMatrix();

      gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);  // Disable texture-coords-array (NEW)
      gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
      gl.glDisable(GL10.GL_CULL_FACE);
   }

   // Load an image into GL texture
   public void loadTexture(GL10 gl, Context context) {
      gl.glGenTextures(1, textureIDs, 0); // Generate texture-ID array
      Log.d(TAG, "gen number = " + textureIDs[0]);
      gl.glBindTexture(GL10.GL_TEXTURE_2D, textureIDs[0]);   // Bind to texture ID
      // Set up texture filters
      gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
      gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

      // Construct an input stream to texture image "res\drawable\nehe.png"
      InputStream istream = context.getResources().openRawResource(R.drawable.crate);
      Bitmap bitmap;
      try {
         // Read and decode input as bitmap
         bitmap = BitmapFactory.decodeStream(istream);
      } finally {
         try {
            istream.close();
         } catch(IOException e) { }
      }

      // Build Texture from loaded bitmap for the currently-bind texture ID
      GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
      bitmap.recycle();
   }
}

SkyBox class

package com.dissertation.dnativeapp;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLUtils;
import android.util.Log;
/*
 * A photo cube with 6 pictures (textures) on its 6 faces.
 */
public class SkyBox {
    private static final String TAG = "skybox";
    private FloatBuffer vertexBuffer;  // Vertex Buffer
   private FloatBuffer texBuffer;     // Texture Coords Buffer

   private int numFaces = 6;
   private int[] imageFileIDs = {  // Image file IDs
      R.drawable.front3,
      R.drawable.left3,
      R.drawable.back3,
      R.drawable.right3,
      R.drawable.top3,
      R.drawable.bot3
   };
   private int[] textureIDs = new int[numFaces];
   private Bitmap[] bitmap = new Bitmap[numFaces];
   private float cubeHalfSize = 1.2f;

   // Constructor - Set up the vertex buffer
   public SkyBox(Context context) {
      // Allocate vertex buffer. An float has 4 bytes
      ByteBuffer vbb = ByteBuffer.allocateDirect(12 * 4 * numFaces);
      vbb.order(ByteOrder.nativeOrder());
      vertexBuffer = vbb.asFloatBuffer();

      // Read images. Find the aspect ratio and adjust the vertices accordingly.
      for (int face = 0; face < numFaces; face++) {
         bitmap[face] = BitmapFactory.decodeStream(
               context.getResources().openRawResource(imageFileIDs[face]));
         int imgWidth = bitmap[face].getWidth();
         int imgHeight = bitmap[face].getHeight();
         float faceWidth = 2.0f;
         float faceHeight = 2.0f;
         // Adjust for aspect ratio
         if (imgWidth > imgHeight) {
            faceHeight = faceHeight * imgHeight / imgWidth; 
         } else {
            faceWidth = faceWidth * imgWidth / imgHeight;
         }
         float faceLeft = -faceWidth / 2;
         float faceRight = -faceLeft;
         float faceTop = faceHeight / 2;
         float faceBottom = -faceTop;

         // Define the vertices for this face
         float[] vertices = {
            faceLeft,  faceBottom, 0.0f,  // 0. left-bottom-front
            faceRight, faceBottom, 0.0f,  // 1. right-bottom-front
            faceLeft,  faceTop,    0.0f,  // 2. left-top-front
            faceRight, faceTop,    0.0f,  // 3. right-top-front
         };
         vertexBuffer.put(vertices);  // Populate
      }
      vertexBuffer.position(0);    // Rewind

      // Allocate texture buffer. An float has 4 bytes. Repeat for 6 faces.
      float[] texCoords = {
         0.0f, 1.0f,  // A. left-bottom
         1.0f, 1.0f,  // B. right-bottom
         0.0f, 0.0f,  // C. left-top
         1.0f, 0.0f   // D. right-top
      };
      ByteBuffer tbb = ByteBuffer.allocateDirect(texCoords.length * 4 * numFaces);
      tbb.order(ByteOrder.nativeOrder());
      texBuffer = tbb.asFloatBuffer();
      for (int face = 0; face < numFaces; face++) {
         texBuffer.put(texCoords);
      }
      texBuffer.position(0);   // Rewind
   }

   // Render the shape
   public void draw(GL10 gl) {
      gl.glFrontFace(GL10.GL_CCW);

      gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
      gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
      gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
      gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, texBuffer);

      // front
      gl.glPushMatrix();
      gl.glTranslatef(0f, 0f, cubeHalfSize);
      gl.glBindTexture(GL10.GL_TEXTURE_2D, textureIDs[0]);
      gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
      gl.glPopMatrix();

      // left
      gl.glPushMatrix();
      gl.glRotatef(270.0f, 0f, 1f, 0f);
      gl.glTranslatef(0f, 0f, cubeHalfSize);
      gl.glBindTexture(GL10.GL_TEXTURE_2D, textureIDs[1]);
      gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 4, 4);
      gl.glPopMatrix();

      // back
      gl.glPushMatrix();
      gl.glRotatef(180.0f, 0f, 1f, 0f);
      gl.glTranslatef(0f, 0f, cubeHalfSize);
      gl.glBindTexture(GL10.GL_TEXTURE_2D, textureIDs[2]);
      gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 8, 4);
      gl.glPopMatrix();

      // right
      gl.glPushMatrix();
      gl.glRotatef(90.0f, 0f, 1f, 0f);
      gl.glTranslatef(0f, 0f, cubeHalfSize);
      gl.glBindTexture(GL10.GL_TEXTURE_2D, textureIDs[3]);
      gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 12, 4);
      gl.glPopMatrix();

      // top
      gl.glPushMatrix();
      gl.glRotatef(270.0f, 1f, 0f, 0f);
      gl.glTranslatef(0f, 0f, cubeHalfSize);
      gl.glBindTexture(GL10.GL_TEXTURE_2D, textureIDs[4]);
      gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 16, 4);
      gl.glPopMatrix();

      // bottom
      gl.glPushMatrix();
      gl.glRotatef(90.0f, 1f, 0f, 0f);
      gl.glTranslatef(0f, 0f, cubeHalfSize);
      gl.glBindTexture(GL10.GL_TEXTURE_2D, textureIDs[5]);
      gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 20, 4);
      gl.glPopMatrix();

      gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
      gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
   }

   // Load images into 6 GL textures
   public void loadTexture(GL10 gl) {
      gl.glGenTextures(6, textureIDs, 0); // Generate texture-ID array for 6 IDs

      Log.d(TAG, "gen number = " + textureIDs[0]);
      // Generate OpenGL texture images
      for (int face = 0; face < numFaces; face++) {
          Log.d(TAG, "gen number " + face + " = " + textureIDs[face]);
         gl.glBindTexture(GL10.GL_TEXTURE_2D, textureIDs[face]);
         // Build Texture from loaded bitmap for the currently-bind texture ID
         GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap[face], 0);
         bitmap[face].recycle();
      }
   }
}

MyGLRenderer

package com.dissertation.dnativeapp;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.opengl.GLU;
import android.util.Log;

import com.dissertation.dnativeapp.GVariables;

public class MyGLRenderer implements GLSurfaceView.Renderer {

   private static final String TAG = "render";
   private Context context;   // Application context needed to read image (NEW)
   private TexturedCube cube;
   private Cube cube1;
   private SkyBox skybox;
   private int scene;
   private int number;

// For controlling cube's z-position, x and y angles and speeds (NEW)
   float angleX = 0;   
   float angleY = 0;  
   float speedX = 0;   
   float speedY = 0;   
   float z = -6.0f;    

   // Constructor
   public MyGLRenderer(Context context) {
      this.context = context;   // Get the application context (NEW)
      cube = new TexturedCube();
      cube1 = new Cube();
      skybox = new SkyBox(context);
      //get scene value
      scene = GVariables.getScene();
   }

   // Call back when the surface is first created or re-created.

   public void onSurfaceCreated(GL10 gl, EGLConfig config) {
      gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);  // Set color's clear-value to black
      gl.glClearDepthf(1.0f);            // Set depth's clear-value to farthest
      gl.glEnable(GL10.GL_DEPTH_TEST);   // Enables depth-buffer for hidden surface removal
      gl.glDepthFunc(GL10.GL_LEQUAL);    // The type of depth testing to do
      gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);  // nice perspective view
      gl.glShadeModel(GL10.GL_SMOOTH);   // Enable smooth shading of color
      gl.glDisable(GL10.GL_DITHER);      // Disable dithering for better performance

      if(scene == 1)
      {
          // Setup Texture, each time the surface is created (NEW)
          cube.loadTexture(gl, context);    // Load image into Texture (NEW)
      }
      if(scene == 2)
      {
          skybox.loadTexture(gl);
      }
          gl.glEnable(GL10.GL_TEXTURE_2D);  // Enable texture (NEW)

   }

   // Call back after onSurfaceCreated() or whenever the window's size changes.

   public void onSurfaceChanged(GL10 gl, int width, int height) {
          if (height == 0) height = 1;   // To prevent divide by zero
          float aspect = (float)width / height;

          // Set the viewport (display area) to cover the entire window
          gl.glViewport(0, 0, width, height);

          // Setup perspective projection, with aspect ratio matches viewport
          gl.glMatrixMode(GL10.GL_PROJECTION); // Select projection matrix
          gl.glLoadIdentity();                 // Reset projection matrix
          // Use perspective projection
          GLU.gluPerspective(gl, 45, aspect, 0.1f, 100.f);

          gl.glMatrixMode(GL10.GL_MODELVIEW);  // Select model-view matrix
          gl.glLoadIdentity();                 // Reset

          // You OpenGL|ES display re-sizing code here
          // ......
       }

   // Call back to draw the current frame.

   public void onDrawFrame(GL10 gl) {

      //get number of objects
      Log.d(TAG, "getting number");
      number = GVariables.getNumberOfObjects();
      Log.d(TAG, "number got");
      // Clear color and depth buffers
      gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

      if(scene == 1)
      {
         for(int i = 0; i < number; i++)
         {
              // ----- Render the Cube -----
              gl.glLoadIdentity();                  // Reset the current model-view matrix
              gl.glTranslatef((-3 + (3*i)), 0.0f, z);   // Translate into the screen
              gl.glRotatef(angleX, 1.0f, 0.0f, 0.0f); // Rotate (NEW)
              gl.glRotatef(angleY, 0.0f, 1.0f, 0.0f); // Rotate (NEW)
              gl.glScalef(0.8f, 0.8f, 0.8f);
              cube.draw(gl);
          }
      }
      if(scene == 0)
      {
          for(int i = 0; i < number; i++)
          {
              gl.glLoadIdentity();
              gl.glTranslatef((-3 + (3*i)), 0.0f, z);
              gl.glRotatef(angleX, 1.0f, 0.0f, 0.0f); // Rotate (NEW)
              gl.glRotatef(angleY, 0.0f, 1.0f, 0.0f); // Rotate (NEW)
              gl.glScalef(0.8f, 0.8f, 0.8f);
              cube1.draw(gl);
          }
      }
      if(scene == 2)
      {
          gl.glLoadIdentity();
          gl.glTranslatef(0.0f, 0.0f, z);
          gl.glRotatef(angleX, 1.0f, 0.0f, 0.0f); // Rotate (NEW)
          gl.glRotatef(angleY, 0.0f, 1.0f, 0.0f); // Rotate (NEW)
          gl.glScalef(1.0f, 1.0f, 1.0f);
          skybox.draw(gl);
      }

      // Update the rotational angle after each refresh (NEW)
      angleX += speedX;  
      angleY += speedY;  
   }
}

and if you need it MainActivity

package com.dissertation.dnativeapp;

import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.util.Log;

public class MainActivity extends Activity {
    private static final String TAG = MainActivity.class.getSimpleName();
    int scene;
    int number;
     /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        scene = 0;
        Button basic = (Button) findViewById(R.id.Basic_Button);
        Button textured = (Button) findViewById(R.id.Textured_Button);
        Button complicated = (Button) findViewById(R.id.Complicated_Button);
        final CheckBox cb1 = (CheckBox) findViewById(R.id.checkBox1);
        final CheckBox cb2 = (CheckBox) findViewById(R.id.checkBox2);
        final CheckBox cb3 = (CheckBox) findViewById(R.id.checkBox3);

        cb1.setOnCheckedChangeListener(new OnCheckedChangeListener()
        {

            public void onCheckedChanged(CompoundButton buttonView,
                    boolean isChecked) 
            {
                cb2.setChecked(false);
                cb3.setChecked(false);

            }

        });

        cb2.setOnCheckedChangeListener(new OnCheckedChangeListener()
        {
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
            {
                cb1.setChecked(false);
                cb3.setChecked(false);
            }
        });

        cb3.setOnCheckedChangeListener(new OnCheckedChangeListener()
        {
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
            {
                cb1.setChecked(false);
                cb2.setChecked(false);
            }
        });


        basic.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                if(cb1.isChecked())
                {
                    GVariables.setNumberOfObjects(1);
                }
                else if(cb2.isChecked())
                {
                    GVariables.setNumberOfObjects(2);
                }
                else if(cb3.isChecked())
                {
                    GVariables.setNumberOfObjects(3);
                }
                else
                {
                    GVariables.setNumberOfObjects(1);
                }
                scene = 0;
                GVariables.setScene(scene);
                Intent myIntent = new Intent(view.getContext(), MyGLActivity.class);

                startActivityForResult(myIntent, 0);
            }

        });

        textured.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {
                if(cb1.isChecked())
                {
                    GVariables.setNumberOfObjects(1);
                }
                else if(cb2.isChecked())
                {
                    GVariables.setNumberOfObjects(2);
                }
                else if(cb3.isChecked())
                {
                    GVariables.setNumberOfObjects(3);
                }
                else
                {
                    GVariables.setNumberOfObjects(1);
                }
                scene = 1;
                GVariables.setScene(scene);
                Intent myIntent = new Intent(v.getContext(), MyGLActivity.class);

                startActivityForResult(myIntent, 0);
            }
        });

        complicated.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {
                // TODO Auto-generated method stub
                scene = 2;
                GVariables.setScene(scene);
                Intent myIntent = new Intent(v.getContext(), MyGLActivity.class);
                startActivityForResult(myIntent, 0);
            }
        });



    }
}

-edit I cant post images, but white faces for the skybox

Upvotes: 0

Views: 1260

Answers (1)

Matic Oblak
Matic Oblak

Reputation: 16774

I am not too certain but it might be that you are missing setting parameters for textures:

gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

in your "for" loop when creating textures (after every "bind" call).

Anyway, you posted much too much code to read this...

Upvotes: 2

Related Questions