谈谈Processing 3D世界 六 (续)
2016-08-18 16:51
225 查看
setp5 将OBJ文件导入Processing
既然我们知道obj实际上就是一个文本本件,我们何不索性将其改成txt?这样,我们用Processing的loadStrings()函数就能轻易读取obj的内容到我们程序的内存中,供我们解码后运用。
String dateFileName; ... String[] lines = loadStrings(dateFileName);好第五步轻松解决。
setp6 在Processing中解码OBJ文件
结合上一节的知识,我们知道要依靠obj文件来替我们画图,关键是在f(面)的文本行描述上。... f 2/2/17 8/11/18 4/4/19 f 4/4/19 8/11/18 6/12/20 ...
而这些信息都是用顶点属性索引来描述的。所以我们需要用数组来装载属性,使其拥有索引,以供将来绘图函数按照f(面)的索引序列来调用属性数据。
1.新建OBJ读取类
class OBJLoader { void init(String dateFileName) { // 载入obj文件,obj文件需要被转换成txt文件 // 以行为单位装载文本 String[] lines = loadStrings(dateFileName); } }
2.为各属性计数
// 在类中新建变量用于个属性计数 int vCount, vtCount, fCount; // 顶点位置、UV、面 计数 // 各属性计数实现方法 void attrArrayCount(String[] lines) { for(int i = 0; i < lines.length; i++) { // 轮询每行文本 // 查找关键字,给属性计数,这里我们只关心v、vt、f if(lines[i].startsWith("v ")){ // 顶点位置 计数 vCount++; }else if(lines[i].startsWith("vt ")) { // 顶点UV 计数 vtCount++; }else if(lines[i].startsWith("f ")){ // 面 计数 fCount++; } } }
3.新建并初始化属性数组容器
// vertices PVector[] v, vt; // 顶点位置、UV,这里我们先忽略顶点法向量。 // face(*三角面)- fx v/vt/vn v/vt/vn v/vt/vn int[] fv1, fv2, fv3; // 顶点位置 索引数组 int[] fvt1, fvt2, fvt3; // 顶点UV 索引数组 // 初始化属性索引数组 void initAttrArray() { // 初始化顶点位置、UV数组 v = new PVector[vCount + 1]; // 注意配合obj文件的语法 vt = new PVector[vtCount + 1]; // 起始数从1开始,这里实际上是让0元素空置了。 // 初始化面数组 fv1 = new int[fCount]; fv2 = new int[fCount]; fv3 = new int[fCount]; fvt1 = new int[fCount]; fvt2 = new int[fCount]; fvt3 = new int[fCount]; }
4.填入属性数据
void assiAttrArray(String[] lines) { int vIndex = 1; // 因为F的引用是从1开始,所以v的起始号是1 int vtIndex = 1; // 同上 int fIndex = 0; // f本身没有描述索引号,所以我们可以按传统安排索引 for(int i = 0; i < lines.length; i++) { // 记录顶点位置 if(lines[i].startsWith("v ")){ assiV(lines[i], vIndex); vIndex++; // 记录顶点UV纹理坐标 }else if(lines[i].startsWith("vt ")) { assiVt(lines[i], vtIndex); vtIndex++; // 记录面构成 }else if(lines[i].startsWith("f ")){ assiF(lines[i], fIndex); fIndex++; } } }
接着我们逐步来实现其功能
// 处理顶点位置 void assiV(String line, int vIndex) { // 把此行信息分解成单个的词语,并提取浮点信息 float[] date = float(splitTokens(line)); v[vIndex] = new PVector(date[1] * UNIT, date[2] * UNIT, date[3] * UNIT); }
// 处理顶点UV void assiVt(String line, int vtIndex) { // 把此行信息分解成单个的词语,并提取浮点信息 float[] date = float(splitTokens(line)); vt[vtIndex] = new PVector(date[1], date[2]); }
// 处理面 void assiF(String line, int fIndex) { // 把此行信息分解成单个的词语 f1 | 1/1/1 | 2/3/1 | 3/2/2 String[] date = splitTokens(line); // 处理面的顶点信息 PVector v1 = fvertex(date[1], fIndex); PVector v2 = fvertex(date[2], fIndex); PVector v3 = fvertex(date[3], fIndex); fv1[fIndex] = int(v1.x); fv2[fIndex] = int(v2.x); fv3[fIndex] = int(v3.x); fvt1[fIndex] = int(v1.y); fvt2[fIndex] = int(v2.y); fvt3[fIndex] = int(v3.y); }
5.处理面的顶点信息
// 处理面的顶点的信息 PVector fvertex(String date, int fIndex) { PVector value = new PVector(); // 因为不清楚数字的位数:123/21/21 | 25452/... int last_n = 0; for(int n = 0; n < 100; n++) { String s = date.substring(n, n + 1); // 获取从参数开始到参数结束的字符串,这里是逐个审核字符 if( s.equals("/")) { // 如果字符为“/” value.x = int(date.substring(0, n)); // 截取v属性索引 last_n = n + 1; break; } } for(int n = last_n; n < 100; n++) { String s = date.substring(n, n + 1); if( s.equals("/")) { value.y = int(date.substring(last_n, n)); // 截取vt属性索引 break; } } return value; }这样我们就解码并在程序内存中组织好了所有的网格数据,等待绘制。
6.载入obj数据 - 小结
// obj文件需要被转换成txt文件
// 本类暂时只处理v、vt、f数据
class OBJLoader {
// 顶点属性
PVector[] v, vt; // 位置、UV
// 面-属性索引
// (*三角面)- fx v/vt/vn v/vt/vn v/vt/vn
int[] fv1, fv2, fv3;
int[] fvt1, fvt2, fvt3;
// 属性计数
int vCount, vtCount, fCount;
void init(String dateFileName) {
// 以行为单位装载文本
String[] lines = loadStrings(dateFileName);
// 属性计数
attrArrayCount(lines);
// 属性数组初始化
initAttrArray();
// 属性数组赋值
assiAttrArray(lines);
}
// 各属性计数实现方法
void attrArrayCount(String[] lines) {
for(int i = 0; i < lines.length; i++) { // 轮询每行文本
// 查找关键字,给属性计数
if(lines[i].startsWith("v ")){ // 顶点位置 计数
vCount++;
}else if(lines[i].startsWith("vt ")) { // 顶点UV 计数
vtCount++;
}else if(lines[i].startsWith("f ")){ // 面 计数
fCount++;
}
}
}
// 初始化属性数组
void initAttrArray() {
// 初始化顶点位置、UV数组
v = new PVector[vCount + 1]; // 注意配合obj文件的语法
vt = new PVector[vtCount + 1]; // 起始数从1开始,这里实际上是让0元素空置了。
// 初始化面数组
fv1 = new int[fCount];
fv2 = new int[fCount];
fv3 = new int[fCount];
fvt1 = new int[fCount];
fvt2 = new int[fCount];
fvt3 = new int[fCount];
}
void assiAttrArray(String[] lines) {
int vIndex = 1; // 因为F的引用是从1开始,所以v的起始号是1
int vtIndex = 1; // 同上
int fIndex = 0; // f本身没有描述索引号,所以我们可以按传统安排索引
for(int i = 0; i < lines.length; i++) {
// 记录顶点位置
if(lines[i].startsWith("v ")){
assiV(lines[i], vIndex);
vIndex++;
// 记录顶点UV纹理坐标
}else if(lines[i].startsWith("vt ")) {
assiVt(lines[i], vtIndex);
vtIndex++;
// 记录面构成
}else if(lines[i].startsWith("f ")){
assiF(lines[i], fIndex);
fIndex++;
}
}
}
// 处理顶点位置
void assiV(String line, int vIndex) {
// 把此行信息分解成单个的词语,并提取浮点信息
float[] date = float(splitTokens(line));
v[vIndex] = new PVector(date[1] * UNIT, date[2] * UNIT, date[3] * UNIT);
}
// 处理顶点UV void assiVt(String line, int vtIndex) { // 把此行信息分解成单个的词语,并提取浮点信息 float[] date = float(splitTokens(line)); vt[vtIndex] = new PVector(date[1], date[2]); }
// 处理面 void assiF(String line, int fIndex) { // 把此行信息分解成单个的词语 f1 | 1/1/1 | 2/3/1 | 3/2/2 String[] date = splitTokens(line); // 处理面的顶点信息 PVector v1 = fvertex(date[1], fIndex); PVector v2 = fvertex(date[2], fIndex); PVector v3 = fvertex(date[3], fIndex); fv1[fIndex] = int(v1.x); fv2[fIndex] = int(v2.x); fv3[fIndex] = int(v3.x); fvt1[fIndex] = int(v1.y); fvt2[fIndex] = int(v2.y); fvt3[fIndex] = int(v3.y); }
// 处理面的顶点的信息 PVector fvertex(String date, int fIndex) { PVector value = new PVector(); // 因为不清楚数字的位数:123/21/21 | 25452/... int last_n = 0; for(int n = 0; n < 100; n++) { String s = date.substring(n, n + 1); // 获取从参数开始到参数结束的字符串,这里是逐个审核字符 if( s.equals("/")) { // 如果字符为“/” value.x = int(date.substring(0, n)); // 截取v属性索引 last_n = n + 1; break; } } for(int n = last_n; n < 100; n++) { String s = date.substring(n, n + 1); if( s.equals("/")) { value.y = int(date.substring(last_n, n)); // 截取vt属性索引 break; } } return value; }
}
利用obj数据绘制模型再开一个坑好了。一篇帖子太长了就不容易编辑,老是要审核审核的。
下篇帖子继续。
相关文章推荐
- 谈谈Processing 3D世界 四(补充)
- 谈谈Processing 3D世界 三
- 谈谈Processing 3D世界 四
- 谈谈Processing 3D世界 五
- 谈谈Processing 3D世界 六 (续二)
- 谈谈Processing 3D世界 一
- 谈谈Processing 3D世界 二
- 谈谈Processing 3D世界 六
- 在3D世界中创建不同的相机模式——创建一个模糊(Blur),(发光)Glow Post-Processing Effect
- 鼠标捡选(窗口坐标系转化为3D世界坐标系)
- 三维世界里的坐标和变换,逆方向旋转移动三维世界的方式来实现3D漫游
- [3D数学]Quake3平面Surface的光照贴图(light map)UV坐标与Surface顶点世界3D坐标之间的转换原理
- 【Stage3D学习笔记续】真正的3D世界(二):显示模型
- 在3D世界中创建不同的相机模式——指定相机的目标
- 在3D世界中创建不同的相机模式——编写自定义内容导入器
- 在3D中, 将世界坐标映射为屏幕上的坐标点
- [文摘20080919]小软件将网页变为3D世界
- 设计自己的软渲染器2-构建3D世界到2D屏幕显示的基本变换
- 走进VR开发世界(5)—— 使用Cocos开发一款简单的3D VR抓钱游戏
- 通过kinect实现3d扫描建立打印模型(processing、skanect、ReconstructMe)