【问题标题】:Rotation issue in 3D Model in OpenGlOpenGL中3D模型的旋转问题
【发布时间】:2013-09-05 12:25:54
【问题描述】:

我想旋转对象 z 轴,所以我使用下面的代码,但它没有在特定位置旋转,它的旋转只是返回并出现在附近。我认为GLU.gluLookAt(gl, 0, 0, 10, 0, 0, 0, 0, 1, 0); 中的值有问题。请帮我设置这些的正确值,这样旋转效果很好。

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


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, mContext);
            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(mContext);
            isPictureTake = false;
        }
    }
}

ObjLoader.java

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_LINEAR);
                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, Context mContext) {
        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();
        }
    }
}

【问题讨论】:

  • 通常你想围绕一个对象的中心旋转。如果您在平移对象之前进行旋转,这将有很大帮助。如果您已经有一个不在 (0.0, 0.0, 0.0) 的相机,您应该:平移 (-CamerPos) ,旋转 ...,平移 (CameraPos + mOrigin)
  • @AndonM.Coleman 感谢您的回复。我没有收到你的最后一个If you already have a camera that's not at (0.0, 0.0, 0.0) you should: Translate (-CamerPos) , Rotate ..., Translate (CameraPos + mOrigin)。请你帮我写一些小代码

标签: android opengl-es rotation


【解决方案1】:

要绕轴在特定位置旋转对象,首先需要将对象的中心平移到原点。在您的示例中,您在 (mOrigin) 有一个对象,可能相对于另一个平移(您的相机的位置)。

您需要将对象平移到 (0,0,0),然后旋转然后平移到最终位置,而不是先将对象平移到最终位置再旋转。

最简单的情况是:

gl.glRotatef    (mRotate.x, 1f, 0f, 0f);
gl.glRotatef    (mRotate.y, 0f, 1f, 0f);
gl.glRotatef    (mRotate.z, 0f, 0f, 1f);
gl.glTranslatef (mOrigin.x, mOrigin.y, mOrigin.z);

在更复杂的情况下,您的对象相对于相机,您必须执行以下操作:

gl.glTranslatef (-Camera.x, -Camera.y, -Camera.z);
gl.glRotatef    (mRotate.x, 1f, 0f, 0f);
gl.glRotatef    (mRotate.y, 0f, 1f, 0f);
gl.glRotatef    (mRotate.z, 0f, 0f, 1f);
gl.glTranslatef (Camera.x + mOrigin.x, Camera.y + mOrigin.y, Camera.z + mOrigin.z);

【讨论】:

  • 我尝试了这两种方法,但仍然有同样的问题,它没有从任何特定的轴旋转..当我只更改 mRotate.z 然后它像斜率或抛物线一样旋转..它不是我的想。我希望你能再看一次:)。我想要这个dropbox.com/s/ozt7beo4gz5q293/demo2__A.avi
  • 我在pastebin.com/PGhG1AM3 添加了我的完整代码。请检查并帮助我。我在上面的评论中添加了一个保管箱文件的链接,这是我的客户要求。
【解决方案2】:

Glulookat 的旋转组件看起来不错,所以我没有看到任何可能导致问题的问题。

首先,从您提供的链接来看,在我看来,您想要围绕 Y 轴旋转,尽管您提到了围绕 Z 轴的旋转,这可能会产生不同的结果。 https://www.dropbox.com/s/ozt7beo4gz5q293/demo2__A.avi

其次,您在 m_Rotate 向量中使用的值是什么?它们是度数还是弧度?

第三,你是推入还是弹出矩阵堆栈?如果是这样怎么办?还是您将自己的矩阵数据输入 OpenGL?

您是否还确保在绘制调用期间调用 glLoadIdentity() 将视图矩阵设置回单位矩阵?

TBH 可能存在许多可能导致问题的区域。要缩小可能的问题区域,请在绘图函数中执行以下操作;

  • 停止使用 GluLookAt。
  • 删除所有推送和弹出调用,
  • 首先确保调用

    glLoadIdentity();
    
  • 将您的相机平移到物体后面(在您的 GLuLookAt 中,此值设置为 0,0,10)。

    glTranslatef(0.0f,0.0f,-10.0f);  
    
  • 然后绕Z轴做简单的旋转;

    glRotatef(mRotate.z, 0.0f, 0.0f, 1.0f);
    

编辑:据我所知,您调用 onDrawFrame 在场景中绘制东西。 .在此通话中,您需要进行这些更改以找出问题所在。

而不是这个;

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);
    }
    ...
    gl.glPopMatrix();
    gl.glPopMatrix();
  }

试试像这样更简单的东西。

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

    gl.glMatrixMode(GL10.GL_MODELVIEW); //making sure OpenGL currently in model view
    gl.glLoadIdentity();                //clear the model view matrix to identity matrix

    gl.glTranslatef(0.0f, 0.0f, -10.0f); //move 10 unit backwards so as if camera moves backwards.
    gl.glRotatef(90.0f,0.0f,0.0f,1.0f)    //rotate 90 degree around the z axis.
    //draw_model
    ...
    //gl.glPopMatrix();
    //gl.glPopMatrix();
  }

通过这样做,您可能出现的问题区域减少了很多。你就可以开始找出问题所在了。如果上面的代码有效,那么可能的错误就会减少很多。 可能是这样的;

  • 您将矩阵模式设置为模型视图以外的其他位置,而不是在您的绘图调用中将其设置回,
  • 您没有在绘图调用中清除单位矩阵。
  • 您的原点和旋转值未正确完成。

顺便说一句:我不是 java 方面的专家,但在 c++ 和目标 c 方面,我们不能做 1f 来将一个值设置为浮动。我们必须使用 1.0f 否则编译器会抱怨。

【讨论】:

  • 我在问题中添加了代码。请检查一下。我希望这将帮助您和我找到解决方案。我希望你能帮助我:)。请通过编辑我的代码来帮助我
  • 您必须了解在 openGL 中转换是如何发生的,仅我编辑您的代码并不能帮助您实现这一目标。从我看到的代码中,您正在使用 openGL 堆栈来管理您的转换。您是否真的尝试过我在答案中建议您做的事情?从更新的代码中,我可以看到您没有将视图矩阵清除为单位矩阵。答案写在上面。你也有一些没有意义的推送和弹出调用。如果您不看方向,您的 GLuLookAt 几乎毫无意义。你可以简单地使用 glTranslatef 代替。
  • 我按照你说的试过了,但现在这里什么都没有显示。这些是更改pastebin.com/znbuQE7Z 请检查它
  • 我没有看到你的draw call中的变化,它们仍然是一样的。我进一步编辑了我的答案,为您提供更多见解。你是如何设置原点和旋转值的,我似乎无法在你的代码中弄清楚
  • 我和你说的一样,但现在对象没有出现..gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); gl.glDisable(GL10.GL_DITHER); gl.glMatrixMode(GL10.GL_MODELVIEW); //making sure OpenGL currently in model view gl.glLoadIdentity(); //clear the model view matrix to identity matrix gl.glTranslatef(0, 0, 10); 并删除了这些//gl.glPopMatrix(); //gl.glPopMatrix();
猜你喜欢
  • 2021-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-06
  • 1970-01-01
  • 2011-09-15
  • 1970-01-01
相关资源
最近更新 更多