Ptex源码学习笔记-1
Ptex是Walt Disney Animation Studios开发的纹理映射工具。在看一个叫appleseed的渲染器时看到他支持这种纹理,所以就查看一下,发现比较轻量,所以就想趁此机会学习下。
Ptex开源代码主要包含该格式的定义、IO、缓存和一些常见filter。头文件Ptexture.h定义了纹理的数据结构和所有操作的API,类定义都是抽象类,ctor和dtor都不是public,生成对象需要通过其他接口来获取实例,或者调用静态函数进行操作,释放对象不能直接调用dtor,统一由release函数delete或返回缓存,大多数对象可以跨线程共用,所以需要ref count,release时大多只是减ref。另外定义了一个用来管理对象的指针类PtexPtr,可以封装所有对象,并在超出作用域后自动release。
主要数据结构:
- struct Res,定义纹理的分辨率,按像素的log2存储,长度为8位int,其ctor可以用16位int作为参数,分高低8位储存uv,最小单元(texel)分辨率为1*1(ulog2 = vlog2 = 0),支持tile划分。
- 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字节,所以在读取时应该以最小的为准,然后计算各个数据的起始位置,调用读取函数,包括:
- 读取面信息。读取过程分三步,首先从压缩的文件中读取FaceInfo,每次读取header中定义的faceinfosize或着16384字节(faceinfosize > BlockSize)为一个block,然后生成rfaceid(先按面在内存中的储存顺序分配id,然后以面的uv分辨率最小的那个作为依据降序排列面的顺序,该顺序就是rfaceid,面为常量则分辨率当作1),并建立rfaceid和faceid的映射关系,最后更新已使用的内存数。
- 读取面的常量像素值。读取过程分三步,第一和三步同上,第二步为alpha通道的预乘处理,先判断alpha通道的位置来确定需要预乘的通道,然后根据不同的像素存储类型归一化alpha值,最后将归一化的alpha值与需要预乘的通道的像素值相乘。
- 读取层次信息。读取过程分三步,第一和三步同上,第二步为层次定位,依次储存每一层次的开始位置。
- 读取编辑数据。读取过程分三步,首先确定编辑位置,然后根据编辑的类型读取,分为面数据和元数据两类,先读取对应的编辑header,然后保存编辑内容,编辑面数据还需要读取面的常数像素值,最后更新内存使用记录。
获取纹理数据:
大部分数据可以通过简单返回获得,下面主要看几个比较复杂的数据:
- 获取元数据。元数据分meta data和large meta data两类,其大小分别定义在header和extheader中。两者的获取类似,都是建立kv映射,key为string表示名字,value为entry存储元数据,entry内保存了数据位置作为key,直接从内存将所需数据拷贝到指定位置,区别在于lmd的entry没有保存解压后的数据,而是数据的位置,只有在载入并引用后才能访问,有一个flag标识lmd。
- 获取一个面的纹理数据。有四种获取方式,获取最高分辨率的纹理、获取指定分辨率的纹理、获取硬盘上保存的最高分辨率的纹理、获取硬盘上保存的指定分辨率的纹理。前两种是把数据拷贝到指定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。
- 获取一个面的纹理的一个texel数据。有两种获取方式,获取最高分辨率纹理的texel、获取指定分辨率纹理的texel。两种方式基本类似,首先获取实际通道数,然后获取facedata,然后就可以得到像素值,然后根据第一通道位置来设置像素保存的偏移量,最后保存,如果像素值不是float,则转成float保存。二者的区别在获取facedata,第二种需要根据reduction来确定mipmap的level获取相应facedata。
Ptex源码学习笔记-1的更多相关文章
- Ptex源码学习笔记-2
写入纹理数据: 主要分为五种写入方式:新建纹理.编辑已有纹理.编辑ExtHeader中的指定项.写入元数据和写入指定面的纹理数据.写入过程中数据存在一个临时文件中,在close时才会把临时文件的内容拷 ...
- Underscore.js 源码学习笔记(下)
上接 Underscore.js 源码学习笔记(上) === 756 行开始 函数部分. var executeBound = function(sourceFunc, boundFunc, cont ...
- Underscore.js 源码学习笔记(上)
版本 Underscore.js 1.9.1 一共 1693 行.注释我就删了,太长了… 整体是一个 (function() {...}()); 这样的东西,我们应该知道这是一个 IIFE(立即执行 ...
- AXI_LITE源码学习笔记
AXI_LITE源码学习笔记 1. axi_awready信号的产生 准备接收写地址信号 // Implement axi_awready generation // axi_awready is a ...
- Hadoop源码学习笔记(6)——从ls命令一路解剖
Hadoop源码学习笔记(6) ——从ls命令一路解剖 Hadoop几个模块的程序我们大致有了点了解,现在我们得细看一下这个程序是如何处理命令的. 我们就从原头开始,然后一步步追查. 我们先选中ls命 ...
- Hadoop源码学习笔记(5) ——回顾DataNode和NameNode的类结构
Hadoop源码学习笔记(5) ——回顾DataNode和NameNode的类结构 之前我们简要的看过了DataNode的main函数以及整个类的大至,现在结合前面我们研究的线程和RPC,则可以进一步 ...
- Hadoop源码学习笔记(4) ——Socket到RPC调用
Hadoop源码学习笔记(4) ——Socket到RPC调用 Hadoop是一个分布式程序,分布在多台机器上运行,事必会涉及到网络编程.那这里如何让网络编程变得简单.透明的呢? 网络编程中,首先我们要 ...
- Hadoop源码学习笔记(3) ——初览DataNode及学习线程
Hadoop源码学习笔记(3) ——初览DataNode及学习线程 进入了main函数,我们走出了第一步,接下来看看再怎么走: public class DataNode extends Config ...
- Hadoop源码学习笔记(2) ——进入main函数打印包信息
Hadoop源码学习笔记(2) ——进入main函数打印包信息 找到了main函数,也建立了快速启动的方法,然后我们就进去看一看. 进入NameNode和DataNode的主函数后,发现形式差不多: ...
随机推荐
- LAN-LAN FREE-SERVER FREE
注:本文转自http://taotao1240.blog.51cto.com/731446/839702 CU上有个板块叫“存储备份”,可见存储和备份是紧紧联系的.在看备份的时候,经常能看到LAN f ...
- MySQL中tinytext、text、mediumtext和longtext详解
一.数字类型 类型 范围 说明 Char(N) [binary] N=1~255 个字元binary :分辨大小写 固定长度 std_name cahr(32) not null VarChar( ...
- sqlserver 2008 建立订阅发布时 报错 解决方案 “错误 2812” 无法创建存储过程
11月10日早上 一大早,还在地铁14号线上 ,接到同事给的信息 说我们的XX系统宕机了,本想没什么问题,一般服务器 只要硬件没有问题 重启一下就可以了, 但是事与愿违,偏偏最后检测到服务器磁盘阵列 ...
- php源码之遍历目录下的所有的文件
<?php //遍历目录下的所有的文件 -- 递归调用 // http://www.manongjc.com/article/1495.html function get_all_file1($ ...
- 【转】HTML5 jQuery图片上传前预览
hTML5实现表单内的上传文件框,上传前预览图片,针刷新预览images,本例子主要是使用HTML5 的File API,建立一個可存取到该 file的url,一个空的img标签,ID为img0,把选 ...
- 扩展 HtmlwebpackPlugin 插入自定义的脚本
webpack提供了一个如何开发 webpack 插件的介绍,你可以直接访问这里查看,这里提供一个扩展 HtmlWebpackPlugin 的开发实例. 前面我们介绍过 HtmlWebpackPlug ...
- 好的sql
select count(2) from vw_pmcthtdj A WHERE a.HTBL_ID not in (select jg.jgjs_htid from PMCTJGJS jg wher ...
- According to TLD or attribute directive in tag file, attribute test does not accept any expressions
HTTP Status 500 - /WEB-INF/views/emp/list.jsp (line: 30, column: 4) According to TLD or attribute di ...
- 一键安装lamp环境 centos
linux centos yum安装LAMP环境 /*************链接**************/http://www.cnblogs.com/suger/p/3832093.html ...
- Swift 3 中的访问控制 open public internal fileprivate private
Swift 3必看:新的访问控制fileprivate和open http://www.jianshu.com/p/604305a61e57 浅谈 Swift 3 中的访问控制 https://mai ...