OpenGL ES 2.0 漫射照明:模型显示为黑色

OpenGL ES 2.0 diffuse lighting: model shows up black

这个问题困扰了我一个星期左右... 我试图加载 stl 文件并将其显示在屏幕上。文件已正确读取。不添加光的渲染非常好。添加光照和着色器代码后,模型还在,但变黑了。

我按照本文下面从 link 下载的示例进行操作: http://www.learnopengles.com/android-lesson-two-ambient-and-diffuse-lighting/

着色器代码与示例完全相同。程序 link 没问题。着色器编译也很好。我找不到问题出在哪里。 PLZ帮帮我。

我的渲染器:

public class MyGLRenderer implements GLSurfaceView.Renderer {

 private Test test;
 private Light1 light1;

 private float range = 145;

 private final float[] mMVMMatrix = new float[16];
 private final float[] mMVPMatrix = new float[16];
 private final float[] mModelMatrix = new float[16];
 private final float[] mProjectionMatrix = new float[16];
 private final float[] mViewMatrix = new float[16];
 protected final static float[] mLightPosInEyeSpace = new float[4];
 private final float[] mLightModelMatrix = new float[16];
 private final float[] mLightPosInModelSpace = new float[] {0.0f, 0.0f, 0.0f, 1.0f};
 private final float[] mLightPosInWorldSpace = new float[4];

 private final float[] mTempMatrix = new float[16];
 public static final float[] mAccumulatedMatrix = new float[16];
 private final float[] mCurrMatrix = new float[16];


 public void onSurfaceCreated(GL10 unused, EGLConfig config) {
    // Set the background frame color
    GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    GLES20.glEnable(GLES20.GL_DEPTH_TEST);
    GLES20.glDepthFunc(GLES20.GL_LEQUAL);
    Matrix.setIdentityM(mTempMatrix, 0);
    Matrix.setIdentityM(mAccumulatedMatrix, 0);

    light1 = new Light1();
    test = new Test();

 }

 public void onDrawFrame(GL10 unused) {
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

    Matrix.setIdentityM(mViewMatrix, 0);
    Matrix.setIdentityM(mModelMatrix, 0);
    Matrix.setIdentityM(mCurrMatrix, 0);
    Matrix.setIdentityM(mLightModelMatrix, 0);

    Matrix.multiplyMV(mLightPosInWorldSpace, 0, mLightModelMatrix, 0, mLightPosInModelSpace, 0);
    Matrix.multiplyMV(mLightPosInEyeSpace, 0, mViewMatrix, 0, mLightPosInWorldSpace, 0);

    Matrix.rotateM(mCurrMatrix, 0, mAngleY, 0.0f, 1.0f, 0.0f);
    Matrix.rotateM(mCurrMatrix, 0, mAngleX, 1.0f, 0, 0.0f);
    mAngleX = 0.0f;
    mAngleY = 0.0f;

    Matrix.multiplyMM(mTempMatrix, 0, mCurrMatrix, 0, mAccumulatedMatrix, 0);
    System.arraycopy(mTempMatrix, 0, mAccumulatedMatrix, 0, 16);

    Matrix.multiplyMM(mTempMatrix, 0, mModelMatrix, 0, mAccumulatedMatrix, 0);
    System.arraycopy(mTempMatrix, 0, mModelMatrix, 0, 16);

    Matrix.translateM(mModelMatrix, 0, -test.meanX, -test.meanY, -test.meanZ);

    Matrix.multiplyMM(mMVMMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
    Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVMMatrix, 0);

    light1.draw(mMVPMatrix);

    test.draw(mMVPMatrix, mMVMMatrix);
 }

 public void onSurfaceChanged(GL10 gl, int width, int height) {
    GLES20.glViewport(0, 0, width, height);

    float ratio = (float) width / height;
    Matrix.orthoM(mProjectionMatrix, 0, -range*ratio, range*ratio, -range, range, -range, range);
 }

 public final static int loadShader(int type, String shaderCode){
    int shader = GLES20.glCreateShader(type);
    GLES20.glShaderSource(shader, shaderCode);
    GLES20.glCompileShader(shader);
    return shader;
 }

 public static volatile float mAngleX;
 public static volatile float mAngleY;

 public static void setAngleX(float angle) {mAngleX = angle;}

 public float getAngleX() {
     return mAngleX;
 }

 public static void setAngleY(float angle) {
    mAngleY = angle;
 }

 public float getAngleY() {
    return mAngleY;
 }}

我用来绘制光线位置的代码:

public class Light1 {
private final String vertexShaderCode =
        "uniform mat4 u_MVPMatrix;      \n"
                +   "attribute vec4 a_Position;     \n"
                + "void main()                    \n"
                + "{                              \n"
                + "   gl_Position = u_MVPMatrix   \n"
                + "               * a_Position;   \n"
                + "   gl_PointSize = 5.0;         \n"
                + "}                              \n";

private final String fragmentShaderCode =
        "precision mediump float;       \n"
                + "void main()                    \n"
                + "{                              \n"
                + "   gl_FragColor = vec4(1.0,    \n"
                + "   1.0, 1.0, 1.0);             \n"
                + "}                              \n";



//Light*******************
public static float[] lightLocation = new float[] {150, 150, 0};//*********ok
private final int mProgram;
//Light*******************


public Light1() {
    // initialize byte buffer for the draw list
    int vertexShader = MyGLRenderer.loadShader(
            GLES20.GL_VERTEX_SHADER,
            vertexShaderCode);
    int fragmentShader = MyGLRenderer.loadShader(
            GLES20.GL_FRAGMENT_SHADER,
            fragmentShaderCode);

    mProgram = GLES20.glCreateProgram();
    GLES20.glAttachShader(mProgram, vertexShader);
    GLES20.glAttachShader(mProgram, fragmentShader);
    GLES20.glLinkProgram(mProgram);
}

public void draw(float[] mvpMatrix) {

    GLES20.glUseProgram(mProgram);
    final int pointMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "u_MVPMatrix");
    final int pointPositionHandle = GLES20.glGetAttribLocation(mProgram, "a_Position");

    GLES20.glVertexAttrib3f(pointPositionHandle, lightLocation[0], lightLocation[1], lightLocation[2]);

    GLES20.glUniformMatrix4fv(pointMVPMatrixHandle, 1, false, mvpMatrix, 0);

    GLES20.glDrawArrays(GLES20.GL_POINTS, 0, 1);

    GLES20.glDisableVertexAttribArray(pointPositionHandle);
}}

我的模型代码:

public class Test {
final String vertexShaderCode =
        "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.
                + "uniform vec3 u_LightPos;       \n"       // The position of the light in eye space.

                + "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.
                + "attribute vec3 a_Normal;       \n"       // Per-vertex normal 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"
                // Transform the normal's orientation into eye space.
                + "   vec3 modelViewNormal = vec3(u_MVMatrix * vec4(a_Normal, 0.0));     \n"
                // Will be used for attenuation.
                + "   float distance = length(u_LightPos - modelViewVertex);             \n"
                // Get a lighting direction vector from the light to the vertex.
                + "   vec3 lightVector = normalize(u_LightPos - modelViewVertex);        \n"
                // Calculate the dot product of the light vector and vertex normal. If the normal and light vector are
                // pointing in the same direction then it will get max illumination.
                + "   float diffuse = max(dot(modelViewNormal, lightVector), 0.1);       \n"
                // Attenuate the light based on distance.
                + "   diffuse = diffuse * (1.0 / (1.0 + (0.25 * distance * distance)));  \n"
                // Multiply the color by the illumination level. It will be interpolated across the triangle.
                + "   v_Color = a_Color * diffuse;                                       \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";

private final String fragmentShaderCode =
        "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";

private FloatBuffer vertexBuffer;
private FloatBuffer colorBuffer;
private FloatBuffer normalBuffer;

private final int mProgram;

private int mPositionHandle;
private int mNormalHandle;
private int mLightLocationHandle;
private int mColorHandle;
private int mMVPMatrixHandle;
private int mMVMatrixHandle;

final int COORDS_PER_VERTEX = 3;
float[] squareCoords;
float[] coordsNormals;

float color[];

public Test() {
    squareCoords = GlassUI10.ReadStlBinary("test.stl");
    coordsNormals = VectorCalculate.getNormByPtArray(squareCoords);
    color = new float[squareCoords.length/3*4];
    for(int i = 0; i < color.length/4 ; i = i+4)
    {
        color[i+0] =0.3f;
        color[i+1] =0.7f;
        color[i+2] =0.6f;
        color[i+3] =1.3f;
    }
    System.gc();
    Log.v("TestLoaded: ", "Loaded");

    // initialize vertex byte buffer for shape coordinates
    ByteBuffer bb = ByteBuffer.allocateDirect(squareCoords.length * 4);
    bb.order(ByteOrder.nativeOrder());
    vertexBuffer = bb.asFloatBuffer();
    vertexBuffer.put(squareCoords);
    vertexBuffer.position(0);

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

    ByteBuffer nb = ByteBuffer.allocateDirect(coordsNormals.length * 4);
    nb.order(ByteOrder.nativeOrder());
    normalBuffer = nb.asFloatBuffer();
    normalBuffer.put(coordsNormals);
    normalBuffer.position(0);

    // initialize byte buffer for the draw list
    int vertexShader = MyGLRenderer.loadShader(
            GLES20.GL_VERTEX_SHADER,
            vertexShaderCode);//*********ok
    int fragmentShader = MyGLRenderer.loadShader(
            GLES20.GL_FRAGMENT_SHADER,
            fragmentShaderCode);//*********ok

    mProgram = GLES20.glCreateProgram();
    GLES20.glAttachShader(mProgram, vertexShader);
    GLES20.glAttachShader(mProgram, fragmentShader);
    GLES20.glBindAttribLocation(mProgram, 0, "a_Position");
    GLES20.glBindAttribLocation(mProgram, 1, "a_Color");
    GLES20.glBindAttribLocation(mProgram, 2, "a_Normal");



    GLES20.glLinkProgram(mProgram);
}

public void draw(float[] mvpMatrix, float[] mvMatrix) {

    GLES20.glUseProgram(mProgram);

    mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "u_MVPMatrix");
    mMVMatrixHandle = GLES20.glGetUniformLocation(mProgram, "u_MVMatrix");
    mLightLocationHandle = GLES20.glGetUniformLocation(mProgram, "u_LightPos");
    mPositionHandle = GLES20.glGetAttribLocation(mProgram, "a_Position");
    mColorHandle = GLES20.glGetUniformLocation(mProgram, "a_Color");
    mNormalHandle = GLES20.glGetAttribLocation(mProgram, "a_Normal");

    vertexBuffer.position(0);
    GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, vertexBuffer);
    GLES20.glEnableVertexAttribArray(mPositionHandle);

    colorBuffer.position(0);
    GLES20.glVertexAttribPointer(mColorHandle, 4, GLES20.GL_FLOAT, false, 0, colorBuffer);
    GLES20.glEnableVertexAttribArray(mColorHandle);

    normalBuffer.position(0);
    GLES20.glVertexAttribPointer(mNormalHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, normalBuffer);
    GLES20.glEnableVertexAttribArray(mNormalHandle);

    GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mvMatrix, 0);

    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);

    GLES20.glUniform3f(mLightLocationHandle, MyGLRenderer.mLightPosInEyeSpace[0],  MyGLRenderer.mLightPosInEyeSpace[1],  MyGLRenderer.mLightPosInEyeSpace[2]);

    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, squareCoords.length/COORDS_PER_VERTEX);              GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);

    GLES20.glDisableVertexAttribArray(mPositionHandle);
}}

任何答案将不胜感激!

在您的代码中,COORDS_PER_VERTEX 是 3。但是在您的着色器代码中 "attribute vec4 a_Position; \n",a_Position 是 vec4。

因此 GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, vertexBuffer); 具有不兼容的矢量大小。

我解决了这个问题。

首先。给定颜色的循环是错误的。修正如下:

for(int i = 0; i < color.length ; i = i+4)

它只导致很少的表面被着色;但这并不是导致模型变黑的主要原因;

主要是漫射光公式中的distance太大了;它导致 diffuse 变成一个非常小的值,导致颜色 RGB 非常接近于零;

" diffuse = diffuse * (1.0 / (1.0 + (0.00000025 * distance * distance)));"

它需要一个更好的公式,但简单地减少距离值应该显示颜色和光线影响。