mesh就是网格,在d3d中有严格的定义, 也有专门的工具来写.x提供给d3d生成mesh,
什么是mesh?
简单的说就是那些点坐标,颜色,纹理,材质,光照等等的一个集合
libgdx定义的mesh
public class Mesh implements Disposable {
public enum VertexDataType {
VertexArray, VertexBufferObject, VertexBufferObjectSubData,
}
/** list of all meshes **/
static final Map
/** used for benchmarking **/
public static boolean forceVBO = false;
final VertexData vertices;
final IndexData indices;
boolean autoBind = true;
final boolean isVertexArray;
int refCount = 0;
/** Creates a new Mesh with the given attributes.
*
* @param isStatic whether this mesh is static or not. Allows for internal optimizations.
* @param maxVertices the maximum number of vertices this mesh can hold
* @param maxIndices the maximum number of indices this mesh can hold
* @param attributes the {@link VertexAttribute}s. Each vertex attribute defines one property of a vertex such as position,
* normal or texture coordinate */
public Mesh (boolean isStatic, int maxVertices, int maxIndices, VertexAttribute... attributes) {
if (Gdx.gl20 != null || Gdx.gl11 != null || Mesh.forceVBO) {
vertices = new VertexBufferObject(isStatic, maxVertices, attributes);
indices = new IndexBufferObject(isStatic, maxIndices);
isVertexArray = false;
} else {
vertices = new VertexArray(maxVertices, attributes);
indices = new IndexBufferObject(maxIndices);
isVertexArray = true;
}
addManagedMesh(Gdx.app, this);
}
... ...
保存了顶点和索引
当然顶点是有不同定义方式的,d3d就是这么做的,这里libgdx有了一个VertexAttribute的概念
VertexAttribute
/** Constructs a new VertexAttribute.
*
* @param usage the usage, used for the fixed function pipeline. Generic attributes are not supported in the fixed function
* pipeline.
* @param numComponents the number of components of this attribute, must be between 1 and 4.
* @param alias the alias used in a shader for this attribute. Can be changed after construction. */
public VertexAttribute (int usage, int numComponents, String alias) {
this.usage = usage;//属性的作用
this.numComponents = numComponents; //这个属性占3个数字
this.alias = alias;
}
构造这个mesh通常是从文件里面来,例子里面就是这么做的
public Renderer (Application app) {
try {
spriteBatch = new SpriteBatch();
InputStream in = Gdx.files.internal("data/ship.obj").read();
shipMesh = ModelLoaderOld.loadObj(in);
in.close();
in = Gdx.files.internal("data/invader.obj").read();
invaderMesh = ModelLoaderOld.loadObj(in);
in.close();
in = Gdx.files.internal("data/block.obj").read();
blockMesh = ModelLoaderOld.loadObj(in);
in.close();
in = Gdx.files.internal("data/shot.obj").read();
shotMesh = ModelLoaderOld.loadObj(in);
in.close();
这段是 invader的Renderer,它就是这么做的
invaderMesh = ModelLoaderOld.loadObj(in);
public class ModelLoaderOld {
/** Loads a Wavefront OBJ file from the given InputStream. The OBJ file must only contain triangulated meshes. Materials are
* ignored.
*
* @param in the InputStream
* @return a Mesh holding the OBJ data or null in case something went wrong. */
public static Mesh loadObj (InputStream in) {
return ObjLoader.loadObj(in);
}
}
ObjLoader就是这个加载器
public static Mesh loadObjFromString (String obj, boolean flipV) {
String[] lines = obj.split("\n");
float[] vertices = new float[lines.length * 3];
float[] normals = new float[lines.length * 3];
float[] uv = new float[lines.length * 3];
int numVertices = 0;
int numNormals = 0;
int numUV = 0;
int numFaces = 0;
int[] facesVerts = new int[lines.length * 3];
int[] facesNormals = new int[lines.length * 3];
int[] facesUV = new int[lines.length * 3];
int vertexIndex = 0;
int normalIndex = 0;
int uvIndex = 0;
int faceIndex = 0;
for (int i = 0; i < lines.length; i++) {
String line = lines[i];
if (line.startsWith("v ")) {
String[] tokens = line.split("[ ]+");
vertices[vertexIndex] = Float.parseFloat(tokens[1]);
vertices[vertexIndex + 1] = Float.parseFloat(tokens[2]);
vertices[vertexIndex + 2] = Float.parseFloat(tokens[3]);
vertexIndex += 3;
numVertices++;
continue;
}
if (line.startsWith("vn ")) {
String[] tokens = line.split("[ ]+");
normals[normalIndex] = Float.parseFloat(tokens[1]);
normals[normalIndex + 1] = Float.parseFloat(tokens[2]);
normals[normalIndex + 2] = Float.parseFloat(tokens[3]);
normalIndex += 3;
numNormals++;
continue;
}
if (line.startsWith("vt")) {
String[] tokens = line.split("[ ]+");
uv[uvIndex] = Float.parseFloat(tokens[1]);
uv[uvIndex + 1] = flipV ? 1 - Float.parseFloat(tokens[2]) : Float.parseFloat(tokens[2]);
uvIndex += 2;
numUV++;
continue;
}
if (line.startsWith("f ")) {
String[] tokens = line.split("[ ]+");
String[] parts = tokens[1].split("/");
facesVerts[faceIndex] = getIndex(parts[0], numVertices);
if (parts.length > 2) facesNormals[faceIndex] = getIndex(parts[2], numNormals);
if (parts.length > 1) facesUV[faceIndex] = getIndex(parts[1], numUV);
faceIndex++;
parts = tokens[2].split("/");
facesVerts[faceIndex] = getIndex(parts[0], numVertices);
if (parts.length > 2) facesNormals[faceIndex] = getIndex(parts[2], numNormals);
if (parts.length > 1) facesUV[faceIndex] = getIndex(parts[1], numUV);
faceIndex++;
parts = tokens[3].split("/");
facesVerts[faceIndex] = getIndex(parts[0], numVertices);
if (parts.length > 2) facesNormals[faceIndex] = getIndex(parts[2], numNormals);
if (parts.length > 1) facesUV[faceIndex] = getIndex(parts[1], numUV);
faceIndex++;
numFaces++;
continue;
}
}
float[] verts = new float[(numFaces * 3) * (3 + (numNormals > 0 ? 3 : 0) + (numUV > 0 ? 2 : 0))];
for (int i = 0, vi = 0; i < numFaces * 3; i++) {
int vertexIdx = facesVerts[i] * 3;
verts[vi++] = vertices[vertexIdx];
verts[vi++] = vertices[vertexIdx + 1];
verts[vi++] = vertices[vertexIdx + 2];
if (numNormals > 0) {
int normalIdx = facesNormals[i] * 3;
verts[vi++] = normals[normalIdx];
verts[vi++] = normals[normalIdx + 1];
verts[vi++] = normals[normalIdx + 2];
}
if (numUV > 0) {
int uvIdx = facesUV[i] * 2;
verts[vi++] = uv[uvIdx];
verts[vi++] = uv[uvIdx + 1];
}
}
Mesh mesh = null;
ArrayList
attributes.add(new VertexAttribute(Usage.Position, 3, ShaderProgram.POSITION_ATTRIBUTE));
if (numNormals > 0) attributes.add(new VertexAttribute(Usage.Normal, 3, ShaderProgram.NORMAL_ATTRIBUTE));
if (numUV > 0) attributes.add(new VertexAttribute(Usage.TextureCoordinates, 2, ShaderProgram.TEXCOORD_ATTRIBUTE + "0"));
mesh = new Mesh(true, numFaces * 3, 0, attributes.toArray(new VertexAttribute[attributes.size()]));
mesh.setVertices(verts);
return mesh;
}
前面一段都是在读数据,重点看后面一段
ArrayList
attributes.add(new VertexAttribute(Usage.Position, 3, ShaderProgram.POSITION_ATTRIBUTE));
if (numNormals > 0) attributes.add(new VertexAttribute(Usage.Normal, 3, ShaderProgram.NORMAL_ATTRIBUTE));
if (numUV > 0) attributes.add(new VertexAttribute(Usage.TextureCoordinates, 2, ShaderProgram.TEXCOORD_ATTRIBUTE + "0"));
有3种属性 位置,法线,纹理
new Mesh(true, numFaces * 3, 0, attributes.toArray(new VertexAttribute[attributes.size()]));
isStatic
顶点数:numFaces * 3
索引:0
上面的数据读取是格式化的读取,这个model的位置,法线,纹理等数据
private void renderInvaders (GL10 gl, ArrayList
invaderTexture.bind();
for (int i = 0; i < invaders.size(); i++) {
Invader invader = invaders.get(i);
gl.glPushMatrix();
gl.glTranslatef(invader.position.x, invader.position.y, invader.position.z);
gl.glRotatef(invaderAngle, 0, 1, 0);
invaderMesh.render(GL10.GL_TRIANGLES);
gl.glPopMatrix();
}
}
这是例子中通过mesh绘图的代码
invaderMesh.render(GL10.GL_TRIANGLES);