如何在 openGL 中同时保留立方体的颜色和纹理

How keep both colors of a cube and a texture in openGL

我构建了一个在 android 上显示 3d 立方体的简单应用程序。当我尝试添加纹理时出现问题。

我的纹理是 png 图像。我意识到如果我想用它们的原始颜色显示图像,我会失去立方体背景颜色。

为了达到目的我做了不同的组合,但是都失败了

"void main() {" +
   "  gl_FragColor = texture2D(u_Texture, v_TexCoordinate) + aColor;" +
"}"

结果:

Combination of texture an color

void main() {" +
"  gl_FragColor =   texture2D(u_Texture, v_TexCoordinate);" +
"}"

only texture

我想要的是保留立方体的颜色并以其原始颜色显示图像。

任何帮助将不胜感激,谢谢

这是我的Cubo class:

public class Cubo {

private Context context;
private final String vertexShaderCode =
        "uniform mat4 uMVPMatrix;" +
                "attribute vec4 vPosition;" +
                "attribute vec4 aColor;" +
                "varying vec4 vColor;" +
                "attribute vec2 a_TexCoordinate;" +
                "varying vec2 v_TexCoordinate;" +
                "void main() {" +
                "  vColor=aColor;" +
                "  gl_Position = uMVPMatrix * vPosition;" +
                "  v_TexCoordinate = a_TexCoordinate;" +
                "}";

private final String fragmentShaderCode =
        "precision mediump float;" +
                "uniform sampler2D u_Texture;" +
                "uniform vec4 aColor;" +
                "varying vec2 v_TexCoordinate;" +
                "void main() {" +
                "  gl_FragColor = aColor + texture2D(u_Texture, v_TexCoordinate);" +
                "}";

private final FloatBuffer vertexBuffer;
private final ShortBuffer drawListBuffer;
private FloatBuffer mTextureBuffer;
private final int mProgram;
private int mPositionHandle;
private int mColorHandle;
private int mMVPMatrixHandle;
private int mTextureUniformHandle;
private int mTextureCoordinateHandle;
private final int mTextureCoordinateDataSize = 2;


static final int COORDS_PER_VERTEX = 3;
static float cubeCoords[] = {
        -0.5f, 0.5f, 0.5f,   // top left
        -0.5f, -0.5f, 0.5f,   // bottom left
        0.5f, -0.5f, 0.5f,   // bottom right
        0.5f, 0.5f, 0.5f,  // top right
        -0.5f, 0.5f, -0.5f,   // top left back
        -0.5f, -0.5f, -0.5f,   // bottom left back
        0.5f, -0.5f, -0.5f,   // bottom right back
        0.5f, 0.5f, -0.5f  // top right back
};

private final short drawOrder[] = {0, 1, 2, 0, 2, 3,
        3, 2, 6, 3, 6, 7,
        0, 3, 7, 0, 7, 4,
        1, 5, 6, 1, 6, 2,
        4, 5, 1, 4, 1, 0,
        7, 6, 5, 7, 5, 4};

private final int vertexStride = COORDS_PER_VERTEX * 4;


float color[] = {0.63671875f, 0.76953125f, 0.22265625f, 0.0f};

private float texture[] = {
        // Mapping coordinates for the vertices
        // Front face
        1.0f, 1.0f,
        1.0f, 0.0f,
        0.0f, 0.0f,
        0.0f, 1.0f


};

private int[] textures = new int[1];


public Cubo(Context context) {
    this.context = context;
    ByteBuffer bb = ByteBuffer.allocateDirect(
            cubeCoords.length * 4);
    bb.order(ByteOrder.nativeOrder());
    vertexBuffer = bb.asFloatBuffer();
    vertexBuffer.put(cubeCoords);
    vertexBuffer.position(0);

    ByteBuffer dlb = ByteBuffer.allocateDirect(
            drawOrder.length * 2);
    dlb.order(ByteOrder.nativeOrder());
    drawListBuffer = dlb.asShortBuffer();
    drawListBuffer.put(drawOrder);
    drawListBuffer.position(0);

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

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

    mProgram = GLES20.glCreateProgram();             // create empty OpenGL Program
    GLES20.glAttachShader(mProgram, vertexShader);   // add the vertex shader to program
    GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
    GLES20.glLinkProgram(mProgram);                  // create OpenGL program executables
}

public void draw(float[] mvpMatrix) {
    GLES20.glUseProgram(mProgram);
    mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
    GLES20.glEnableVertexAttribArray(mPositionHandle);
    GLES20.glVertexAttribPointer(
            mPositionHandle, COORDS_PER_VERTEX,
            GLES20.GL_FLOAT, false,
            vertexStride, vertexBuffer);
    mColorHandle = GLES20.glGetAttribLocation(mProgram, "aColor");
    GLES20.glUniform4fv(mColorHandle, 1, color, 0);
    mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
    //---------------textura-------------------
    mTextureUniformHandle = GLES20.glGetUniformLocation(mProgram, "u_Texture");
    mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgram, "a_TexCoordinate");
    GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
    GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false,
            0, mTextureBuffer);
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
    GLES20.glUniform1i(mTextureUniformHandle, 0);
    //------------------------------------------
    GLES20.glDrawElements(
            GLES20.GL_TRIANGLES, drawOrder.length,
            GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
    GLES20.glDisableVertexAttribArray(mPositionHandle);
}

public void loadTexture() {
    GLES20.glGenTextures(1, textures, 0);
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inScaled = false;
    final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.casilla27, options);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
    GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
    bitmap.recycle();
}

这是我的渲染器:

public class MyGLRenderer implements GLSurfaceView.Renderer {


private Cubo cubo;
private Context context;
private final float[] mMVPMatrix = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mViewMatrix = new float[16];
private final float[] mRotationMatrix_x = new float[16];
private final float[] mRotationMatrix_y = new float[16];
private final float[] mRotationMatrix = new float[16];

private float mXAngle;
private float mYAngle;

public MyGLRenderer(Context context) {
    this.context = context;
}

@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
    GLES20.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
    GLES20.glClearDepthf(1.0f);
    GLES20.glEnable(GL10.GL_DEPTH_TEST);
    cubo = new Cubo(context);
    cubo.loadTexture();
}

@Override
public void onSurfaceChanged(GL10 gl10, int i, int i1) {
    GLES20.glViewport(0, 0, i, i1);
    float ratio = (float) i / i1;
    Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}

@Override
public void onDrawFrame(GL10 gl10) {
    float[] scratch = new float[16];
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
    Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -4, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
    Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
    Matrix.setRotateM(mRotationMatrix_x, 0, mYAngle, 1.0f, 0, 0);
    Matrix.setRotateM(mRotationMatrix_y, 0, mXAngle, 0, 1.0f,  0);
    Matrix.multiplyMM(mRotationMatrix, 0, mRotationMatrix_y, 0, mRotationMatrix_x, 0);
    Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
    cubo.draw(scratch);
}


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

public float getmXAngle() {
    return mXAngle;
}

public void setmXAngle(float mXAngle) {
    this.mXAngle = mXAngle;
}

public float getmYAngle() {
    return mYAngle;
}

public void setmYAngle(float mYAngle) {
    this.mYAngle = mYAngle;
}

您必须mix属性颜色和纹理颜色取决于纹理的 Alpha 通道:

void main() {
    vec4 textureColor = texture2D(u_Texture, v_TexCoordinate);
    gl_FragColor = vec4(mix(aColor.rgb, textureColor.rgb, textureColor.a), 1.0);
}