java - 在 OpenGL 2.0+ 中照亮纹理对象

标签 java android-studio opengl-es shader

我一直在开发一个立方体程序,它提供了许多具有所需品质的立方体。然而,每当我尝试照亮一个有纹理的立方体时,我的立方体就会变得非常暗。照明与无纹理的立方体配合得很好,所以我相信它做得很好,就像没有照明的简单纹理立方体一样。似乎没有关于如何在 OpenGL 2.0+ 中解决此问题的重要文档,但有一些与旧版本有关的内容。

以下link提供了有关为什么我的立方体表现如此的信息,但我在将解决方案转换为较新版本时遇到了麻烦,特别是在我的着色器代码中,我不确定是否应该进行进一步的更改。我正在使用 Android Studio 2.1.3,如果它及其包含的模拟器会对预期效果造成问题。如果有人可以提供任何建议,我将不胜感激。我有一个单独的(大型)渲染器,需要绘制立方体,请告诉我除了我的立方体之外,该代码是否也有用。下面是我的立方体:

public class TexturedLightCube {


/** Cube vertices */
private static final float VERTICES[] = {
        -0.3f, -0.3f, -0.3f, //top front right
        0.3f, -0.3f, -0.3f,  //bottom front right
        0.3f, 0.3f, -0.3f, //bottom front left
        -0.3f, 0.3f, -0.3f, //top front left
        -0.3f, -0.3f, 0.3f,  //top back right
        0.3f, -0.3f, 0.3f, //bottom back right
        0.3f, 0.3f, 0.3f,  //bottom back left
        -0.3f, 0.3f, 0.3f // top back left
};

/** Vertex colors. */
private static final float COLORS[] = {
        0.0f, 1.0f, 1.0f, 1.0f,
        1.0f, 0.0f, 0.0f, 1.0f,
        1.0f, 1.0f, 0.0f, 1.0f,
        0.0f, 1.0f, 0.0f, 1.0f,
        0.0f, 0.0f, 1.0f, 1.0f,
        1.0f, 0.0f, 1.0f, 1.0f,
        1.0f, 1.0f, 1.0f, 1.0f,
        0.0f, 1.0f, 1.0f, 1.0f,
};


/** Order to draw vertices as triangles. */
private static final byte INDICES[] = {
        0, 1, 3, 3, 1, 2, // Front face.
        0, 1, 4, 4, 5, 1, // Bottom face.
        1, 2, 5, 5, 6, 2, // Right face.
        2, 3, 6, 6, 7, 3, // Top face.
        3, 7, 4, 4, 3, 0, // Left face.
        4, 5, 7, 7, 6, 5, // Rear face.
};


private static final float TEXTURECOORDS[] =
        {

                0.0f, 1.0f, //left-bottom
                0.0f, 0.0f, //right bottom
                1.0f, 0.0f, //left top
                1.0f, 1.0f, //right top

                0.0f, 1.0f, //left-bottom
                0.0f, 0.0f, //right bottom
                1.0f, 0.0f, //left top
                1.0f, 1.0f, //right top


        };


private static final float NORMALS[] = {

        //set all normals to all light for testing
        1.0f, 1.0f, 1.0f,  //top front right
        1.0f, 0.0f, 1.0f,  //bottom front right
        0.0f, 0.0f, 1.0f,  //bottom front left
        0.0f, 1.0f, 1.0f,  //top front left
        1.0f, 1.0f, 0.0f,  //top back right
        1.0f, 0.0f, 0.0f,  //bottom back right
        0.0f, 0.0f, 0.0f,  //bottom back left
        0.0f, 1.0f, 0.0f  //top back left
};

static final int COORDS_PER_VERTEX = 3;

private static final int VALUES_PER_COLOR = 4;

/** Vertex size in bytes. */
final int VERTEX_STRIDE = COORDS_PER_VERTEX * 4;

/** Color size in bytes. */
private final int COLOR_STRIDE = VALUES_PER_COLOR * 4;

/** Shader code for the vertex. */
private static final String VERTEX_SHADER_CODE =
        "uniform mat4 uMVPMatrix;" +
        "uniform mat4 uMVMatrix;" +
        "uniform vec3 u_LightPos;" +
        "attribute vec4 vPosition;" +
        "attribute vec4 a_Color;" +
        "attribute vec3 a_Normal;" +
        "varying vec4 v_Color;" +
        "attribute vec2 a_TexCoordinate;" +
        "varying vec2 v_TexCoordinate;" +
        "void main() {" +
        "vec3 modelViewVertex = vec3(uMVMatrix * vPosition);"+
        "vec3 modelViewNormal = vec3(uMVMatrix * vec4(a_Normal, 0.0));" +
        "float distance = length(u_LightPos - modelViewVertex);" +
        "vec3 lightVector = normalize(u_LightPos - modelViewVertex);" +
        "float diffuse = max(dot(modelViewNormal, lightVector), 0.1);" +
        "diffuse = diffuse * (1.0/(1.0 + (0.00000000000002 * distance * distance)));" + //attenuation factor
        "v_Color = a_Color * a_Color * diffuse;" +
        "gl_Position = uMVPMatrix * vPosition;" +
        "v_TexCoordinate = a_TexCoordinate;" +
        "}";



/** Shader code for the fragment. */
private static final String FRAGMENT_SHADER_CODE =
        "precision mediump float;" +
                "varying vec4 v_Color;" +
                "uniform sampler2D u_Texture;"+ //The input texture
                "varying vec2 v_TexCoordinate;" +
                "void main() {" +
                "  gl_FragColor =  v_Color * texture2D(u_Texture, v_TexCoordinate) ;" +   //still works with just color
                "}";


private int mTextureUniformHandle; //Pass in texture.
private int mTextureCoordinateHandle; //Pass in model texture coordinate information.
private final int mTextureCoordinateDataSize = 2; //Size of texture coordinate data in elements
public static int mTextureDataHandle; //Handle to texturedata;
private final FloatBuffer mTextureBuffer; //Store model data in float buffer.
private final FloatBuffer mVertexBuffer;
private final FloatBuffer mColorBuffer;
private final FloatBuffer mNormalBuffer;
private final ByteBuffer mIndexBuffer;
private final int mProgram;
private final int mPositionHandle;
private final int mColorHandle;
private final int mMVPMatrixHandle;
private final int mNormalHandle;
public static int mLightPosHandle;
public final int mMVMatrixHandle;



public static int loadTexture(final Context context, final int resourceId) {
    //Get the texture from the Android resource directory
    final int[] textureHandle = new int[1];

    InputStream is = context.getResources().openRawResource(+ R.drawable.teneighty);
    Bitmap bitmap = null;
    try {
        //BitmapFactory is an Android graphics utility for images
        bitmap = BitmapFactory.decodeStream(is);

    } finally {
        //Always clear and close
        try {
            is.close();
            is = null;
        } catch (IOException e) {
        }
    }

    //Generate one texture pointer...
    GLES20.glGenTextures(1, textureHandle, 0);
    //and bind it to our array.
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);

    //Create Nearest Filtered Texture.
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);

    //Accounting for different texture parameters.
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);

    //Use the Android GLUtils to specify a two-dimensional texture image from our bitmap.
    GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);

    //Clean up
    bitmap.recycle();


    if (textureHandle[0] == 0)

    {
        throw new RuntimeException("Error loading texture");
    }

    return textureHandle[0];
}



public TexturedLightCube() {

    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(VERTICES.length * 4);
    byteBuffer.order(ByteOrder.nativeOrder());
    mVertexBuffer = byteBuffer.asFloatBuffer();
    mVertexBuffer.put(VERTICES);
    mVertexBuffer.position(0);


    byteBuffer = ByteBuffer.allocateDirect(COLORS.length * 4);
    byteBuffer.order(ByteOrder.nativeOrder());
    mColorBuffer = byteBuffer.asFloatBuffer();
    mColorBuffer.put(COLORS);
    mColorBuffer.position(0);

    byteBuffer = ByteBuffer.allocateDirect(NORMALS.length * 4);
    byteBuffer.order(ByteOrder.nativeOrder());
    mNormalBuffer = byteBuffer.asFloatBuffer();
    mNormalBuffer.put(NORMALS);
    mNormalBuffer.position(0);

    byteBuffer = ByteBuffer.allocateDirect(TEXTURECOORDS.length * 4);
    byteBuffer.order(ByteOrder.nativeOrder());
    mTextureBuffer = byteBuffer.asFloatBuffer();
    mTextureBuffer.put(TEXTURECOORDS);
    mTextureBuffer.position(0);


    mIndexBuffer = ByteBuffer.allocateDirect(INDICES.length);
    mIndexBuffer.put(INDICES);
    mIndexBuffer.position(0);

    mProgram = GLES20.glCreateProgram();
    GLES20.glAttachShader(mProgram, loadShader(GLES20.GL_VERTEX_SHADER, VERTEX_SHADER_CODE));
    GLES20.glAttachShader(mProgram, loadShader(GLES20.GL_FRAGMENT_SHADER, FRAGMENT_SHADER_CODE));
    GLES20.glLinkProgram(mProgram);


    mTextureDataHandle = GLES20.glGetUniformLocation(mProgram, "u_Texture");
    mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgram, "a_TexCoordinate");
    mTextureUniformHandle = GLES20.glGetUniformLocation(mProgram, "u_Texture");
    mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
    mMVMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVMatrix");
    mLightPosHandle = GLES20.glGetUniformLocation(mProgram, "u_LightPos");
    mNormalHandle = GLES20.glGetAttribLocation(mProgram, "a_Normal");
    mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
    mColorHandle = GLES20.glGetAttribLocation(mProgram, "a_Color");

}

/**
 * Encapsulates the OpenGL ES instructions for drawing this shape.
 *
 * @param mvpMatrix The Model View Project matrix in which to draw this shape
 */
public void draw(float[] mvpMatrix) {
    // Add program to OpenGL environment.
    GLES20.glUseProgram(mProgram);

    //set active texture unit to texture unit 0.
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle);

    // Prepare the cube coordinate data.
    GLES20.glEnableVertexAttribArray(mPositionHandle);
    GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, VERTEX_STRIDE, mVertexBuffer);


    // Prepare the cube color data.
    GLES20.glEnableVertexAttribArray(mColorHandle);
    GLES20.glVertexAttribPointer(mColorHandle, 4, GLES20.GL_FLOAT, false, COLOR_STRIDE, mColorBuffer);

    //Will have the same size as Vertex as we are implementing per vertex lighting
    GLES20.glEnableVertexAttribArray(mNormalHandle);
    GLES20.glVertexAttribPointer(mNormalHandle, 3, GLES20.GL_FLOAT, false, VERTEX_STRIDE, mNormalBuffer);

    // Prepare the cube texture data.
    GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
    //Pass texture coordinate information.
    GLES20.glVertexAttribPointer(mTextureCoordinateHandle,4, GLES20.GL_FLOAT, false, mTextureCoordinateDataSize, mTextureBuffer);

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

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


    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    GLES20.glUniform1i(mTextureUniformHandle, 0);


    // Draw the cube.
    GLES20.glDrawElements(GLES20.GL_TRIANGLES, INDICES.length, GLES20.GL_UNSIGNED_BYTE, mIndexBuffer); //-removed indices-

    // Disable vertex arrays.
    GLES20.glDisableVertexAttribArray(mPositionHandle);
    GLES20.glDisableVertexAttribArray(mTextureCoordinateHandle);
    GLES20.glDisableVertexAttribArray(mColorHandle);
    GLES20.glDisableVertexAttribArray(mNormalHandle);


}

/** Loads the provided shader in the program. */
private static int loadShader(int type, String shaderCode){
    int shader = GLES20.glCreateShader(type);

    GLES20.glShaderSource(shader, shaderCode);
    GLES20.glCompileShader(shader);

    return shader;
}



 }

最佳答案

  1. 您的照明缺少一个环境组件,该组件模拟您在现实生活中获得的二阶(及更高阶)反射,但无法直接进入光栅化器。
  2. 不确定为什么要在片段着色器中对 a_Color 进行平方。这肯定会让事情变得更暗,因为所有值都在 0 和 1 之间;例如0.1^2 == 0.01
  3. 请记住,您的点积可能为负,因此您需要消除负漫射分量(例如背向光线的表面上没有光强度)。

关于java - 在 OpenGL 2.0+ 中照亮纹理对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39667096/

相关文章:

java - Android studio setContentView(R.layout.activity_login);即使我的第二个 Activity 名称 Activity_login 出现在布局文件夹中也无法正常工作

Android Studio 更新到 1.0 失败

android - 为什么我的 Intent 启动一个空的 Activity 而不是正确的 Activity ?

Android NDK - OpenGL ES 教程/库

opengl-es - YUV图像使用单个纹理还是多个纹理更好

java - 如何解码 JSON 文件上的 Base64 编码字符串

java - 对象构造在实践中是否保证所有线程都看到已初始化的非最终字段?

java - 如何在 php 中使用 SOAP 进行 wsdl 请求响应?

java - 如果存在零长度数组,我是否应该返回空列表?

ios - 在 OpenGL ES 中绑定(bind)多个缓冲区