0,引入

其实,这一章节的内容是之前落下的。
当时,觉得“磨边物体”只是磨边前的物体与部分圆环、部分球面组成的复合物体(Compound Objects)。感觉太简单了,所以没有仔细看。
我们在前面的某些章节中已经有用到过“磨边”的概念,比如:
“Q91:真实地模拟透明材质(Realistic Transparency)(4)——Fish Bowl”中的鱼缸的边沿;
(http://blog.csdn.net/libing_zeng/article/details/65442187)
“ Q101:真实地模拟一个玻璃酒杯(Wine Glass)(回旋曲面)”中酒杯的边沿;
(http://blog.csdn.net/libing_zeng/article/details/69791261)

1,简单的磨边的物体

另外,我们再看一些简单几何图形的磨边后的图形(如下三张图片来自《Ray Tracing from the Ground Up》官网):
磨边前:

磨边后:

看看其中磨边封闭圆柱面的各个部分分离的图形:

注意到:
“磨边”的意思就是:
面与面相交为曲线时,添加一个圆环面来过渡;
面与面相交为直线时,添加一个开放圆柱面来过渡;
线与线相交时,添加一个球面来过渡;

所以,
磨边的封闭圆柱面是由:1个开放圆柱面、2个底面、2个圆环组成;
磨边的长方体是由:磨边前长方体对应的8个矩形、长方体的边对应的12个圆环、长方体的顶点对应的8个球面组成。

2,磨边的楔形物体(Beveled Wedges)

2.1 理论分析

我们在前面看到的都是对简单物体的磨边。但是,楔形物体的磨边貌似没有如此简单。


(相关参数:内经r0=1.5,外径r1=3,磨边半径rb=0.25)

这样一个磨边的楔形是由哪些基本图形组成的呢?
第一部分:磨边前的面:前后2个矩形、左右2个部分圆柱面、上下2个annulus;
第二部分:面与面的过渡:圆柱面和上下两个annulus相交过渡的4个圆环、圆柱面和矩形相交过渡的4个圆柱面、矩形和annulus相交过渡的4个圆柱面;
第三部分:线与线的过渡:8个小球面
总共是2+2+2+4+4+4+8=26个基本图形。

但是,书上说是一共是30个基本图形,另外4个是什么呢?在哪呢?
书上说,另外4个是上下面上的patch annuli(annuli补丁)。
“annuli补丁”,也就是说,磨边后的楔形的上下表面若分别只用一个annulus的话,则是缺一块的。所以,才需要“补丁”。

若将代码中的补丁图形注释掉一个,则得到的图形是:

看到木有?上表面是不是缺一块哈?
为了,看得更清晰些,咱改一下楔形的参数:内经r0=0.5,外径r1=3,磨边半径rb=0.5。得到的图形是:

磨边楔形俯视图如下:

参数的具体计算,咱在此不做推导(初中几何的常见内容)。
咱特别指出的是patch annulus,因为这个特别容易被忽略。

2.2 C++代码实现

// ------------------------------------------------------------------------------ constructorBeveledWedge::BeveledWedge( const double _y0,       // minimum y valueconst double _y1,       // maximum y valueconst double _r0,       // inner radiusconst double _r1,       // outer radiusconst double _rb,       // bevel radiusconst double _phi0,     // minimum azimuth angle in degreesconst double _phi1)     // maximum azimuth angle in degrees:   y0(_y0),y1(_y1),r0(_r0),r1(_r1),rb(_rb),phi0(_phi0),phi1(_phi1)
{double sin_phi0 = sin(phi0 * PI_ON_180);  // in radiansdouble cos_phi0 = cos(phi0 * PI_ON_180);  // in radiansdouble sin_phi1 = sin(phi1 * PI_ON_180);  // in radiansdouble cos_phi1 = cos(phi1 * PI_ON_180);  // in radiansdouble sin_alpha = rb / (r0 + rb);double cos_alpha = sqrt(r0 * r0 + 2.0 * r0 * rb) / (r0 + rb);double sin_beta = rb / (r1 - rb);double cos_beta = sqrt(r1 * r1 - 2.0 * r1 * rb) / (r1 - rb);double xc1 = (r0 + rb) * (sin_phi0 * cos_alpha + cos_phi0 * sin_alpha);double zc1 = (r0 + rb) * (cos_phi0 * cos_alpha - sin_phi0 * sin_alpha);double xc2 = (r1 - rb) * (sin_phi0 * cos_beta + cos_phi0 * sin_beta);double zc2 = (r1 - rb) * (cos_phi0 * cos_beta - sin_phi0 * sin_beta);double xc3 = (r0 + rb) * (sin_phi1 * cos_alpha - cos_phi1 * sin_alpha);double zc3 = (r0 + rb) * (cos_phi1 * cos_alpha + sin_phi1 * sin_alpha);double xc4 = (r1 - rb) * (sin_phi1 * cos_beta - cos_phi1 * sin_beta);double zc4 = (r1 - rb) * (cos_phi1 * cos_beta + sin_phi1 * sin_beta);// corner spheres -------------------------------------------------------------------------------// bottom spheresSphere* bottom_c1 = new Sphere(Point3D(xc1, y0 + rb, zc1), rb);objects.push_back(bottom_c1);Sphere* bottom_c2 = new Sphere(Point3D(xc2, y0 + rb, zc2), rb);objects.push_back(bottom_c2);Sphere* bottom_c3 = new Sphere(Point3D(xc3, y0 + rb, zc3), rb);objects.push_back(bottom_c3);Sphere* bottom_c4 = new Sphere(Point3D(xc4, y0 + rb, zc4), rb);objects.push_back(bottom_c4);// top spheresSphere* top_c1 = new Sphere(Point3D(xc1, y1 - rb, zc1), rb);objects.push_back(top_c1);Sphere* top_c2 = new Sphere(Point3D(xc2, y1 - rb, zc2), rb);objects.push_back(top_c2);Sphere* top_c3 = new Sphere(Point3D(xc3, y1 - rb, zc3), rb);objects.push_back(top_c3);Sphere* top_c4 = new Sphere(Point3D(xc4, y1 - rb, zc4), rb);objects.push_back(top_c4);// vertical cylinders ------------------------------------------------------------------------------Instance* bottom_c1_cylinder = new Instance(new OpenCylinder(y0 + rb, y1 - rb, rb));bottom_c1_cylinder->translate(xc1, 0.0, zc1);bottom_c1_cylinder->transform_texture(false);objects.push_back(bottom_c1_cylinder);Instance* bottom_c2_cylinder = new Instance(new OpenCylinder(y0 + rb, y1 - rb, rb));bottom_c2_cylinder->translate(xc2, 0.0, zc2);bottom_c2_cylinder->transform_texture(false);objects.push_back(bottom_c2_cylinder);Instance* bottom_c3_cylinder = new Instance(new OpenCylinder(y0 + rb, y1 - rb, rb));bottom_c3_cylinder->translate(xc3, 0.0, zc3);bottom_c3_cylinder->transform_texture(false);objects.push_back(bottom_c3_cylinder);Instance* bottom_c4_cylinder = new Instance(new OpenCylinder(y0 + rb, y1 - rb, rb));bottom_c4_cylinder->translate(xc4, 0.0, zc4);bottom_c4_cylinder->transform_texture(false);objects.push_back(bottom_c4_cylinder);// inner curved surface ---------------------------------------------------------------------------------// the azimuth angle range has to be specified in degreesdouble alpha = acos(cos_alpha);  // radiansdouble phi_min = phi0 + alpha * 180.0 / PI;double phi_max = phi1 - alpha * 180.0 / PI;OpenCylinderPartConcave* inner_cylinder_ptr = new OpenCylinderPartConcave(y0 + rb, y1 - rb, r0, phi_min, phi_max);objects.push_back(inner_cylinder_ptr);// outer curved surface -----------------------------------------------------------------------------------// the azimuth angle range has to be specified in degreesdouble beta = acos(cos_beta);  // radiansphi_min = phi0 + beta * 180.0 / PI;phi_max = phi1 - beta * 180.0 / PI;OpenCylinderPartConvex* outer_cylinder_ptr = new OpenCylinderPartConvex(y0 + rb, y1 - rb, r1, phi_min, phi_max);objects.push_back(outer_cylinder_ptr);// phi0 vertical rectangledouble s1 = sqrt(r0 * r0 + 2.0 * r0 * rb);double s2 = sqrt(r1 * r1 - 2.0 * r1 * rb);Point3D p1(s1 * sin_phi0, y0 + rb, s1 * cos_phi0);Point3D p2(s2 * sin_phi0, y0 + rb, s2 * cos_phi0);Vector3D a = p2 - p1;Vector3D b(0, y1 - y0 - 2.0 * rb, 0);Rectangle* phi0_rectangle_ptr = new Rectangle(p1, a, b);objects.push_back(phi0_rectangle_ptr);// phi1 vertical rectanglePoint3D p3(s1 * sin_phi1, y0 + rb, s1 * cos_phi1);Point3D p4(s2 * sin_phi1, y0 + rb, s2 * cos_phi1);a = p3 - p4;Rectangle* phi1_rectangle_ptr = new Rectangle(p4, a, b);objects.push_back(phi1_rectangle_ptr);// the tori --------------------------------------------------------------------------------------------// inner bottomphi_min = phi0 - 90 + alpha * 180.0 / PI; // "-90" transform angle of against z-axis to x-axisphi_max = phi1 - 90 - alpha * 180.0 / PI;Instance* inner_bottom_torus = new Instance(new TorusPartConvex(r0 + rb, rb, phi_min, phi_max, 0, 360));inner_bottom_torus->translate(0.0, y0 + rb, 0.0);inner_bottom_torus->transform_texture(false);objects.push_back(inner_bottom_torus);// inner topInstance* inner_top_torus = new Instance(new TorusPartConvex(r0 + rb, rb, phi_min, phi_max, 0, 360));inner_top_torus->translate(0.0, y1 - rb, 0.0);inner_top_torus->transform_texture(false);objects.push_back(inner_top_torus);// outer bottomphi_min = phi0 - 90 + beta * 180.0 / PI;phi_max = phi1 - 90 - beta * 180.0 / PI;Instance* outer_bottom_torus = new Instance(new TorusPartConvex(r1 - rb, rb, phi_min, phi_max, 0, 360));outer_bottom_torus->translate(0.0, y0 + rb, 0.0);outer_bottom_torus->transform_texture(false);objects.push_back(outer_bottom_torus);// outer topInstance* outer_top_torus = new Instance(new TorusPartConvex(r1 - rb, rb, phi_min, phi_max, 0, 360));outer_top_torus->translate(0.0, y1 - rb, 0.0);outer_top_torus->transform_texture(false);objects.push_back(outer_top_torus);// horizontal cylinders ----------------------------------------------------------------------------------// phi0 bottom cylinderInstance* phi0_bottom_cylinder_ptr = new Instance(new OpenCylinder(0, s2 - s1, rb));phi0_bottom_cylinder_ptr->rotate_x(90);phi0_bottom_cylinder_ptr->rotate_y(phi0);phi0_bottom_cylinder_ptr->translate(xc1, y0 + rb, zc1);phi0_bottom_cylinder_ptr->transform_texture(false);objects.push_back(phi0_bottom_cylinder_ptr);// phi0 top cylinderInstance* phi0_top_cylinder_ptr = new Instance(new OpenCylinder(0, s2 - s1, rb));phi0_top_cylinder_ptr->rotate_x(90);phi0_top_cylinder_ptr->rotate_y(phi0);phi0_top_cylinder_ptr->translate(xc1, y1 - rb, zc1);phi0_top_cylinder_ptr->transform_texture(false);objects.push_back(phi0_top_cylinder_ptr);// phi1 bottom cylinderInstance* phi1_bottom_cylinder_ptr = new Instance(new OpenCylinder(0, s2 - s1, rb));phi1_bottom_cylinder_ptr->rotate_x(90);phi1_bottom_cylinder_ptr->rotate_y(phi1);phi1_bottom_cylinder_ptr->translate(xc3, y0 + rb, zc3);phi1_bottom_cylinder_ptr->transform_texture(false);objects.push_back(phi1_bottom_cylinder_ptr);// phi1 top cylinderInstance* phi1_top_cylinder_ptr = new Instance(new OpenCylinder(0, s2 - s1, rb));phi1_top_cylinder_ptr->rotate_x(90);phi1_top_cylinder_ptr->rotate_y(phi1);phi1_top_cylinder_ptr->translate(xc3, y1 - rb, zc3);phi1_top_cylinder_ptr->transform_texture(false);objects.push_back(phi1_top_cylinder_ptr);// top flat surface -----------------------------------------------------------------------------------// main partPoint3D center(0, y1, 0);Normal normal(0, 1, 0);double r_min = r0 + rb;double r_max = r1 - rb;phi_min = phi0 + alpha * 180.0 / PI;phi_max = phi1 - alpha * 180.0 / PI;AnnulusPart* top_main_part_ptr = new AnnulusPart(center, normal, r_min, r_max, phi_min, phi_max);objects.push_back(top_main_part_ptr);// small phi0 side patchr_min = 0.0;r_max = s2 - s1;phi_min = 0.0;phi_max = alpha * 180.0 / PI;Instance* top_phi0_patch_ptr = new Instance(new AnnulusPart(center, normal, r_min, r_max, phi_min, phi_max));top_phi0_patch_ptr->rotate_y(phi0);top_phi0_patch_ptr->translate(xc1, 0.0, zc1);top_phi0_patch_ptr->transform_texture(false);objects.push_back(top_phi0_patch_ptr);// small phi1 side patchphi_min = 360.0 - alpha * 180.0 / PI;phi_max = 360.0;Instance* top_phi1_patch_ptr = new Instance(new AnnulusPart(center, normal, r_min, r_max, phi_min, phi_max));top_phi1_patch_ptr->rotate_y(phi1);top_phi1_patch_ptr->translate(xc3, 0.0, zc3);top_phi1_patch_ptr->transform_texture(false);objects.push_back(top_phi1_patch_ptr);// bottom flat surface ---------------------------------------------------------------------------------// main partcenter = Point3D(0, y0, 0);normal = Normal(0, -1, 0);r_min = r0 + rb;r_max = r1 - rb;phi_min = phi0 + alpha * 180.0 / PI;phi_max = phi1 - alpha * 180.0 / PI;AnnulusPart* bottom_main_part_ptr = new AnnulusPart(center, normal, r_min, r_max, phi_min, phi_max);objects.push_back(bottom_main_part_ptr);// small phi0 side patchr_min = 0.0;r_max = s2 - s1;phi_min = 0.0;phi_max = alpha * 180.0 / PI;Instance* bottom_phi0_patch_ptr = new Instance(new AnnulusPart(center, normal, r_min, r_max, phi_min, phi_max));bottom_phi0_patch_ptr->rotate_y(phi0);bottom_phi0_patch_ptr->translate(xc1, 0.0, zc1);bottom_phi0_patch_ptr->transform_texture(false);objects.push_back(bottom_phi0_patch_ptr);// small phi1 side patchphi_min = 360.0 - alpha * 180.0 / PI;phi_max = 360.0;Instance* bottom_phi1_patch_ptr = new Instance(new AnnulusPart(center, normal, r_min, r_max, phi_min, phi_max));bottom_phi1_patch_ptr->rotate_y(phi1);bottom_phi1_patch_ptr->translate(xc3, 0.0, zc3);bottom_phi1_patch_ptr->transform_texture(false);objects.push_back(bottom_phi1_patch_ptr);// compute the bounding boxdouble x[4] = {xc1, xc2, xc3, xc4};double z[4] = {zc1, zc2, zc3, zc4};// first, assume that the wedge is completely inside a quadrant, which will be true for most wedges// work out the maximum and minimum valuesdouble x0 = kHugeValue;double z0 = kHugeValue;for (int j = 0; j <= 3; j++)  {if (x[j] < x0)x0 = x[j];}for (int j = 0; j <= 3; j++) {if (z[j] < z0)z0 = z[j];}double x1 = -kHugeValue;double z1 = -kHugeValue;for (int j = 0; j <= 3; j++) {if (x[j] > x1)x1 = x[j];}for (int j = 0; j <= 3; j++) {if (z[j] > z1)z1 = z[j];}// assign values to the bounding boxbbox.x0 = x0 - rb;bbox.y0 = y0;bbox.z0 = z0 - rb;bbox.x1 = x1 + rb;bbox.y1 = y1;bbox.z1 = z1 + rb;bool spans90 = phi0 < 90 and phi1 > 90;bool spans180 = phi0 < 180 and phi1 > 180;bool spans270 = phi0 < 270 and phi1 > 270;if (spans90 && spans180 && spans270) {bbox.x0 = -r1;bbox.z0 = -r1;bbox.x1 = r1;bbox.z1 = max(zc2, zc4);}else if (spans90 && spans180) {bbox.x0 = xc4 - rb;bbox.z0 = -r1;bbox.x1 = r1;bbox.z1 = zc2 + rb;}else if (spans180 && spans270) {bbox.x0 = -r1;bbox.z0 = -r1;bbox.x1 = xc2 + rb;bbox.z1 = zc4 + rb;}else if (spans90) {bbox.x0 = min(xc1, xc3);bbox.z0 = zc4 - rb;bbox.x1 = r1;bbox.z1 = zc2 + rb;}else if (spans180) {bbox.x0 = xc4 - rb;bbox.z0 = -r1;bbox.x1 = xc2 + rb;bbox.z1 = max(zc1, zc3);}else if (spans270) {bbox.x0 = -r1;bbox.z0 = zc2 - rb;bbox.x1 = max(xc1, xc3);bbox.z1 = zc4 + rb;}
}

3,其他说明

完整代码下载链接:
http://download.csdn.net/detail/libing_zeng/9815179

Q103:磨边的物体(Beveled Objects)相关推荐

  1. Max Script|物体选择和拷贝

    本章记录Max脚本的中的简单操作-物体选择和拷贝 •对物体的简单操作 sphere() box() torus() plane() *******************创建物体,更多类型请根据max ...

  2. 如何成为TD 系列【2】--给场景中的物体名字添加后缀

    # -*- coding:utf-8 -*- # 导入maya命令模块 from maya import cmds # 列一个字典,给物体种类相应的尾缀 SUFFIXES = {     " ...

  3. CVPR2021满分论文 | GeoSim: Camera Simulation

    作者丨陈云@知乎 来源丨https://zhuanlan.zhihu.com/p/377570852 编辑丨3D视觉工坊 <GeoSim: Realistic Video Simulation ...

  4. 机器之心 Synced 08月12日 20:59

     机器之心 Synced 08月12日 20:59 机器学习 人工智能 谷歌大脑 分类 :互联网 阅读:333 抢沙发 分享到: 0 分享到微信朋友圈 打开微信.点击 " 发现 &quo ...

  5. Lightweight Render Pipeline

    (翻译) Lightweight Render Pipeline (LWRP),轻量级渲染管线,是一个Unity预制的Scriptable Render Pipeline (SRP).LWRP可以为移 ...

  6. es6 迭代器_揭秘ES6迭代器和迭代器

    es6 迭代器 by Tiago Lopes Ferreira 由Tiago Lopes Ferreira 揭秘ES6迭代器和迭代器 (Demystifying ES6 Iterables & ...

  7. flutter 序列化_如何在Flutter中序列化对象

    flutter 序列化 If you intend to save user data to the shared preferences or local storage in your Flutt ...

  8. lumion自动保存_Lumion所有快捷键,值得收藏

    made by Lumion 8 2018.11.2 这里,除了BIM,就是建筑相关干货.工具.教程分享,小鱼当的建筑BIM日志 来源于网络,整理了Lumion 所有快捷键,特来此分享,值得收藏,用时 ...

  9. SQL Server中的聚集索引与堆

    摘要 (Summary) There are few topics so widely misunderstood and that generates such frequent bad advic ...

最新文章

  1. javascript里面RegExp的exec函数的总结
  2. 矩阵连乘算法代码JAVA_矩阵连乘问题的动态规划算法(java)
  3. #ifdef __cplusplus extern “C” { #endif的作用!
  4. 《java多线程编程实战指南 核心篇》读书笔记二
  5. 当maven引用的jar在maven库中下载不到源代码
  6. 饿了么超时20分钟_饿了么回应“多等5分钟”,网友气炸了
  7. Jeewx-Boot 1.0.3 版本发布,基于SpringBoot的免费微信管家平台
  8. PHP 解决session 死锁
  9. 计算机动画---计算机动画的光栅方法
  10. kettle教程,简单插入与更新
  11. 一种基于折射反向学习机制与自适应控制因子的改进樽海鞘群算法
  12. Pyecharts 1.7.0制作图表,运行生成的html文件用浏览器打开空白问题(以桑基图为例)
  13. 电容笔有必要买吗?双十一性价比高的电容笔推荐
  14. Android沙箱自动化安全产品
  15. ActionListenner
  16. 一个好的“班子”,让你的团队事半功倍
  17. Jeff Dean长文展望:2021年后,机器学习领域的五大潜力趋势!
  18. iOS 增量代码覆盖率检测实践
  19. 1. 响应式编程的前世今生及实践
  20. 光缆线路网的组网结构是怎样的

热门文章

  1. 解决 PhpStorm 对 用单例模式实例化PHP类时,代码自动提示功能失效 的问题
  2. Bosh vs Comet vs Long Polling vs Polling
  3. java 十六进制数的转换
  4. Python的切片操作
  5. torch.nn.Module.eval
  6. 操作系统实验一:并发程序设计
  7. 课设2--线性表的操作
  8. 从0开始搭建SQL Server AlwaysOn 第一篇(配置域控)
  9. CentOS使用NTFS-3G加载NTFS硬盘
  10. request,response,session