模型姿态问题原因及解决——以obj格式为例
在Cesium中加载模型时一个需要注意的地方就是模型的姿态问题,我们在本篇文章及下一篇与大家进行探讨。
一、背景概述
cesium-1.47,gltf 2.0
我们知道目前市面上有许多种3d格式,各大厂商纷纷开发自己的数据格式以争取话语权。
而cesium支持多种格式的三维模型,主要有dae,gltf,glb,czml以及3d-tiles,它们的文件组织格式和坐标系统不尽相同,所以我们需要进行探讨。顺便说一下踩过的坑。
在本篇文章中,我们主要探讨的是obj格式的模型,为什么是obj呢?因为之前的几篇中写到了osgb-->obj-->gltf的格式转换路线,obj正是其中的关键环节。在这个地方主要出现了两个问题,一是纹理贴错了,需要做一个镜像;二是模型的姿态在转换到gltf是总是错误的,我用的是obj2gltf工具。那么我们就这两个问题分别进行探讨,以姿态为主,纹理的问题我只提供一个简单的方法。
注:3d-tiles的事情以后再讨论
二、解决方法
1、对于纹理镜像的问题提供一个简单思路:
在进行dds-->png的转化中,我们使用了工具DDS4J。看他的源码发现其实是以横排的像素作为单位进行转换的,那么我们在此就可以做一点文章了。
ddsImageDecoder.java------>convertToPNG(....)
修改前:
DdsHeader header = dds.getHeader();FormatDecoder decoder = Decoders.getDecoder(dds);ImageInfo imageInfo = new ImageInfo(header.getDwWidth(), header.getDwHeight(), 8, true);PngWriter pngWriter = new PngWriter(outputStream, imageInfo);ImageLineInt imageLine = new ImageLineInt(imageInfo);for (int[] ints : decoder) {swizzle(ints, swizzle);ImageLineHelper.setPixelsRGBA8(imageLine, ints);pngWriter.writeRow(imageLine);}pngWriter.end();
修改后:
DdsHeader header = dds.getHeader();FormatDecoder decoder = Decoders.getDecoder(dds);ImageInfo imageInfo = new ImageInfo(header.getDwWidth(), header.getDwHeight(), 8, true);PngWriter pngWriter = new PngWriter(outputStream, imageInfo);ImageLineInt imageLine = new ImageLineInt(imageInfo);// 镜像List<int[]> data=new ArrayList<>();for (int[] ints:decoder){data.add(ints);}for (int i=data.size();i>0;i--){int[] linedata=data.get(i-1);swizzle(linedata,swizzle);ImageLineHelper.setPixelsRGBA8(imageLine,linedata);pngWriter.writeRow(imageLine);}pngWriter.end();
2、解决姿态问题的方法:使用软件blender对模型进行旋转操作
[1]手动方式解决:
file-->import-->obj导入模型;在右上角的outliner操作框中可以看到scene中加了几个object,这就是我们的模型,请把自带的cube右键删除掉;选中我们模型里的任意一个object,按键盘R键(旋转的快捷键),然后输入xyz字母中的一个作为约束轴,最后输入角度值(可以为负),回车确定即完成旋转操作;以同上的操作对该模型的其他object进行旋转;file-->export-->obj导出模型。
[2]代码解决:
blender是可以进行二次开发的,可以使用python脚本(3.x)扩展blender功能,但是也有一些不能由python脚本实现,需要使用C/C++进行开发。
有两种方式来进行开发,一种是使用内置的python控制台来写代码,这种比较简单,但是不适合较大任务;所以另外blender提供文本编辑器(Text Editor)来进行开发,所以我们切换到文本编辑器进行开发,其中也提供了常见功能的代码例子以供参阅。
下面是我的一些代码,主要就是实现了旋转的功能。注意,在写代码前请先配置好python 3.x环境。
# 目标1:读取文件夹下所有obj文件
# 目标2:对obj模型中所有mesh进行旋转(x轴 -90度)
# 目标3:对旋转后obj模型进行保存(原文件名 + "-RotateX-90")import bpy,osInputFileDirectory="E:/obj/obj";
OutputFileDirectory="E:/obj/obj/RotateX-90Out";
Files=os.listdir(InputFileDirectory);
for file in Files:if file.endswith(".obj"):bpy.ops.import_scene.obj(filepath=(InputFileDirectory+"/"+file)); # 导入模型bpy.ops.transform.rotate(axis=(-90,0,0)); # 以x为轴旋转-90度str=file.split('.');OutPath=str[0]+'-RotateX-90.obj';bpy.ops.export_scene.obj(filepath=(OutputFileDirectory+"/"+OutPath)); # 输出模型# 删除模型override = bpy.context.copy();override['selected_bases'] = list(bpy.context.scene.object_bases);bpy.ops.object.delete(override);print(file+" is over");
注:输出在菜单栏 window-->Toggle System console 查看
如果想对gltf模型直接进行操作,请先导入gltf导入和导出模块,才能对其进行操作。不过我测试用的时候总是丢失纹理,所以我还是选择了对obj文件进行旋转操作。
对于blender中的任意按钮或菜单,鼠标悬停后可以看到其对应的python命令,右键单击可以进入API文档查看该命令的具体参数和使用方法。
三、理论依据和原因追究
以上呢都是关于问题的描述以及如何去解决这个问题,那么除此之外,我们还要去弄清楚这到底是怎么回事,那么我们一起来看一下。
在我们这里遇到的模型姿态问题实际上是坐标轴朝向问题。glTF使用满足右手准则的三维空间笛卡尔坐标系,其中Y轴表示物体的上方向、Z轴垂直屏幕指向屏幕外、X轴为Y轴与Z轴向量的叉积。而大部分建模软件(如blender,3ds Max)和人们平常认知中都是以Z轴向上的坐标系,所以就导致了转化出来的 glTF场景中三维物体的底层顶点数据是以Z轴正方向为上方向的。最重要的是Cesium也是以Z轴向上,X轴向外,Y轴为XZ叉积的右手坐标系,那么就会显示出我们这里说的姿态问题。就这个问题的解决还有其他的方法:
1、使用blender导入obj模型后,再导出模型,但是导出的模型选项应为 -Z Froward, Y Up
在bpy.ops.export_scene.obj(.....) 参数中修改即可,API在此
2、在gltf文件的节点树中增加一个根节点以实现坐标系统的旋转,该节点的matrix属性应为[0,0,1,0, 0,1,0,0, -1,0,0,0, 0,0,0,1],
起初我以为这个方法很简单,写个符合json格式的转换的对象填进去就行了,实际上好像并不是这么简单。根据我的询问和摸索,这种方法需要对原来的gltf文件做如下改动:
(1) 在源文件中的"scenes"对象中查看"nodes"节点,把这些节点记录一下一会还要用,比如说为[0,1,2,3,4,5,6],然后将内容改为[8];
(2) 在源文件中的"nodes"节点数组中加入两个对象。一是在开头处加一个子节点数组对象,如{ "children": [1,2,3,4,5,6,7] };之后在末尾处加一个转换矩阵的对象,如{ "name": "Y_UP_Transform","matrix": [0,0,1,0,0,1,0,0,-1,0,0,0,0,0,0,1],"children" : [0] }
我来大概解释一下为什么,因为scenes是我们的场景,也就是要渲染的东西。修改前后分别渲染的是[0,1,2,3,4,5,6]和[8],这里面的数字或数组就是node节点对应的位置。那么根据我们这里提供的数字,可以找到对应的对象。在修改后的[8]处,我们可以看到,这就是我们的转换矩阵,而它所对应的子节点就是[0]号节点,继而渲染出所有对象并且执行了旋转。
这个地方有一点需要注意,如果把这个矩阵直接加到[0]节点也是可以的
{"children": [1,2,3,4,5,6,7],"matrix": [0,0,1,0,0,1,0,0,-1,0,0,0,0,0,0,1]}
但是不建议这么做,因为会污染我们的场景。大家也可以看一个其他例子。
四、参考资料
Blender Manual中文版: https://docs.blender.org/manual/zh-hans/dev/getting_started/index.html
Blender python API Documents: https://docs.blender.org/api/current/contents.html
obj文件格式详述: http://paulbourke.net/dataformats/obj/
论文:《3D Tiles 定义解析与生产规范设计》
likangning93
在此一并感谢!
模型姿态问题原因及解决——以obj格式为例相关推荐
- 模型过拟合原因及解决办法
模型过拟合原因及解决办法 过拟合现象 导致过拟合原因 解决办法 过拟合现象 对于样本量有限.但需要使用强大模型的复杂任务,模型很容易出现过拟合的表现,即在训练集上的损失小,在验证集或测试集上的损失较大 ...
- 【BIM模型生成点云数据】revit转obj格式,全网最详细最简单的步骤了!
最近,学习到了一种新方法,用于制作点云数据集,那就是----用BIM三维模型转obj格式之后导入到cloudcompare生成点云数据.该方式适合做仿真实验,也可以用于三维建模的精度对比. 关键性问题 ...
- osg导入模型时,模型全黑的原因及解决方法分析
在导入飞机模型时,发现模型是黑咕隆咚一片,然后翻阅资料,找到三个可能性. (一)几何模型没有法线导致 利用osgUtil::SmoothingVisitor自动生成法线 #include <os ...
- zbrush导入obj模型不显示_zbrush软件怎么导入obj格式文件?Zbrush2018教程在哪可以看?...
回答: 关于ZBrush的学习,我大致整理了一些经常会被问到的问题和我的见解,可以参考一下. Q1:次世代ZB到底难不难?因为技术要求的全面升级,次世代确实不简单,但是新手能不能学习次世代呢? A1: ...
- 【深度学习】模型过拟合的原因以及解决办法
[深度学习]模型过拟合的原因以及解决办法 1.背景 2.模型拟合 3.简述原因 4.欠拟合解决办法 5.过拟合解决办法 1.背景 所谓模型过拟合现象: 在训练网络模型的时候,会发现模型在训练集上表现很 ...
- 解决导入obj模型时出现模型镂空的问题
解决导入obj模型时出现模型镂空的问题 这实际上是因为导入的模型采用四边形而非三角形的面片,导致splish采样不全. 使用houdini的divide节点就能将任意面片转化为三角形面片.从而解决问题 ...
- IE6IE7Firefox浏览器不兼容原因及解决办法
IE6IE7Firefox浏览器不兼容原因及解决办法 一.IE6IE7Firefox浏览器不兼容原因及解决办法 1.文字 本身的大小不兼容.同样是font-size:14px的宋体文字,在不同浏览器下 ...
- 欠拟合的原因以及解决办法(深度学习)
之前这篇文章,我分析了一下深度学习中,模型过拟合的主要原因以及解决办法: 过拟合的原因以及解决办法(深度学习)_大黄的博客-CSDN博客 这篇文章中写一下深度学习中,模型欠拟合的原因以及一些常见的解决 ...
- python内核死亡的原因_Kernel Panic常见原因以及解决方法
Technorati 标签: Kernel Panic 出现原因 1. Linux在中断处理程序中,它不处于任何一个进程上下文,如果使用可能睡眠的函数,则系统调度会被破坏,导致kernel panic ...
最新文章
- Hadoop集群搭建(二:集群主机间免密登录配置)
- ajax提交数据到后台php接收
- 串口ic读卡器源码-c#代码(2)续上
- xdebug影响php运行速度
- jzoj4051-序列统计【NTT】
- 2016_shengyang_onsite
- 滴水课后作业(1-5)
- 荔枝派 Nano 全志 F1C100s 编译运行 Linux ubuntu并升级gcc
- 【Siddhi】Syntax error in SiddhiQL, no viable alternative at input
- SpringBoot基础篇日志管理之logback配置文件
- AI 崛起?科技公司却偷偷用人类做机器人的工作!
- 【SQL】IN、EXISTS和表连接三者的效率比较
- 通过修改word文件,来屏蔽宏代码
- Android 动画 Kotlin 教程
- cd 命令行进入目标文件夹
- 苹果6s上市时间_为什么苹果能用5年,安卓1年得换?原因太真实了
- Eclipese快捷键
- HM编码器代码阅读(13)——帧间预测之AMVP模式(一)总体流程
- python之旅六【第六篇】模块
- 叶武滨老师时间管理学习感悟