-1

我正在尝试为 android 实现 3d 应用程序,并且在绘制 3d 对象(例如圆锥体)时遇到了麻烦。问题是我无法注意到不同面孔之间的过渡,它们都是用相同的颜色绘制的。我想我需要为多边形添加阴影,但我找不到任何教程告诉我如何做到这一点。这是我用来绘制圆锥的代码。

public class Cone{
float baseSize = 0f;
float height = 0f;
protected final float[] mTransformMatrix = new float[16];
private FloatBuffer vertexBuffer;
private final int mProgram;
private final String vertexShaderCode =
        // This matrix member variable provides a hook to manipulate
        // the coordinates of the objects that use this vertex shader
        "uniform mat4 uMVPMatrix;" +
                "attribute vec4 vPosition;" +
                "void main() {" +
                // the matrix must be included as a modifier of gl_Position
                // Note that the uMVPMatrix factor *must be first* in order
                // for the matrix multiplication product to be correct.
                "  gl_Position = uMVPMatrix * vPosition;" +
                "}";

// Use to access and set the view transformation
private int mMVPMatrixHandle;
private final String fragmentShaderCode =
        "precision mediump float;" +
                "uniform vec4 vColor;" +
                "void main() {" +
                "  gl_FragColor = vColor;" +
                "}";

// number of coordinates per vertex in this array
static final int COORDS_PER_VERTEX = 3;
static float topCoords[] = new float[30];
static float baseCoords[] = new float[30];
static float lineCoords[] = new float[96];
// Set color with red, green, blue and alpha (opacity) values
float color[] = { 1f, 0f, 0f, 1.0f };
float linecolor[] = { 1f, 1f, 1f, 1.0f };

public Cone(float baseSize , float height) {
    this.baseSize = baseSize;
    this.height = height;
    float ang = (float) ((2*Math.PI) / 8);
    Matrix.setIdentityM(mTransformMatrix, 0);
    // initialize vertex byte buffer for shape coordinates
    ByteBuffer bb = ByteBuffer.allocateDirect(
            // (number of coordinate values * 4 bytes per float)
            (topCoords.length * 2 + lineCoords.length) * 4);
    // use the device hardware's native byte order
    bb.order(ByteOrder.nativeOrder());

    // create a floating point buffer from the ByteBuffer
    vertexBuffer = bb.asFloatBuffer();
    // add the coordinates to the FloatBuffer
    topCoords[0] = 0;
    topCoords[1] = height;
    topCoords[2] = 0;
    baseCoords[0]= 0;
    baseCoords[1]= 0;
    baseCoords[2]= 0;
    for(int i=1; i < 10;i++) {
        topCoords[i*3] = this.baseSize * (float) Math.cos(i*ang);
        topCoords[i*3 + 1] = 0;
        topCoords[i*3 + 2] = this.baseSize * (float) Math.sin(i*ang);

        baseCoords[i*3] = this.baseSize * (float) Math.cos(i*ang);
        baseCoords[i*3 + 1] = 0;
        baseCoords[i*3 + 2] = this.baseSize * (float) Math.sin(i*ang);

    }
    for (int i = 0 ; i < 8 ; i ++) {
        lineCoords[i*6] = 0;
        lineCoords[i*6 + 1] = height;
        lineCoords[i*6 + 2] = 0;
        lineCoords[i*6 + 3] = this.baseSize *(float) Math.cos((i+1)*ang);
        lineCoords[i*6 + 4] = 0;
        lineCoords[i*6 + 5] = this.baseSize * (float) Math.sin((i+1)*ang);

    }
    int j = 0;
    for (int i = 8 ; i < 16 ; i++){
        lineCoords[i*6] = this.baseSize *(float) Math.cos((j+1)*ang);
        lineCoords[i*6 + 1] = 0;
        lineCoords[i*6 + 2] = this.baseSize * (float) Math.sin((j+1)*ang);

        lineCoords[i*6 + 3] = this.baseSize *(float) Math.cos((j+2)*ang);
        lineCoords[i*6 + 4] = 0;
        lineCoords[i*6 + 5] = this.baseSize * (float) Math.sin((j+2)*ang);
        j++;
    }



    vertexBuffer.put(topCoords);
    vertexBuffer.put(baseCoords);
    vertexBuffer.put(lineCoords);
    // set the buffer to read the first coordinate
    vertexBuffer.position(0);

    int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
            vertexShaderCode);
    int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
            fragmentShaderCode);

    // create empty OpenGL ES Program
    mProgram = GLES20.glCreateProgram();

    // add the vertex shader to program
    GLES20.glAttachShader(mProgram, vertexShader);

    // add the fragment shader to program
    GLES20.glAttachShader(mProgram, fragmentShader);

    // creates OpenGL ES program executables
    GLES20.glLinkProgram(mProgram);
}
private int mPositionHandle;
private int mColorHandle;

private final int topVertexCount = topCoords.length / COORDS_PER_VERTEX;
private final int lineVertexCount = lineCoords.length / COORDS_PER_VERTEX;


private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex

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

    // 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 cone
    GLES20.glUniform4fv(mColorHandle, 1, color, 0);

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

    // Pass the projection and view transformation to the shader
    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);

    // Draw the cone
    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, topVertexCount);
    //Draw base
    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, topVertexCount, topVertexCount);
    //Draw cone lines

    GLES20.glUniform4fv(mColorHandle, 1, linecolor, 0);
    GLES20.glDrawArrays(GLES20.GL_LINES, topVertexCount*2, lineVertexCount);

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

}

}

谢谢您的帮助

4

1 回答 1

0

您的片段着色器代码确实为每个片段分配了相同的颜色是进程。您可以通过多种不同的方式将“照明”添加到场景中。'Gouraud shading'是最容易使用现代着色器实现的一种。它在三角形的每个顶点处插入法线,并根据光的方向计算光强度。在现代着色语言(包括 OpenGL ES 2)中,这种插值是为您完成的。

还有许多其他可能的照明模型,但是大多数(如果不是全部,包括 Gouraud 着色)都需要您生成顶点法线,而您在圆锥网格生成代码中没有这样做。

于 2017-03-11T18:45:36.360 回答