扩展AndEngine以渲染3D模型的问题

时间:2014-04-21 12:37:25

标签: java android opengl-es-2.0 andengine

对于我在AndEngine游戏开发上写的一本书,我正在尝试开发一个示例AndEngine应用程序,展示如何导入和渲染3D模型。对于导入,我使用我成功为Android编译的Assimp库,并使用C ++中基于NDK的小包装器。

我导入的模型是使用其OBJ导出器从3DS Max 2013导出的基本茶壶模型。在Java调试器中,生成的顶点,普通和uv数组数据看起来很好。我遇到的问题是在AndEngine应用程序中实际显示模型。 OpenGL ES 2.0相关代码遍布AndEngine代码,因此很难确定究竟是什么以及以什么顺序执行。此时,我交替看到正在渲染的模型,或者只看到以下输出:Vague outline of a teapot on top of a sprite.

为了显示模型,我扩展了许多AndEngine类。首先,我创建了一个只保存数据数组的ModelData类。这被传递给一个Model类,它类似于Sprite派生自Shape。在它当前,凌乱,精灵衍生的时尚中,它看起来像这样:

public class Model extends Shape {
public static final int VERTEX_INDEX_X = 0;
public static final int VERTEX_INDEX_Y = Model.VERTEX_INDEX_X + 1;
public static final int COLOR_INDEX = Model.VERTEX_INDEX_Y + 1;
public static final int TEXTURECOORDINATES_INDEX_U = Model.COLOR_INDEX + 1;
public static final int TEXTURECOORDINATES_INDEX_V = Model.TEXTURECOORDINATES_INDEX_U + 1;

public static final int VERTEX_SIZE = 2 + 1 + 2;
public static final int VERTICES_PER_SPRITE = 4;
public static final int SPRITE_SIZE = Model.VERTEX_SIZE * Model.VERTICES_PER_SPRITE;

public static final int POSITION_ATTRIBUTE_ID = 0;
public static final int NORMAL_ATTRIBUTE_ID = 1;
public static final int TEXTURE_COORDINATE_ATTRIBUTE_ID = 2;

public static final VertexBufferObjectAttributes VERTEXBUFFEROBJECTATTRIBUTES_DEFAULT = 
        new VertexBufferObjectAttributesBuilder(3)
        .add(POSITION_ATTRIBUTE_ID, "Position", 3, GLES20.GL_FLOAT, false)
        .add(NORMAL_ATTRIBUTE_ID, "Normal", 3, GLES20.GL_FLOAT, true)
        .add(TEXTURE_COORDINATE_ATTRIBUTE_ID, "Texture_Coordinate", 2,
                GLES20.GL_FLOAT, false).build();


protected final ModelData mModelData;
protected final ITextureRegion mTextureRegion;
protected final HighPerformanceModelVertexBufferObject mModelVertexBufferObject;
//private int mMVPMatrixHandle;
private float[] mVMatrix = new float[16];
private float[] mProjMatrix = new float[16];
//private float[] mMVPMatrix = new float[16];
private float[] mInterleavedArray;
//private FloatBuffer interleavedBuffer;


// --- CONSTRUCTOR ---
public Model(final float pX, final float pY, final ITextureRegion pTextureRegion, 
        ModelData pModelData, VertexBufferObjectManager pVertexBufferObjectManager) {
    super(pX, pY, ModelShaderProgram.getInstance());
    mTextureRegion = pTextureRegion;
    mInterleavedArray = pModelData.getInterleavedArray();
    mModelVertexBufferObject = new HighPerformanceModelVertexBufferObject(
            pVertexBufferObjectManager, mInterleavedArray, DrawType.STATIC, 
            true, Model.VERTEXBUFFEROBJECTATTRIBUTES_DEFAULT);
    mModelData = pModelData;

    //mMVPMatrixHandle = GLES20.glGetUniformLocation(
        //  ((ModelShaderProgram) mShaderProgram).getProgramId(), "uMVPMatrix");
}


// --- GET VERTEX BUFFER OBJECT ---
@Override
public IVertexBufferObject getVertexBufferObject() {
    return mModelVertexBufferObject;
}


// --- ON SURFACE CHANGED ---
public void onSurfaceChanged(GLState pGLState, int pWidth, int pHeight) {
    // onSurfaceChanged
    float ratio = (float) pWidth / pHeight;
    // create a projection matrix from device screen geometry
    Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 37);

    // Create a camera view matrix
    Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);

    /*int[] buffers = new int[2];
    GLES20.glGenBuffers(2, buffers, 0);
    int rectVerts = buffers[0];
    //int rectInds = buffers[1];
    interleavedBuffer = FloatBuffer.wrap(mInterleavedArray);
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, rectVerts);
    GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mInterleavedArray.length, 
            interleavedBuffer, GLES20.GL_STATIC_DRAW);*/

    /*GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, rectInds);
    GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, 
            (rectIndices.limit()*4), rectIndices, GLES20.GL_STATIC_DRAW);*/
}


// --- PREDRAW ---
@Override
protected void preDraw(GLState pGLState, Camera pCamera) {
    super.preDraw(pGLState, pCamera);

    //this.mTextureRegion.getTexture().bind(pGLState); // TODO
    this.mModelVertexBufferObject.bind(pGLState, this.mShaderProgram);
}


// --- DRAW ---
@Override
protected void draw(GLState pGLState, Camera pCamera) {
    // Combine the projection and camera view matrices
    //Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);

    // Apply the combined projection and camera view transformations
    //GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);

    // Draw the model
    //GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount); // TODO
    this.mModelVertexBufferObject.draw(GLES20.GL_TRIANGLES, 
            mInterleavedArray.length);
}


// --- POST-DRAW ---
@Override
protected void postDraw(GLState pGLState, Camera pCamera) {
    this.mModelVertexBufferObject.unbind(pGLState, this.mShaderProgram);

    super.postDraw(pGLState, pCamera);
}


// --- ON UPDATE VERTICES ---
@Override
protected void onUpdateVertices() {
    this.mModelVertexBufferObject.onUpdateVertices(this);
}


// --- ON UPDATE COLOR ---
@Override
protected void onUpdateColor() {
    this.mModelVertexBufferObject.onUpdateColor(this);
}


// --- ON UPDATE TEXTURE COORDINATES ---
protected void onUpdateTextureCoordinates() {
    this.mModelVertexBufferObject.onUpdateTextureCoordinates(this);
}
}

HighPerformanceModelVertexBufferObject类如下所示:

public class HighPerformanceModelVertexBufferObject extends
    HighPerformanceVertexBufferObject {
ModelShaderProgram mModelShaderProgram;

public HighPerformanceModelVertexBufferObject(
        VertexBufferObjectManager pVertexBufferObjectManager,
        final float[] pBufferData, DrawType pDrawType, boolean pAutoDispose,
        VertexBufferObjectAttributes pVertexBufferObjectAttributes) {
    super(pVertexBufferObjectManager, pBufferData, pDrawType, pAutoDispose,
            pVertexBufferObjectAttributes);
}


// --- SET VERTEX DATA ---
/*public void setVertexData(float[] va) {
    mBufferData = va;
}*/


@Override
public void bind(final GLState pGLState, final ShaderProgram pShaderProgram) {
    mModelShaderProgram = (ModelShaderProgram) pShaderProgram;
    super.bind(pGLState, pShaderProgram);
}


@Override
public void draw(final int pPrimitiveType, final int pCount) {
    GLES20.glDrawArrays(pPrimitiveType, 0, pCount);
    //GLES20.glDrawElements(pPrimitiveType, pCount, GLES20.GL_UNSIGNED_SHORT, mByteBuffer);
}


public void onUpdateColor(final Model pModel) {
    //
}


public void onUpdateVertices(final Model pModel) {
    //
}


public void onUpdateTextureCoordinates(final Model pModel) {
    //
}
}

最后是ModelShaderProgram类,包含顶点和片段着色器:

public class ModelShaderProgram extends ShaderProgram {
private static ModelShaderProgram INSTANCE;

public static final String VERTEXSHADER =
        "attribute vec3 positionAttrib; \n" +
        "attribute vec3 normalAttrib; \n" +
        "attribute vec2 uvAttrib; \n" +

        // This matrix member variable provides a hook to manipulate
        // the coordinates of objects that use this vertex shader.
        "uniform mat4 uMVPMatrix;   \n" +
        "void main() {\n" +         
        // The matrix must be included as part of gl_Position
        // Note that the uMVPMatrix factor *must be first* in order
        // for the matrix multiplication product to be correct.
        "gl_Position = uMVPMatrix * vec4(positionAttrib, 1.0); \n" +
        "}";

public static final String FRAGMENTSHADER =
        "void main() {\n" +
        " gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); \n" +
        "}";

public static int sUniformModelViewPositionMatrixLocation = -1;
public static int sUniformTexture0Location = -1;


private ModelShaderProgram() {
    super(ModelShaderProgram.VERTEXSHADER, ModelShaderProgram.FRAGMENTSHADER);
}

public static ModelShaderProgram getInstance() {
    if (ModelShaderProgram.INSTANCE == null) {
        ModelShaderProgram.INSTANCE = new ModelShaderProgram();
    }

    return ModelShaderProgram.INSTANCE;
}


@Override
protected void link(final GLState pGLState) throws ShaderProgramLinkException {
    GLES20.glBindAttribLocation(this.mProgramID, 0, "positionAttrib");
    GLES20.glBindAttribLocation(this.mProgramID, 1, "normalAttrib");
    GLES20.glBindAttribLocation(this.mProgramID, 2, "uvAttrib");

    super.link(pGLState);

    ModelShaderProgram.sUniformModelViewPositionMatrixLocation = 
            this.getUniformLocation("uMVPMatrix");
    //ModelShaderProgram.sUniformTexture0Location = 
        //  this.getUniformLocation(ShaderProgramConstants.UNIFORM_TEXTURE_0);
}

@Override
public void bind(final GLState pGLState, final VertexBufferObjectAttributes pVertexBufferObjectAttributes) {
    super.bind(pGLState, pVertexBufferObjectAttributes);

    GLES20.glUniformMatrix4fv(ModelShaderProgram.sUniformModelViewPositionMatrixLocation, 1, false, pGLState.getModelViewProjectionGLMatrix(), 0);
    //GLES20.glUniform1i(ModelShaderProgram.sUniformTexture0Location, 0);
}
}

正如您在片段着色器中看到的那样,它应该将任何片段着色为红色,但这显然不会发生。奇怪的轮廓图也非常好奇。在集成此代码时是否遗漏了一些内容?我是否试图在AndEngine的代码中覆盖一些我应该单独留下的代码?

提前感谢您提供任何提示/建议。随意询问更多信息等。

更新一位同事指出我正在使用的模型已编入索引。使用glDrawElements而不是glDrawArray切换到索引绘图。

0 个答案:

没有答案