2013-08-28 33 views
0

我是OpenGL的新手。我在填充紋理時加載Obj模型,但紋理未完全填充到對象上。它會填充某些部分的紋理而不是整個模型。我附上了兩張照片,其中有一個模型沒有紋理,另一個模型是紋理但紋理不完整。紋理不完全在模型中

這是我的紋理圖像:

Texture

package com.amplimesh.models; 

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.nio.ByteBuffer; 
import java.nio.ByteOrder; 
import java.nio.FloatBuffer; 
import java.util.ArrayList; 
import java.util.StringTokenizer; 

import javax.microedition.khronos.opengles.GL10; 

import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.opengl.GLUtils; 

import com.amplimesh.renderer.RendererView; 
import com.amplimesh.util.Point3; 

/** 
* Object Loader and draw the texture and object. 
* @author Ajay 
*/ 
public class ObjModel { 

    /** 
    * It fill the texture into the mesh 
    * @param context 
    * @param gl 
    */ 
    public void bindTextures(Context context, GL10 gl) { 
     Bitmap bitmap; 
     try { 
      InputStream is = context.getAssets().open("textures/"+RendererView.textureFileName); 
      bitmap = BitmapFactory.decodeStream(is); 
      if(bitmap != null) { 
       // generate one texture pointer 
       gl.glGenTextures(1, mTextures, 0); 
       // ...and bind it to our array 
       gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextures[0]); 

       // create nearest filtered 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); 

       //Different possible texture parameters, e.g. GL10.GL_CLAMP_TO_EDGE 
       //gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT); 
       //gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT); 

       // Use Android GLUtils to specify a two-dimensional texture image from our bitmap 
       GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); 
       // Clean up 
       bitmap.recycle(); 
      } 
     } catch (java.io.IOException e) { 
      return; 
     } 
    } 

    /** 
    * It draw the object. 
    * @param gl 
    */ 
    public void draw(GL10 gl) { 
     gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); 
     gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 
     gl.glEnableClientState(GL10.GL_NORMAL_ARRAY); 
     for (Model model : mModels) { 

      gl.glVertexPointer(3, GL10.GL_FLOAT, 0, model.v); 
      if (model.vt != null && mTextures != null) { 
       gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextures[0]); 
       gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, model.vt); 
      } 

      if (model.vn != null) { 
       gl.glNormalPointer(GL10.GL_FLOAT, 0, model.vn); 
      } 
      gl.glDrawArrays(GL10.GL_TRIANGLES, 0, model.v_size); 

     } 

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

    /** 
    * It Load the object from stream. 
    * @param is 
    * @param texture_name 
    * @return 
    * @throws IOException 
    */ 
    public static ObjModel loadFromStream(InputStream is, String texture_name) throws IOException { 
     ObjModel obj = ObjLoader.loadFromStream(is); 
     return obj; 
    } 

    private Model mModels[]; 
    private int mTextures[] = new int[1];; 

    /** 
    * It read the the obj file. 
    * @author Ajay 
    */ 
    private static class ObjLoader { 

     public static ObjModel loadFromStream(InputStream is) throws IOException { 
      BufferedReader reader = new BufferedReader(new InputStreamReader(is)); 
      ObjModel obj = new ObjModel(); 
      ArrayList<Point3> v = new ArrayList<Point3>(); 
      ArrayList<Point3> vt = new ArrayList<Point3>(); 
      ArrayList<Point3> vn = new ArrayList<Point3>(); 
      ArrayList<Face> f = new ArrayList<Face>(); 

      ArrayList<Model> o = new ArrayList<Model>(); 

      boolean o_pending=false; 

      while(reader.ready()) { 
       String line = reader.readLine(); 
       if (line == null) 
        break; 

       StringTokenizer tok = new StringTokenizer(line); 
       String cmd = tok.nextToken(); 

       if (cmd.equals("o")) { 
        if (o_pending) { 
         Model model = new Model(); 
         model.fill(f, vt.size() > 0, vn.size() > 0); 
         o.add(model); 
        } 
        else { 
         o_pending=true; 
        } 
       } 
       else 
        if (cmd.equals("v")) { 
         v.add(read_point(tok)); 
        } 
        else 
         if (cmd.equals("vn")) { 
          vn.add(read_point(tok)); 
         } 
         else 
          if (cmd.equals("vt")) { 
           vt.add(read_point(tok)); 
          } 
          else 
           if (cmd.equals("f")) { 
            if (tok.countTokens() != 3) 
             continue; 

            Face face = new Face(3); 
            while (tok.hasMoreTokens()) { 
             StringTokenizer face_tok = new StringTokenizer(tok.nextToken(), "/"); 

             int v_idx = -1; 
             int vt_idx = -1; 
             int vn_idx = -1; 
             v_idx = Integer.parseInt(face_tok.nextToken()); 
             if (face_tok.hasMoreTokens()) vt_idx = Integer.parseInt(face_tok.nextToken()); 
             if (face_tok.hasMoreTokens()) vn_idx = Integer.parseInt(face_tok.nextToken()); 

             //Log.v("objmodel", "face: "+v_idx+"/"+vt_idx+"/"+vn_idx); 

             face.addVertex(
               v.get(v_idx-1), 
               vt_idx == -1 ? null : vt.get(vt_idx-1), 
                 vn_idx == -1 ? null : vn.get(vn_idx-1) 
               ); 
            } 
            f.add(face); 
           } 
      } 

      if (o_pending) { 
       Model model = new Model(); 
       model.fill(f, vt.size() > 0, vn.size() > 0); 
       o.add(model); 
      } 

      obj.mModels = new Model[o.size()]; 
      o.toArray(obj.mModels); 
      return obj; 
     } 

     private static Point3 read_point(StringTokenizer tok) { 
      Point3 ret = new Point3(); 
      if (tok.hasMoreTokens()) { 
       ret.x = Float.parseFloat(tok.nextToken()); 
       if (tok.hasMoreTokens()) { 
        ret.y = Float.parseFloat(tok.nextToken()); 
        if (tok.hasMoreTokens()) { 
         ret.z = Float.parseFloat(tok.nextToken()); 
        } 
       } 
      } 
      return ret; 
     } 

    } 

    private static class Face { 
     Point3 v[]; 
     Point3 vt[]; 
     Point3 vn[]; 
     int size; 
     int count; 

     public Face(int size) { 
      this.size = size; 
      this.count = 0; 
      this.v = new Point3[size]; 
      this.vt = new Point3[size]; 
      this.vn = new Point3[size]; 
     } 

     public boolean addVertex(Point3 v, Point3 vt, Point3 vn) { 
      if (count >= size) 
       return false; 
      this.v[count] = v; 
      this.vt[count] = vt; 
      this.vn[count] = vn; 
      count++; 
      return true; 
     } 

     public void pushOnto(FloatBuffer v_buffer, FloatBuffer vt_buffer, FloatBuffer vn_buffer) { 
      int i; 
      for (i=0; i<size; i++) { 
       v_buffer.put(v[i].x); v_buffer.put(v[i].y); v_buffer.put(v[i].z); 

       if (vt_buffer != null && vt[i] != null) { 
        vt_buffer.put(vt[i].x); vt_buffer.put(vt[i].y); 
       } 

       if (vn_buffer != null && vn[i] != null) { 
        vn_buffer.put(vn[i].x); vn_buffer.put(vn[i].y); vn_buffer.put(vn[i].z); 
       } 
      } 
     } 
    } 

    /** 
    * It hold the vertex buffer, vertex normal and texture. 
    * @author Ajay 
    */ 
    private static class Model { 
     public FloatBuffer v; 
     public FloatBuffer vt; 
     public FloatBuffer vn; 
     public int v_size; 

     public void fill(ArrayList<Face> faces, boolean has_tex, boolean has_normals) { 
      int f_len = faces.size(); 

      this.v_size = f_len * 3; 

      ByteBuffer tBuf = ByteBuffer.allocateDirect(this.v_size*3 * 4); 
      tBuf.order(ByteOrder.nativeOrder()); 
      this.v = tBuf.asFloatBuffer(); 

      if (has_tex) { 
       ByteBuffer vtBuf = ByteBuffer.allocateDirect(this.v_size*3 * 4); 
       vtBuf.order(ByteOrder.nativeOrder()); 
       this.vt = vtBuf.asFloatBuffer(); 
      } 

      if (has_normals) { 
       ByteBuffer vnBuf = ByteBuffer.allocateDirect(this.v_size*3 * 4); 
       vnBuf.order(ByteOrder.nativeOrder()); 
       this.vn = vnBuf.asFloatBuffer(); 
      } 

      int i; 
      for (i=0; i < f_len; i++) { 
       Face face = faces.get(i); 
       face.pushOnto(this.v, this.vt, this.vn); 
      } 

      this.v.rewind(); 
      if (this.vt != null) 
       this.vt.rewind(); 
      if (this.vn != null) 
       this.vn.rewind(); 
     } 
    } 
} 

Render.java

public void start() { 
    mRenderer = new Renderer(); 
    setEGLContextClientVersion(1); 
    setPreserveEGLContextOnPause(true); 
    setRenderer(mRenderer); 
} 

float mRotationFinal=-1f; 
float mRotationDelta=0f; 
int mRotationAxis=-1; 

private class Renderer implements GLSurfaceView.Renderer { 
    public Renderer() { 
     setEGLConfigChooser(8, 8, 8, 8, 16, 0); 
     getHolder().setFormat(PixelFormat.TRANSLUCENT); 
     setZOrderOnTop(true); 
    } 

    public void onSurfaceCreated(GL10 gl, EGLConfig config) { 
     gl.glClearColor(0.0f,0.0f,0.0f, 0.0f); 
     gl.glEnable(GL10.GL_DEPTH_TEST); 
     gl.glDepthFunc(GL10.GL_LEQUAL); 
     gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST); 

     gl.glEnable(GL10.GL_TEXTURE_2D); 
     gl.glShadeModel(GL10.GL_SMOOTH); 
    } 

    public void onSurfaceChanged(GL10 gl, int w, int h) { 
     mViewWidth = (float)w; 
     mViewHeight = (float)h; 
     gl.glViewport(0,0,w,h); 

     gl.glMatrixMode(GL10.GL_PROJECTION); 
     gl.glLoadIdentity(); 
     GLU.gluPerspective(gl, 45, mViewWidth/mViewHeight, 0.1f, 100f); 

     gl.glMatrixMode(GL10.GL_MODELVIEW); 
     gl.glLoadIdentity(); 
    } 

    public void onDrawFrame(GL10 gl) { 
     gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); 
     gl.glPushMatrix(); 

     gl.glDisable(GL10.GL_DITHER); 

     GLU.gluLookAt(gl, 0, 0, 10, 0, 0, 0, 0, 1, 0); 

     //draw_model 
     gl.glPushMatrix(); 

     if(mOrigin != null && mRotate != null) { 
      gl.glTranslatef(mOrigin.x, mOrigin.y, mOrigin.z); 
      gl.glRotatef(mRotate.x, 1f, 0f, 0f); 
      gl.glRotatef(mRotate.y, 0f, 1f, 0f); 
      gl.glRotatef(mRotate.z, 0f, 0f, 1f); 
     } 

     if(mModel != null) { 
      mModel.draw(gl); 
      if(!RendererView.textureFileName.equals("")) 
       mModel.bindTextures(mContext, gl); 
     } 

     gl.glPopMatrix(); 
     gl.glPopMatrix(); 

     if(isPictureTake) { 

      w = getWidth(); 
      h = getHeight(); 
      b = new int[w*(y+h)]; 
      bt = new int[w*h]; 

      IntBuffer ib = IntBuffer.wrap(b); 
      ib.position(0); 
      gl.glReadPixels(0, 0, w, h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, ib); 
      createBitmapFromGLSurface(context); 
      isPictureTake = false; 
     } 
    } 
} 

Point3.java

public class Point3 extends Object { 
    public float x; 
    public float y; 
    public float z; 

    public Point3() { 
    x = 0.0f; 
    y = 0.0f; 
    z = 0.0f; 
    } 

    public Point3(float x, float y, float z) { 
    set(x,y,z); 
    } 

    public Point3(Point3 src) { 
    set(src.x, src.y, src.z); 
    } 

    public final boolean equals(float x, float y, float z) { 
    return ((this.x == x) && (this.y == y) && (this.z == z)); 
    } 

    public void set(float x, float y, float z) { 
    this.x = x; 
    this.y = y; 
    this.z = z; 
    } 

    public void minmax(float minx, float miny, float minz, float maxx, float maxy, float maxz) { 
    this.x = Math.min(Math.max(this.x, minx), maxx); 
    this.y = Math.min(Math.max(this.y, miny), maxy); 
    this.z = Math.min(Math.max(this.z, minz), maxz); 
    } 

    @Override 
    public boolean equals(Object o) { 
    if (this == o) 
     return true; 

    if (!(o instanceof Point3)) 
     return false; 

    Point3 obj = (Point3)o; 
    return this.equals(obj.x, obj.y, obj.z); 
    } 

    @Override 
    public String toString() { 
    return "("+x+","+y+","+z+")"; 
    } 

    @Override 
    public int hashCode() { throw new UnsupportedOperationException(); } 
} 

Screen 1

Screen 2

Screen 3

+0

一方面,在繪製模型後,您正在綁定您的紋理。將該調用移動到'mModel.bindTextures(mContext,gl)',使其在'mModel.draw(gl)之前出現;'另外,您是否真的需要在每次繪製模型時重新加載此紋理?這似乎很浪費。 –

+0

@ AndonM.Coleman我在'mModel.draw(gl);'之前調用了'mModel.bindTextures(mContext,gl)',但它仍然沒有填充紋理。請幫我解決這個問題,無法理解過去20天的這個問題。 –

+0

@ AndonM.Coleman請幫幫我。我希望你能幫助我:) –

回答

0

仔細檢查後,我注意到,您的紋理座標數組是一個Point3但你的紋理座標的指針使用2個GL_FLOAT部件和爲0的步幅中的第一頂點後,你的座標指針將不會提供有效的數據。

有幾種方法可以解決這個問題:

  1. 使用Point2數組(如果這樣的事情存在)
  2. 使用12字節的步幅:

    gl.glTexCoordPointer (2, GL10.GL_FLOAT, 12, model.vt); 
    
  3. 使用3D紋理座標:

    gl.glTexCoordPointer (3, GL10.GL_FLOAT, 0, model.vt); 
    
+0

我試着用你的解決方案,但它仍然不工作。儘管如此,紋理仍然不完整。請再看一遍。我希望我很快得到你的回覆:) –

+0

我試過第二個和第三個解決方案,但沒有變化。請你能寫一些更多的代碼,我不明白你的第一個解決方案。請幫助我希望我會得到答覆:) –

+0

我在問題中添加了Point3.java類。請檢查一下 –