Implementing Surfaces in Open GL
Implementing Surfaces in Open GL
by
Hui Zhao
University of Waterloo
Master of Mathematics
in
Statistics
I would like to thank Professor Wayne Oldford for all the help given in this
essay.
2
Contents
1 Why OpenGL 6
2.1 An Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.2.1 Colour . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.2.3 Polygons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3
2.3.2 Translation . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.3.3 Rotation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.3.4 Scaling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.5.1 Lighting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.1.2 Implementation . . . . . . . . . . . . . . . . . . . . . . . . . 37
4
3.2 AGL Programming Overview . . . . . . . . . . . . . . . . . . . . . 38
4 Surface Implementation 43
4.1 Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
4.2 Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
4.2.1 Wire-Frame . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
4.2.3 Rotation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
4.2.4 Scaling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
5 Summary 52
Bibliography 54
5
Chapter 1
Why OpenGL
Introduced in 1992, OpenGL has become the industry’s most widely used pro-
“An interactive and dynamic visual display model is the key to statistical analysis,
the key to fostering the illusion that the user is working directly with their familiar
concepts, and the key to an integrated support environment. And this integrated
environment must be flexible so as to allow the analyst to pursue new lines of at-
tack whenever appropriate.” Quail has its own self-contained graphics system, but
6
OpenGL is a natural choice for the evolution of Quail.
The OpenGL design is intuitive and logical. The result is that powerful
underlying hardware, freeing the applications from having to design for spe-
• Multi-platform Availability
many variations of UNIX (e.g. SUN Solaris, IBM AIX, HP UX, Linux) with
X windows, and Microsoft windows systems. It also works with every major
7
OpenGL implementations have been available on all platforms for years. Ad-
ditions to the specification are well controlled, and proposed updates are
prove rendering speeds. Graphics card vendors, such as 3Dlabs, ATI Tech-
These graphics chips implement most of the OpenGL functions, and only a few
OpenGL routines are left for CPU processing. 3Dlabs’ GLINT 300SX graph-
ics processor was the industry’s first full 3D-capable graphics chip. Where
once this kind of graphics chip was expensive and only available on high-
end workstations and supercomputers, today there are more and more low-
cost OpenGL accelerator chips having a least some OpenGL functions imple-
industry has been the driving force behind this wide availability of graphics
hardware.
8
1.2 The objective of this project
from it. Visualization can provide understanding of statistical data, and can reveal
intricate structure that might not be obvious from a set of numbers. Examining
a surface, either from a real world data set or from explicit functions, is useful to
statistical analysis. For example, “A statistical analyst may need to visualize sur-
the first step to have Quail make use of OpenGL. The current surface plot makes
example rotation, are all done in Quail and use the CPU only.
OpenGL will solve these problems. Furthermore, OpenGL can achieve more
powerful visual effects and functionality, such as applying lighting, surface material
which are available in the current Quail graphics package. This paper uses OpenGL
9
MAC OS X as the starting point, there are three basic tasks ahead of us.
OpenGL is callable from Ada, C++, Fortran, Python, Perl and Java through
various OpenGL bindings which are found in OpenGL official web-site (OpenGL
Web). Meanwhile, calling OpenGL from Common Lisp is broadly being prac-
tised (Zhao, 2006). The OpenGL binding for Allegro in UNIX platform by R.
Mann (Mann, 1998 ) was one of these pioneer attempts. The OpenGL engine
The OpenGL libraries do not provide interactive input and output routines.
interfaces (or APIs). They are NSOpenGL classes for Cocoa applications,
the AGL API for Carbon applications, and the CGL API accessible for both
Cocoa and Carbon applications. These Apple specific APIS do not create
OpenGL content. They are what Cocoa and Carbon applications use to
communicate with the Mac OS X windowing system. This paper will use AGL
10
API in a MCL environment to communicate with the Mac OS X windowing
system.
This paper assumes readers have little OpenGL experience. The goal is to tackle
This essay first introduces relevant OpenGL techniques, and then gives a de-
11
Chapter 2
2.1 An Introduction
OpenGL provides a basic or core library of functions for specifying graphics prim-
other operations. To be hardware independent, the core library does not provide
interactive input and output routines; however these routines are available in aux-
iliary libraries.
Generally speaking, there are three kinds of items available from the OpenGL
basic library which are distinguished by their prefix: OpenGL functions, symbolic
constants and built-in data types. The prefixes are part of OpenGL naming con-
12
ventions.
functions extend the GL functions, and these routines are distinguished by having
the prefix “glu”. Furthermore, OpenGL Utility Toolkit (GLUT) contains a set of
functions with prefix “glut” to interact with windowing systems. Table 2.1 gives a
cannot create the display window directly. However, there are several window-
system libraries that support OpenGL for a variety of machines. In most Unix
system, the OpenGL Extension to the X window system(GLX) fulfills this role.
management operation.
A computer scene contains various components which can be called graphics out-
put primitives. These geometric primitives include points, straight line segments,
circles, conic sections, and polygons. All geometric primitives are positioned in a
reference frame called the world coordinate system. Furthermore, each geometric
13
Table 2.1: A summary OpenGL Libraries
windowing system
14
primitive has associated with it various attributes such as size and color. In gen-
eral, there are two methods used for dealing with attributes. First an OpenGL
function can be called with attribute values as arguments. Secondly, and more
typically, OpenGL attributes are treated as state variables. All OpenGL primitives
are displayed with the current state values until these attribute setting are changed.
2.2.1 Colour
Colour is a basic attribute for all primitives, and this can be represented by a red-
green-blue triple (R, G, B). OpenGL provides two modes: RGB and RGBA . The
difference is that RGBA has a fourth parameter, α, for color blending of which
glColor(colorComponent) (2.1)
and
glClearColor(colorComponent) (2.2)
world coordinate system. The attributes associated with points include colour and
15
size. For a raster system, the point size is an integer multiple of the pixel size, so
that a large point is displayed as a square block of pixels. The following OpenGL
glBegin(GL_POINT)
glVertex(x, y, z)
glEnd()
enclose a list of glVertex functions between a glBegin/glEnd pair, and use symbolic
straight line segments. A straight line segment can be displayed with three basic
2.2.3 Polygons
Although in principle any filled area shape is possible, we will only be concerned
about convex polygons as provided by OpenGL. Just as a curved line can be ap-
proximated with a set of line segments, a curved surface can be described by a set
16
implement surfaces. A polygon is a plane segment determined by a set of vertices,
and the order in which they are to be connected by line segments. In OpenGL, a
We also distinguish the back face from the front face of a polygon by imagining
an object enclosed by a set of polygonal surfaces. The side of a polygon facing into
an object is called the back face, the outward side is the front face. Color and other
attributes can be set for the back face and the front face separately.
Ax + By + Cz + D = 0 (2.3)
A vector space is formed through multiplying the vector (A, B, C) by constants. The
normal vector of the polygon contained by the plane represented by the equation 2.3
belongs to this vector space. This normal vector is perpendicular to the polygon,
and points in a direction from the back face of the polygon to its front face. Figure
we view the polygon from “outside” or view its front face. The following example
glBegin(GL_POLYGON)
17
Figure 2.1: The normal vector N of a polygon
glVertex(P1)
glVertex(P2)
glVertex(P3)
glVertex(P4)
glVertex(P5)
glEnd()
an object), rotation, and scaling are fundamental operations. We will briefly discuss
18
these first in this section, and then discuss projections, that is a three dimensional
t* = At + c (2.4)
or in more detail
⎛ ⎞ ⎛ ⎞ ⎛ ⎞ ⎛ ⎞
∗
⎜ x ⎟ ⎜ axx axy axz ⎟ ⎜ x ⎟ ⎜ cx ⎟
⎜ ⎟ ⎜ ⎟ ⎜ ⎟ ⎜ ⎟
⎜ ⎟ ⎜ ⎟ ⎜ ⎟ ⎜ ⎟
⎜ y∗ ⎟ = ⎜ a ⎟.⎜ y ⎟+ ⎜ c ⎟
⎜ ⎟ ⎜ yx ayy ayz ⎟ ⎜ ⎟ ⎜ y ⎟
⎜ ⎟ ⎜ ⎟ ⎜ ⎟ ⎜ ⎟
⎝ ⎠ ⎝ ⎠ ⎝ ⎠ ⎝ ⎠
z∗ azx azy axz z cz
here ⎛ ⎞ ⎛ ⎞
∗
⎜ x ⎟ ⎜ x ⎟
⎜ ⎟ ⎜ ⎟
⎜ ⎟ ⎜ ⎟
t=⎜ ⎟
⎜ y ⎟ and ⎜
t* = ⎜ y ∗ ⎟
⎟
⎜ ⎟ ⎜ ⎟
⎝ ⎠ ⎝ ⎠
z z∗
19
2.4 can be represented as
p* = Ap (2.5)
which is expanded as
⎛ ⎞ ⎛ ⎞ ⎛ ⎞
⎜ t* ⎟ ⎜ A c ⎟ ⎜ t ⎟
⎜ ⎟=⎜ ⎟.⎜ ⎟
⎝ ⎠ ⎝ ⎠ ⎝ ⎠
1 0T 1 1
2.3.2 Translation
Or
p∗ = T p (2.6)
20
where T is the translation matrix.
This new generated translation matrix will be multiplied by the current matrix,
and the current matrix will be updated. The new position is determined by the
current matrix. In OpenGL, with the following function, we can assign the identity
glLoadIdentity() (2.8)
2.3.3 Rotation
The easiest three dimensional rotation is to rotate an object around the Cartesian
coordinate axes. The transformation matrices are given by the following equations:
around z axis ⎛ ⎞ ⎛ ⎞ ⎛ ⎞
∗
⎜ x ⎟ ⎜ cos θ − sin θ 0 0 ⎟ ⎜ x ⎟
⎜ ⎟ ⎜ ⎟ ⎜ ⎟
⎜ ⎟ ⎜ ⎟ ⎜ ⎟
⎜ y ∗ ⎟ ⎜ sin θ cos θ 0 0 ⎟ ⎜ y ⎟
⎜ ⎟ ⎜ ⎟ ⎜ ⎟
⎜ ⎟=⎜ ⎟.⎜ ⎟
⎜ ⎟ ⎜ ⎟ ⎜ ⎟
⎜ z∗ ⎟ ⎜ 0 1 0 ⎟ ⎜ z ⎟
⎜ ⎟ ⎜ 0 ⎟ ⎜ ⎟
⎜ ⎟ ⎜ ⎟ ⎜ ⎟
⎝ ⎠ ⎝ ⎠ ⎝ ⎠
1 0 0 0 1 1
21
around x axis ⎛ ⎞ ⎛ ⎞ ⎛ ⎞
∗
⎜ x ⎟ ⎜ 1 0 0 0 ⎟ ⎜ x ⎟
⎜ ⎟ ⎜ ⎟ ⎜ ⎟
⎜ ⎟ ⎜ ⎟ ⎜ ⎟
⎜ y ∗ ⎟ ⎜ 0 cos θ − sin θ 0 ⎟ ⎜ y ⎟
⎜ ⎟ ⎜ ⎟ ⎜ ⎟
⎜ ⎟=⎜ ⎟.⎜ ⎟
⎜ ⎟ ⎜ ⎟ ⎜ ⎟
⎜ z ∗ ⎟ ⎜ 0 sin θ cos θ 0 ⎟ ⎜ z ⎟
⎜ ⎟ ⎜ ⎟ ⎜ ⎟
⎜ ⎟ ⎜ ⎟ ⎜ ⎟
⎝ ⎠ ⎝ ⎠ ⎝ ⎠
1 0 0 0 1 1
around y axis ⎛ ⎞ ⎛ ⎞ ⎛ ⎞
∗
⎜ x ⎟ ⎜ cos θ 0 sin θ 0 ⎟ ⎜ x ⎟
⎜ ⎟ ⎜ ⎟ ⎜ ⎟
⎜ ⎟ ⎜ ⎟ ⎜ ⎟
⎜ y∗ ⎟ ⎜ 0 ⎟ ⎜ y ⎟
⎜ ⎟ ⎜ 0 1 0 ⎟ ⎜ ⎟
⎜ ⎟=⎜ ⎟.⎜ ⎟
⎜ ⎟ ⎜ ⎟ ⎜ ⎟
⎜ z ∗ ⎟ ⎜ − sin θ 0 cos θ 0 ⎟ ⎜ z ⎟
⎜ ⎟ ⎜ ⎟ ⎜ ⎟
⎜ ⎟ ⎜ ⎟ ⎜ ⎟
⎝ ⎠ ⎝ ⎠ ⎝ ⎠
1 0 0 0 1 1
or is represented as
p∗ = R(θ).p (2.9)
The rotation around any arbitrary rotation axis in space can be done in five steps
1. Translate the object so that the rotation axis passes through the coordinate
origin
2. Rotate the object so that the axis of rotation coincides with one of the co-
around the Cartesian coordinate axes. First, rotate the object so that the
axis of rotation falls into the x-y plane, the x-z plane, or the z-y plane. Next,
22
rotate the object around the Cartesian coordinate axis which is perpendicular
4. Apply inverse rotation of step 2 to bring the rotation axis back to its original
orientation
5. Apply the inverse translation of step 1 to bring the rotation axis back to its
(rx, ry, rz) defines the orientation of the rotation axis. This OpenGL command
2.3.4 Scaling
23
The transformation matrix is given by
⎛ ⎞ ⎛ ⎞ ⎛ ⎞
∗
⎜ x ⎟ ⎜ sx 0 0 0 ⎟ ⎜ x ⎟
⎜ ⎟ ⎜ ⎟ ⎜ ⎟
⎜ ⎟ ⎜ ⎟ ⎜ ⎟
⎜ y∗ ⎟ ⎜ 0 s 0 0 ⎟ ⎜ y ⎟
⎜ ⎟ ⎜ y ⎟ ⎜ ⎟
⎜ ⎟=⎜ ⎟.⎜ ⎟
⎜ ⎟ ⎜ ⎟ ⎜ ⎟
⎜ z∗ ⎟ ⎜ 0 0 s 0 ⎟ ⎜ z ⎟
⎜ ⎟ ⎜ y ⎟ ⎜ ⎟
⎜ ⎟ ⎜ ⎟ ⎜ ⎟
⎝ ⎠ ⎝ ⎠ ⎝ ⎠
1 0 0 0 1 1
or is represented as
p∗ = Sp (2.11)
Scaling an object will change the position of the object relative to the coordinate
origin. We can construct a scaling transformation with respect to any fixed position
glScale(sx , sy , sy ) (2.12)
24
2.3.5 Projection transformations
plane along the direction of the projection plane’s normal vector. In oblique parallel
projections, shown in Figure 2.3, the projection path is not perpendicular to the
projection plane, and coordinate positions are transferred to the projection plane
along parallel lines. However in perspective projection, shown in Figure 2.4, the
projection is along paths which converge to a point called the projection reference
point.
25
Figure 2.3: Oblique parallel projections of an object
26
2.4 Three-dimensional viewing
Procedures for generating a three dimensional scene are analogous to that of taking
a photo. First of all, choose a position to place the camera, and orient the camera in
the direction to be photographed, and then snap the shutter. Figure 2.5 shows the
general processing steps for creating and transforming a three dimensional scene to
is defined by given the origin of the viewing coordinate system and the orientation
of the projection plane, which we can imagine as a camera film plane. Usually
in the world coordinate are transformed to the viewing coordinates to project the
27
objects to the projection plane. Following up the projection operation, objects are
reference frame. Vector u, (ux , uy , uz ), defines the orientation of the xview axis.
Vector v, (vx , vy , vz ), and vector n, (nx , ny , nz ), define the yview axis and the zview
axis respectively. The vectors u, v, and n are pairwise orthonormal. Typically, the
projection plane in the viewing coordinates is parallel to the x-y plane. Figure 2.6
The transformation from the world to the viewing coordinates can be accom-
M =R×T (2.13)
28
Figure 2.6: A uvn viewing coordinate reference frame
29
where R is ⎛ ⎞
⎜ ux uy uz 0 ⎟
⎜ ⎟
⎜ ⎟
⎜ v v v 0 ⎟
⎜ x y z ⎟
R=⎜
⎜
⎟
⎟
⎜ n n n 0 ⎟
⎜ x y z ⎟
⎜ ⎟
⎝ ⎠
0 0 0 1
and T is ⎛ ⎞
⎜ 1 0 0 −x0 ⎟
⎜ ⎟
⎜ ⎟
⎜ 0 1 0 −y ⎟
⎜ 0 ⎟
T =⎜
⎜
⎟
⎟
⎜ 0 0 0 −z ⎟
⎜ 0 ⎟
⎜ ⎟
⎝ ⎠
0 0 0 1
where P0 = (x0 , y0 , z0 ) is the origin of the viewing coordinate system, Pref = (xref ,
yref , zref ) is the center of the scene we want to aim the camera, the vector V =
30
where the argument (xwmin , ywmin ) and (xwmax , ywmax ) define the clipping window
given by
A surface in real life is visible only in the presence of a light source. This light
source can have a variety of shapes and characteristics. The source is typically
separate from the surface and shining on it, but it might also be the case that the
surface is the source itself. The term, surface rendering, means a procedure for
the surface. Here, mainly we consider two elements: surface properties, and lighting
2.5.1 Lighting
A light source is an object to illuminate the scene. We can specify its position,
the color, the emission direction, and its shape. The simplest light source is point
31
light source with a single color. Radial intensity attenuation is a factor we have to
take into account, otherwise undesirable display effects can result. Radial intensity
a light source travels outward. a0 , a1 and a2 are three parameters we could use to
the scene a general brightness. This background lighting is called ambient with a
diffuse reflection and specular reflection. Imagine a surface that is rough, and so
tends to scatter the light in all directions. This scattered light is called diffuse
reflection. However, for some shiny material the reflected light is concentrated into
parameter which determines the fraction of the incident light that is to be scattered.
assigned to a surface to adjust the lighting effects. It also could be expected, the
where a very shiny surface is modelled with a large value, and smaller values are
32
used for duller surfaces. All the parameters stated above will be used for setting
The simplest method for rendering a polygonal surface is to assign the same color
to all surface points inside that polygon. This approach is called flat surface ren-
the intensities of colors across the polygon area, which can eliminate the intensity
OpenGL routine glLight is used to set up a point light source and designate its
position, type, color, and other properties. Note that, we could have maximum
Reflection coefficients and other optical properties associated with a surface are
33
surface rendering which is indicated by
34
Chapter 3
from MCL and how to set up a windowing system in which OpenGL drawing is
displayed onscreen.
OpenGL accelerator hardware is also built into every iMac, iBook, PowerBook,
PPC. Generally speaking, there are two types of binaries in Mac OS X: Code
Fragment Manager (CFM), and Mach-O. CFM works under MacOS 8, 9, and X,
35
while Mach-O only works under OS X.
MCL is a CFM application. This means calling a CFM library from MCL is eas-
ier than calling Mach-O libraries. Note that, MCL does not support calling Mach-O
libraries. Even so, it is still possible to use Mach-O libraries. Fortunately, OpenGL
CFM libraries are still available in MAC OS X. These libraries are: OpenGLEngine,
OpenGLUtility.
the Mac OS X. For example, the procedure to draw and fill a circle in a window
requires calling an entry point, which calls a Mac OS X procedure that knows
how to draw and fill a circle. Be aware, the term “trap” and “entry point” are
folder within the “Library” folder within the directory where MCL is installed.
36
When the value of *autoload-traps* is true, information is automatically read from
The “# symbol” reader macro tries to load the trap definition of symbol from
the appropriate interface file and interns symbol in the traps package. For example,
traps package. The “require-trap” macro is an alternative way to auto load a trap
whether called at read time or at macro expand time. After calling “# symbol” or
“require-trap”, MCL searches the entry point in known system libraries. Although
MCL gives definitions of over 2000 Macintosh entry points, it is still possible to
extend the set of libraries to meet the problems. The function “add-to-shared-
string which names the shared library in question, informs MCL of any additional
libraries to search for entry points. The macro “deftrap” provides a way to define
3.1.2 Implementation
After examining the file of traps.idx located in the “index” folder within the “in-
terfaces” folder within the installed MCL 5.0 directory, no trap names related to
37
form MCL the additional OpenGL libraries is necessary.
function, having the same name as the OpenGL function, in which we issue a
Define a trap in line having the name same as the OpenGL function, and provide
Apple Graphics Library (AGL) is the Apple interface to OpenGL for Carbon ap-
plications. It can be used by both Mach-O and CFM binaries. AGL provides a
38
system.
The following steps describes how a Carbon application provides data for OpenGL
processing
1. Set up a list of buffer and renderer attributes that support the OpenGL
2. Request, from the operating system, a pixel format object that encapsulates
pixel storage information and the renderer and buffer attributes required by
the application. The returned pixel format object contains all possible com-
binations of renderers and displays available on the system that the program
3. Create a rendering context to hold state information that controls such things
39
object can be a Carbon window, offscreen memory, a full-screen graphics
device, etc.
5. Make the rendering context the current context. OpenGL automatically tar-
gets the current context. Although the application might have several ren-
dering contexts set up, only the current one is the active one for drawing
purposes.
The following code fragments (AgentSheet, 2005) give a flavour of how to implement
(let
40
;; create a context
(rlet
(GDhandleArray :pointer)
(let
(#_disposePtr attributes)
(aglDestroyPixelFormat AGLPixelFormat)
41
;; Get a port associated with the Carbon window by calling the
;; the window.
(glclear gl_color_buffer_bit)
(glfinish)
42
Chapter 4
Surface Implementation
This chapter describes the design and development of a surface by using OpenGL
in MCL.
4.1 Design
Figure 4.1 gives a high level class diagram that describes the types of objects, and
43
GL
surfaceFunction
+sfunction
+dx
+dy
opengl-window +dz
+function-at()
glDataSet
+point-gradient-at()
+surface-function
+surface-heights
+x-range
+y-range
Range
+z-range
+color-range +Min : double
glSurfaceWindow +x-sequence +Max : double
44
+glds +y-sequence
+rotate-axis : char +x-sequence-type : char
+gain : double +y-sequence-type : char
+counterclockwise? : Boolean +x-data-size : double
+add-dataSet() +y-data-size : double
+data-points glDataPoint
+init()
+display() +wireframe? : Boolean +x : double
Class glDataPoint
Class glDataP oint defines a three dimensional position in the world coordinate
system located at (x, y, z), having attributes of color and a normal vector at that
point.
Class surfaceFunction
1. Compute the height by giving a (x, y) pair through evaluating the function
Class glDataSet
Class glDataSet playes a role as a three dimensional data point container. Class
surf aceF unction and class glDataP oint hold an aggregation or composition rela-
tionship with class glDataSet. That is an instance of class glDataSet has an object
45
of surf aceF unction and many objects of glDataSet as its parts. Class glDataSet’s
and a y sequence
3. Assemble data points into a data structure supporting object storage and
Class glSurfaceWindow
46
4.2 Implementation
4.2.1 Wire-Frame
three dimensional data points are stored in a hash table. The pair (i, j) is the key
for each key-value pair in the hash table. The number i is the ordinal number of the
sequence x. The number j is the ordinal number of the sequence y. Four adjacent
triples are fetched from the hash table to form a polygon. That is for each point
(i, j), the points (i + 1, j), (i + 1, j + 1), and (i, j + 1) are adjacent to point (i, j),
and together these four points form a rectangle having point (i, j) as its bottom-left
corner. These four vertexes are given to the OpenGL polygon drawing routine in
facets. Figure 4.2 shows a wire-frame surface for a bivariate normal distribution.
Get the point (i, j) and its three adjacent points from the has table.
47
Figure 4.2: A wire-frame surface for a bivariate normal distribution
I used the Gouraud method to implement the surface rendering. The normal vector
for each three dimensional point needs to be calculated. I gave two solutions for
0, then, a normal vector at a point (x, y, z) on the surface is given by its gra-
dient
∂f ∂f ∂f
∇f = , , (4.1)
∂x ∂y ∂z
48
Quail provides a facility to compute the partial derivatives.
3. If there are no analytic methods available, a normal vector for each point can
mesh that share that point. This is illustrated in the figure 4.3
Set up a local lights, and designate its position, diffuse and sepcular properties.
49
Designate polygon display mode as GL FILL.
Get the point (i, j) and its three adjacent points from the has table.
Figure 4.4 is an example by using the surface rendering technique for the above
50
4.2.3 Rotation
OpenGL provides the routine glRotate(theta, rx, ry, rz) to complete rotation oper-
ations. Where theta is a rotation angle in degree, and vector r = (rx, ry, rz) defines
the orientation of the rotation axis. For example, if we want a rotation around z
axis with 5 degree, we simply set vector r = (0, 0, 1), and issue the OpenGL com-
mand glRotate(5, 0, 0, 1). The change of the speed of the rotation can be achieved
4.2.4 Scaling
tions. Where sx , sy and sz are the scaling factors. For example, if we want to
enlarge the object as 2 times as its original size, we simply issue the OpenGL
command glScale(2, 2, 2) .
51
Chapter 5
Summary
This paper solved the problem of implementing a surface, either from a real world
data set or from explicit or implicit functions, by using the OpenGL technique in a
MCL environment. In summary, the three tasks listed in chapter 1 are accomplished
52
3. Identify the most effective OpenGL techniques to implement a surface.
surface. And the surface rendering technique is applied to render the surface.
The rotation and scaling operations on the surface are also developed.
This is a start. To make Quail fully benefit from OpenGL needs more work.
The next step would be to merge the current OpenGL surfaces into a Quail surface
plot.
53
Glossary
- AGL
in Mac OS X.
- Allegro
- API
- Carbon
- CFM
- CGL
The Core OpenGL API. It is the basis for the NSOpenGL classes and AGL
- CL
Common Lisp.
54
- Cocoa
- GL
- GLU
- GLUT
- Mach-O
- MCL
language.
- NSOpenGL
55
Bibliography
[Oldford 1998] R.W. Oldford, 1998, “The Quail Project: A Current Overview”
[Hurley Oldford 1999] C.B. Hurley and R.W. Oldford, 1999, “Statistical Graph-
56
[Apple Guide 2004] Apple Computer, Inc., 2004, “OpenGL Programming Guide
for Mac OS X”
[Apple Reference 2004] Apple Computer, Inc., 2004, “AGL Framework Reference”
[Guy Steele 1990] Guy L. Steele JR., 1990, “COMMON LISP : the lan-
[Hearn 1994] Donald Hearn, 1994, “Computer Graphics” Second Edition, Prentice-
Hall, 1994
[Poirier 1992] Paul Poirier, 1992, “Visualizing Surfaces”. A master research paper,
University of Waterloo
[Zhao 2006] Hui Zhao, 2006, “A Quick Preview on OpenGL and Common Lisp”
xlib-and-gl.tar.gz
57
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Appendix ;;; Define class surface function
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defclass surfaceFunction()
;;; glSurfaceWindow.lisp
(
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
( sfunction :accessor sfunction-of :initform nil :initarg :sfunction
;;; Draw surfaces of arbitrary functions by using OpenGL
:documentation "a function")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
( dx :accessor dx-of :initform nil :initarg :dx :documentation "partial derivative
w.r.t x for point (x, y, z)")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
( dy :accessor dy-of :initform nil :initarg :dy :documentation "partial derivative
;;; define structures
w.r.t y for point (x, y, z)")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
( dz :accessor dz-of :initform nil :initarg :dz :documentation "partial derivative
w.r.t z for point (x, y, z)")
(defstruct Range
)
(min 0 )
(:documentation "a general 2 dimensional function")
(max 0 )
)
(:documentation "structure Range will be used for coordinates, color, size, or
any pairs")
(defmethod set-sfunction( (self surfaceFunction) function)
)
(setf (sfunction-of self) function)
)
(defstruct normal
(x 0 )
;;; compute heights given (x, y) pair
(y 0 )
;;; the function is either a list or a common lisp function object
(z 0 )
(defmethod function-at ((self surfaceFunction) x y)
(:documentation "structure normal will be used for plan and vertex")
)
(cond
(defstruct normals
;; the function is a common lisp function object
(normal1 )
((functionp (sfunction-of self)) (funcall (sfunction-of self) x y)
(normal2 )
)
(normal3 )
(normal4 )
;; the function is a list
(:documentation "normals will be used for computing vertex normal when using
((listp (sfunction-of self)) (funcall (eval `(lambda(x y) ,(sfunction-of self))) x y)
mesh patch approximation")
)
)
)
)
)
;;; substitute the prefix q:: by cl:: )
(defun q-to-cl-functions (fns &rest body)
;;; compute the partial derivatives with respect to x, y, z respectively, if analytic
"Restores the original meaning of the functions listed, ~ results exist
but only at the top level, not in a called function. ~ ;;; use q:deriv to compute partial derivatives
Then evaluates body, returning the value of the last form." ;;; first convert cl:* cl:+ cl:expt cl:/ cl:- to q:* q:+ q:expt q:/ q:- for q:deriv
;;; then convert the q:* q:+ q:expt q:/ q:- in the returned results back to cl:* cl:+
(let* ( cl:expt cl:/ cl:-
(a-list ;;; then evaluate the partial derivatives at point (x, y)
(mapcar #'(lambda (f) (cons f (find-symbol (string f) (string-upcase "cl")))) ;;; dz will always be -1
fns)
) (defmethod point-gradient-at ((self surfaceFunction) x y)
(new-body (loop for form in body collect (sublis a-list form))) (if (listp (sfunction-of self))
) (let*
(push 'progn new-body) (
new-body (qList (second (cl-to-q-functions '(cl:* cl:+ cl:expt cl:/ cl:-) (sfunction-of
) self))))
) ;; dx
(dxQList (q:deriv qList :wrt 'x))
;;; substitute the prefix cl:: by q:: (dxCLList (second (q-to-cl-functions '(q:* q:+ q:expt q:/ q:-) dxQList)))
(defun cl-to-q-functions (fns &rest body) ;; dy
(dyQList (q:deriv qList :wrt 'y))
"Restores the original meaning of the functions listed, ~ (dyCLList (second (q-to-cl-functions '(q:* q:+ q:expt q:/ q:-) dyQList)))
but only at the top level, not in a called function. ~ )
Then evaluates body, returning the value of the last form." (setf (dx-of self) (funcall (eval `(lambda (x y) ,dxCLList)) x y))
(setf (dy-of self) (funcall (eval `(lambda (x y) ,dyCLList)) x y))
(let* ( (setf (dz-of self) -1)
(a-list )
(mapcar #'(lambda (f) (cons f (find-symbol (string f) (string-upcase (error "The sfunction of ~s is not a list" self)
"q")))) )
fns) )
)
(new-body (loop for form in body collect (sublis a-list form))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
) ;;; Define class glDataPoint
(push 'progn new-body) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
new-body
(defclass glDataPoint()
( ;;; divide a point's coordinate by a non zero constant
( x :accessor x-of :initform nil :initarg :x :type double :documentation "x (defmethod divide ((self glDataPoint) (value number))
coordinates") (if (/= value 0)
( y :accessor y-of :initform nil :initarg :y :type double :documentation "y (let
coordinates") ()
( z :accessor z-of :initform nil :initarg :z :type double :documentation "z (setf (x-of Self) (/ (x-of Self) value))
coordinates") (setf (y-of Self) (/ (y-of Self) value))
( color :accessor color-of :initform nil :initarg :color :type double (setf (z-of Self) (/ (z-of Self) value))
:documentation "color") (setf (color-of Self) (/ (color-of Self) value))
( normal :accessor normal-of :initform nil :initarg :normal :type normal )
:documentation "") (error "The divide of ~s by zero" self)
) )
(:documentation "super class") )
)
;;; compare two points' coordinate equality
(defmethod initialize-instance ((self glDataPoint) &rest initargs) (defmethod equal-coord-p ((self glDataPoint) (dp glDataPoint))
(declare (ignore initargs)) (and (= (x-of Self) (x-of dp) )
) (= (y-of Self) (y-of dp) )
(= (z-of Self) (z-of dp) )
(defmethod assign-value ((self glDataPoint) xValue yValue zValue colorValue )
normal) )
(setf (x-of self) xValue)
(setf (y-of self) yValue) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(setf (z-of self) zValue) ;;; Define class glDataSet
(setf (color-of self) colorValue) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(setf (normal-of self) normal)
) (defclass glDataSet()
(
;;; add two points' coordinates together ( x-range :accessor x-range-of :initform (make-Range :min 0.0 :max 0.0)
(defmethod add ((Self glDataPoint) (dp glDataPoint)) :initarg :x-range :type Range :documentation "x axis range")
(setf (x-of Self) (+ (x-of Self) (x-of dp))) ( y-range :accessor y-range-of :initform (make-Range :min 0.0 :max 0.0)
(setf (y-of Self) (+ (y-of Self) (y-of dp))) :initarg :y-range :type Range :documentation "y axis range")
(setf (z-of Self) (+ (z-of Self) (z-of dp))) ( z-range :accessor z-range-of :initform nil :initarg :z-range :type Range
(setf (color-of Self) (+ (color-of Self) (color-of dp))) :documentation "z axis range")
(setf (normal-of Self) (+ (normal-of Self) (normal-of dp))) ( color-range :accessor color-range-of :initform nil :initarg :color-range :type
) Range :documentation "color range")
( x-sequence :accessor x-sequence-of :initform nil :initarg :x-sequence
:documentation "x Sequence, could be list or vector or array") (defmethod toggle-surface ((self glDataSet))
( y-sequence :accessor y-sequence-of :initform nil :initarg :y-sequence (if (surfacep self)
:documentation "y Sequence could be list or vector or array") (setf (surfacep self) nil)
( x-sequence-type :accessor x-sequence-type-of :initform nil :initarg :x- (setf (surfacep self) T)
sequence-type :documentation "x Sequence type, could be list or vector or )
array") )
( y-sequence-type :accessor y-sequence-type-of :initform nil :initarg :y-
sequence-type :documentation "y Sequence type, could be list or vector or array") (defmethod toggle-wireframe ((self glDataSet) )
( surface-function :accessor surface-function-of :initform (make-instance (if (wireframep self)
'surfaceFunction ) :initarg :surface-function :documentation "surface Function (setf (wireframep self) nil)
either cl function or list") (setf (wireframep self) T)
( surface-heights :accessor surface-heights-of :initarg :surface-heights :initform )
NIL :documentation "The heights of the surface at each (x,y) location in the grid. )
The locations must be arranged in a vector varying the y coordinate fastest.")
( x-data-size :accessor x-data-size-of :initform 0 :initarg :x-data-size (defmethod toggle-hidden-lines ((self glDataSet) )
:documentation "the size of x sequence ") (if (hidden-Lines-p self)
( y-data-size :accessor y-data-size-of :initform 0 :initarg :y-data-size (setf (hidden-Lines-p self) nil)
:documentation "the size of y sequence ") (setf (hidden-Lines-p self) T)
( data-points :accessor data-points-of :initform (make-hash-table) :initarg :data- )
points :documentation "all 3 dimension data points stored in a hash table") )
( min-z-value :accessor min-z-value-of :initform 0 :initarg :min-z-value
:documentation "min z value to determine the camaer position") (defmethod initialize-instance ((self glDataSet) &rest initargs)
( max-z-value :accessor max-z-value-of :initform 0 :initarg :max-z-value (declare (ignore initargs))
:documentation "max z value to determine the camaer position") ;; create hash-table
( cube-diagonal-length :accessor cube-diagonal-length-of :initform 0 :initarg (setf (data-points-of Self) (make-hash-table))
:cube-diagonal-length :documentation "") ;; create surface function class
( wireframe? :accessor wireframep :initform T :initarg :wireframe? (setf (surface-function-of Self) (make-instance 'surfaceFunction ))
:documentation "switch on off wireframe, default is on") (setf (max-z-value-of self) 0)
( surface? :accessor surfacep :initform T :initarg :surface? :documentation (setf (min-z-value-of self) 0)
"switch on off surface, default is no surface") (setf (x-range-of self) (make-Range :min 0.0 :max 0.0))
( hiddenLines? :accessor hidden-Lines-p :initform T :initarg :hiddenLines? (setf (y-range-of self) (make-Range :min 0.0 :max 0.0))
:documentation "switch on off iHiddenLines, default is on") (setf (x-data-size-of self) 0)
) (setf (y-data-size-of self) 0)
(:documentation "class") (setf (wireframep self) T)
) (setf (surfacep self) T)
(setf (hidden-Lines-p self) T)
) (cond
((listp (x-sequence-of self)) (setf (x-data-size-of self) (list-length (x-sequence-of
self))))
(defmethod set-surface-function ((self glDataSet) functionObject) ((vectorp (x-sequence-of self) ) (setf (x-data-size-of self) (length (x-sequence-of
(if (or (functionp functionObject) (listp functionObject)) self))))
(set-sfunction (surface-function-of self) functionObject) ((arrayp (x-sequence-of self)) (setf (x-data-size-of self) (array-total-size (x-
(error "The ~s is not a function" functionObject) sequence-of self))))
) )
)
)
;;; sequence will be a list or a vector or a array
(defmethod set-sequence-type ((self glDataSet) axis sequence) ;;; assinge values to the slot y-sequence, and identify the sequence type, and
(if (eq axis :x) compute the sequence size
(cond (defmethod set-y-sequence ((self glDataSet) ysequence)
((listp sequence) (setf (x-sequence-type-of self) :list)) ;; assign value
((vectorp sequence) (setf (x-sequence-type-of self) :vector)) (setf (y-sequence-of self) ysequence)
((arrayp sequence) (setf (x-sequence-type-of self) :array))
) ;; identify the sequence type list = list vector = vector array = array
(cond (set-sequence-type self :y ysequence)
((listp sequence) (setf (y-sequence-type-of self) :list))
((vectorp sequence) (setf (y-sequence-type-of self) :vector)) ;; compute the size y-sequence
((arrayp sequence) (setf (y-sequence-type-of self) :array)) (cond
) ((listp (y-sequence-of self)) (setf (y-data-size-of self) (list-length (y-sequence-
) of self))))
) ((vectorp (y-sequence-of self) ) (setf (y-data-size-of self) (length (y-sequence-
of self))))
((arrayp (y-sequence-of self)) (setf (y-data-size-of self) (array-total-size (y-
;;; assinge values to the slot x-sequence, and identify the sequence type, and sequence-of self))))
compute the sequence size )
(defmethod set-x-sequence ((self glDataSet) xsequence) )
;; assign value
(setf (x-sequence-of self) xsequence) (defmethod sort-sequence ((self glDataSet))
;; sort x and y sequence
;; identify the sequence type list = l vector = v array = a (setf (x-sequence-of self) (sort (x-sequence-of self) #'<=))
(set-sequence-type self :x xsequence) (setf (y-sequence-of self) (sort (y-sequence-of self) #'<=))
;;; compute heights given a function, x sequence and y sequence (sort-sequence self)
(defmethod compute-points-triples ((self glDataSet) &optional functionObject
xSequence ySequence) (if (and (not (eq (surface-function-of self) Nil)) (not (eq (x-sequence-of self)
Nil)) (not (eq (y-sequence-of self) Nil)))
(if (not (eq xSequence Nil)) (progn
(set-x-sequence self xSequence) (dotimes (i (x-data-size-of self))
(dotimes (j (y-data-size-of self)) )
(let* ( )
(x (access-sequence self :x i)) )
(y (access-sequence self :y j)) (error "missing surface funcations or x sequence or y sequence")
(dp (make-instance 'glDataPoint)) )
zValue )
)
;; dpNormal = nil, color = 0
(if (arrayp functionObject) ;;; compute a normal vector for triangle
(setf zValue (aref (surface-heights-of self) i j)) (defmethod compute-triangle-normal ((self glDataSet) dp1 dp2 dp3)
(setf zValue (function-at (surface-function-of self) x y)) (let
) (
(x1 (x-of dp1))
(assign-value dp x y zValue 0 Nil) (y1 (y-of dp1))
(z1 (z-of dp1))
(if (> zValue (max-z-value-of self)) (x2 (x-of dp2))
(setf (max-z-value-of self) zValue) (y2 (y-of dp2))
) (z2 (z-of dp2))
(if (< zValue (min-z-value-of self)) (x3 (x-of dp3))
(setf (min-z-value-of self) zValue) (y3 (y-of dp3))
) (z3 (z-of dp3))
;; put into hash table (n (make-Normal :x 0 :y 0 :z 0))
(setf (gethash (complex i j) (data-points-of self) ) dp) )
) (setf (Normal-x n) (- (* (- y2 y1) (- z3 z1)) (* (- z2 z1) (- y3 y1))))
) (setf (Normal-y n) (- (* (- z2 z1) (- x3 x1)) (* (- x2 x1) (- z3 z1))))
) (setf (Normal-z n) (- (* (- x2 x1) (- y3 y1)) (* (- y2 y1) (- x3 x1))))
(setf (z-range-of self) (make-Range :min (min-z-value-of self) :max (max-z- n
value-of self)) ) )
(setf (cube-diagonal-length-of self) (sqrt )
(+
(expt (- (Range-max (z-range-of self)) (Range-min
(z-range-of self))) 2) ;;; compute the normal vector for a point by averaging the adjacent triangles
(expt (- (Range-max (x-range-of self)) (Range-min sharing that point
(x-range-of self))) 2) ;;; the four triangles will be
(expt (- (Range-max (y-range-of self)) (Range-min ;;; ((i j), (i+1 j), (i j+1)), ((i j), (i-1 j), (i j+1)), ((i j), (i-1 j), (i j-1)), ((i j), (i j-1),
(y-range-of self))) 2) (i+1 j))
) (defmethod compute-points-normal ((self glDataSet))
(if (/= (hash-table-size (data-points-of self)) 0) (if (and (< i 0) (< j 0))
(let (let
(
( (dp1 (gethash (complex i j) (data-points-of self)))
(dp (make-instance 'glDataPoint)) (dp2 (gethash (complex (1- i) j) (data-points-of self)))
) (dp3 (gethash (complex i (1- j)) (data-points-of self)))
(dotimes (i (x-data-size-of self)) )
(dotimes (j (y-data-size-of self)) (setf normal3 (compute-triangle-normal self dp1 dp2 dp3))
(let* (
;; assgin value )
(normal1 (make-Normal :x 0 :y 0 :z 0)) )
(normal2 (make-Normal :x 0 :y 0 :z 0)) (if(and (< j 0) (< i (- (x-data-size-of self) 1)))
(normal3 (make-Normal :x 0 :y 0 :z 0)) (let
(normal4 (make-Normal :x 0 :y 0 :z 0)) (
(normalPoint (make-Normal :x 0 :y 0 :z 0)) (dp1 (gethash (complex i j) (data-points-of self)))
) (dp2 (gethash (complex i (1- j)) (data-points-of self)))
(if (and (< i (- (x-data-size-of self) 1)) (< j (- (y-data-size-of self) 1))) (dp3 (gethash (complex (1+ i) j) (data-points-of self)))
(let )
( (setf normal4 (compute-triangle-normal self dp1 dp2 dp3))
(dp1 (gethash (complex i j) (data-points-of self)))
(dp2 (gethash (complex (1+ i) j) (data-points-of self))) )
(dp3 (gethash (complex i (1+ j) ) (data-points-of self))) )
) (setf (Normal-x normalPoint)(/ (+ (Normal-x normal1) (Normal-x
(setf normal1 (compute-triangle-normal self dp1 dp2 dp3)) normal2) (Normal-x normal3)(Normal-x normal4)) 4) )
) (setf (Normal-y normalPoint)(/ (+ (Normal-y normal1) (Normal-y
) normal2) (Normal-y normal3)(Normal-y normal4)) 4) )
(if (and (< i 0) (< j (- (y-data-size-of self) 1))) (setf (Normal-z normalPoint)(/ (+ (Normal-z normal1) (Normal-z
(let normal2) (Normal-z normal3)(Normal-z normal4)) 4) )
( (setf dp (gethash (complex i j) (data-points-of self)))
(dp1 (gethash (complex i j) (data-points-of self))) (setf (normal-of dp) normalPoint)
(dp2 (gethash (complex (1- i) j) (data-points-of self))) )
(dp3 (gethash (complex i (1+ j)) (data-points-of self))) )
) )
(setf normal2 (compute-triangle-normal self dp1 dp2 dp3)) )
(error "The size of ~s is zero" (data-points-of self))
) )
) )
(glmaterialfv gl_front_and_back gl_ambient_and_diffuse V)
)
(defmethod draw ((self glDataSet)) (let
(
(if (hidden-Lines-p self) (dp (make-instance 'glDataPoint))
;; enable the surface visibility : hidden lines )
(glenable gl_depth_test) (dotimes (i (1- (x-data-size-of self)) )
) (dotimes (j (1- (y-data-size-of self)) )
(progn
(glClear (logior GL_COLOR_BUFFER_BIT gl_depth_buffer_bit)) (glBegin gl_polygon)
(glenable gl_normalize) (setf dp (gethash (complex i j) (data-points-of self)))
(glVertex3f (x-of dp) (y-of dp) (z-of dp))
;;; wireframe (setf dp (gethash (complex (1+ i) j) (data-points-of self)))
(if (wireframep self) (glVertex3f (x-of dp) (y-of dp) (z-of dp))
(progn (setf dp (gethash (complex (1+ i) (1+ j) ) (data-points-of self)))
;(glcolor3f 0.0 0.0 1.0) (glVertex3f (x-of dp) (y-of dp) (z-of dp))
;; axes (setf dp (gethash (complex i (1+ j)) (data-points-of self)))
(glenable gl_normalize) (glVertex3f (x-of dp) (y-of dp) (z-of dp))
(with-rgba-vector v (0.0 0.0 1.0 1.0) (glEnd)
(glmaterialfv gl_front_and_back gl_ambient_and_diffuse V) )
) )
(gllinewidth 1.2) )
(glBegin gl_lines) )
(glVertex3f -2.1s0 0.0s0 0.0s0) )
(glVertex3f 2.1s0 0.0s0 0.0s0) )
(glVertex3f 0.0s0 -2.1s0 0.0s0)
(glVertex3f 0.0s0 2.1s0 0.0s0) ;;; surface rendering
(glVertex3f 0.0s0 0.0s0 0.0s0) (if (surfacep self)
(glVertex3f 0.0s0 0.0s0 1.0s0) (progn
(glEnd)
(glpolygonmode gl_front_and_back gl_fill)
;;; set to wireframe (if (hidden-Lines-p self)
(gllinewidth 1.0) (let
(glpolygonmode gl_front_and_back gl_line) ()
(glenable gl_polygon_offset_fill)
(glpolygonoffset 1.0 1.0)
(with-rgba-vector V (0.9 0.0 0.0 0.5) )
(glEnd)
) )
)
;;; here the surface color will be set to light green )
(with-rgba-vector V (0.0 0.9 0.0 0.0)
(glmaterialfv gl_front_and_back gl_ambient_and_diffuse V) )
) (gldisable gl_polygon_offset_fill)
(glcolor3f 0.0 0.9 0.0) (glPopAttrib )
(let )
( )
(dp (make-instance 'glDataPoint)) )
)
(dotimes (i (1- (x-data-size-of self)) )
(dotimes (j (1- (y-data-size-of self)) ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(progn ;;; Define class glSurfaceWindow
(glBegin gl_polygon) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; define surface property (R G B Alpha) and use specular reflection (defmethod set-rotate-axis ((self glSurfaceWindow) axis)
(with-rgba-vector (setf (rotate-axis-of self) axis)
specularity (0.5 0.5 0.5 1.0) )
(glmaterialfv gl_front_and_back gl_specular specularity)
) (defmethod switch-direction ((self glSurfaceWindow) )
(glmaterialf gl_front_and_back gl_shininess 10.0) ; 0 - 128
(if (counterclockwisep self)
;;; lights, here has two lights, one is local lights located at (setf (counterclockwisep self) nil)
;;; at world coordinate position ( ). (setf (counterclockwisep self) T)
;;; the other is the ambient lights to give a general brightness )
;;; and also set the diffuse and sepcular properties )
;;; (0.5 0.5 0.5 1.0) is light white lights
;;; override the view-click-event-handler
;;; set up the global lights (defmethod view-click-event-handler ((Self glSurfaceWindow) Where)
(with-rgba-vector (declare (ignore Where))
globalAmbient (0.5 0.5 0.5 1.0) (let (
(gllightmodelfv gl_light_model_ambient globalAmbient) (axis (rotate-axis-of self))
) (xAxis 0)
(yAxis 0)
;;; set up the local lights (zAxis 0)
(with-rgba-vector position (-5.0 5.0 5.0 1.0) (gain (gain self))
(gllightfv gl_light1 gl_position position) (counterClockWise (counterclockwisep self))
) )
(cond )
((eq axis :x) (setf xAxis 1)) (view-draw-contents Self)
((eq axis :y) (setf yAxis 1)) )
((eq axis :z) (setf zAxis 1))
) (defmethod toggle-hidden-lines ((self glSurfaceWindow) )
(toggle-hidden-lines (glds-of self))
(if counterClockWise (display self)
(setf gain (+ gain)) (glflush)
(setf gain (- gain)) )
)
(defun gl-surface-plot (xSequence ySequence surfaceFunction)
(glMatrixMode gl_modelview) (let
(loop (
(unless (mouse-down-p) (return)) (x xSequence)
(glrotatef gain xAxis yAxis zAxis) (y ySequence)
(view-draw-contents Self) (sf surfaceFunction)
) (ds2 (make-instance 'glDataSet))
) )
) (compute-points-triples ds2 sf x y)
(compute-points-normal ds2)
(defmethod toggle-surface ((self glSurfaceWindow)) (make-instance 'glSurfaceWindow :glds ds2)
(toggle-surface (glds-of self)) )
(display self) )
(glflush)
)
(glMatrixMode gl_modelview)
(glScalef
scalar scalar scalar
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (setf x (list -3.0 -2.8 -2.6 -2.4 -2.2 -2.0 -1.8 -1.6 -1.4 -1.2 -1.0 -0.8 -0.6 -0.4 -0.2
;;; glSurfaceWindow-examples.lisp 0.0 0.2 0.4 0.6 0.8 1.0 1.2 1.4 1.6 1.8 2.0 2.2 2.4 2.6 2.8 3.0))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (setf y (vector -3.0 -2.8 -2.6 -2.4 -2.2 -2.0 -1.8 -1.6 -1.4 -1.2 -1.0 -0.8 -0.6 -0.4 -
;;; examples for glSurfaceWindow 0.2 0.0 0.2 0.4 0.6 0.8 1.0 1.2 1.4 1.6 1.8 2.0 2.2 2.4 2.6 2.8 3.0))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (setf fw1 (gl-surface-plot x y #'my-surface))
(gl-surface-plot x y z)
)
)
;;; scale
(change-scale fw2 0.8)
(* (pdf-at self x y)
(/ 1 (* 2 pi sigma1 sigma2 (sqrt (- 1 (expt corr 2))))
) (- 0
(*
(exp (- 0 (/ temp (/ 1 (* 2 (- 1 (expt corr 2))))
(* 2 (- 1 (expt corr 2))) (- (* 2 (- y mu2) (/ 1 (expt sigma2 2)))
))) (* 2 corr (- x mu1) (/ 1 (* sigma1 sigma2)))
) )
) )
) )
)
(defmethod compute-point-gradient ((self bivariate-normal-pdf) x y) )
(let* (
(mu1 (mu1-of self)) (dz -1)
(sigma1 (sigma1-of self)) )
(mu2 (mu2-of self)) (setf (dx-of self) dx)
(sigma2 (sigma2-of self)) (setf (dy-of self) dy)
(corr (corr-of self)) (setf (dz-of self) dz)
(dx
(* )
)
)
)