OpenGLES3D编程技巧:材质、法线与光照应用
立即解锁
发布时间: 2025-08-24 00:51:23 阅读量: 4 订阅数: 17 


Android游戏开发入门与实践
# OpenGL ES 3D 编程技巧:材质、法线与光照应用
## 1. 指定材质
在 OpenGL ES 中,材质由几个属性定义。和 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);
}
}
```
在这个 `Material` 类中,我们存储了材质的三个组成部分,并提供了设置方法和 `enable()` 方法来设置材质。
除了使用 `glMaterialfv()` 方法,OpenGL ES 还提供了另一种材质设置方式,即颜色材质。通过调用 `gl.glEnable(GL10.GL_COLOR_MATERIAL)`,OpenGL ES 会将模型的顶点颜色作为环境光和漫反射光的材质颜色。由于环境光和漫反射光颜色通常相同,并且在大多数演示和游戏中不使用镜面高光,因此可以只启用颜色材质,而不使用 `glMaterialfv()` 调用。是否使用 `Material` 类或颜色材质,可根据具体需求决定。
## 2. 指定法线
在 OpenGL ES 中,为了使光照正常工作,需要为模型的每个顶点指定顶点法线。顶点法线必须是单位长度的向量,指向顶点所属表面的(平均)朝向方向。
为了上传顶点法线,需要对 `Vertices3` 类进行修改。使用 `glNormalPointer()` 方法告诉 OpenGL ES 在哪里可以找到每个顶点的法线。以下是最终修订后的 `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(prim
```
0
0
复制全文
相关推荐







