OpenGLES3D编程技巧与优化
立即解锁
发布时间: 2025-08-24 00:53:58 阅读量: 4 订阅数: 25 


Android游戏开发入门指南
### OpenGL ES 3D 编程技巧与优化
#### 1. 指定材质
在 OpenGL ES 中,材质由几个属性定义,它是一种状态,会一直保持激活,直到我们再次更改或 OpenGL ES 上下文丢失。要设置当前激活的材质属性,可以使用以下代码:
```java
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, ambientColor, 0);
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, diffuseColor, 0);
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SPECULAR, specularColor, 0);
```
通常,我们需要指定环境光、漫反射光和镜面反射光的 RGBA 颜色,这与指定光源属性时一样,通过四元素浮点数组来完成。将这些操作封装到一个辅助类中非常简单,以下是示例代码:
```java
package com.badlogic.androidgames.framework.gl;
import javax.microedition.khronos.opengles.GL10;
public class Material {
float[] ambient = { 0.2f, 0.2f, 0.2f, 1.0f };
float[] diffuse = { 1.0f, 1.0f, 1.0f, 1.0f };
float[] specular = { 0.0f, 0.0f, 0.0f, 1.0f };
public void setAmbient(float r, float g, float b, float a) {
ambient[0] = r;
ambient[1] = g;
ambient[2] = b;
ambient[3] = a;
}
public void setDiffuse(float r, float g, float b, float a) {
diffuse[0] = r;
diffuse[1] = g;
diffuse[2] = b;
diffuse[3] = a;
}
public void setSpecular(float r, float g, float b, float a) {
specular[0] = r;
specular[1] = g;
specular[2] = b;
specular[3] = a;
}
public void enable(GL10 gl) {
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, ambient, 0);
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, diffuse, 0);
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SPECULAR, specular, 0);
}
}
```
此外,OpenGL ES 还有一种颜色材质的技巧。通过调用 `gl.glEnable(GL10.GL_COLOR_MATERIAL);`,OpenGL ES 会将模型的顶点颜色作为环境光和漫反射光的材质颜色。由于环境光和漫反射光颜色通常相同,且在大多数演示和游戏中不使用镜面高光,因此可以只启用颜色材质,而不使用 `glMaterialfv()` 调用。
#### 2. 指定法线
为了使 OpenGL ES 中的光照正常工作,我们必须为模型的每个顶点指定顶点法线。顶点法线是一个单位长度的向量,指向顶点所属表面的(平均)朝向方向。以下是一个简单的示例:
```java
float[] vertices = { -0.5f, -0.5f, 0, 0, 0, 1,
0.5f, -0.5f, 0, 0, 0, 1,
0.0f, 0.5f, 0, 0, 0, 1 };
Vertices3 vertices = new Vertices3(glGraphics, 3, 0, false, false, true);
vertices.setVertices(vertices);
```
为了上传顶点法线,我们需要修改 `Vertices3` 类。以下是最终修订后的 `Vertices3` 类:
```java
package com.badlogic.androidgames.framework.gl;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import javax.microedition.khronos.opengles.GL10;
import com.badlogic.androidgames.framework.impl.GLGraphics;
public class Vertices3 {
final GLGraphics glGraphics;
final boolean hasColor;
final boolean hasTexCoords;
final boolean hasNormals;
final int vertexSize;
final IntBuffer vertices;
final int[] tmpBuffer;
final ShortBuffer indices;
public Vertices3(GLGraphics glGraphics, int maxVertices, int maxIndices,
boolean hasColor, boolean hasTexCoords, boolean hasNormals) {
this.glGraphics = glGraphics;
this.hasColor = hasColor;
this.hasTexCoords = hasTexCoords;
this.hasNormals = hasNormals;
this.vertexSize = (3 + (hasColor ? 4 : 0) + (hasTexCoords ? 2 : 0) +
(hasNormals ? 3 : 0)) * 4;
this.tmpBuffer = new int[maxVertices * vertexSize / 4];
ByteBuffer buffer = ByteBuffer.allocateDirect(maxVertices * vertexSize);
buffer.order(ByteOrder.nativeOrder());
vertices = buffer.asIntBuffer();
if (maxIndices > 0) {
buffer = ByteBuffer.allocateDirect(maxIndices * Short.SIZE / 8);
buffer.order(ByteOrder.nativeOrder());
indices = buffer.asShortBuffer();
} else {
indices = null;
}
}
public void setVertices(float[] vertices, int offset, int length) {
this.vertices.clear();
int len = offset + length;
for (int i = offset, j = 0; i < len; i++, j++)
tmpBuffer[j] = Float.floatToRawIntBits(vertices[i]);
this.vertices.put(tmpBuffer, 0, length);
this.vertices.flip();
}
public void setIndices(short[] indices, int offset, int length) {
this.indices.clear();
this.indices.put(indices, offset, length);
this.indices.flip();
}
public void bind() {
GL10 gl = glGraphics.getGL();
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
vertices.position(0);
gl.glVertexPointer(3, GL10.GL_FLOAT, vertexSize, vertices);
if (hasColor) {
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
vertices.position(3);
gl.glColorPointer(4, GL10.GL_FLOAT, vertexSize, vertices);
}
if (hasTexCoords) {
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
vertices.position(hasColor ? 7 : 3);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, vertexSize, vertices);
}
if (hasNormals) {
gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
int offset = 3;
if (hasColor)
offset += 4;
if (hasTexCoords)
offset += 2;
vertices.position(offset);
gl.glNormalPointer(GL10.GL_FLOAT, vertexSize, vertices);
}
}
public void draw(int primitiveType, int offset, int numVertices) {
GL10 gl = glGraphics.getGL();
if (indices != null) {
indices.position(offset);
gl.glDrawElements(primitiveType, numVertices,
GL10.GL_UNSIGNED_SHORT, indices);
} else {
gl.glDrawArrays(primitiveType, offset, numVertices);
}
}
public void unbind() {
GL10 gl = glGraphics.getGL();
if (hasTexCoords)
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
if (hasColor)
gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
if (hasNormals)
gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
}
}
```
这个类的修改主要包括添加了 `hasNormals` 布尔值来跟踪顶点是否有法线,修改了 `vertexSize` 的计算,以及在 `bind()` 方法中添加了对法线的处理。
#### 3. 综合应用:光照场景示例
以下是一个综合示例,展示了如何使用上述技巧创建一个包含全局环
0
0
复制全文
相关推荐









