-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTornado.cpp
166 lines (154 loc) · 5.38 KB
/
Tornado.cpp
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#include "Tornado.h"
#define TORNADO_INIT_HEIGHT 90.0
#define TORNADO_INIT_SPEED 3.5
#define TORNADO_INIT_FORCE 20.0
#define TORNADO_SCALE_FACTOR 35.0
#define TORNADO_SUB_GROUND 10.0
Tornado::Tornado(){
// Just initialize with default values.
m_origin = vec3(0.0, 0.0, 0.0);
init();
}
Tornado::Tornado(vec3 startOrigin, Terrain* terr)
{
// Add origin, then initialize.
m_terrain = terr;
m_origin = startOrigin;
init();
}
void Tornado::init()
{
// Initialize height and age...
m_height = TORNADO_INIT_HEIGHT;
m_age = 0.0;
m_speed = TORNADO_INIT_SPEED;
m_force = TORNADO_INIT_FORCE;
// Don't go anywhere until setDestination is a thing.
m_destination = m_origin;
// Initialize an array of control points and widths...
m_controlPoints = new vec3[NUM_CONTROL_POINTS];
m_controlWidths = new float[NUM_CONTROL_POINTS];
m_initWidths = new float[NUM_CONTROL_POINTS];
float segmentSize = m_height/(NUM_CONTROL_POINTS - 1);
for(int it = 0; it < NUM_CONTROL_POINTS; it++){
float th = it * segmentSize;
m_controlPoints[it].setX(0.0);
m_controlPoints[it].setZ(0.0);
m_controlPoints[it].setY(th);
// width should be a function of height.
// Should edit scale factor to match texture?
m_initWidths[it] = initWidth(th);
m_controlWidths[it] = m_initWidths[it];
}
}
Tornado::~Tornado()
{
delete[] m_controlPoints;
delete[] m_controlWidths;
delete[] m_initWidths;
}
// Interpolate the tornado's spine position at a given world-space height.
vec3 Tornado::interp(float height)
{
return interpLocal(height - m_origin.y());
}
// Interpolate the tornado's local spine position at a some height in the tornado.
vec3 Tornado::interpLocal(float height)
{
float segmentSize = m_height/(NUM_CONTROL_POINTS - 1);
int ind = height / segmentSize;
float offset = height - (float) (segmentSize * ind);
offset /= segmentSize;
if(height >= m_height){
ind = NUM_CONTROL_POINTS - 2;
offset = 1.0;
}
else if(height <= 0.0){
ind = 0;
offset = 0.0;
}
vec3 p1 = m_controlPoints[ind];
vec3 p2 = m_controlPoints[ind + 1];
vec3 rv;
// Right now, this is just linear interpolation. If we want, we can bring in a bezier curve or something.
rv.setX(p1.x() * (1.0 - offset) + (p2.x() * offset));
rv.setZ(p1.z() * (1.0 - offset) + (p2.z() * offset));
rv.setY(height);
return rv;
}
// Interpolate to find the tornado width at some local height.
float Tornado::interpWidth(float height)
{
float segmentSize = m_height/(NUM_CONTROL_POINTS - 1);
int ind = height / segmentSize;
float offset = height - (float) (segmentSize * ind);
offset /= segmentSize;
if(height >= m_height){
ind = NUM_CONTROL_POINTS - 2;
offset = 1.0;
}
else if(height <= 0.0){
ind = 0;
offset = 0.0;
}
float w1 = m_controlWidths[ind];
float w2 = m_controlWidths[ind + 1];
// Right now, this is just linear interpolation. If we want, we can bring in a bezier curve or something.
float rv = (w1 * (1.0 - offset)) + (w2 * offset);
return rv;
}
// Interpolate to find the tornado width at some local height.
float Tornado::initWidth(float height)
{
float wp = abs(height)/m_height;
if (wp < 0.25)
wp = 0.5 - wp;
float rv = pow(wp, 2.0) * TORNADO_SCALE_FACTOR;
return rv;
}
#define TORNADO_RAND_SCALE 10.0
#define TORNADO_MAX_TWIST 0.10
#define TORNADO_MAX_DELTA 0.20
void Tornado::update(float dt)
{
vec3 diff = m_destination - m_origin;
diff.setY(0.0);
float dist = min((double) diff.length(), (double) m_speed * dt);
diff.normalize();
m_origin += (diff * dist);
// Set the origin's y-value to sub_ground below the height map at the current point.
float terrainHeight = m_terrain->height(m_origin.x(), m_origin.z());
// std::cout<<terrainHeight<<endl;
m_origin.setY(terrainHeight - TORNADO_SUB_GROUND);
// Add a little random shake to the control points...
for(int it = 0; it < NUM_CONTROL_POINTS; it++){
// Shake control point position...
vec3 rvec;
double hprop = (double)it / (double)(NUM_CONTROL_POINTS - 1);
double rx = dt * hprop * TORNADO_RAND_SCALE * randf(-1.0, 1.0);
double ry = dt * hprop * TORNADO_RAND_SCALE * randf(-1.0, 1.0);
rvec.setX(min(TORNADO_MAX_TWIST, max(-TORNADO_MAX_TWIST, rx)));
rvec.setZ(min(TORNADO_MAX_TWIST, max(-TORNADO_MAX_TWIST, ry)));
rvec.setY(0.0);
// Shake control point widths...
float rwf = dt * hprop * TORNADO_RAND_SCALE * 0.5;
m_controlWidths[it] *= randf(1.0 - rwf, 1.0 + rwf);
m_controlPoints[it] += rvec;
}
capControls();
}
void Tornado::capControls()
{
for(int it = 0; it < NUM_CONTROL_POINTS; it++){
float hprop = (float)it / (float)(NUM_CONTROL_POINTS - 1);
float maxDelta = TORNADO_MAX_DELTA * hprop;
float maxDT = maxDelta * 20.0;
// Cap control point x and z...
m_controlPoints[it].setX(min(maxDT, max(-maxDT, (float)m_controlPoints[it].x())));
m_controlPoints[it].setZ(min(maxDT, max(-maxDT, (float)m_controlPoints[it].z())));
// Cap control width...
float minW = (1.0 - maxDelta) * m_initWidths[it];
float maxW = (1.0 + maxDelta) * m_initWidths[it];
m_controlWidths[it] = min(maxW, max(minW, m_controlWidths[it]));
}
}