奥斯汀项目第2部分(共6部分):页面卷曲

嗨,我叫埃里克·布鲁默。我是C++编译器优化器上的开发人员,但我花了一些时间来研究项目代码名称奥斯丁,以帮助展示C++在真实世界程序中的能力和性能。关于这个项目的概述,请查看 原创博客文章 . Austin的源代码,包括这里描述的特定于页面卷曲的位,可以在上下载 码丛 .

null

在这篇博文中,我将解释如何在“整页”查看模式下实现翻页。我们想让在奥斯汀翻阅书页的感觉就像翻阅一本真正的书。为此,我们在已有的一些已发表工作的基础上实现了 性能 现实的 卷页。

走之前 更进一步,看一个视频页卷曲在行动!

(您可以使用下载mp4格式的视频 此链接 )

真实页面卷曲

Hong等人的一篇名为“3D电子书翻页”的精彩论文声称,翻动实体书的一页可以被模拟为使一页围绕一个圆锥体变形。  详见[1]。

这里有一张(画得不好的)图表来帮助解释论文中的概念。扁平纸张围绕圆锥体变形以模拟卷曲。通过更改圆锥体的形状和位置,可以模拟或多或少的卷曲。

图片[1]-奥斯汀项目第2部分(共6部分):页面卷曲-yiteyi-C++库

同样,您也可以将一张平纸卷曲在圆柱体上。下面是另一个(画得不好的)图表来帮助解释这个概念。

图片[2]-奥斯汀项目第2部分(共6部分):页面卷曲-yiteyi-C++库

为了模拟卷曲,我们使用了围绕圆锥体卷曲和围绕圆柱体卷曲的组合:

  • 如果用户试图从页面的右上角卷曲,我们将模拟通过围绕页面变形来挤压纸张的右上角 圆锥体 .
  • 如果用户试图从页面的右中心卷曲,我们将模拟通过围绕页面变形来挤压纸张的中心 圆柱 .
  • 如果用户试图从页面的右下角卷曲,我们将模拟通过在页面周围变形来挤压纸张的右下角 圆锥体翻转过来 .

在两者之间的任何地方,我们使用圆锥和圆柱变形的组合。

几何学

下面是围绕圆柱体转换页面的详细信息。有类似的几何图形可以将页面转换为[1]中描述的圆柱体。考虑到P点 平的 坐标为{x 1 1 ,z轴 1 =0}的平面页,我们要将其转换为P 卷曲 坐标为{x 2 2 ,z轴 2 }半径为r的圆柱体上位于书的“书脊”上的点。考虑下面的图表。注意x和z轴(y轴在计算机屏幕内外)。还要记住,我代表平面纸和圆柱使用相同的颜色,如上图。

图片[3]-奥斯汀项目第2部分(共6部分):页面卷曲-yiteyi-C++库

关键是从原点到P的距离 平的 (十) 1 )与从原点到P的弧距离相同 卷曲 沿着圆柱体 . 那么,从简单的几何学,我们可以这样说β = 十 1 /r。现在,为了得到P 卷曲 ,我们取原点,沿z轴向下移动r,旋转β, 然后在z轴上向上移动r。因此,数学最终是:

图片[4]-奥斯汀项目第2部分(共6部分):页面卷曲-yiteyi-C++库

以上方程计算P 卷曲 用平页包住圆筒。 [1] 包含计算不同P的方程式 卷曲 把一页纸包在一个圆锥体上。一旦我们计算出P 卷曲 值,我们根据用户尝试卷曲页面的位置组合结果。最后,在我们计算了两个卷曲点之后,我们围绕书脊旋转整个页面。

具体的参数是手动调整的:圆锥体参数、圆柱体宽度和围绕书脊的旋转。

代码

Austin的源代码,包括这里描述的特定于页面卷曲的位,可以在上下载 码丛 . 页面卷曲转换在journal/views/pageu curl.cpp中完成,特别是在pageu curl::curlPage()中。该文件中的其余代码是在用户将手指从屏幕上移开时处理展开的页面(向前或向后)。我省略了一些重要的细节,但这段代码给出了大致的想法。

对于(b::int32 j=0;j { 对于(b::int32 i=0;i { {加载x,y,z=0}

浮子coneX=x; 浮球圆锥=y; 浮子coneZ=z; { //计算圆锥参数coneX,coneY,coneZ }

浮动油缸x=x; 浮筒y=y; 浮动圆柱z=z; { 浮动β=圆柱体x/圆柱体半径;

//围绕x=0,z=cylRadius的直线旋转(0,0,0)β。 //又名旋转(0,0,-cylRadius)beta,然后将cylRadius添加回z坐标 cylZ=-圆柱体半径; cylX=-cylZ*sin(β); cylZ=cylZ*cos(β); cylZ+=圆柱半径;

//然后绕y轴旋转一个角度 cylX=cylX*cos(角度)–cylZ*sin(角度); cylZ=cylX*sin(角度)+cylZ*cos(角度);

//将坐标转换到页面 cylX=(cylX*pageCoordTransform)–pageMaxX; cylY=(-cylY*pageCoordTransform)+页面最大值; cylZ=cylZ*pageCoordTransform; }

//圆锥和圆柱组合系统 x=圆锥分布*圆锥分布+(1-圆锥分布)*圆柱x; y=圆锥分布*圆锥+(1-圆锥分布)*圆柱; z=圆锥分布*coneZ+(1-圆锥分布)*cylZ;

顶点缓冲区[jOffset+i].position.x=x; 顶点缓冲区[jOffset+i].position.y=y; 顶点缓冲区[jOffset+i].position.z=z; } }

自动矢量化

Visual Studio 2012 C++编译器中的一个新特性是自动矢量化。C++编译器分析循环体并生成以SSE2指令集为目标的代码,以利用CPU向量单元。有关自动矢量器的介绍和大量其他信息,请参阅 矢量器博客系列 .

上面的内环由Visual Studio 2012 C++编译器进行矢量化。 编译器能够矢量化math.h中的所有超越函数,以及标准的算术运算(加法、乘法等)。生成的代码加载 x、y和z的四个值。然后它 计算 四 每次计算cylX,cylY,cylZ的值 一次卷曲,卷曲,卷曲,并将结果存储到四个顶点的顶点缓冲区中。

我知道代码是矢量化的,因为我指定了/Qvec-report:1 option 在我的项目设置下,在配置属性-> C/C++ +>命令行中,按以下图片:

图片[5]-奥斯汀项目第2部分(共6部分):页面卷曲-yiteyi-C++库

然后,在编译之后, 输出窗口显示哪些循环已矢量化,如下图所示:

图片[6]-奥斯汀项目第2部分(共6部分):页面卷曲-yiteyi-C++库

Eric的社论:我们决定在产品周期的后期加入/Qvec-report:1 and /Qvec公司-report:2 switches,和 我们没有时间把它们放在合适的菜单位置。

如果您没有看到一个循环被矢量化并且不知道为什么,您可以指定/Qvec-report:2 option. 我们提供了一些关于处理中没有矢量化的循环的指导 一 矢量器博客文章 .

由于CPU向量单元的强大,“i”循环的速度加快了 乘以1.75 . 在这个例子中,我们可以计算P 卷曲 (圆锥体和圆柱体的组合)一次四个顶点。这将为其他呈现任务(如页面着色)释放CPU时间。

性能

要卷曲一页,我们需要计算P 卷曲 每个顶点都包含一张纸。据我所知,这涉及到4个sin调用,3个cos调用,1个arcin调用,1个sqrt调用,以及12个左右的乘法、加法和减法-对于一张纸上的每个顶点-对于我们渲染的每个帧!

我们的目标是以60帧/秒的速度渲染,这意味着我们有大约15毫秒的时间来卷曲页面顶点并渲染它们,否则应用程序会感觉迟钝。随着这个循环得到自动矢量化,我们能够为其他渲染任务释放CPU时间,比如给页面着色。

工具书类

[1] L。香港,S.K.卡,  和J。陈先生,   “翻页3D电子图书”,正在进行中。3DUI,2006年,第159-165页。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享