OpenGL ES 2四面体,带有彩色面

时间:2013-07-15 17:51:08

标签: opengl-es-2.0

我正在学习OpenGL ES 2进行定向研究,有些事情我不理解。我不太明白传递给glVertexAttribPointer的步幅是什么。此外,我能够绘制一个纯色四面体,但现在我正在尝试扩展它,使每个面部都有不同的颜色。它进展不顺利。有人可以帮助我在着色器方面做错了,为什么它会使颜色变得模糊/不能正确旋转。我使用http://www.learnopengles.com/android-lesson-two-ambient-and-diffuse-lighting/作为理解绘图如何工作的基础。任何帮助理解着色器如何工作和步伐等等以及我做错了什么都将非常感激。

package com.example.lab5task1;

//middle of screen is 0,0.  To left/right is -/+ x, up/down is +/- y

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import java.util.Random;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Point;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.os.SystemClock;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;

public class MyGLRenderer implements GLSurfaceView.Renderer
{

private static final String TAG = "MyGLRenderer";
private Tetrahedron mTet;
private float height, width;
public float xTouch, yTouch;
Random rand = new Random();

private final float[] mMVPMatrix = new float[16]; //model view and projection matrix
private final float[] mProjMatrix = new float[16]; //projection matrix
private final float[] mVMatrix = new float[16]; //view matrix
private final float[] mRotationMatrix = new float[16]; //rotation matrix
private float[] drawColor = { rand.nextFloat(), rand.nextFloat(), rand.nextFloat(), 1f };
private float[] mModelMatrix = new float[16];

@SuppressLint("NewApi")
MyGLRenderer(Context context)
{
    WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    Display display = wm.getDefaultDisplay();
    Point size = new Point();
    display.getSize(size);

    //used for correct drawing and touch
    this.height = size.y;
    this.width = size.x;
    this.xTouch = this.yTouch = 0;
}

@Override
public void onSurfaceCreated(GL10 unused, EGLConfig config)
{

    GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    // Use culling to remove back faces.
    GLES20.glEnable(GLES20.GL_CULL_FACE);

    // Enable depth testing
    GLES20.glEnable(GLES20.GL_DEPTH_TEST);

    //eye positions
    final float eyeX = 0.0f;
    final float eyeY = 0.0f;
    final float eyeZ = -3f;

    // We are looking toward the distance
    final float lookX = 0.0f;
    final float lookY = 0.0f;
    final float lookZ = -1.0f;

    // Set our up vector. This is where our head would be pointing were we holding the camera.
    final float upX = 0.0f;
    final float upY = 1.0f;
    final float upZ = 0.0f;

    // Set the view matrix. This matrix can be said to represent the camera position.
    Matrix.setLookAtM(mVMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);

}

@Override
public void onDrawFrame(GL10 unused)
{

    // Draw background color
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

    Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);

    // Calculate the projection and view transformation
    Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);

    long time = SystemClock.uptimeMillis() % 10000L;
    float angleInDegrees = (360.0f / 10000.0f) * ((int) time);

    mTet = new Tetrahedron();

    // Draw the triangle facing straight on.
    Matrix.setIdentityM(mRotationMatrix, 0);
    Matrix.rotateM(mRotationMatrix, 0, angleInDegrees, .5f, .5f, 0.0f);
    Matrix.multiplyMM(mMVPMatrix, 0, mRotationMatrix, 0, mMVPMatrix, 0);

    mTet.draw(mMVPMatrix);
}

@Override
public void onSurfaceChanged(GL10 unused, int width, int height)
{
    // Adjust the viewport based on geometry changes,
    // such as screen rotation
    GLES20.glViewport(0, 0, width, height);

    final float ratio = (float) width / height;
    final float left = -ratio;
    final float right = ratio;
    final float bottom = -1.0f;
    final float top = 1.0f;
    final float near = 1.0f;
    final float far = 10.0f;

    Matrix.frustumM(mProjMatrix, 0, left, right, bottom, top, near, far);

}

public static int loadShader(int type, String shaderCode)
{

    // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
    // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
    int shader = GLES20.glCreateShader(type);

    // add the source code to the shader and compile it
    GLES20.glShaderSource(shader, shaderCode);
    GLES20.glCompileShader(shader);

    return shader;
}

public static void checkGlError(String glOperation)
{
    int error;
    while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR)
    {
        Log.e(TAG, glOperation + ": glError " + error);
        throw new RuntimeException(glOperation + ": glError " + error);
    }
}
}

class Tetrahedron
{

enum STYLE
{
    OLD, NEW
};

private STYLE codeType = STYLE.NEW;

private final FloatBuffer vertexBuffer;
private final FloatBuffer mColors;
private final ShortBuffer drawListBuffer;
private final int mProgram;
private int mPositionHandle;
private int mColorHandle;
private int mMVPMatrixHandle;
private int mMVMatrixHandle;

private final String vertexShaderCode = "uniform mat4 uMVPMatrix;" + " attribute vec4 vPosition;" + "void main() {" + "  gl_Position = vPosition * uMVPMatrix;" + "}";

private final String fragmentShaderCode = "precision mediump float;" + "uniform vec4 vColor;" + "void main() {" + "  gl_FragColor = vColor;" + "}";

// number of coordinates per vertex in this array
// 72d angles at center, 108 angle at vertex
static final int COORDS_PER_VERTEX = 3;
static final int COLOR_DATA_SIZE = 4;

static float tetCoords[] = { 0.0f, 0.622008459f, 0.0f,//
        -0.5f, -0.311004243f, 0.0f,//
        0.5f, -0.311004243f, 0.0f,//
        0.0f, 0.0f, .622008459f };

static float colors[] = {
        //face one
        1.0f, 0.0f, 0.0f, 1.0f,//             
        1.0f, 0.0f, 0.0f, 1.0f,//
        1.0f, 0.0f, 0.0f, 1.0f,//
        //face two
        0.0f, 1.0f, 0.0f, 1.0f,//             
        0.0f, 1.0f, 0.0f, 1.0f,//
        0.0f, 1.0f, 0.0f, 1.0f,//
        //face three
        0.0f, 0.0f, 1.0f, 1.0f,//             
        0.0f, 0.0f, 1.0f, 1.0f,//
        0.0f, 0.0f, 1.0f, 1.0f,//
        //face four
        1.0f, 1.0f, 0.0f, 1.0f,//             
        1.0f, 1.0f, 0.0f, 1.0f,//
        1.0f, 1.0f, 0.0f, 1.0f,//
};

String[] attributes = { "a_Position", "a_Color" };

private short drawOrder[] = { 0, 1, 2, 3, 0, 1 };
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
private final int colorStride = COLOR_DATA_SIZE * 4;

float color[] = { .5f, .5f, .5f, 1f };

public Tetrahedron()
{
    // initialize vertex byte buffer for shape coordinates

    //this.color = color;
    ByteBuffer bb = ByteBuffer.allocateDirect(
    // (# of coordinate values * 4 bytes per float)
            tetCoords.length * 4);
    bb.order(ByteOrder.nativeOrder());
    vertexBuffer = bb.asFloatBuffer();
    vertexBuffer.put(tetCoords);
    vertexBuffer.position(0);

    // initialize byte buffer for the draw list
    // (# of coordinate values * 2 bytes per short)
    ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 2);
    dlb.order(ByteOrder.nativeOrder());
    drawListBuffer = dlb.asShortBuffer();
    drawListBuffer.put(drawOrder);
    drawListBuffer.position(0);

    mColors = ByteBuffer.allocateDirect(colors.length * 4).order(ByteOrder.nativeOrder())
            .asFloatBuffer();
    mColors.put(colors);
    mColors.position(0);

    if (codeType == STYLE.NEW)
    {

        final String vertexShader = getVertexShader();
        final String fragmentShader = getFragmentShader();

        int vertexShaderHandle = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER, vertexShader);
        int fragmentShaderHandle = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
                fragmentShader);
        mProgram = GLES20.glCreateProgram();
        GLES20.glAttachShader(mProgram, vertexShaderHandle);
        GLES20.glAttachShader(mProgram, fragmentShaderHandle);
        for (int i = 0; i < attributes.length; i++)
        {
            GLES20.glBindAttribLocation(mProgram, i, attributes[i]);
        }

        GLES20.glLinkProgram(mProgram);

    }
    else
    {
        int vertexShaderHandle = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
                vertexShaderCode);
        int fragmentShaderHandle = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
                fragmentShaderCode);
        mProgram = GLES20.glCreateProgram();
        GLES20.glAttachShader(mProgram, vertexShaderHandle);
        GLES20.glAttachShader(mProgram, fragmentShaderHandle);
        for (int i = 0; i < attributes.length; i++)
        {
            GLES20.glBindAttribLocation(mProgram, i, attributes[i]);
        }

        GLES20.glLinkProgram(mProgram);

    }
}

protected String getVertexShader()
{

    // TODO: Explain why we normalize the vectors, explain some of the vector math behind it all. Explain what is eye space.
    final String vertexShader = "uniform mat4 u_MVPMatrix;      \n" // A constant representing the combined model/view/projection matrix.
            + "uniform mat4 u_MVMatrix;       \n" // A constant representing the combined model/view matrix.  
            + "attribute vec4 a_Position;     \n" // Per-vertex position information we will pass in.
            + "attribute vec4 a_Color;        \n" // Per-vertex color information we will pass in.
            + "varying vec4 v_Color;          \n" // This will be passed into the fragment shader.

            + "void main()                    \n" // The entry point for our vertex shader.
            + "{                              \n"
            // Transform the vertex into eye space.
            + "   vec3 modelViewVertex = vec3(u_MVMatrix * a_Position);              \n"
            // Multiply the color by the illumination level. It will be interpolated across the triangle.
            + "   v_Color = a_Color;                                       \n"
            // gl_Position is a special variable used to store the final position.
            // Multiply the vertex by the matrix to get the final point in normalized screen coordinates.       
            + "   gl_Position = u_MVPMatrix * a_Position;                            \n" + "}                                                                     \n";

    return vertexShader;
}

protected String getFragmentShader()
{
    final String fragmentShader = "precision mediump float;       \n" // Set the default precision to medium. We don't need as high of a 
                                                                      // precision in the fragment shader.                
            + "varying vec4 v_Color;          \n" // This is the color from the vertex shader interpolated across the 
                                                  // triangle per fragment.             
            + "void main()                    \n" // The entry point for our fragment shader.
            + "{                              \n" + "   gl_FragColor = v_Color;     \n" // Pass the color directly through the pipeline.          
            + "}                              \n";

    return fragmentShader;
}

public void draw(float[] mvpMatrix)
{
    // Add program to OpenGL environment
    GLES20.glUseProgram(mProgram);

    if (codeType == STYLE.NEW)
    {
        mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "u_MVPMatrix");
        mMVMatrixHandle = GLES20.glGetUniformLocation(mProgram, "u_MVMatrix");
        mPositionHandle = GLES20.glGetAttribLocation(mProgram, "a_Position");
        mColorHandle = GLES20.glGetAttribLocation(mProgram, "a_Color");
        // Prepare the triangle coordinate data
        GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT,
                false, vertexStride, vertexBuffer);

        // Enable a handle to the triangle vertices
        GLES20.glEnableVertexAttribArray(mPositionHandle);

        // Pass in the color information
        GLES20.glVertexAttribPointer(mColorHandle, COLOR_DATA_SIZE, GLES20.GL_FLOAT, false,
                colorStride, mColors);
        GLES20.glEnableVertexAttribArray(mColorHandle);

        // Apply the projection and view transformation
        GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
        MyGLRenderer.checkGlError("glUniformMatrix4fv");

    }
    else
    {

        // get handle to vertex shader's vPosition member
        mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");

        // Enable a handle to the triangle vertices
        GLES20.glEnableVertexAttribArray(mPositionHandle);

        // Prepare the triangle coordinate data
        GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT,
                false, vertexStride, vertexBuffer);

        // get handle to fragment shader's vColor member
        mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");

        // Set color for drawing the triangle
        GLES20.glUniform4fv(mColorHandle, 1, color, 0);

        // get handle to shape's transformation matrix
        mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
        MyGLRenderer.checkGlError("glGetUniformLocation");

        // Apply the projection and view transformation
        GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
        MyGLRenderer.checkGlError("glUniformMatrix4fv");

    }

    // Draw the square
    GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, drawOrder.length, GLES20.GL_UNSIGNED_SHORT,
            drawListBuffer);

    // Disable vertex array
    GLES20.glDisableVertexAttribArray(mPositionHandle);
}
}

2 个答案:

答案 0 :(得分:1)

你传递了4个顶点和12种颜色。您为顶点0-11指定了1 vec4颜色,并且仅在索引0-3之间绘制三角形,因此仅使用了前四种颜色。

答案 1 :(得分:0)

步幅是以字节为单位的属性之间的距离,如果要将多个属性打包到同一个数组中,则使用步长。看来你在这里每个属性使用一个数组,所以你可以传入0作为告诉OpenGL属性紧密打包的步幅。

您的位置和颜色数组在组件方面应该是相同的长度。即一种颜色的一个位置。这可能就是为什么颜色没有像你期望的那样出现的原因。

如果您希望每个面都是不同的实心颜色,请设置顶点以使每个三角形不同,并使用GL_TRIANGLES绘制。例如:

{ 0f, 1f, 0f,    // Left
  -1, 0f, 1f,
  -1, 0f, -1f,

  0f, 1f, 0f,    // Right
  1f, 0f, 1f,
  1f, 0f, 1f,

  0f, 1f, 0f,    // Near 
 -1f, 0f, 1f,
  1f, 0f, 1f,

  0f, 1f, 0f,    // Far 
 -1f, 0f, -1f,
  1f, 0f, -1f }

并使用GL_TRIANGLES绘制。如果这导致改进,请告诉我们!