1 Mesh 和 ShaderProgram 簡(jiǎn)介
1.1 創(chuàng)建 Mesh
1)Mesh 的構(gòu)造方法
public Mesh(boolean isStatic, int maxVertices, int maxIndices, VertexAttribute... attributes)
public Mesh(boolean isStatic, int maxVertices, int maxIndices, VertexAttributes attributes)
- isStatic:網(wǎng)格是否是靜態(tài)的蓖墅,如果網(wǎng)格數(shù)據(jù)不經(jīng)常改動(dòng),設(shè)置為靜態(tài)的可以優(yōu)化性能躲撰;
- maxVertices:頂點(diǎn)最大個(gè)數(shù);
- maxIndices:三角形頂點(diǎn)索引最大個(gè)數(shù)昆禽;
- attributes:頂點(diǎn)屬性茬缩,主要包含:位置卿拴、顏色、法線梨与、紋理坐標(biāo)等堕花。
2)VertexAttribute 的構(gòu)造方法
public VertexAttribute(int usage, int numComponents, String alias)
- usage:頂點(diǎn)屬性編號(hào);
- numComponents:該屬性的維度粥鞋;
- alias:屬性別名缘挽,在 Shader 中會(huì)用到該別名,建議以 “a_” 開頭呻粹,如:a_position壕曼。
3)網(wǎng)格創(chuàng)建實(shí)例
private void initMesh() { // 初始化網(wǎng)格
float[] vertices = {...}; // 頂點(diǎn)序列
short[] indices = {...}; // 三角形頂點(diǎn)索引
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:圖元類型等浊,即:點(diǎn)(GL_POINTS)腮郊、線(GL_LINES、GL_LINE_LOOP筹燕、GL_LINE_STRIP)伴榔、面(GL_TRIANGLES、GL_TRIANGLE_STRIP庄萎、GL_TRIANGLE_FAN)踪少;
- offset:頂點(diǎn)數(shù)據(jù)偏移,通常取 0.
- count:頂點(diǎn)個(gè)數(shù)糠涛。
2)圖元類型(primitiveType)
對(duì)于線段類型圖元援奢,輸入頂點(diǎn)序列 abcdef,根據(jù)圖元類型忍捡,組裝成的線段如下:
對(duì)于三角形類型圖元集漾,輸入頂點(diǎn)序列 abcdef,根據(jù)圖元類型砸脊,組裝成的三角形如下:
1.3 ShaderProgram 簡(jiǎn)介
1)綁定和釋放著色器程序
// 開始渲染(已過(guò)時(shí), 內(nèi)部直接調(diào)用bind, 因此可以使用bind方法替換begin方法)
public void begin()
// 綁定著色器程序, 內(nèi)部調(diào)用: gl.glUseProgram(program)
public void bind()
// 結(jié)束渲染(已過(guò)時(shí), 內(nèi)部是空實(shí)現(xiàn), 因此可以不調(diào)用end方法)
public void end()
// 釋放資源
public void dispose()
2)設(shè)置著色器程序參數(shù)
// 設(shè)置整型Uniform變量
public void setUniformi(String name, int value)
// 設(shè)置二維整型Uniform向量
public void setUniformi(String name, int value1, int value2)
// 設(shè)置三維整型Uniform向量
public void setUniformi(String name, int value1, int value2, int value3)
// 設(shè)置四維整型Uniform向量
public void setUniformi(String name, int value1, int value2, int value3, int value4)
// 設(shè)置浮點(diǎn)型Uniform變量
public void setUniformf(String name, float value)
public void setUniform1fv(String name, float[] values, int offset, int length)
// 設(shè)置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)
// 設(shè)置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)
// 設(shè)置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)
// 設(shè)置三維Uniform矩陣
public void setUniformMatrix(String name, Matrix3 matrix)
// 設(shè)置四維Uniform矩陣
public void setUniformMatrix(String name, Matrix4 matrix)
說(shuō)明: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 繪制三角形
本節(jié)將使用 Mesh驱显、ShaderProgram、Shader 繪制三角形瞳抓,OpenGL ES 的實(shí)現(xiàn)見博客 → 繪制三角形埃疫、繪制彩色三角形,本節(jié)完整代碼資源見 → 使用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(); // 已過(guò)時(shí), 請(qǐng)使用bind方法替換
mShaderProgram.bind();
mMesh.render(mShaderProgram, GL30.GL_TRIANGLES);
// mShaderProgram.end(); // 已過(guò)時(shí), 可以去掉
}
@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() { // 初始化網(wǎng)格
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);
}
說(shuō)明: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);
}
說(shuō)明:triangle_fragment.glsl 文件放在【assets / shaders】目錄下面。
運(yùn)行效果如下横蜒。
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(); // 已過(guò)時(shí), 請(qǐng)使用bind方法替換
mShaderProgram.bind();
mMesh.render(mShaderProgram, GL30.GL_TRIANGLES);
// mShaderProgram.end(); // 已過(guò)時(shí), 可以去掉
}
@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() { // 初始化網(wǎng)格
float[] vertices = {
// 前3位是頂點(diǎn)位置數(shù)據(jù), 后4位是頂點(diǎn)顏色數(shù)據(jù)
-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;
}
運(yùn)行效果如下胳蛮。
2.3 三角形寬高比適配
本節(jié)通過(guò)引入相機(jī)销凑,使得繪制后的三角形寬高比與三角形模型的寬高比一致。
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(); // 已過(guò)時(shí), 請(qǐng)使用bind方法替換
mShaderProgram.bind();
mShaderProgram.setUniformMatrix("u_projectionViewMatrix", mCamera.combined);
mMesh.render(mShaderProgram, GL30.GL_TRIANGLES);
// mShaderProgram.end(); // 已過(guò)時(shí), 可以去掉
}
@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; // 相機(jī)縮放級(jí)別, 值越大觀察范圍越大, 看到的圖形越小
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() { // 初始化網(wǎng)格
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);
}
}
說(shuō)明:這里設(shè)置的三角形底邊和高都為 1仅炊,即寬高比為 1: 1斗幼,我們期望繪制后的三角形寬高比也是 1 : 1,這時(shí)就需要通過(guò)相機(jī)進(jìn)行變換茂洒。
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);
}
說(shuō)明:這里通過(guò)正交相機(jī)的觀察矩陣和投影矩陣變換,實(shí)現(xiàn)模型寬高比的適配瓶竭,也可以對(duì)輸入坐標(biāo)的 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);
}
運(yùn)行效果如下斤贰,可以看到智哀,繪制后的三角形寬高比也是 1 : 1。
聲明:本文轉(zhuǎn)自【libGDX】使用Mesh繪制三角形荧恍。