3D编程技巧:从相机到模型加载与物理模拟
立即解锁
发布时间: 2025-08-24 00:51:24 阅读量: 1 订阅数: 13 

### 3D编程技巧:从相机到模型加载与物理模拟
#### 1. 多触摸支持提示
在开发中,添加多触摸支持是个很棒的想法。可以不使用轮询方式,而是利用实际的触摸事件。在“触摸按下”事件发生时,检查按钮是否被点击。若被点击,标记与之关联的指针ID,使其在对应的“触摸抬起”事件触发前不能产生滑动手势。而其他指针ID的触摸事件则可被解释为滑动手势。
#### 2. 视角相机(Look - At Camera)
视角相机是游戏中常见的另一种相机类型,它由以下要素定义:
- **空间位置**:相机在空间中的具体位置。
- **上向量**:可想象为相机平放在水平表面时,贴在相机背面的“此面朝上”贴纸所对应的箭头方向。
- **视角位置**:相机所看向的空间位置。
- **视野角度**:以度为单位的相机视野范围。
- **视口宽高比**:视口的宽度与高度的比例。
- **近裁剪面距离和远裁剪面距离**:决定相机能看到的最近和最远的距离。
以下是视角相机的代码实现:
```java
package com.badlogic.androidgames.framework.gl;
import javax.microedition.khronos.opengles.GL10;
import android.opengl.GLU;
import com.badlogic.androidgames.framework.math.Vector3;
public class LookAtCamera {
final Vector3 position;
final Vector3 up;
final Vector3 lookAt;
float fieldOfView;
float aspectRatio;
float near;
float far;
public LookAtCamera(float fieldOfView, float aspectRatio, float near, float far) {
this.fieldOfView = fieldOfView;
this.aspectRatio = aspectRatio;
this.near = near;
this.far = far;
position = new Vector3();
up = new Vector3(0, 1, 0);
lookAt = new Vector3(0,0,-1);
}
public Vector3 getPosition() {
return position;
}
public Vector3 getUp() {
return up;
}
public Vector3 getLookAt() {
return lookAt;
}
public void setMatrices(GL10 gl) {
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
GLU.gluPerspective(gl, fieldOfView, aspectRatio, near, far);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
GLU.gluLookAt(gl, position.x, position.y, position.z, lookAt.x, lookAt.y, lookAt.z,
up.x, up.y, up.z);
}
}
```
视角相机与欧拉相机的区别在于相机方向的编码方式。视角相机通过上向量和视角位置来指定方向。`setMatrices()`方法先将投影矩阵设置为基于视野角度、宽高比以及近远裁剪面距离的透视投影矩阵,再通过`gluLookAt()`方法设置模型视图矩阵,包含相机的位置和方向矩阵。
实际上,视角相机可以像欧拉相机一样使用。步骤如下:
1. 通过视角点减去相机位置得到方向向量,并进行归一化处理。
2. 用偏航角和俯仰角旋转该方向向量。
3. 将新的视角位置设置为相机位置加上方向向量。
#### 3. 模型加载
在代码中定义模型(如立方体)是很繁琐的。更好的方法是使用专业软件进行所见即所得的复杂模型创建,常见软件如下:
| 软件名称 | 特点 |
| ---- | ---- |
| Blender | 开源项目,功能强大且灵活,但有一定学习难度 |
| Wings3D | 开源,用于简单低多边形静态对象建模,操作简单 |
| 3D Studio Max | 行业标准商业软件,有学生版本 |
| Maya | 行业常用商业软件,有适合小预算的定价选项 |
#### 4. Wavefront OBJ格式
我们将实现一个支持部分OBJ格式的加载器,该加载器支持仅由三角形组成的模型,可选择性包含纹理坐标和法线。OBJ格式是基于行的,以下是我们要处理的语法部分:
- `v x y z`:表示顶点位置,x、y、z为浮点数坐标。
- `vn i j k`:表示顶点法线,i、j、k为法线的x、y、z分量。
- `vt u v`:表示纹理坐标对,u和v为纹理坐标。
- `f v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3`:表示一个三角形,每个`v/vt/vn`块包含三角形单个顶点的位置、纹理坐标和法线的索引。
以下是一个简单的带法线的纹理三角形的OBJ格式示例:
```
v -0.5 -0.5 0
v 0.5 -0.5 0
v 0 0.5 0
vn 0 0 1
vn 0 0 1
vn 0 0 1
vt 0 1
vt 1 1
vt 0.5 0
f 1/1/1 2/2/2 3/3/3
```
需要注意的是,顶点位置、纹理坐标和法线的定义顺序不一定整齐,且`f`语句中的索引是从1开始的,有些软件还会输出负索引,处理时需要根据已加载的顶点属性数量进行调整。
#### 5. 实现OBJ加载器
加载OBJ文件的步骤如下:
```mermaid
graph TD;
A[打开输入流读取资产文件] --> B[读取文件的所有行];
B --> C[根据行数分配临时数组];
C --> D[遍历每行解析数据];
D --> E[处理顶点位置、法线、纹理坐标和三角形索引];
E --> F[组装顶点数组];
F --> G[创建Vertices3实例并设置顶点];
G --> H[返回模型];
```
以下是OBJ加载器的代码实现:
```java
package com.badlogic.androidgames.framework.gl;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import com.badlogic.androidgames.framework.impl.GLGame;
public class ObjLoader {
public static Vertices3 load(GLGame game, String file) {
InputStream in = null;
try {
in = game.getFileIO().readAsset(file);
List<String> lines = readLines(in);
float[] vertices = new float[lines.size()* 3];
float[] normals = new float[lines.size()* 3];
float[] uv = new float[lines.size()* 2];
int numVertices = 0;
```
0
0
复制全文
相关推荐









