0,引入

前续:
Q79:怎么用三角形网格(Triangle Mesh)细分曲面
http://blog.csdn.net/libing_zeng/article/details/60600404
Q80:平坦着色(Flat Shading)和平滑着色(Smooth Shading)——“Q79:怎么用三角形网格(Triangle Mesh)细分曲面”(补充)
http://blog.csdn.net/libing_zeng/article/details/60760296
【修正】问题五十五:怎么用ray tracing画Utah teapot (bicubic bezier patches)
http://blog.csdn.net/libing_zeng/article/details/69258616

这一章节,我们以Utah Teapot(Bicubic Bezier Patches)为例来进行说明。

1,理论分析

我们知道Utah Teapot是由若干个Bicubic Bezier Patch拼接而成(我们这里用到的数据是32-patches、306-vertices版本)。
关于Bezier曲面的介绍,参考:“问题五十四:怎么用ray tracing画参数方程表示的曲面(2)—— bezier surface”
http://blog.csdn.net/libing_zeng/article/details/54565264

Bezier曲面的本质是:参数方程表示的曲面。这个“参数方程”就是两条Bezier曲线的的张量积。

在求得球面的参数方程之后,用三角形网格细分该曲面的方式可以参考:
“Q79:怎么用三角形网格(Triangle Mesh)细分曲面”
http://blog.csdn.net/libing_zeng/article/details/60600404

2,C++代码实现

2.1 读取teapot数据文件

本人是将文件读取函数移植到Vector3D.cpp中

// ----------------------------------------------------------  get_teapot_data
// read utah teapot with 32 patches and 306 vertices from external filebool get_teapot_data(int (&patches)[32][16], float (&vertices)[306][3]) {
    ifstream infile( ".\\teaset\\teapot");
    char str[100];
    char *token;
    int item_num;
    int patch_num = 0;
    int vertex_num = 0;
    int flag = 0;
    int tokens_i[16];
    float tokens_f[3];
    while (infile >> str) {        item_num = 0;
        token = strtok(str, ",");
        if ((flag == 0) || (flag == 1)) {            sscanf(token, "%d", &(tokens_i[item_num]));
            if (tokens_i[0] == 32) {                flag = 1;
            }
            else if (tokens_i[0] == 306) {                flag = 2;
            }
            else {                patches[patch_num][item_num] = tokens_i[item_num];
                item_num ++;
            }
            token = strtok(NULL, ",");
        }        while (token != NULL) {            if (flag == 1) {                sscanf(token, "%d", &(tokens_i[item_num]));
                patches[patch_num][item_num] = tokens_i[item_num];
            }
            if (flag == 2) {                sscanf(token, "%f", &(tokens_f[item_num]));
                vertices[vertex_num][item_num] = tokens_f[item_num];
            }
            item_num ++;
            token = strtok(NULL, ",");
        }
        if ((flag == 1) && (tokens_i[0] != 32)) {patch_num ++;}
        if (flag == 2) {            if ((tokens_i[0] == 306)) {tokens_i[0] = 0;}
            else {vertex_num ++;}
        }
    }
    infile.close();
    return true;
}// ----------------------------------------------------------  matrix_4_4_multiply_4_4void matrix_4_4_multiply_4_4(const float matrix1[4][4], const float matrix2[4][4], float (&result)[4][4]) {
    for (int k=0; k<4; k++) {        for (int i=0; i<4; i++) {            result[i][k] = 0.0;
            for (int j=0; j<4; j++) {                result[i][k] = result[i][k] + matrix1[i][j]*matrix2[j][k];
            }
        }
    }
}

2.2 矩阵运算

计算过程会用到“矩阵运算”(没有使用“矩阵类”,仍旧使用二维数组表示矩阵)。矩阵运算的相关函数也是在Vector3D.cpp中实现:

// ----------------------------------------------------------  matrix_4_4_multiply_4_4void matrix_4_4_multiply_4_4(const float matrix1[4][4], const float matrix2[4][4], float (&result)[4][4]) {
    for (int k=0; k<4; k++) {        for (int i=0; i<4; i++) {            result[i][k] = 0.0;
            for (int j=0; j<4; j++) {                result[i][k] = result[i][k] + matrix1[i][j]*matrix2[j][k];
            }
        }
    }
}// ----------------------------------------------------------  matrix_1_4_multiply_4_4void matrix_1_4_multiply_4_4(const float matrix1[1][4], const float matrix2[4][4], float (&result)[1][4]) {
    for (int k=0; k<4; k++) {        result[0][k] = 0.0;
        for (int j=0; j<4; j++) {            result[0][k] = result[0][k] + matrix1[0][j]*matrix2[j][k];
        }
    }
}// ----------------------------------------------------------  matrix_1_4_multiply_4_1void matrix_1_4_multiply_4_1(const float matrix1[1][4], const float matrix2[4][1], float &result) {
    result = 0.0;
    for (int j=0; j<4; j++) {        result = result + matrix1[0][j]*matrix2[j][0];
    }
}

2.3 细分Bezier曲面

像之前一样,细分函数在Grid.cpp中实现。

// ------------------------------------  tessellate_flat_bezier_patches  ---------------------------------------
// tesselate a cubic bezier patch into flat triangles that are stored directly in the gridvoid
Grid::tessellate_flat_bezier_patches(const int horizontal_steps, const int vertical_steps,float vertices[306][3], int patches[32][16], const int patches_num) {Vector3D patches_vertices[patches_num][16];float matrix_c_x[4][4], matrix_c_y[4][4], matrix_c_z[4][4];float   points_x[4][4],   points_y[4][4],   points_z[4][4];float points_x_t[4][4], points_y_t[4][4], points_z_t[4][4];float        uuu[1][4],        vvv[4][1];float       uuu1[1][4],       vvv1[4][1];float      xxx_t[1][4],      yyy_t[1][4],      zzz_t[1][4];float              xxx,              yyy,              zzz;float             xxx1,             yyy1,             zzz1;float             xxx2,             yyy2,             zzz2;float             xxx3,             yyy3,             zzz3;float matrix_t[4][4] = {{ 1,  0,  0, 0},{-3,  3,  0, 0},{ 3, -6,  3, 0},{-1,  3, -3, 1}};float matrix[4][4]   = {{1, -3,  3, -1},{0,  3, -6,  3},{0,  0,  3, -3},{0,  0,  0,  1}};int ip1, ip2, ipv;for (int i=0; i<patches_num; i++) {for (int j=0; j<16; j++) {ip1 = int(j/4);ip2 = int(j%4);ipv = patches[i][j] - 1;points_x[ip1][ip2] = vertices[ipv][0];points_y[ip1][ip2] = vertices[ipv][1];points_z[ip1][ip2] = vertices[ipv][2];}matrix_4_4_multiply_4_4(matrix_t, points_x, points_x_t);matrix_4_4_multiply_4_4(points_x_t, matrix, matrix_c_x);matrix_4_4_multiply_4_4(matrix_t, points_y, points_y_t);matrix_4_4_multiply_4_4(points_y_t, matrix, matrix_c_y);matrix_4_4_multiply_4_4(matrix_t, points_z, points_z_t);matrix_4_4_multiply_4_4(points_z_t, matrix, matrix_c_z);for (int k = 0; k <= vertical_steps - 1; k++) {for (int m = 0; m <= horizontal_steps - 1; m++) {uuu[0][0] = 1.0;uuu[0][1] = float(m) / float(horizontal_steps);uuu[0][2] = uuu[0][1] * uuu[0][1];uuu[0][3] = uuu[0][1] * uuu[0][2];vvv[0][0] = 1.0;vvv[1][0] = float(k) / float(vertical_steps);vvv[2][0] = vvv[0][1] * vvv[0][1];vvv[3][0] = vvv[0][1] * vvv[0][2];uuu1[0][0] = 1.0;uuu1[0][1] = float(m+1) / float(horizontal_steps);uuu1[0][2] = uuu1[0][1] * uuu1[0][1];uuu1[0][3] = uuu1[0][1] * uuu1[0][2];vvv1[0][0] = 1.0;vvv1[1][0] = float(k+1) / float(vertical_steps);vvv1[2][0] = vvv1[0][1] * vvv1[0][1];vvv1[3][0] = vvv1[0][1] * vvv1[0][2];matrix_1_4_multiply_4_4(uuu, matrix_c_x, xxx_t);matrix_1_4_multiply_4_1(xxx_t, vvv, xxx);matrix_1_4_multiply_4_4(uuu, matrix_c_y, yyy_t);matrix_1_4_multiply_4_1(yyy_t, vvv, yyy);matrix_1_4_multiply_4_4(uuu, matrix_c_z, zzz_t);matrix_1_4_multiply_4_1(zzz_t, vvv, zzz);matrix_1_4_multiply_4_4(uuu, matrix_c_x, xxx_t);matrix_1_4_multiply_4_1(xxx_t, vvv1, xxx1);matrix_1_4_multiply_4_4(uuu, matrix_c_y, yyy_t);matrix_1_4_multiply_4_1(yyy_t, vvv1, yyy1);matrix_1_4_multiply_4_4(uuu, matrix_c_z, zzz_t);matrix_1_4_multiply_4_1(zzz_t, vvv1, zzz1);matrix_1_4_multiply_4_4(uuu1, matrix_c_x, xxx_t);matrix_1_4_multiply_4_1(xxx_t, vvv, xxx2);matrix_1_4_multiply_4_4(uuu1, matrix_c_y, yyy_t);matrix_1_4_multiply_4_1(yyy_t, vvv, yyy2);matrix_1_4_multiply_4_4(uuu1, matrix_c_z, zzz_t);matrix_1_4_multiply_4_1(zzz_t, vvv, zzz2);matrix_1_4_multiply_4_4(uuu1, matrix_c_x, xxx_t);matrix_1_4_multiply_4_1(xxx_t, vvv1, xxx3);matrix_1_4_multiply_4_4(uuu1, matrix_c_y, yyy_t);matrix_1_4_multiply_4_1(yyy_t, vvv1, yyy3);matrix_1_4_multiply_4_4(uuu1, matrix_c_z, zzz_t);matrix_1_4_multiply_4_1(zzz_t, vvv1, zzz3);// define the first trianglePoint3D v0(xxx2, yyy2, zzz2);Point3D v1(xxx3, yyy3, zzz3);Point3D v2( xxx,  yyy,  zzz);Triangle* triangle_ptr1 = new Triangle(v0, v1, v2);objects.push_back(triangle_ptr1);// define the second trianglev0 = Point3D(xxx1, yyy1, zzz1);v1 = Point3D( xxx,  yyy,  zzz);v2 = Point3D(xxx3, yyy3, zzz3);Triangle* triangle_ptr2 = new Triangle(v0, v1, v2);objects.push_back(triangle_ptr2);}}}}

如上代码的截图分析如下:

3,测试图形

3.1 测试代码





3.2 输出图形

teapot_32_0,0,100_rx-90,ts(0,-2,0)_light,directional(10,-20,-20)_20,20

teapot_32_0,0,100_rx-90,ts(0,-2,0)_light,directional(10,-20,-20)_40,40_190s_ns1

teapot_32_0,0,100_rx-90,ts(0,-2,0)_light,directional(10,-20,-20)_40,40_207s_ns16

teapot_32_0,0,100_rx-90,ts(0,-2,0)_light,directional(10,-20,-20)_40,40_176s_ns16_marble,p0.1

teapot_32_0,0,100_rx-90,ts(0,-2,0)_light,directional(10,-20,-20)_40,40_183s_ns16_marble,p4

teapot_32_0,0,100_rx-90,ts(0,-2,0)_light,directional(10,-20,-20)_40,40_226s_ns16_sandstone,p0.1

teapot_32_0,0,100_rx-90,ts(0,-2,0)_light,directional(10,-20,-20)_40,40_234s_ns16_wood

4,其他说明

完整代码链接:http://download.csdn.net/detail/libing_zeng/9804597

Q97:怎么用三角形网格细分Bezier曲面——以Utah Teapot为例相关推荐

  1. Q98:三角形网格细分Bezier曲面时,注意三角形顶点的顺序(确保其对应的法向量向外)

    这一章节又是修正之前的错误."Q97:怎么用三角形网格细分Bezier曲面--以Utah Teapot为例" (http://blog.csdn.net/libing_zeng/a ...

  2. Q99:当Bezier曲面(Utah Teapot)同时遇上“噪声纹理”和“Phong反射模型”

    1,理论介绍 完整标题应该是:当"三角形网格细分后的"Bezier曲面(Utah Teapot)同时遇上"噪声纹理"和"Phong反射模型" ...

  3. Q100:怎么用三角形网格细分回旋体(rotational sweeping / revolution)

    0,引入 我们在"问题六十:怎么用ray tracing画回旋体(rotational sweeping / revolution)"中已经学习了这类曲面的画法: http://b ...

  4. Geometry 曲面细分和曲面简化

    Geometry 曲面细分和曲面简化 1 曲面细分 a) Loop细分 b) Catmull-Clark细分(Catmull-Clark Subdivision) 曲面简化 边坍缩 总结: 1 曲面细 ...

  5. OpenGL(可编程管线):Bezier曲面

    Bezier曲面 Bezier线 de Casteljau算法 Bezier曲面 bezier曲面编程思想 实例 代码 运行结果 Bezier线 贝塞尔曲线由一组参数方程定义,方程组中使用控制点指定特 ...

  6. MFC绘制双有理Bezier曲面

    MFC绘制双有理Bezier曲面 双有理Bezier曲面可以精确表示任意二次曲面,如球面.柱面及圆锥面等,下面给出1/8球面的绘制类. 参考<计算几何算法与实现>–孔令德 #pragma ...

  7. 计算机图形学【GAMES-101】5、几何(距离函数SDF、点云、贝塞尔曲线、曲面细分、曲面简化)

    快速跳转: 1.矩阵变换原理Transform(旋转.位移.缩放.正交投影.透视投影) 2.光栅化(反走样.傅里叶变换.卷积) 3.着色计算(深度缓存.着色模型.着色频率) 4.纹理映射(重心坐标插值 ...

  8. MFC绘制旋转Bezier曲面

    MFC绘制旋转Bezier曲面 给出一条Bezier曲线,通过旋转64个控制点,4个曲面片,绘制出一个完整曲面 已知四个控制点:(50,100)(150,70)(120,-30)(90,-80) 理论 ...

  9. 曲面细分(subdivision)曲面细分着色器GPU的LOD

    曲面细分是指将一个模型的面合理的分成更多小的面,从而提升模型精度,提高渲染效果 曲面简化是指将一个模型的面合理的合成更少的面,从而降低模型精度,为特定情形下提供使用(如LOD技术) .这一过程是可以在 ...

最新文章

  1. [BZOJ2527]Meteors
  2. 你在做大数据?你有目标么?
  3. python颜色填充随机_使用python中的随机数据填充mysql表
  4. PC如何接管手机的双因子身份验证 靠的是英特尔的CPU
  5. ESP8266串口模块的基本使用【转】
  6. 配合理lcd的c语言小游戏,C语言源程序LCD.doc
  7. Spring的核心机制依赖注入,Junit测试与Java基础Getter和Setter两种方法意义——2017.07.26...
  8. STM32F7xx —— QSPI
  9. SpringCloud Config手动刷新及自动刷新
  10. python儿童入门视频-Python入门视频课程
  11. html pt兼容,FCKEditor,一个HTML可视化编辑器,兼容很好
  12. c语言正弦函数图像,正弦函数图像
  13. 计算机科学技术学院迎新晚会主题,我校计算机科学与技术学院举行迎新晚会
  14. 报错:TypeError: Image data of dtype object cannot be converted to float
  15. SendMessgae
  16. 剑指offer刷题笔记-篇2
  17. 电子秤称重系统设计,HX711压力传感器,51单片机(Proteus仿真、C程序、原理图、论文等全套资料)
  18. 【B端·BI系统实战分析】BI系统概述
  19. nginx隐藏Vary头信息
  20. 站内搜寻引擎 php mysql_迅搜(xunsearch) - 开源免费中文全文搜索引擎|PHP全文检索|mysql全文检索|站内搜索...

热门文章

  1. 最适合孩子入门的十大编程语言
  2. 创业心得--国产化图形引擎
  3. 纵览2023世界人工智能大会:百模大战4个月,中国AI产业怎么样了?
  4. laravel Eloquent的模式事件
  5. PYTHON -- 基础3
  6. 三星Bixby和苹果Siri大比拼 这两个东西真的有用吗?
  7. LCD1602模块-带IIC转接板
  8. 关于MySQL可重复读的理解
  9. 【调研】基于Prompt的小样本文本分类调研:PET,LM-BFF,KPT,PTR
  10. python docx页面设置_python-docx指定页面设置成横向