Ptex是Walt Disney Animation Studios开发的纹理映射工具。在看一个叫appleseed的渲染器时看到他支持这种纹理,所以就查看一下,发现比较轻量,所以就想趁此机会学习下。

  Ptex开源代码主要包含该格式的定义、IO、缓存和一些常见filter。头文件Ptexture.h定义了纹理的数据结构和所有操作的API,类定义都是抽象类,ctor和dtor都不是public,生成对象需要通过其他接口来获取实例,或者调用静态函数进行操作,释放对象不能直接调用dtor,统一由release函数delete或返回缓存,大多数对象可以跨线程共用,所以需要ref count,release时大多只是减ref。另外定义了一个用来管理对象的指针类PtexPtr,可以封装所有对象,并在超出作用域后自动release。

主要数据结构:

  1. struct Res,定义纹理的分辨率,按像素的log2存储,长度为8位int,其ctor可以用16位int作为参数,分高低8位储存uv,最小单元(texel)分辨率为1*1(ulog2 = vlog2 = 0),支持tile划分。
  2. FaceInfo,定义面信息,主要包括面的分辨率、相邻面和相邻边(对应相邻面的边ID),相邻面为32位int数组,一个面有4个相邻面,-1表示该相邻面为空,相邻边为8位uint,每个长度为2位,合并为8位保存,相邻面的遍历按边的ID从底部逆时针进行,边的左右顶底在该头文件的enum定义中(三角形没定义),如果相邻面是细分面(有多个面在当前面的同一边),则以逆时针遍历第一个遇到的面为整个相邻面的ID。

读取header信息:

  纹理信息保存在PtexTexture对象中,该对象不能由自己生成,只能通过静态open函数(PtextReader)或PtexCache接口生成。首先,锁mutex,将ptex文件以二进制形式打开(不转译回车和换行字符)并设置buffer,然后读取header,保存有各种校验信息和大小数目参数,以此对读取的文件进行校验,然后读取extended header,header中可以定义extended header的大小,struct ExtHeader的大小为40字节,所以在读取时应该以最小的为准,然后计算各个数据的起始位置,调用读取函数,包括:

  1. 读取面信息。读取过程分三步,首先从压缩的文件中读取FaceInfo,每次读取header中定义的faceinfosize或着16384字节(faceinfosize > BlockSize)为一个block,然后生成rfaceid(先按面在内存中的储存顺序分配id,然后以面的uv分辨率最小的那个作为依据降序排列面的顺序,该顺序就是rfaceid,面为常量则分辨率当作1),并建立rfaceid和faceid的映射关系,最后更新已使用的内存数。
  2. 读取面的常量像素值。读取过程分三步,第一和三步同上,第二步为alpha通道的预乘处理,先判断alpha通道的位置来确定需要预乘的通道,然后根据不同的像素存储类型归一化alpha值,最后将归一化的alpha值与需要预乘的通道的像素值相乘。
  3. 读取层次信息。读取过程分三步,第一和三步同上,第二步为层次定位,依次储存每一层次的开始位置。
  4. 读取编辑数据。读取过程分三步,首先确定编辑位置,然后根据编辑的类型读取,分为面数据和元数据两类,先读取对应的编辑header,然后保存编辑内容,编辑面数据还需要读取面的常数像素值,最后更新内存使用记录。

获取纹理数据:

  大部分数据可以通过简单返回获得,下面主要看几个比较复杂的数据:

  1. 获取元数据。元数据分meta data和large meta data两类,其大小分别定义在header和extheader中。两者的获取类似,都是建立kv映射,key为string表示名字,value为entry存储元数据,entry内保存了数据位置作为key,直接从内存将所需数据拷贝到指定位置,区别在于lmd的entry没有保存解压后的数据,而是数据的位置,只有在载入并引用后才能访问,有一个flag标识lmd。
  2. 获取一个面的纹理数据。有四种获取方式,获取最高分辨率的纹理、获取指定分辨率的纹理、获取硬盘上保存的最高分辨率的纹理、获取硬盘上保存的指定分辨率的纹理。前两种是把数据拷贝到指定buffer里,后两种是返回facedata的指针,在获取指定分辨率的纹理时,如果mipmap有对应的分辨率就直接从mipmap获取,否则就用最近的分辨率生存新的纹理。第一种:首先获取面的分辨率,然后调用第二种函数。第二种:使用PtexPtr管理对象,调用第四种函数获取facedata指针,如果是常数,则直接用该像素充填buffer;如果不是常数且分tile,则按tile(v major遍历)充填buffer,如果tile为常数,则直接用该像素充填tile的第一行,然后用第一行充填其他行,如果tile不是常数,则根据stride大小决定拷贝方式,如果stride等于行长度,则直接整体拷贝相应数据到tile,否则按行拷贝,如果不是常数且不分tile,则根据stride大小决定拷贝方式。第三种:获取level 0后根据level获取facedata,如果level没有被读取过,则初始化level,如果face没有和level建立关系,则根据face data header的编码方式初始化指定facedata并保存。第四种:主要处理mipmap,如果设置的分辨率不需要reduction则直接获取level 0的facedata,如果是对称reduction,则用u方向的reduction作为levelid直接查找facedata,如果不能查到,则需要动态reduction,首先在cache里查,如果没有则生存新的reduction,根据reduction的方向(u或v)来reduce,生存后存入reduction cache并返回facedata。
  3. 获取一个面的纹理的一个texel数据。有两种获取方式,获取最高分辨率纹理的texel、获取指定分辨率纹理的texel。两种方式基本类似,首先获取实际通道数,然后获取facedata,然后就可以得到像素值,然后根据第一通道位置来设置像素保存的偏移量,最后保存,如果像素值不是float,则转成float保存。二者的区别在获取facedata,第二种需要根据reduction来确定mipmap的level获取相应facedata。

Ptex源码学习笔记-1的更多相关文章

  1. Ptex源码学习笔记-2

    写入纹理数据: 主要分为五种写入方式:新建纹理.编辑已有纹理.编辑ExtHeader中的指定项.写入元数据和写入指定面的纹理数据.写入过程中数据存在一个临时文件中,在close时才会把临时文件的内容拷 ...

  2. Underscore.js 源码学习笔记(下)

    上接 Underscore.js 源码学习笔记(上) === 756 行开始 函数部分. var executeBound = function(sourceFunc, boundFunc, cont ...

  3. Underscore.js 源码学习笔记(上)

    版本 Underscore.js 1.9.1 一共 1693 行.注释我就删了,太长了… 整体是一个 (function() {...}());  这样的东西,我们应该知道这是一个 IIFE(立即执行 ...

  4. AXI_LITE源码学习笔记

    AXI_LITE源码学习笔记 1. axi_awready信号的产生 准备接收写地址信号 // Implement axi_awready generation // axi_awready is a ...

  5. Hadoop源码学习笔记(6)——从ls命令一路解剖

    Hadoop源码学习笔记(6) ——从ls命令一路解剖 Hadoop几个模块的程序我们大致有了点了解,现在我们得细看一下这个程序是如何处理命令的. 我们就从原头开始,然后一步步追查. 我们先选中ls命 ...

  6. Hadoop源码学习笔记(5) ——回顾DataNode和NameNode的类结构

    Hadoop源码学习笔记(5) ——回顾DataNode和NameNode的类结构 之前我们简要的看过了DataNode的main函数以及整个类的大至,现在结合前面我们研究的线程和RPC,则可以进一步 ...

  7. Hadoop源码学习笔记(4) ——Socket到RPC调用

    Hadoop源码学习笔记(4) ——Socket到RPC调用 Hadoop是一个分布式程序,分布在多台机器上运行,事必会涉及到网络编程.那这里如何让网络编程变得简单.透明的呢? 网络编程中,首先我们要 ...

  8. Hadoop源码学习笔记(3) ——初览DataNode及学习线程

    Hadoop源码学习笔记(3) ——初览DataNode及学习线程 进入了main函数,我们走出了第一步,接下来看看再怎么走: public class DataNode extends Config ...

  9. Hadoop源码学习笔记(2) ——进入main函数打印包信息

    Hadoop源码学习笔记(2) ——进入main函数打印包信息 找到了main函数,也建立了快速启动的方法,然后我们就进去看一看. 进入NameNode和DataNode的主函数后,发现形式差不多: ...

随机推荐

  1. IOS 判断耳机插入/拔出

    一. 方式 1.注册监听 //注册监听耳机设备的插入/拔出 AudioSessionAddPropertyListener (kAudioSessionProperty_AudioRouteChang ...

  2. UDP/TCP

    转载地址http://blog.csdn.net/wwmusic/article/details/8875748 Socket  是一套建立在TCP/IP协议上的接口不是一个协议 应用层:  HTTP ...

  3. 百度echart使用心得,百度图表。

    百度echart算是百度针对数据展示做的一个图表插件吧,一般我们使用都不是问题,主要还是对于对动态数据的解析.我这里使用饼状图,和柱状图为例: 首先,我们需要定义一个绘图的容器:(class是我自己定 ...

  4. 二模14day1解题报告

    注:Index数☞由4,7组成的十进制数. T1.全排列(permutation) 求n个数的第k个排列中,有多少个Index位置上是Index数. 由于k的范围比较小,n的范围比较大(都是109), ...

  5. Linux:添加永久路由

    没有以下文件时,可创建 vim /etc/sysconfig/network-scripts/route-eth0添加如下信息:192.168.142.100/32 via 192.168.142.1 ...

  6. MySQL 对于千万级的大表要怎么优化?

    作者:哈哈链接:https://www.zhihu.com/question/19719997/answer/81930332来源:知乎著作权归作者所有,转载请联系作者获得授权. 第一优化你的sql和 ...

  7. Android开发--页面切换

    1.创建android项目.项目文档如下 2.activity_main布局,Androidv4包里自带的,既然是自带的那么直接拿来用就可以了,当然前提是你得工程里有v4包 <LinearLay ...

  8. android开发--数据库(更新或者降低版本)

    Andoird的SQLiteOpenHelper类中有一个onUpgrade方法. 1. 帮助文档里说的"数据库升级"是指什么? 你开发了一个应用,当前是1.0版本.该程序用到了数 ...

  9. python 数据处理中各种存储方式里数据类型的转换

    自己记录,仅供参考 在数据处理时经常会遇到数据类型不匹配的事情,为了方便查看各种存储方式中数据类型的改变.我把一些自己常用的整理方式记录下来,希望可以为以后数据类型的处理工作提供便利. 数据常用的基本 ...

  10. JDK&JRE&JVM

    JDK:—Java Development kit  (Java开发工具包) JRE:—Java Runtime Environment (Java运行时环境) JVM:Java Virtual Ma ...