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

2 回答 2

1

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

于 2013-07-16T14:55:34.523 回答
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 绘制。让我们知道这是否会导致改进!

于 2013-07-15T19:02:59.913 回答