1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
let pi2 = 6.2831853
(* draws the specified cylinder along the z axis.
* explanation of how this works can be found at the bottom of this file *)
let cylinder ~numl ~numa ~length ~rmod ~rmodd ~xmod ~xmodd ~ymod ~ymodd =
(* the formula for the normal and the vertex *)
let point a r dr x dx y dy o =
let nx = sin a *. r in
let ny = cos a *. r in
let nz = (sin a *. dr +. dx) *. -1.0 *. sin a *. r
-. cos a *. r *. (cos a *. dr +. dy) in
let len = sqrt (nx*.nx +. ny*.ny +. nz*.nz) in
GlDraw.normal3 (nx/.len, ny/.len, nz/.len);
GlDraw.vertex3 (
sin a *. r +. x,
cos a *. r +. y,
o
)
in
(* cache previous values *)
let pl = ref 0.0 and
pr = ref (rmod 0.0) and
prd = ref (rmodd 0.0) and
px = ref (xmod 0.0) and
pxd = ref (xmodd 0.0) and
py = ref (ymod 0.0) and
pyd = ref (ymodd 0.0) in
(* generate stuff *)
GlDraw.begins `quads;
for li = 1 to numl do
let l = (float li) /. (float numl) *. length in
let cr = rmod l and crd = rmodd l in
let cx = xmod l and cxd = xmodd l in
let cy = ymod l and cyd = ymodd l in
let p = ref 0.0 in
for ai = 1 to numa do
let a = pi2 *. (float (ai mod numa)) /. (float numa) in
point a cr crd cx cxd cy cyd l;
point a !pr !prd !px !pxd !py !pyd !pl;
point !p !pr !prd !px !pxd !py !pyd !pl;
point !p cr crd cx cxd cy cyd l;
p := a;
done;
pl := l;
pr := cr; prd := crd;
px := cx; pxd := cxd;
py := cy; pyd := cyd;
done;
GlDraw.ends ()
let draw t =
Gl.enable `lighting;
GlMat.push ();
GlMat.translate3 (-4.5, 0.0, -4.0);
GlMat.rotate ~angle:90.0 ~y:1.0 ();
GlDraw.color (0.2, 0.2, 0.6);
GlLight.material ~face:`both (`specular (0.1, 0.1, 0.1, 1.0));
cylinder ~numl:45 ~numa:20 ~length:9.0
~rmod: (fun l -> 0.75 +. 0.5*.sin (l *. pi2 *. 0.2 +. t))
~rmodd:(fun l -> 0.5 *. cos (l *. pi2 *. 0.2 +. t) *. pi2 *. 0.2)
~xmod: (fun l -> 0.0)
~xmodd:(fun l -> 0.0)
~ymod: (fun l -> 0.5 *. sin (l *. pi2 *. 0.15 +. t))
~ymodd:(fun l -> 0.5 *. cos (l *. pi2 *. 0.15 +. t) *. pi2 *. 0.15);
GlMat.pop ()
(*
a = angle of the circle
l = length of the cylinder
rmod(l) = function returning the radius of the cylinder at the given length
xmod(l)
ymod(l) = functions returning the x and y positions of the center of the circle
at a given length in the cylinder
Every point on the cylinder can be described with the following formula:
V(a,l) = [
x = sin(a) * rmod(l) + xmod(l)
y = cos(a) * rmod(l) + ymod(l)
| | \-- translating the circle
| \-- scaling the circle
\-- formula for a normal circle
z = l
]
(z could also be modulated to create more complex models, but let's keep
things simple for now)
This is an "Analytic Surface", as explained in http://glprogramming.com/red/appendixe.html
So the normal can be calculated with:
dV/dl -> l = [
x = sin(a) * rmod'(l) + xmod'(l)
y = cos(a) * rmod'(l) + ymod'(l)
z = 1
]
dV/da -> a = [
x = cos(a) * rmod(l),
y = -sin(a) * rmod(l),
z = 0
]
normal = [
x = l.y * a.z - a.y * l.z = sin(a) * rmod(l)
y = a.x * l.z - l.x * a.z = cos(a) * rmod(l)
z = l.x * a.y - a.x * l.y
= (sin(a) * rmod'(l) + xmod'(l)) * -sin(a) * rmod(l)
- cos(a) * rmod(l) * (cos(a) * rmod'(l) + ymod'(l))
]
*)
|