模型姿态问题原因及解决——以obj格式为例

版权声明: https://blog.csdn.net/zxzfcsu/article/details/82532491

在Cesium中加载模型时一个需要注意的地方就是模型的姿态问题,我们在本篇文章及下一篇与大家进行探讨。

一、背景概述

cesium-1.47,gltf 2.0
我们知道目前市面上有许多种3d格式,各大厂商纷纷开发自己的数据格式以争取话语权。
而cesium支持多种格式的三维模型,主要有dae,gltf,glb以及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,os

InputFileDirectory="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文件进行旋转操作。

三、理论依据和原因追究

以上呢都是关于问题的描述以及如何去解决这个问题,那么除此之外,我们还要去弄清楚这到底是怎么回事,那么我们一起来看一下。

1、obj模型的朝向问题:在默认情况下 -Z forward, +Y up

      gltf模型的朝向问题:

四、参考资料

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/

猜你喜欢

转载自blog.csdn.net/zxzfcsu/article/details/82532491
今日推荐