📌  相关文章
📜  使用颜色交换方法对图形进行顶点着色的Java程序(1)

📅  最后修改于: 2023-12-03 15:22:27.345000             🧑  作者: Mango

使用颜色交换方法对图形进行顶点着色的Java程序介绍

简介

本文介绍使用Java代码实现颜色交换方法对图形进行顶点着色的方法。该方法可以用于绘制三角形、多边形等简单图形,并可以自定义颜色和顶点坐标。

实现步骤

程序的实现步骤如下所示:

  1. 定义颜色数组。在本例中,我们使用了 RGB 值来表示颜色。
float[] colors = {
    // R, G, B, A
    1.0f, 0.0f, 0.0f, 1.0f, // 红色
    0.0f, 1.0f, 0.0f, 1.0f, // 绿色
    0.0f, 0.0f, 1.0f, 1.0f, // 蓝色
};
  1. 定义顶点坐标。
int[] indices = { 0, 1, 2 }; // 三角形
float[] vertices = {
    // X, Y, Z
    -0.5f, -0.5f, 0f, // 左下角
     0.5f, -0.5f, 0f, // 右下角
     0.0f,  0.5f, 0f, // 顶部
};
  1. 定义顶点着色器。
String vertexShaderSource =
    "attribute vec3 a_Position;\n" +
    "attribute vec4 a_Color;\n" +
    "varying vec4 v_Color;\n" +
    "void main() {\n" +
    "  gl_Position = vec4(a_Position, 1.0);\n" +
    "  v_Color = a_Color;\n" +
    "}";

着色器中将传入的顶点坐标和颜色值赋值给 gl_Positionv_Color 变量。varying 关键字用来将颜色值从顶点着色器传递到片元着色器。

  1. 定义片元着色器。
String fragmentShaderSource =
    "precision mediump float;\n" +
    "varying vec4 v_Color;\n" +
    "void main() {\n" +
    "  gl_FragColor = v_Color;\n" +
    "}";

片元着色器的作用是计算每个像素的颜色值。在本例中,我们直接将 v_Color 变量的值赋给 gl_FragColor,达到绘制多个颜色的目的。

  1. 创建绘制程序并链接着色器。
int program = GLES20.glCreateProgram(); // 创建绘制程序
int vertexShader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER); // 创建顶点着色器
int fragmentShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER); // 创建片元着色器

GLES20.glShaderSource(vertexShader, vertexShaderSource);
GLES20.glCompileShader(vertexShader);

GLES20.glShaderSource(fragmentShader, fragmentShaderSource);
GLES20.glCompileShader(fragmentShader);

GLES20.glAttachShader(program, vertexShader);
GLES20.glAttachShader(program, fragmentShader);
GLES20.glLinkProgram(program); // 链接绘制程序

在创建绘制程序、顶点着色器和片元着色器后,需要将着色器源码分别加载到对应的着色器中,并编译。接着将着色器附加到绘制程序中,并链接绘制程序。

  1. 激活绘制程序,设置顶点坐标和颜色。
GLES20.glUseProgram(program); // 激活程序

int positionHandle = GLES20.glGetAttribLocation(program, "a_Position");
GLES20.glEnableVertexAttribArray(positionHandle);
GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 0, verticesBuffer);

int colorHandle = GLES20.glGetAttribLocation(program, "a_Color");
GLES20.glEnableVertexAttribArray(colorHandle);
GLES20.glVertexAttribPointer(colorHandle, 4, GLES20.GL_FLOAT, false, 0, colorsBuffer);

激活绘制程序后,需要指定顶点着色器中定义的顶点坐标和颜色属性。glGetAttribLocation 函数返回顶点属性的位置,并启用顶点纹理坐标属性。glVertexAttribPointer 函数则将属性绑定到顶点数组中。

  1. 绘制图形。
GLES20.glDrawElements(GLES20.GL_TRIANGLES, indices.length, GLES20.GL_UNSIGNED_INT, indicesBuffer);

glDrawElements 函数用于实际绘制图形。本例中使用 GL_TRIANGLES 三角形绘制模式,并将顶点坐标和索引数组传递给函数。

  1. 最后释放资源。
GLES20.glDisableVertexAttribArray(positionHandle);
GLES20.glDisableVertexAttribArray(colorHandle);
GLES20.glDeleteShader(vertexShader);
GLES20.glDeleteShader(fragmentShader);
示例代码

完整的示例代码如下所示:

import android.opengl.GLES20;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

public class TriangleRenderer implements GLSurfaceView.Renderer {

    private static final String VERTEX_SHADER_SOURCE =
        "attribute vec3 a_Position;\n" +
        "attribute vec4 a_Color;\n" +
        "varying vec4 v_Color;\n" +
        "void main() {\n" +
        "    gl_Position = vec4(a_Position, 1.0);\n" +
        "    v_Color = a_Color;\n" +
        "}";
    private static final String FRAGMENT_SHADER_SOURCE =
        "precision mediump float;\n" +
        "varying vec4 v_Color;\n" +
        "void main() {\n" +
        "    gl_FragColor = v_Color;\n" +
        "}";
    private static final float[] COLORS = {
        // R, G, B, A
        1.0f, 0.0f, 0.0f, 1.0f,
        0.0f, 1.0f, 0.0f, 1.0f,
        0.0f, 0.0f, 1.0f, 1.0f
    };
    private static final int[] INDICES = { 0, 1, 2 };
    private static final float[] VERTICES = {
        -0.5f, -0.5f, 0f,
         0.5f, -0.5f, 0f,
         0.0f,  0.5f, 0f
    };

    private final FloatBuffer verticesBuffer;
    private final IntBuffer indicesBuffer;
    private final FloatBuffer colorsBuffer;

    public TriangleRenderer() {
        verticesBuffer = ByteBuffer
                .allocateDirect(VERTICES.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer();
        verticesBuffer.put(VERTICES).position(0);

        indicesBuffer = ByteBuffer
                .allocateDirect(INDICES.length * 4)
                .order(ByteOrder.nativeOrder())
                .asIntBuffer();
        indicesBuffer.put(INDICES).position(0);

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

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        int program = GLES20.glCreateProgram();
        int vertexShader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
        int fragmentShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);

        GLES20.glShaderSource(vertexShader, VERTEX_SHADER_SOURCE);
        GLES20.glCompileShader(vertexShader);
        GLES20.glShaderSource(fragmentShader, FRAGMENT_SHADER_SOURCE);
        GLES20.glCompileShader(fragmentShader);
        GLES20.glAttachShader(program, vertexShader);
        GLES20.glAttachShader(program, fragmentShader);
        GLES20.glLinkProgram(program);

        GLES20.glUseProgram(program);

        int positionHandle = GLES20.glGetAttribLocation(program, "a_Position");
        GLES20.glEnableVertexAttribArray(positionHandle);
        GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT,
          false, 0, verticesBuffer);

        int colorHandle = GLES20.glGetAttribLocation(program, "a_Color");
        GLES20.glEnableVertexAttribArray(colorHandle);
        GLES20.glVertexAttribPointer(colorHandle, 4, GLES20.GL_FLOAT,
          false, 0, colorsBuffer);

        GLES20.glDrawElements(GLES20.GL_TRIANGLES, INDICES.length,
          GLES20.GL_UNSIGNED_INT, indicesBuffer);

        GLES20.glDisableVertexAttribArray(positionHandle);
        GLES20.glDisableVertexAttribArray(colorHandle);
        GLES20.glDeleteShader(vertexShader);
        GLES20.glDeleteShader(fragmentShader);
    }

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

    @Override
    public void onDrawFrame(GL10 gl) {}
}
结束语

本文介绍了使用颜色交换方法对图形进行顶点着色的Java程序。该程序可以用于绘制简单的三角形、多边形等图形,并可以自定义顶点坐标和颜色。程序代码非常简单易懂,适合OpenGL初学者入门。