2015-08-27 2 views
0

Я делаю приложение для Android с OpenGL-Es, следуя руководству Nehe. У меня есть куб с текстурой, и моя проблема в том, что я хочу изменить его, нажав кнопку (у меня есть 2 текстуры в папке «raw»). Я думаю, что это связано с моей переменной imagenes, в которой я сохраняю маршрут моих изображений (R.raw.imagen и R.raw.imagen2 на MainActivity.java), только заряжайте изображение один раз в начале приложения, поэтому даже если Я изменяю переменную позже в своей функции onClick(), текстура остается неизменной.
Зарядка нескольких текстур OpenGL-ES Android

То, что я пытался сделать, это сделать переключатель в классе TextureCube.java глядя мои переменные imagenes в функции, где я загрузить текстуру поэтому он должен зарядить первое изображение в начале приложения, а затем, если нажать кнопка изменит его на другое изображение из-за кода onClick().

Изображение никогда не меняется, потому что я напечатал переменную imagenes. Я не знаю, что я делаю неправильно.

MainActivity:

b.setOnClickListener(new OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       if (get_imagenes() == R.raw.imagen) { 
        imagenes = R.raw.imagen2; 
        b.setText("image2"); 
       } else if (get_imagenes() == R.raw.imagen2) { 
        imagenes = R.raw.imagen; 
        b.setText("image1"); 
       } 
      } 
     }); 

TextureCube:

// Construct an input stream to texture image 
       switch (main.imagenes) { 
        case R.raw.imagen: 
         is = context.getResources().openRawResource(R.raw.imagen); 
         break; 
        case R.raw.imagen2: 
         is = context.getResources().openRawResource(R.raw.imagen2); 
         break; 
       } 

Я оставил остальную часть кода приложения here.Here мой код MainActivity:

public class MainActivity extends AppCompatActivity { 
    private GLSurfaceView glView; 
    private TextureCube cube; 
    int imagenes = R.raw.imagen; 
    Button b; 
    Bitmap bitmap; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     //GLSurfaceView 
     glView = new MyGLSurfaceView(this); 
     cube = new TextureCube(); 
     setContentView(glView); 
     createButtons(); 
    } 

    public void createButtons() { 
     //ButtonB 
     LinearLayout ll = new LinearLayout(this); 
     b = new Button(this); 
     b.setText("Change Texture"); 
     ll.addView(b); 
     ll.setGravity(Gravity.BOTTOM | Gravity.CENTER); 
     this.addContentView(ll, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); 

     b.setOnClickListener(new OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       if (get_imagenes() == R.raw.imagen) { 
        imagenes = R.raw.imagen2; 
        b.setText("image2"); 
       } else if (get_imagenes() == R.raw.imagen2) { 
        imagenes = R.raw.imagen; 
        b.setText("image1"); 
       } 
      } 
     }); 
    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     super.onCreateOptionsMenu(menu); 
     getMenuInflater().inflate(R.menu.menu_main, menu); 
     return true; 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 
     // Handle action bar item clicks here. The action bar will 
     // automatically handle clicks on the Home/Up button, so long 
     // as you specify a parent activity in AndroidManifest.xml. 
     int id = item.getItemId(); 

     //noinspection SimplifiableIfStatement 
     if (id == R.id.action_settings) { 
      return true; 
     } 
     return super.onOptionsItemSelected(item); 
    } 

    // Call back when the activity is going into the background 
    @Override 
    protected void onPause() { 
     super.onPause(); 
     glView.onPause(); 
    } 

    // Call back after onPause() 
    @Override 
    protected void onResume() { 
     super.onResume(); 
     glView.onResume(); 
    } 

    public int get_imagenes() { 
     return imagenes; 
    } 
} 

Мой код Релеранс:

public class MyGLRenderer implements GLSurfaceView.Renderer { 

    private Context context; 
    private TextureCube cube; 
    private MainActivity main; 
    // For controlling cube's z-position, x and y angles and speeds 
    float angleX = 0; 
    float angleY = 0; 
    float speedX = 0; 
    float speedY = 0; 
    float z = -6.0f; 

    int currentTextureFilter = 0; // Texture filter 

    // Lighting (NEW) 
    boolean lightingEnabled = false; // Is lighting on? (NEW) 
    private float[] lightAmbient = {0.5f, 0.5f, 0.5f, 1.0f}; 
    private float[] lightDiffuse = {1.0f, 1.0f, 1.0f, 1.0f}; 
    private float[] lightPosition = {0.0f, 0.0f, 2.0f, 1.0f}; 
    // Blending (NEW) 
    boolean blendingEnabled = false; // Is blending on? (NEW) 
    // Constructor 
    public MyGLRenderer(Context context) { 
     this.context = context; // Get the application context (NEW) 
     cube = new TextureCube(); 
    } 

    // Call back when the surface is first created or re-created. 
    @Override 
    public void onSurfaceCreated(GL10 gl, EGLConfig config) { 
     gl.glClearColor(0.5f, 0.5f, 0.5f, 1.0f); // Set color's clear-value to black 
     //gl.glClearColor(0f, 0f, 0f, 1.0f); 
     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 

     // Setup Texture, each time the surface is created (NEW) 
     cube.loadTexture(gl, context); // Load image into Texture (NEW) 
     gl.glEnable(GL10.GL_TEXTURE_2D); // Enable texture (NEW) 

     // Setup lighting GL_LIGHT1 with ambient and diffuse lights (NEW) 
     gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_AMBIENT, lightAmbient, 0); 
     gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_DIFFUSE, lightDiffuse, 0); 
     gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_POSITION, lightPosition, 0); 
     gl.glEnable(GL10.GL_LIGHT1); // Enable Light 1 (NEW) 
     gl.glEnable(GL10.GL_LIGHT0); // Enable the default Light 0 (NEW) 

     // Setup Blending (NEW) 
     gl.glColor4f(1.0f, 1.0f, 1.0f, 0.5f);   // Full brightness, 50% alpha (NEW) 
     gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE); // Select blending function (NEW) 
    } 


    // Call back after onSurfaceCreated() or whenever the window's size changes. 
    @Override 
    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 
    } 

    @Override 
    public void onDrawFrame(GL10 gl) { 
     // Clear color and depth buffers 
     gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); 

     if (lightingEnabled) { //Enable lighting 
      gl.glEnable(GL10.GL_LIGHTING); 
     } else { 
      gl.glDisable(GL10.GL_LIGHTING); 
     } 

     if (blendingEnabled) { //Enable blending 
      gl.glEnable(GL10.GL_BLEND);  // Turn blending on (NEW) 
      gl.glDisable(GL10.GL_DEPTH_TEST); // Turn depth testing off (NEW) 
     } else { 
      gl.glDisable(GL10.GL_BLEND);  // Turn blending off (NEW) 
      gl.glEnable(GL10.GL_DEPTH_TEST); // Turn depth testing on (NEW) 
     } 

     // ----- Render the Cube ----- // 
     gl.glLoadIdentity();    // Reset the model-view matrix 
     gl.glTranslatef(0.0f, 0.0f, z); // Translate into the screen (NEW) 
     gl.glRotatef(angleX, 1.0f, 0.0f, 0.0f); // Rotate (NEW) 
     gl.glRotatef(angleY, 0.0f, 1.0f, 0.0f); // Rotate (NEW) 
     cube.draw(gl); 

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

    } 
} 

GLSurfaceView:

public class MyGLSurfaceView extends GLSurfaceView { 
    MyGLRenderer renderer; 
    MainActivity main; 

    private final float TOUCH_SCALE_FACTOR = 180.0f/320.0f; 
    private float previousX; 
    private float previousY; 

    //Allocate and set the renderer 
    public MyGLSurfaceView(Context context) { 
     super(context); 
     renderer = new MyGLRenderer(context); 
     this.setRenderer(renderer); 
     this.requestFocus(); 
     this.setFocusableInTouchMode(true); 
    } 

    // Handler for key event 
    @Override 
    public boolean onKeyUp(int keyCode, KeyEvent evt) { 
     switch(keyCode) { 
      case KeyEvent.KEYCODE_DPAD_LEFT: // Decrease Y-rotational speed 
       renderer.speedY += 0.1f; 
       break; 
      case KeyEvent.KEYCODE_DPAD_RIGHT: // Increase Y-rotational speed 
       renderer.speedY -= 0.1f; 
       break; 
      case KeyEvent.KEYCODE_DPAD_UP:  // Decrease X-rotational speed 
       renderer.speedX += 0.1f; 
       break; 
      case KeyEvent.KEYCODE_DPAD_DOWN: // Increase X-rotational speed 
       renderer.speedX -= 0.1f; 
       break; 
      case KeyEvent.KEYCODE_A:   // Zoom out (decrease z) 
       renderer.z -= 0.2f; 
       break; 
      case KeyEvent.KEYCODE_Z:   // Zoom in (increase z) 
       renderer.z += 0.2f; 
       break; 
      case KeyEvent.KEYCODE_B: // Toggle Blending on/off (NEW) 
       renderer.blendingEnabled = !renderer.blendingEnabled; 
       break; 
      case KeyEvent.KEYCODE_L: // Toggle lighting on/off (NEW) 
       renderer.lightingEnabled = !renderer.lightingEnabled; 
       break; 
     } 
     return true; 
    } 

    // Handler for touch event 
    @Override 
    public boolean onTouchEvent(final MotionEvent event) { 
     float currentX = event.getX(); 
     float currentY = event.getY(); 
     float deltaX, deltaY; 
     switch (event.getAction()) { 
      case MotionEvent.ACTION_MOVE: 
       // Modify rotational angles according to movement 
       deltaX = currentX - previousX; 
       deltaY = currentY - previousY; 
       renderer.angleX += deltaY * TOUCH_SCALE_FACTOR; 
       renderer.angleY += deltaX * TOUCH_SCALE_FACTOR; 
       break; 
     } 
     // Save current x, y 
     previousX = currentX; 
     previousY = currentY; 
     return true; // Event handled 
    } 
} 

А вот TextureCube:

public class TextureCube { 
    private FloatBuffer vertexBuffer; //Buffer for vertex-array 
    private FloatBuffer texBuffer; //Buffer for texture-coords-array (NEW) 
    private MainActivity main = new MainActivity(); 

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

    float[] texCoords = { // Texture coords 
      0.0f, 1.0f, //left-bottom 
      1.0f, 1.0f, //right-bottom 
      0.0f, 0.0f, //left-top 
      1.0f, 0.0f //right-top (
    }; 
    int[] textureIDs = new int[1]; //new 


    public TextureCube() { 
     // Setup vertex-array buffer 
     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-array buffer 
     ByteBuffer tbb = ByteBuffer.allocateDirect(texCoords.length * 4); 
     tbb.order(ByteOrder.nativeOrder()); 
     texBuffer = tbb.asFloatBuffer(); 
     texBuffer.put(texCoords); 
     texBuffer.position(0); 
    } 

    // Draw the cube 
    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) 

     //Enable vertex and texture client 
     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) 

     //Draw all the faces 
     //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 new 

     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); 


     InputStream is = new InputStream() { 
      @Override 
      public int read() throws IOException { 
       return 0; 
      } 
     }; 
     // Construct an input stream to texture image 
     switch (main.imagenes) { 
      case R.raw.imagen: 
       is = context.getResources().openRawResource(R.raw.imagen); 
       break; 
      case R.raw.imagen2: 
       is = context.getResources().openRawResource(R.raw.imagen2); 
       break; 
     } 

     Log.d("prueba","imagenes"+main.imagenes); 

     Bitmap bitmap; 
     try { 
      // Read and decode input as bitmap 
       bitmap = BitmapFactory.decodeStream(is); 
     } finally { 
      try { 
        is.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(); 
    } 
} 

ответ

0

В программе инициализации, вам необходимо загрузить 2 растровых изображений и загрузить их в 2-х новых текстур к GPU (glGenTextures/glBindTexture/GLUtils.texImage2D), это должно дать вам два разных идентификатора textureID: textureIDs[0] и textureIDs[1].

Затем, когда вы рисуете куб в public void draw(GL10 gl) вам нужно добавить вызов glBindTexture используя либо textureIDs[0] или textureIDs[1] в зависимости от вашего состояния кнопки.

Ваш текущий код загружает только одну из двух текстур на GPU, а второй загружается в ОЗУ только при нажатии кнопки. А также вы забыли позвонить glBindTexture в функцию draw для куба.

- EDIT -

Пытаясь объяснить лучше с некоторыми прийти:

Прежде всего, необходимо загрузить два изображения в OpenGL текстуры, когда программа запускается, вместо загрузки только второй при нажатии кнопки.

Это упростит работу и позволит избежать утечки памяти. Поэтому я создаю новый loadTextures функция которым делает это:

// you need 2 texture IDs now ... 
int NB_GL_TEXTURES = 2; 
int[] textureIDs = new int[NB_GL_TEXTURES]; 

// tool function to load a texture to OpenGL 
public void loadTexture(GL10 gl, Context context, InputStream is, int GL_id_slot) { 

    // decode is to a Bitmap 
    Bitmap bitmap; 
    try { 
     bitmap = BitmapFactory.decodeStream(is); 
    } finally { 
     try { 
      is.close(); 
     } catch (IOException e) { 
     } 
    } 

    // tell OpenGL what is the current GL texture 
    gl.glBindTexture(GL10.GL_TEXTURE_2D, textureIDs[GL_id_slot]); 

    // Set up texture filters for current GL texture 
    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); 

    // load the bitmap into current GL texture 
    GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); 

    // destroy the bitmap 
    bitmap.recycle(); 
} 

// Loads the two images into two OpenGL textures 
public void loadTextures(GL10 gl, Context context) { 

    // generate 2 GL textures IDs => textureIDs[0], textureIDs[1] 
    gl.glGenTextures(NB_GL_TEXTURES, textureIDs, 0); 

    // load imagen into GL tex of id textureIDs[0] 
    InputStream is_bitmap_0 = context.getResources().openRawResource(R.raw.imagen); 
    loadTexture(gl, context, is_bitmap_0, 0); 

    // load imagen2 into GL tex of id textureIDs[1] 
    InputStream is_bitmap_1 = context.getResources().openRawResource(R.raw.imagen2); 
    loadTexture(gl, context, is_bitmap_1, 1); 
} 

public void onSurfaceCreated(GL10 gl, EGLConfig config) { 
    // ... 

    // Setup the 2 GL Textures, each time the surface is created 
    gl.glEnable(GL10.GL_TEXTURE_2D); 
    cube.loadTextures(gl, context); 

    // ... 
} 

Следующий шаг заключается в изменении куба визуализации код для вызова glBindTexture в каждом кадре, передавая ему правильный GL текстуры ID:

// Draw the cube 
public void draw(GL10 gl) { 
    // ... 

    //Enable vertex and texture client 
    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) 

    // choose which texture to use on the cube 
    int GL_id_slot = 0; 
    if (main.imagenes == R.raw.imagen) 
     GL_id_slot = 0; 
    else if (main.imagenes == R.raw.imagen2) 
     GL_id_slot = 1; 
    gl.glBindTexture(GL10.GL_TEXTURE_2D, textureIDs[GL_id_slot]); 

    //Draw all the faces 
    // ... 
} 
+0

Что делать ты имеешь в виду? Потому что, если я добавлю 'gl.glBindTexture (GL10.GL_TEXTURE_2D, main.get_imagenes());', чтобы узнать, каково изображение, которое я хочу поставить, когда я нажимаю «public void draw (GL10 gl)», что происходит что куб белый, потому что он не отображает ни одну из текстур. То, что вы сказали в первую очередь о 'glGenTextures, glBindTexture, GLUtils.texImage2D', находится в моей функции loadTexture (GL10 gl, контекст контекста)', которую я вызываю в моем рендерере. Поэтому я вообще этого не понимаю, если бы вы могли это объяснить, это будет здорово. Но спасибо за ответ в любом случае :) –

+0

Я отредактировал свой ответ, добавив код, надеюсь, это поможет –

+0

Он взрывается, я не знаю причины, потому что весь код имеет смысл. Я продолжу поиск способов устранения ошибок, большое спасибо за ваши усилия! –