2

【libGDX】使用Mesh绘制三角形 - little_fat_sheep

 6 months ago
source link: https://www.cnblogs.com/zhyan8/p/18024334
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

1 Mesh 和 ShaderProgram 简介

1.1 创建 Mesh

1)Mesh 的构造方法

public Mesh(boolean isStatic, int maxVertices, int maxIndices, VertexAttribute... attributes)
public Mesh(boolean isStatic, int maxVertices, int maxIndices, VertexAttributes attributes)
  • isStatic:网格是否是静态的,如果网格数据不经常改动,设置为静态的可以优化性能;
  • maxVertices:顶点最大个数;
  • maxIndices:三角形顶点索引最大个数;
  • attributes:顶点属性,主要包含:位置、颜色、法线、纹理坐标等。

2)VertexAttribute 的构造方法

public VertexAttribute(int usage, int numComponents, String alias)
  • usage:顶点属性编号;
  • numComponents:该属性的维度;
  • alias:属性别名,在 Shader 中会用到该别名,建议以 “a_” 开头,如:a_position。

3)网格创建实例

private void initMesh() { // 初始化网格
	float[] vertices = {...}; // 顶点序列
	short[] indices = {...}; // 三角形顶点索引
	VertexAttribute vertexAttr = new VertexAttribute(Usage.Position, 3, "a_position");
	mMesh = new Mesh(true, vertices.length / 3, indices.length, vertexAttr);
	mMesh.setVertices(vertices);
	mMesh.setIndices(indices);
}

1.2 绘制 Mesh

1)Mesh 的 render 方法

public void render(ShaderProgram shader, int primitiveType)
public void render(ShaderProgram shader, int primitiveType, int offset, int count)
  • shader:着色器程序;
  • primitiveType:图元类型,即:点(GL_POINTS)、线(GL_LINES、GL_LINE_LOOP、GL_LINE_STRIP)、面(GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN);
  • offset:顶点数据偏移,通常取 0.
  • count:顶点个数。

2)图元类型(primitiveType)

​ 对于线段类型图元,输入顶点序列 abcdef,根据图元类型,组装成的线段如下:

img

​ 对于三角形类型图元,输入顶点序列 abcdef,根据图元类型,组装成的三角形如下:

img

1.3 ShaderProgram 简介

1)绑定和释放着色器程序

// 开始渲染(已过时, 内部直接调用bind, 因此可以使用bind方法替换begin方法)
public void begin()
// 绑定着色器程序, 内部调用: gl.glUseProgram(program)
public void bind()
// 结束渲染(已过时, 内部是空实现, 因此可以不调用end方法)
public void end()
// 释放资源
public void dispose()

2)设置着色器程序参数

// 设置整型Uniform变量
public void setUniformi(String name, int value)
// 设置二维整型Uniform向量
public void setUniformi(String name, int value1, int value2)
// 设置三维整型Uniform向量
public void setUniformi(String name, int value1, int value2, int value3)
// 设置四维整型Uniform向量
public void setUniformi(String name, int value1, int value2, int value3, int value4)
// 设置浮点型Uniform变量
public void setUniformf(String name, float value)
public void setUniform1fv(String name, float[] values, int offset, int length)
// 设置vec2型Uniform变量
public void setUniform2fv(String name, float[] values, int offset, int length)
public void setUniformf(String name, float value1, float value2)
public void setUniformf(String name, Vector2 values)
// 设置vec3型Uniform变量
public void setUniform3fv(String name, float[] values, int offset, int length)
public void setUniformf(String name, float value1, float value2, float value3)
public void setUniformf(String name, Vector3 values)
// 设置vec4型Uniform变量
public void setUniform4fv(String name, float[] values, int offset, int length)
public void setUniformf(String name, float value1, float value2, float value3, float value4)
public void setUniformf(String name, Color values)
// 设置三维Uniform矩阵
public void setUniformMatrix(String name, Matrix3 matrix)
// 设置四维Uniform矩阵
public void setUniformMatrix(String name, Matrix4 matrix)

​ 说明:name 可以使用 int 型的 location 变量替换,在 VertexAttributes.Usage 中有定义,如下。

public static final class Usage {
	public static final int Position = 1;
	public static final int ColorUnpacked = 2;
	public static final int ColorPacked = 4;
	public static final int Normal = 8;
	public static final int TextureCoordinates = 16;
	public static final int Generic = 32;
	public static final int BoneWeight = 64;
	public static final int Tangent = 128;
	public static final int BiNormal = 256;
}

2 绘制三角形

​ 本节将使用 Mesh、ShaderProgram、Shader 绘制三角形,OpenGL ES 的实现见博客 → 绘制三角形绘制彩色三角形,本节完整代码资源见 → 使用Mesh绘制三角形

2.1 绘制纯色三角形

​ DesktopLauncher.java

package com.zhyan8.game;

import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application;
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration;

public class DesktopLauncher {
	public static void main (String[] arg) {
		Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration();
		config.setForegroundFPS(60);
		config.setTitle("Triangle");
		new Lwjgl3Application(new Triangle(), config);
	}
}

​ Triangle.java

package com.zhyan8.game;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL30;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.VertexAttribute;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;

public class Triangle extends ApplicationAdapter {
	private ShaderProgram mShaderProgram;
	private Mesh mMesh;

	@Override
	public void create() {
		initShader();
		initMesh();
	}

	@Override
	public void render() {
		Gdx.gl.glClearColor(0.455f, 0.725f, 1.0f, 1.0f);
		Gdx.gl.glClear(GL30.GL_COLOR_BUFFER_BIT);
		// mShaderProgram.begin(); // 已过时, 请使用bind方法替换
		mShaderProgram.bind();
		mMesh.render(mShaderProgram, GL30.GL_TRIANGLES);
		// mShaderProgram.end(); // 已过时, 可以去掉
	}

	@Override
	public void dispose() {
		mShaderProgram.dispose();
		mMesh.dispose();
	}

	private void initShader() { // 初始化着色器程序
		String vertex = Gdx.files.internal("shaders/triangle_vertex.glsl").readString();
		String fragment = Gdx.files.internal("shaders/triangle_fragment.glsl").readString();
		mShaderProgram = new ShaderProgram(vertex, fragment);
	}

	private void initMesh() { // 初始化网格
		float[] vertices = {
			-0.5f, -0.5f, 0.0f,
			0.5f, -0.5f, 0.0f,
			0.0f, 0.5f, 0.0f
		};
		short[] indices = {0, 1, 2};
		VertexAttribute vertexAttr = new VertexAttribute(Usage.Position, 3, "a_position");
		mMesh = new Mesh(true, vertices.length / 3, indices.length, vertexAttr);
		mMesh.setVertices(vertices);
		mMesh.setIndices(indices);
	}
}

​ triangle_vertex.glsl

#version 300 es

in vec3 a_position;

void main() {
    gl_Position = vec4(a_position, 1.0);
}

​ 说明:triangle_vertex.glsl 文件放在【assets / shaders】目录下面。

​ triangle_fragment.glsl

#version 300 es
precision mediump float; // 声明float型变量的精度为mediump

out vec4 fragColor;

void main() {
    fragColor = vec4(1, 0, 0, 1);
}

​ 说明:triangle_fragment.glsl 文件放在【assets / shaders】目录下面。

​ 运行效果如下。

img

2.2 绘制彩色三角形

​ Triangle.java

package com.zhyan8.game;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL30;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.VertexAttribute;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;

public class Triangle extends ApplicationAdapter {
	private ShaderProgram mShaderProgram;
	private Mesh mMesh;

	@Override
	public void create() {
		initShader();
		initMesh();
	}

	@Override
	public void render() {
		Gdx.gl.glClearColor(0.455f, 0.725f, 1.0f, 1.0f);
		Gdx.gl.glClear(GL30.GL_COLOR_BUFFER_BIT);
		// mShaderProgram.begin(); // 已过时, 请使用bind方法替换
		mShaderProgram.bind();
		mMesh.render(mShaderProgram, GL30.GL_TRIANGLES);
		// mShaderProgram.end(); // 已过时, 可以去掉
	}

	@Override
	public void dispose() {
		mShaderProgram.dispose();
		mMesh.dispose();
	}

	private void initShader() { // 初始化着色器程序
		String vertex = Gdx.files.internal("shaders/triangle_vertex.glsl").readString();
		String fragment = Gdx.files.internal("shaders/triangle_fragment.glsl").readString();
		mShaderProgram = new ShaderProgram(vertex, fragment);
	}

	private void initMesh() { // 初始化网格
		float[] vertices = {
			// 前3位是顶点位置数据, 后4位是顶点颜色数据
			-0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
			0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
			0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f
		};
		short[] indices = {0, 1, 2};
		VertexAttribute vertexPosition = new VertexAttribute(Usage.Position, 3, "a_position");
		VertexAttribute vertexColor = new VertexAttribute(Usage.ColorUnpacked, 4, "a_color");
		mMesh = new Mesh(true, vertices.length / 7, indices.length, vertexPosition, vertexColor);
		mMesh.setVertices(vertices);
		mMesh.setIndices(indices);
	}
}

​ triangle_vertex.glsl

#version 300 es

in vec3 a_position;
in vec4 a_color;

out vec4 v_color;

void main() {
    gl_Position = vec4(a_position, 1.0);
    v_color = a_color;
}

​ triangle_fragment.glsl

#version 300 es
precision mediump float; // 声明float型变量的精度为mediump

in vec4 v_color;

out vec4 fragColor;

void main() {
    fragColor = v_color;
}

​ 运行效果如下。

img

2.3 三角形宽高比适配

​ 本节通过引入相机,使得绘制后的三角形宽高比与三角形模型的宽高比一致。

​ Triangle.java

package com.zhyan8.game;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL30;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.VertexAttribute;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;

public class Triangle extends ApplicationAdapter {
	private OrthographicCamera mCamera;
	private ShaderProgram mShaderProgram;
	private Mesh mMesh;

	@Override
	public void create() {
		initCamera();
		initShader();
		initMesh();
	}

	@Override
	public void render() {
		Gdx.gl.glClearColor(0.455f, 0.725f, 1.0f, 1.0f);
		Gdx.gl.glClear(GL30.GL_COLOR_BUFFER_BIT);
		// mShaderProgram.begin(); // 已过时, 请使用bind方法替换
		mShaderProgram.bind();
		mShaderProgram.setUniformMatrix("u_projectionViewMatrix", mCamera.combined);
		mMesh.render(mShaderProgram, GL30.GL_TRIANGLES);
		// mShaderProgram.end(); // 已过时, 可以去掉
	}

	@Override
	public void dispose() {
		mShaderProgram.dispose();
		mMesh.dispose();
	}

	private void initCamera() {
		mCamera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
		mCamera.near = 0.3f;
		mCamera.far = 1000f;
		mCamera.zoom = 0.005f; // 相机缩放级别, 值越大观察范围越大, 看到的图形越小
		mCamera.position.set(0f, 0f, -5f);
		mCamera.lookAt(0, 0, 0);
		mCamera.update();
	}

	private void initShader() { // 初始化着色器程序
		String vertex = Gdx.files.internal("shaders/triangle_vertex.glsl").readString();
		String fragment = Gdx.files.internal("shaders/triangle_fragment.glsl").readString();
		mShaderProgram = new ShaderProgram(vertex, fragment);
	}

	private void initMesh() { // 初始化网格
		float[] vertices = {
			-0.5f, -0.5f, 0.0f,
			0.5f, -0.5f, 0.0f,
			0.0f, 0.5f, 0.0f,
		};
		short[] indices = {0, 1, 2};
		VertexAttribute vertexPosition = new VertexAttribute(Usage.Position, 3, "a_position");
		mMesh = new Mesh(true, vertices.length / 3, indices.length, vertexPosition);
		mMesh.setVertices(vertices);
		mMesh.setIndices(indices);
	}
}

​ 说明:这里设置的三角形底边和高都为 1,即宽高比为 1: 1,我们期望绘制后的三角形宽高比也是 1 : 1,这时就需要通过相机进行变换。

​ triangle_vertex.glsl

#version 300 es

in vec3 a_position;

uniform mat4 u_projectionViewMatrix;

void main() {
    gl_Position = u_projectionViewMatrix * vec4(a_position, 1.0);
}

​ 说明:这里通过正交相机的观察矩阵和投影矩阵变换,实现模型宽高比的适配,也可以对输入坐标的 y 值乘以屏幕宽高比,作为 gl_Position.y 的值。

​ triangle_fragment.glsl

#version 300 es
precision mediump float; // 声明float型变量的精度为mediump

out vec4 fragColor;

void main() {
    fragColor = vec4(0, 1, 0, 0);
}

​ 运行效果如下,可以看到,绘制后的三角形宽高比也是 1 : 1。

img

​ 声明:本文转自【libGDX】使用Mesh绘制三角形


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK