220

# SER431 Lecture 19

NURBS
(201810)

October 31, 2018

## Transcript

1. jgs
SER 431
Lecture 19: Non-Uniform Rational Basis Splines
Javier Gonzalez-Sanchez
[email protected]
PERALTA 230U
Office Hours: By appointment

2. Javier Gonzalez-Sanchez | SER431 | Fall 2018 | 1
jgs
NURBS
§ Non-Uniform Rational Basis Splines
§ They are generalizations of B-Splines - are defined by some control points
and a knot vector,
§ Rational – ratio of two polynomials (spline functions)
§ Non-Uniform – Use knot multiplicity to produce variations in curve
§ Control points are specified in homogeneous coordinates.
§ NURBS rendering is part of the OpenGL Utilities library of functions
(prefixed with “glu”).

3. Javier Gonzalez-Sanchez | SER431 | Fall 2018 | 2
jgs
Definition
§ They reduce the memory consumption when storing shapes (compared to
simpler methods). They can be evaluated reasonably quickly by
numerically stable and accurate algorithms.

4. jgs
Surfaces From Scratch

5. Javier Gonzalez-Sanchez | SER431 | Fall 2018 | 4
jgs
Screenshot
https://github.com/javiergs/SER431/blob/master/Lecture19/surface_bezier.cpp

6. Javier Gonzalez-Sanchez | SER431 | Fall 2018 | 5
jgs
Screenshot
4 Bezier Curves
with 4 Control
Points Each
https://github.com/javiergs/SER431/blob/master/Lecture19/surface_bezier.cpp

7. Javier Gonzalez-Sanchez | SER431 | Fall 2018 | 6
jgs
Code
// a structure to hold a control point of the surface
struct Point {
float x;
float y;
float z;
};
// 4x4 grid of points that will define the surface
Point points[4][4] = {
{ { 20, 0, 10 }, { 0, 0, 10 }, { -5, 0, 10 }, { -10, 0, 10 } },
{ { 20, 0, 5 }, { 0, 15, 5 }, { -5, 15, 5 }, { -10, 0, 5 } },
{ { 20, 0, -5 }, { 0, 10, -5 }, { -5, 10, -5 }, { -10, 0, -5 } },
{ { 20, 0, -10 }, { 0, 0, -10 }, { -5, 0, -10 }, { -10, 0, -10 } }
};

8. Javier Gonzalez-Sanchez | SER431 | Fall 2018 | 7
jgs
// display
void display() {
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
gluLookAt(30, 20, -30, 0, 0, 0, 0, 1, 0);
glColor3f(0, 1, 0);
glPointSize(3);
// curves
glBegin(GL_POINTS);
for (int i = 0; i != N; ++i) {
float u = (float)i / (N - 1);
for (int j = 0; j != N; ++j) {
float v = (float)j / (N - 1);
Point p = calculate(u, v);
glVertex3f(p.x, p.y, p.z);
}
}
glEnd();
// more...
}

9. Javier Gonzalez-Sanchez | SER431 | Fall 2018 | 8
jgs
Point calculate(float u, float v) {
Point temp[4];
// calculate each point on our final v curve
temp[0] = CalculateU(u, 0);
temp[1] = CalculateU(u, 1);
temp[2] = CalculateU(u, 2);
temp[3] = CalculateU(u, 3);
// integrate curves as a surface (in columns)
return CalculateV(v, temp);
}

10. Javier Gonzalez-Sanchez | SER431 | Fall 2018 | 9
jgs
// calculate each point on our final v curve
Point CalculateU(float t, int row) {
Point p;
float it = 1.0f - t;
// blending functions
float b0 = t * t*t;
float b1 = 3 * t*t*it;
float b2 = 3 * t*it*it;
float b3 = it * it*it;
// curve
p.x = b0 * points[row][0].x + b1 * points[row][1].x + b2 * points[row][2].x + b3 * points[row][3].x;
p.y = b0 * points[row][0].y + b1 * points[row][1].y + b2 * points[row][2].y + b3 * points[row][3].y;
p.z = b0 * points[row][0].z + b1 * points[row][1].z + b2 * points[row][2].z + b3 * points[row][3].z;
return p;
}

11. Javier Gonzalez-Sanchez | SER431 | Fall 2018 | 10
jgs
// integrate curves as a surface (in columns)
Point CalculateV(float t, Point* pnts) {
Point p;
float it = 1.0f - t;
// calculate blending functions
float b0 = t * t*t;
float b1 = 3 * t*t*it;
float b2 = 3 * t*it*it;
float b3 = it * it*it;
// blending functions
p.x = b0 * pnts[0].x + b1 * pnts[1].x + b2 * pnts[2].x + b3 * pnts[3].x;
p.y = b0 * pnts[0].y + b1 * pnts[1].y + b2 * pnts[2].y + b3 * pnts[3].y;
p.z = b0 * pnts[0].z + b1 * pnts[1].z + b2 * pnts[2].z + b3 * pnts[3].z;
return p;
}

12. Javier Gonzalez-Sanchez | SER431 | Fall 2018 | 11
jgs
Screenshot
4 Bezier Curves
with 4 Control
Points Each
https://github.com/javiergs/SER431/blob/master/Lecture19/surface_bezier.cpp

13. jgs
Surfaces using OpenGL Support
First, Let us review Curves

14. Javier Gonzalez-Sanchez | SER431 | Fall 2018 | 13
jgs
Screenshot
https://github.com/javiergs/SER431/blob/master/Lecture16/bspline_connected.cpp
https://github.com/javiergs/SER431/blob/master/Lecture19/nurbs_curve.cpp

15. Javier Gonzalez-Sanchez | SER431 | Fall 2018 | 14
jgs
display()
GLUnurbs* nurb = gluNewNurbsRenderer();
GLfloat ctlpoints[7][3] = { { 10, 10, 0 }, { 5, 10, 0 }, { 0, 0, 0 },
{ -5, -5, 0 }, { -10, 0, 0 }, { -5, 10, 0 },
{ 0, 5, 0 } };
GLfloat knots[11] = {0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 6.0, 6.0 };
gluBeginCurve(nurb);
gluNurbsCurve(nurb,
11, // how many knots
knots,
3, //offset between consecutive control points in ctlpoints
&ctlpoints[0][0],
4, // order is the degree + 1
GL_MAP1_VERTEX_3); // type
gluEndCurve(nurb);
// display method continues here…

16. Javier Gonzalez-Sanchez | SER431 | Fall 2018 | 15
jgs
void gluBeginCurve(GLUnurbsObj * nobj)
Start NURBS curve rendering.
void gluEndCurve(GLUnurbsObj * nobj)
Stop NURBS curve rendering.
void gluNurbsCurve(GLUnurbsObj * nobj, GLint nknots, GLfloat * knot,
GLint stride, GLfloat * ctlpoints, GLint order, GLenum type)
nobj: Pointer to NURBS object
nknots: Number of knot values
knot: Array of knot values
stride: Offset between consecutive control point data in ctlpoints
ctlpoints: Array of control point coordinates
order: Blending function degree plus one.
type: Any valid one-dimensional evaluator types. Such as GL_MAP1_VERTEX_3,
GL_MAP1_COLOR_4, etc.
gluBeginCurve, gluNurbsCurve, gluEndCurve

17. jgs
Surfaces using OpenGL Support

18. Javier Gonzalez-Sanchez | SER431 | Fall 2018 | 17
jgs
Screenshot
https://github.com/javiergs/SER431/blob/master/Lecture19/surface_bezier.cpp
https://github.com/javiergs/SER431/blob/master/Lecture19/nurbs_surface_grid.cpp

19. Javier Gonzalez-Sanchez | SER431 | Fall 2018 | 18
jgs
Code
// control points
GLfloat ctlpoints[4][4][3] = {
{ { 20, 0, 10 },{ 0, 0, 10 },{ -5, 0, 10 },{ -10, 0, 10 } },
{ { 20, 0, 5 },{ 0, 15, 5 },{ -5, 15, 5 },{ -10, 0, 5 } },
{ { 20, 0, -5 },{ 0, 10, -5 },{ -5, 10, -5 },{ -10, 0, -5 } },
{ { 20, 0, -10 },{ 0, 0, -10 },{ -5, 0, -10 },{ -10, 0, -10 } }
};
GLfloat knots[8] = { 0.0, 0.0, 0.0, 0.0, 3.0, 3.0, 3.0, 3.0 };
GLUnurbsObj *theNurb;
// init
void init(void) {
theNurb = gluNewNurbsRenderer();
gluNurbsProperty(theNurb, GLU_SAMPLING_TOLERANCE, 25.0);
gluNurbsProperty(theNurb, GLU_DISPLAY_MODE, GLU_OUTLINE_POLYGON);
}

20. Javier Gonzalez-Sanchez | SER431 | Fall 2018 | 19
jgs
// display
void display(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gluLookAt(2, 2, -6.5, 0, 0, 0, 0, 1, 0);
glPushMatrix();
glScalef(0.125, 0.125, 0.125);
// NURBS
glColor3f(0, 1, 0);
gluBeginSurface(theNurb);
gluNurbsSurface(theNurb,
8, knots, 8, knots, // knots u and v
4 * 3, 3, // offset u and v
&ctlpoints[0][0][0],
4, 4, // function degree u and v
GL_MAP2_VERTEX_3);
gluEndSurface(theNurb);
// more ...
}

21. Javier Gonzalez-Sanchez | SER431 | Fall 2018 | 20
jgs
void gluNurbsProperty( GLUnurbsObj *nobj, GLenum property, TYPE value)
property = GLU_DISPLAY_MODE
Specify how NURBS surface is rendered.
value Meaning
GLU_FILL The surface is rendered as filled polygons. (Default value)
GLU_OUTLINE_POLYGON Only render outlines of the polygons.
GLU_OUTLINE_PATCH Only render outlines of patches and trimming curves.
gluNurbsProperty
property = GLU_SAMPLING_METHOD
Specify how NURBS surface is tessellated.
Value Meaning
GLU_PATH_LENGTH Specify the maximum length, in pixels, of the edges of the
tessellated polygons. (Default value)
GLU_PARAMETRIC_ERROR Specify the maximum distance, in pixels, between the
tessellated polygons and the true NURBS surface.
GLU_DOMAIN_DISTANCE Specify, in parametric coordinates, how many sample points
per unit length in u and v directions.

22. Javier Gonzalez-Sanchez | SER431 | Fall 2018 | 21
jgs
property = GLU_SAMPLING_TOLERANCE
Specify the maximum length, in pixels, to be used when the sampling
method is set to GLU_PATH_LENGTH. Default value is 50.0.
property = GLU_PARAMETRIC_TOLERANCE
Specify the maximum length, in pixels, to be used when the sampling
method is set to GLU_PARAMETRIC_ERROR. Default value is 0.5.
property = GLU_U_STEP
Specify the number of sample points per unit length in u direction when
sampling method is set to GLU_DOMAIN_DISTANCE. Default value is 100.
property = GLU_V_STEP
Specify the number of sample points per unit length in v direction when
sampling method is set to GLU_DOMAIN_DISTANCE. Default value is 100.

23. Javier Gonzalez-Sanchez | SER431 | Fall 2018 | 22
jgs
void gluBeginSurface(GLUnurbsObj * nobj)
Start NURBS surface rendering.
void gluEndSurface(GLUnurbsObj * nobj)
Stop NURBS surface rendering.
gluBeginCurve, gluNurbsCurve, gluEndCurve
nobj: Pointer to NURBS object
uknot_count: Number of knot values in u direction
uknot: Array of knot values in u direction
vknot_count: Number of knot values in v direction
vknot: Array of knot values in v direction
ustride: Offset between consecutive control point data in ctlpoints in u
direction
vstride: Offset between consecutive control point data in ctlpoints in v
direction
ctlpoints: 2D Array of control point coordinates
uorder: Blending function degree plus one for u direction.
vorder: Blending function degree plus one for v direction.
type: Any valid two-dimensional evaluator types.
void gluNurbsSurface(GLUnurbsObj * nobj, GLint uknot_count, GLfloat * uknot,
GLint vknot_count, GLfloat * vknot,
GLint ustride, GLint vstride, GLfloat * ctlpoints,
GLint uorder, GLint vorder, GLenum type)

24. jgs
Surfaces using OpenGL Support
Solid Shape with Materials and Light

25. Javier Gonzalez-Sanchez | SER431 | Fall 2018 | 24
jgs
Screenshot
https://github.com/javiergs/SER431/blob/master/Lecture19/nurbs_surface_grid.cpp
https://github.com/javiergs/SER431/blob/master/Lecture19/nurbs_surface_solid.cpp

26. Javier Gonzalez-Sanchez | SER431 | Fall 2018 | 25
jgs
Code
// same control points and knots that before
GLUnurbsObj *theNurb;
// init
void init(void) {
// Materials and Light
GLfloat mat_diffuse[] = { 1.0f, 0.5f, 0.31f, 1. };
GLfloat mat_specular[] = { 0.5f, 0.5f, 0.5f, 1. };
GLfloat mat_ambient[] = { 1.0f, 0.5f, 0.31f, 1. };
GLfloat mat_shininess[] = { 100.0 };
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST);
// We need normals
glEnable(GL_AUTO_NORMAL);
glEnable(GL_NORMALIZE);
theNurb = gluNewNurbsRenderer();
gluNurbsProperty(theNurb, GLU_SAMPLING_TOLERANCE, 25.0);
gluNurbsProperty(theNurb, GLU_DISPLAY_MODE, GLU_OUTLINE_POLYGON);
}

27. Javier Gonzalez-Sanchez | SER431 | Fall 2018 | 26
jgs
Homework
§ Review the source codes posted on GitHub

28. jgs