[图形学] Chp14 GLU曲面裁剪函数程序示例及样条表示遗留问题
样条表示这章已经看完,最后的GLU曲面裁剪函数,打算按书中的示例实现一下,其中遇到了几个问题。
先介绍一下GLU曲面裁剪函数的使用方法。
1 裁剪函数是成对出现的: gluBeginTrim和gluEndTrim。它们必须出现并且可以多对存在于gluBeginSurface和gluEndSurface之间。
2 在裁剪函数中间,可以插入B样条分段线型裁剪曲线gluPwlCurve或者B样条一般裁剪曲线gluNurbsCurve或者是它们的混合。
3 必须要注意的是,每一组裁剪函数中间的裁剪曲线,必须是封闭的,不自交并且不与其他曲线相交的。
gluBeginSurface(surfName); gluBeginTrim(surfName); gluPwlCurve(...);
gluNurbsCurve(...);
.... gluEndTrim(surfName); gluEndSurface(surfName);
以下是示例程序:
1 先用GLU画出一个坐标范围是(-1.5, -1.5)到(1.5, 1.5)的B样条曲面(其实是个平面)
2 用一条逆时针裁剪曲线表示裁剪保留区域
3 用一条顺时针的组合封闭分段线型曲线和B样条曲线,标出要裁掉的区域
#include <GLUT/GLUT.h>
#include <iostream> GLsizei winWidht = , winHeight = ; void init (void)
{
glClearColor(1.0, 1.0, 1.0, 0.0); glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-, , -, );
} void xyCoords (void)
{
glBegin(GL_LINES);
glColor3f(1.0, 0.0, 0.0); // red x axis
glVertex2i(-, );
glVertex2i(, );
glColor3f(0.0, 1.0, 0.0); // green y aixs
glVertex2i(, -);
glVertex2i(, );
glEnd();
} void errorCallback (void)
{
std::cout << "errorCallback" << std::endl;
} void displayFcn1 (void)
{
glClear(GL_COLOR_BUFFER_BIT); glColor3f(0.0, 0.0, 1.0); GLfloat ctrlPts [][][] = {
{{-, -, 0.0}, {-, -, 0.0}, {, -, 0.0}, {, -, 0.0}},
{{-, -, 0.0}, {-, -, 0.0}, {, -, 0.0}, {, -, 0.0}},
{{-, , 0.0}, {-, , 0.0}, {, , 0.0}, {, , 0.0}},
{{-, , 0.0}, {-, , 0.0}, {, , 0.0}, {, , 0.0}}
}; GLUnurbsObj *bezSurface;
GLfloat outerTrimPts [][] = {{0.0, 0.0}, {1.0, 0.0}, {1.0, 1.0}, {0.0, 1.0}, {0.0, 0.0}};
GLfloat innerTrimPts1 [][] = {{0.5, 0.25}, {0.01, 0.02}, {0.2, 0.75}};
GLfloat innerTrimPts2 [][] = {{0.2, 0.75}, {0.5, 0.99}, {0.75, 0.5}, {0.5, 0.25}};
GLfloat surfKnots [] = {0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0};
GLfloat trimCurveKnots [] = {0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0};
bezSurface = gluNewNurbsRenderer();
gluNurbsCallback(bezSurface, GLU_NURBS_ERROR, errorCallback); gluBeginSurface(bezSurface);
// gluNurbsProperty(bezSurface, GLU_DISPLAY_MODE, GLU_OUTLINE_POLYGON); // 线框图划分三角形
// gluNurbsProperty(bezSurface, GLU_NURBS_MODE, GLU_NURBS_TESSELLATOR); // ???? 细分 不好用 // ???? 注意 sStride和tStride的顺序,如果颠倒了,对于后面的裁剪坐标,也是颠倒的
gluNurbsSurface(bezSurface, , surfKnots, , surfKnots, , , &ctrlPts[][][], , , GL_MAP2_VERTEX_3); // ???? 必须先提供一个单位正方形的逆时针区域,是确保所有的图案都能正常显示
// http://csweb.cs.wfu.edu/~torgerse/Kokua/Irix_6.5.21_doc_cd/usr/share/Insight/library/SGI_bookshelves/SGI_Developer/books/OpenGL_PG/sgi_html/ch13.html
// counterclockwise around the entire unit square of parametric space. This ensures that everything is drawn, provided it isn't removed by a clockwise trimming curve inside of it.
gluBeginTrim(bezSurface);
gluPwlCurve(bezSurface, , &outerTrimPts[][], , GLU_MAP1_TRIM_2);
gluEndTrim(bezSurface); // 注意 1 裁剪曲线的坐标设置,必须按照顺时针,最后必须封闭
// ???? 注意 2 根据逆时针的坐标范围,整个裁剪区域被看做(0,0)到(1,1)的一个区域,裁剪曲线的坐标必须在0-1之间,并且不能等于0和1,否则会将所有区域都裁减掉
gluBeginTrim(bezSurface);
gluNurbsCurve(bezSurface, , trimCurveKnots, , &innerTrimPts2[][], , GLU_MAP1_TRIM_2);
gluPwlCurve(bezSurface, , &innerTrimPts1[][], , GLU_MAP1_TRIM_2);
gluEndTrim(bezSurface); gluEndSurface(bezSurface); xyCoords(); glFlush();
} void winReshapeFcn (GLint newWidth, GLint newHeight)
{
glViewport(, , newWidth, newHeight);
} int main(int argc, char * argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(winWidht, winHeight);
glutInitWindowPosition(, );
glutCreateWindow("OpenGL Bézier Curve Surface"); init();
glutDisplayFunc(displayFcn1);
glutReshapeFunc(winReshapeFcn);
glutMainLoop(); return ;
}
图0
其中,遇到的几个问题是:
1 逆时针裁剪曲线,我尝试过非矩形的情况,也尝试了范围不是(0,0)到(1,1)的范围,但最终的效果是:(0,0)到(1,1)的单位逆时针曲线就可以保留整个曲面,即使整个逆时针裁剪曲线再大,也只是全部显示曲面。当整个逆时针裁剪曲线小于(0,0)到(1,1)的区间时,才能裁剪保留曲面的一部分。
“counterclockwise around the entire unit square of parametric space. This ensures that everything is drawn, provided it isn't removed by a clockwise trimming curve inside of it.”
例如:曲面是(-1.5,-1.5)到(1.5,1.5)的3*3曲面,如果将第一个逆时针裁剪曲线规划为1*1的单位矩形,那么3*3的曲面将全部保留;假如将第一个裁剪曲线的坐标设置为: (0.2,0.0) (0.8,0.0) (1.0, 1.0) (0.0,1.0) (0.2, 0.0)即为一个倒梯形,那么保留下来的曲面将是区域(-0.9, -1.5) (0.9, -1.5) (1.5, 1.5) (-1.5, 1.5)这样的倒梯形。
图1
2 这时再添加顺时针裁剪曲线时,可用的坐标范围即是前面逆时针规定的范围,但不能超过或者等于边界坐标。一旦顺时针裁剪坐标点与逆时针的裁剪曲线边界重合,则会返回error。并且整个曲面都无法正确显示。
图2
3 如果添加顺时针裁剪曲线,之前必须要逆时针的裁剪区域,否则也会报错。
4 gluNurbsSurface函数,其中注意sStride和tStride的顺序。如果sStride=3,tStride=12,即为u方向连续控制点的坐标以行来读取ctrlPts内容,v方向连续控制点的坐标以列方向为读取方向。即u方向是对应裁剪区域的x轴,而v方向对应裁剪区域的y轴(不很确定是不是这个理解)。那么之后的裁剪坐标的第一个值与sStride方向的坐标对应,而第二个值与tStride方向的坐标对应。加入替换了tStride和sStride的值,那么裁剪掉的内容与原内容是相对轴y=x是对称的。
extern void gluNurbsSurface (GLUnurbs* nurb, GLint sKnotCount, GLfloat* sKnots, GLint tKnotCount, GLfloat* tKnots, GLint sStride, GLint tStride, GLfloat* control, GLint sOrder, GLint tOrder, GLenum type) OPENGL_DEPRECATED(10_0, 10_9);
图3 sStride = 12, tStride = 3的才见情况
感觉很多内容理解的不是很透彻,样条曲线这章花了很多时间看,但还是一知半解。在这里列出本章还未解决的几个问题:
1 相邻曲线段的一阶几何连续性,表示一阶导数在两条相邻曲线段的交点处成比例,但不一定相等。这个比例是谁与谁的比例?
2 样条曲线可用于模拟动画路径,相机路径等,是用按代码实现的曲线路径做运动效率高还是美术在Unity中做好的animation效率更高?
3 周期性三次B样条在四个连续控制点上的边界条件P(0) = 1/6(p0 + 4p1 + p2), P(1) = 1/6(p1 + 4p2 +p3), P'(0) = 1/2(p2-p1), P'(1) = 1/2(p3-p1)是如何得到的?
4 样条表示之间的转换: P(u) = U•Mspline1•Mgeom1 = U•Mspline2•Mgeom2 = U•Mspline2•(M-1spline2•Mspline1)•Mgeom1,Ms1,s2 = M-1spline2•Mspline1。书上说这个Ms1,s2是从第一个样条表达式转变到第二个表达式的变换矩阵,即Mspline1 = Mspline2•Ms1,s2,这难道不是第二个样条表达式转变到第一个表达式的变换矩阵吗?
5 递归样条细分方法:取中间点切开原三次Bézier曲线(控制点是p0, p1, p2, p3),左右两段分别构造Bézier样条,获取新控制点的坐标,结果是:p1,0 = p0, p1,1 = 1/2(p0 + p1), p1,2 = 1/4(p0+2p1+p2), p1,3 = 1/8(p0+3p1+3p2+p3)。 在假设:3(p1,1-p1,0) = 1/2(P'(0)) = 1/2•3(p1-p0)的情况下可以推导出上述坐标,但这个假设为什么成立?是Bézier样条曲线的性质决定的吗?
[图形学] Chp14 GLU曲面裁剪函数程序示例及样条表示遗留问题的更多相关文章
- [图形学] Chp10 OpenGL三维观察程序示例
10.10节书中给出了一个程序示例,有一个填充正方形,从侧面的角度观察并画到屏幕上. 图0 这里进一步画出一个立方体,将相机放入立方体中心,旋转相机,达到在立方体中旋转看到不同画面的效果. 步骤: 1 ...
- PHP实现的自定义图像居中裁剪函数示例
图像居中裁减的大致思路: 1.首先将图像进行缩放,使得缩放后的图像能够恰好覆盖裁减区域.(imagecopyresampled ― 重采样拷贝部分图像并调整大小) 2.将缩放后的图像放置在裁减区域中间 ...
- oracle常用函数及示例
学习oracle也有一段时间了,发现oracle中的函数好多,对于做后台的程序猿来说,大把大把的时间还要学习很多其他的新东西,再把这些函数也都记住是不太现实的,所以总结了一下oracle中的一些常用函 ...
- Arduino 入门程序示例之一个 LED(2015-06-11)
前言 答应了群主写一些示例程序,一直拖延拖延拖延唉.主要还是害怕在各大高手面前班门弄斧……(这也算是给拖延症找一个美好的理由吧),这几天终于下决心要写出来了,各位高手拍砖敬请轻拍啊. 示例程序 首先是 ...
- WinDBG调试.NET程序示例
WinDBG调试.NET程序示例 好不容易把环境打好了,一定要试试牛刀.我创建了一个极其简单的程序(如下).让我们期待会有好的结果吧,阿门! using System; using System.Co ...
- Shell脚本中使用function(函数)示例
这篇文章主要介绍了Shell脚本中使用function(函数)示例,本文着重讲解的是如何在shell脚本中使用自定义函数,并给出了两个例子,需要的朋友可以参考下 函数可以在shell script ...
- map reduce程序示例
map reduce程序示例 package test2; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop. ...
- Android : 跟我学Binder --- (3) C程序示例
目录: Android : 跟我学Binder --- (1) 什么是Binder IPC?为何要使用Binder机制? Android : 跟我学Binder --- (2) AIDL分析及手动实现 ...
- 微信小程序通过api接口将json数据展现到小程序示例
这篇文章主要介绍了微信小程序通过api接口将json数据展现到小程序示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看看吧实现知乎客户端的一个重要知识前提就是,要知道怎么通过 ...
随机推荐
- 对类对象使用new时地址分配的情况
我们知道,string类内部的构造函数是采用new来分配地址的.当创建对象时,会调用string的构造函数,从而实质上也使用了new.那么问题来了,如果我用new再创建一个string类型的指针呢?下 ...
- 【试验局】ReentrantLock中非公平锁与公平锁的性能测试
硬件环境: CPU:AMD Phenom(tm) II X4 955 Processor Memory:8G SSD(128G):/ HDD(1T):/home/ 软件环境: OS:Ubuntu14. ...
- 原生js实现图片网格式渐显、渐隐效果
写正文前先吐槽一下:端午放假完第一天去某千人以上公司面试前端工程师,第一轮是我应聘职位的部门小领导,谈的不错,面试主要围绕要用到的技术来:第二轮来了我要说的正主,我了个去,问的问题一个和前端无关,问我 ...
- WebSocket+MSE——HTML5 直播技术解析
作者 | 刘博(又拍云多媒体开发工程师) 当前为了满足比较火热的移动 Web 端直播需求,一系列的 HTML5 直播技术迅速的发展起来. 常见的可用于 HTML5 的直播技术有 HLS.WebSock ...
- 史上最完整Hadoop2.x完全分布式安装部署-小白也能学会
一.环境要求: 1. 虚拟机安装并设置网络: 2. 修改主机地址映射: 3. 必备软件:Jdk.Development Tools Development ...
- 分享两个网址,一个是使用mssql自带的跟踪工具和分析工具
http://www.cnblogs.com/Fooo/archive/2013/02/19/2916789.html 使用mssql自带的跟踪工具和分析工具 http://blog.csdn.net ...
- 16.3Sum Closet
思路: 暴力,复杂度为 \(O(n^3)\),超时 class Solution { public: int threeSumClosest(vector<int>& nums, ...
- 网络数据传输安全及SSH与HTTPS工作原理
本节内容 网络数据传输安全概述 数据加密算法分类 SSH工作原理 HTTPS工作原理 参考资料 个人一直在努力推动git在公司内部的普及和使用,前些日子在公司内部做了一次分享课,给大家介绍了下项目发布 ...
- oracle中的function的简单语法定义
1. create or replace 函数名 (参数名 in 类型) return 返回值类型 as 定义变量 begin 函数体 end;
- HTTP协议 --- 图解三次握手过程
TCP(Transmission Control Protocol) 传输控制协议 TCP是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接: 位码即tcp标志位,有6种标 ...