Merge lp:~xalioth/stellarium/planet-shadows into lp:stellarium
- planet-shadows
- Merge into trunk
Proposed by
Fabien Chéreau
Status: | Merged |
---|---|
Merged at revision: | 6810 |
Proposed branch: | lp:~xalioth/stellarium/planet-shadows |
Merge into: | lp:stellarium |
Diff against target: |
1688 lines (+752/-533) 11 files modified
src/core/StelPainter.cpp (+21/-274) src/core/StelPainter.hpp (+0/-41) src/core/StelTexture.cpp (+2/-2) src/core/StelTexture.hpp (+1/-1) src/core/StelUtils.cpp (+100/-0) src/core/StelUtils.hpp (+22/-0) src/core/modules/Comet.cpp (+0/-5) src/core/modules/Planet.cpp (+560/-191) src/core/modules/Planet.hpp (+38/-18) src/core/modules/SolarSystem.cpp (+6/-1) src/core/modules/SolarSystem.hpp (+2/-0) |
To merge this branch: | bzr merge lp:~xalioth/stellarium/planet-shadows |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alexander Wolf | Needs Fixing | ||
Review via email: mp+221967@code.launchpad.net |
Commit message
Description of the change
Re-integrated Jörg's work on planet shadow rendering
To post a comment you must log in.
- 6814. By Fabien Chéreau
-
Don't draw planet when standing on it, even for planet with rings.
- 6815. By Fabien Chéreau
-
Fixed sun rendering.
- 6816. By Fabien Chéreau
-
Use new moon eclipse rendering. Got rid of old stencil based code.
Revision history for this message
Fabien Chéreau (xalioth) wrote : | # |
Thanks. I fixed this issue. I also improved moon eclipse rendering.
On Wed, Jun 4, 2014 at 7:20 PM, Alexander Wolf <email address hidden>
wrote:
> Review: Needs Fixing
>
> This code give strange effect on the Sun in the moment of solar eclipse.
> --
> https:/
> You are the owner of lp:~xalioth/stellarium/planet-shadows.
>
- 6817. By Fabien Chéreau
-
First shader cleanup.
More can probably be done by replacing some trigo with simpler
vector operations. - 6818. By Fabien Chéreau
-
Simplified further shader.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'src/core/StelPainter.cpp' |
2 | --- src/core/StelPainter.cpp 2014-05-23 22:05:02 +0000 |
3 | +++ src/core/StelPainter.cpp 2014-06-04 22:13:44 +0000 |
4 | @@ -226,94 +226,7 @@ |
5 | enableClientStates(false); |
6 | } |
7 | |
8 | -// Arrays to keep cos/sin of angles and multiples of angles. rho and theta are delta angles, and these arrays |
9 | -#define MAX_STACKS 4096 |
10 | -static float cos_sin_rho[2*(MAX_STACKS+1)]; |
11 | -#define MAX_SLICES 4096 |
12 | -static float cos_sin_theta[2*(MAX_SLICES+1)]; |
13 | - |
14 | -//! Compute cosines and sines around a circle which is split in "segments" parts. |
15 | -//! Values are stored in the global static array cos_sin_theta. |
16 | -//! Used for the sin/cos values along a latitude circle, equator, etc. for a spherical mesh. |
17 | -//! @param dTheta a difference angle between the stops. Always use 2*M_PI/segments! |
18 | -//! @param segments number of partitions (elsewhere called "slices") for the circle |
19 | -static void ComputeCosSinTheta(const float dTheta, const int segments) |
20 | -{ |
21 | - float *cos_sin = cos_sin_theta; |
22 | - float *cos_sin_rev = cos_sin + 2*(segments+1); |
23 | - const float c = std::cos(dTheta); |
24 | - const float s = std::sin(dTheta); |
25 | - *cos_sin++ = 1.f; |
26 | - *cos_sin++ = 0.f; |
27 | - *--cos_sin_rev = -cos_sin[-1]; |
28 | - *--cos_sin_rev = cos_sin[-2]; |
29 | - *cos_sin++ = c; |
30 | - *cos_sin++ = s; |
31 | - *--cos_sin_rev = -cos_sin[-1]; |
32 | - *--cos_sin_rev = cos_sin[-2]; |
33 | - while (cos_sin < cos_sin_rev) // compares array address indices only! |
34 | - { |
35 | - // avoid expensive trig functions by use of the addition theorem. |
36 | - cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s; |
37 | - cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c; |
38 | - cos_sin += 2; |
39 | - *--cos_sin_rev = -cos_sin[-1]; |
40 | - *--cos_sin_rev = cos_sin[-2]; |
41 | - } |
42 | -} |
43 | - |
44 | -//! Compute cosines and sines around a half-circle which is split in "segments" parts. |
45 | -//! Values are stored in the global static array cos_sin_rho. |
46 | -//! Used for the sin/cos values along a meridian for a spherical mesh. |
47 | -//! @param dRho a difference angle between the stops. Always use M_PI/segments! |
48 | -//! @param segments number of partitions (elsewhere called "stacks") for the half-circle |
49 | -static void ComputeCosSinRho(const float dRho, const int segments) |
50 | -{ |
51 | - float *cos_sin = cos_sin_rho; |
52 | - float *cos_sin_rev = cos_sin + 2*(segments+1); |
53 | - const float c = std::cos(dRho); |
54 | - const float s = std::sin(dRho); |
55 | - *cos_sin++ = 1.f; |
56 | - *cos_sin++ = 0.f; |
57 | - *--cos_sin_rev = cos_sin[-1]; |
58 | - *--cos_sin_rev = -cos_sin[-2]; |
59 | - *cos_sin++ = c; |
60 | - *cos_sin++ = s; |
61 | - *--cos_sin_rev = cos_sin[-1]; |
62 | - *--cos_sin_rev = -cos_sin[-2]; |
63 | - while (cos_sin < cos_sin_rev) // compares array address indices only! |
64 | - { |
65 | - // avoid expensive trig functions by use of the addition theorem. |
66 | - cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s; |
67 | - cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c; |
68 | - cos_sin += 2; |
69 | - *--cos_sin_rev = cos_sin[-1]; |
70 | - *--cos_sin_rev = -cos_sin[-2]; |
71 | - // segments--; // GZ: WHAT'S THAT GOOD FOR? |
72 | - } |
73 | -} |
74 | - |
75 | -//! Compute cosines and sines around part of a circle (from top to bottom) which is split in "segments" parts. |
76 | -//! Values are stored in the global static array cos_sin_rho. |
77 | -//! Used for the sin/cos values along a meridian. |
78 | -//! GZ: allow leaving away pole caps. The array now contains values for the region minAngle+segments*phi |
79 | -//! @param dRho a difference angle between the stops |
80 | -//! @param segments number of segments |
81 | -//! @param minAngle start angle inside the half-circle. maxAngle=minAngle+segments*phi |
82 | -static void ComputeCosSinRhoZone(const float dRho, const int segments, const float minAngle) |
83 | -{ |
84 | - float *cos_sin = cos_sin_rho; |
85 | - const float c = cos(dRho); |
86 | - const float s = sin(dRho); |
87 | - *cos_sin++ = cos(minAngle); |
88 | - *cos_sin++ = sin(minAngle); |
89 | - for (int i=0; i<segments; ++i) // we cannot mirror this, it may be unequal. |
90 | - { // efficient computation, avoid expensive trig functions by use of the addition theorem. |
91 | - cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s; |
92 | - cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c; |
93 | - cos_sin += 2; |
94 | - } |
95 | -} |
96 | + |
97 | |
98 | void StelPainter::computeFanDisk(float radius, int innerFanSlices, int level, QVector<double>& vertexArr, QVector<float>& texCoordArr) |
99 | { |
100 | @@ -326,9 +239,8 @@ |
101 | rad[i] = rad[i+1]*(1.f-M_PI/(innerFanSlices<<(i+1)))*2.f/3.f; |
102 | } |
103 | int slices = innerFanSlices<<level; |
104 | - const float dtheta = 2.f * M_PI / slices; |
105 | - Q_ASSERT(slices<=MAX_SLICES); |
106 | - ComputeCosSinTheta(dtheta,slices); |
107 | + |
108 | + float* cos_sin_theta = StelUtils::ComputeCosSinTheta(slices); |
109 | float* cos_sin_theta_p; |
110 | int slices_step = 2; |
111 | float x,y,xa,ya; |
112 | @@ -419,83 +331,6 @@ |
113 | |
114 | } |
115 | |
116 | -void StelPainter::sRing(const float rMin, const float rMax, int slices, const int stacks, const int orientInside) |
117 | -{ |
118 | - float x,y; |
119 | - int j; |
120 | - |
121 | - static Vec3f lightPos3; |
122 | - static Vec4f ambientLight; |
123 | - static Vec4f diffuseLight; |
124 | - float c; |
125 | - const bool isLightOn = light.isEnabled(); |
126 | - if (isLightOn) |
127 | - { |
128 | - lightPos3.set(light.getPosition()[0], light.getPosition()[1], light.getPosition()[2]); |
129 | - Vec3f tmpv(0.f); |
130 | - prj->getModelViewTransform()->forward(tmpv); // -posCenterEye |
131 | - //lightPos3 -= tmpv; |
132 | - //lightPos3 = prj->modelViewMatrixf.transpose().multiplyWithoutTranslation(lightPos3); |
133 | - prj->getModelViewTransform()->getApproximateLinearTransfo().transpose().multiplyWithoutTranslation(Vec3d(lightPos3[0], lightPos3[1], lightPos3[2])); |
134 | - prj->getModelViewTransform()->backward(lightPos3); |
135 | - lightPos3.normalize(); |
136 | - ambientLight = light.getAmbient(); |
137 | - diffuseLight = light.getDiffuse(); |
138 | - } |
139 | - |
140 | - const float nsign = orientInside?-1.f:1.f; |
141 | - |
142 | - const float dr = (rMax-rMin) / stacks; |
143 | - const float dtheta = 2.f * M_PI / slices; |
144 | - if (slices < 0) slices = -slices; |
145 | - Q_ASSERT(slices<=MAX_SLICES); |
146 | - ComputeCosSinTheta(dtheta,slices); |
147 | - float *cos_sin_theta_p; |
148 | - |
149 | - static QVector<double> vertexArr; |
150 | - static QVector<float> texCoordArr; |
151 | - static QVector<float> colorArr; |
152 | - |
153 | - // draw intermediate stacks as quad strips |
154 | - for (float r = rMin; r < rMax; r+=dr) |
155 | - { |
156 | - const float tex_r0 = (r-rMin)/(rMax-rMin); |
157 | - const float tex_r1 = (r+dr-rMin)/(rMax-rMin); |
158 | - vertexArr.resize(0); |
159 | - texCoordArr.resize(0); |
160 | - colorArr.resize(0); |
161 | - for (j=0,cos_sin_theta_p=cos_sin_theta; j<=slices; ++j,cos_sin_theta_p+=2) |
162 | - { |
163 | - x = r*cos_sin_theta_p[0]; |
164 | - y = r*cos_sin_theta_p[1]; |
165 | - if (isLightOn) |
166 | - { |
167 | - c = nsign * (lightPos3[0]*x + lightPos3[1]*y); |
168 | - if (c<0) {c=0;} |
169 | - colorArr << c*diffuseLight[0] + ambientLight[0] << c*diffuseLight[1] + ambientLight[1] << c*diffuseLight[2] + ambientLight[2]; |
170 | - } |
171 | - texCoordArr << tex_r0 << 0.5f; |
172 | - vertexArr << x << y << 0.f; |
173 | - x = (r+dr)*cos_sin_theta_p[0]; |
174 | - y = (r+dr)*cos_sin_theta_p[1]; |
175 | - if (isLightOn) |
176 | - { |
177 | - c = nsign * (lightPos3[0]*x + lightPos3[1]*y); |
178 | - if (c<0) {c=0;} |
179 | - colorArr << c*diffuseLight[0] + ambientLight[0] << c*diffuseLight[1] + ambientLight[1] << c*diffuseLight[2] + ambientLight[2]; |
180 | - } |
181 | - texCoordArr << tex_r1 << 0.5f; |
182 | - vertexArr << x << y << 0.f; |
183 | - } |
184 | - |
185 | - if (isLightOn) |
186 | - setArrays((Vec3d*)vertexArr.constData(), (Vec2f*)texCoordArr.constData(), (Vec3f*)colorArr.constData()); |
187 | - else |
188 | - setArrays((Vec3d*)vertexArr.constData(), (Vec2f*)texCoordArr.constData()); |
189 | - drawFromArray(TriangleStrip, vertexArr.size()/3); |
190 | - } |
191 | -} |
192 | - |
193 | static void sSphereMapTexCoordFast(float rho_div_fov, const float costheta, const float sintheta, QVector<float>& out) |
194 | { |
195 | if (rho_div_fov>0.5f) |
196 | @@ -507,17 +342,13 @@ |
197 | { |
198 | float rho,x,y,z; |
199 | int i, j; |
200 | + const float* cos_sin_rho = StelUtils::ComputeCosSinRho(stacks); |
201 | + const float* cos_sin_rho_p; |
202 | + |
203 | + const float* cos_sin_theta = StelUtils::ComputeCosSinTheta(slices); |
204 | + const float* cos_sin_theta_p; |
205 | + |
206 | float drho = M_PI / stacks; |
207 | - Q_ASSERT(stacks<=MAX_STACKS); |
208 | - ComputeCosSinRho(drho,stacks); |
209 | - float* cos_sin_rho_p; |
210 | - |
211 | - const float dtheta = 2.f * M_PI / slices; |
212 | - Q_ASSERT(slices<=MAX_SLICES); |
213 | - |
214 | - ComputeCosSinTheta(dtheta,slices); |
215 | - float* cos_sin_theta_p; |
216 | - |
217 | drho/=textureFov; |
218 | |
219 | // texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y axis |
220 | @@ -1546,28 +1377,6 @@ |
221 | // GZ This used to draw a full sphere. Now it's possible to have a spherical zone only. |
222 | void StelPainter::sSphere(const float radius, const float oneMinusOblateness, const int slices, const int stacks, const int orientInside, const bool flipTexture, const float topAngle, const float bottomAngle) |
223 | { |
224 | - // It is really good for performance to have Vec4f,Vec3f objects |
225 | - // static rather than on the stack. But why? |
226 | - // Is the constructor/destructor so expensive? |
227 | - static Vec3f lightPos3; |
228 | - static Vec4f ambientLight; |
229 | - static Vec4f diffuseLight; |
230 | - float c; |
231 | - const bool isLightOn = light.isEnabled(); |
232 | - if (isLightOn) |
233 | - { |
234 | - lightPos3.set(light.getPosition()[0], light.getPosition()[1], light.getPosition()[2]); |
235 | - Vec3f tmpv(0.f); |
236 | - prj->getModelViewTransform()->forward(tmpv); // -posCenterEye |
237 | - //lightPos3 -= tmpv; |
238 | - //lightPos3 = prj->modelViewMatrixf.transpose().multiplyWithoutTranslation(lightPos3); |
239 | - prj->getModelViewTransform()->getApproximateLinearTransfo().transpose().multiplyWithoutTranslation(Vec3d(lightPos3[0], lightPos3[1], lightPos3[2])); |
240 | - prj->getModelViewTransform()->backward(lightPos3); |
241 | - lightPos3.normalize(); |
242 | - ambientLight = light.getAmbient(); |
243 | - diffuseLight = light.getDiffuse(); |
244 | - } |
245 | - |
246 | GLfloat x, y, z; |
247 | GLfloat s=0.f, t=0.f; |
248 | GLint i, j; |
249 | @@ -1584,20 +1393,19 @@ |
250 | t=1.f; |
251 | } |
252 | |
253 | + const float* cos_sin_rho = NULL; |
254 | Q_ASSERT(topAngle<bottomAngle); // don't forget: These are opening angles counted from top. |
255 | - const float drho = (bottomAngle-topAngle) / stacks; // deltaRho: originally just 180degrees/stacks, now the range clamped. |
256 | - Q_ASSERT(stacks<=MAX_STACKS); |
257 | - //if ((bottomAngle==M_PI) && (topAngle==0)) |
258 | if ((bottomAngle>3.1415) && (topAngle<0.0001)) // safety margin. |
259 | - ComputeCosSinRho(drho, stacks); |
260 | + cos_sin_rho = StelUtils::ComputeCosSinRho(stacks); |
261 | else |
262 | - ComputeCosSinRhoZone(drho, stacks, M_PI-bottomAngle); |
263 | + { |
264 | + const float drho = (bottomAngle-topAngle) / stacks; // deltaRho: originally just 180degrees/stacks, now the range clamped. |
265 | + cos_sin_rho = StelUtils::ComputeCosSinRhoZone(drho, stacks, M_PI-bottomAngle); |
266 | + } |
267 | // GZ: Allow parameters so that pole regions may remain free. |
268 | - float* cos_sin_rho_p; |
269 | + const float* cos_sin_rho_p; |
270 | |
271 | - const float dtheta = 2.f * M_PI / slices; |
272 | - Q_ASSERT(slices<=MAX_SLICES); |
273 | - ComputeCosSinTheta(dtheta,slices); |
274 | + const float* cos_sin_theta = StelUtils::ComputeCosSinTheta(slices); |
275 | const float *cos_sin_theta_p; |
276 | |
277 | // texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y axis |
278 | @@ -1627,23 +1435,11 @@ |
279 | y = cos_sin_theta_p[0] * cos_sin_rho_p[1]; |
280 | z = nsign * cos_sin_rho_p[0]; |
281 | texCoordArr << s << t; |
282 | - if (isLightOn) |
283 | - { |
284 | - c = nsign * (lightPos3[0]*x*oneMinusOblateness + lightPos3[1]*y*oneMinusOblateness + lightPos3[2]*z); |
285 | - if (c<0) {c=0;} |
286 | - colorArr << c*diffuseLight[0] + ambientLight[0] << c*diffuseLight[1] + ambientLight[1] << c*diffuseLight[2] + ambientLight[2]; |
287 | - } |
288 | vertexArr << x * radius << y * radius << z * oneMinusOblateness * radius; |
289 | x = -cos_sin_theta_p[1] * cos_sin_rho_p[3]; |
290 | y = cos_sin_theta_p[0] * cos_sin_rho_p[3]; |
291 | z = nsign * cos_sin_rho_p[2]; |
292 | texCoordArr << s << t - dt; |
293 | - if (isLightOn) |
294 | - { |
295 | - c = nsign * (lightPos3[0]*x*oneMinusOblateness + lightPos3[1]*y*oneMinusOblateness + lightPos3[2]*z); |
296 | - if (c<0) {c=0;} |
297 | - colorArr << c*diffuseLight[0] + ambientLight[0] << c*diffuseLight[1] + ambientLight[1] << c*diffuseLight[2] + ambientLight[2]; |
298 | - } |
299 | vertexArr << x * radius << y * radius << z * oneMinusOblateness * radius; |
300 | s += ds; |
301 | } |
302 | @@ -1657,10 +1453,7 @@ |
303 | } |
304 | |
305 | // Draw the array now |
306 | - if (isLightOn) |
307 | - setArrays((Vec3d*)vertexArr.constData(), (Vec2f*)texCoordArr.constData(), (Vec3f*)colorArr.constData()); |
308 | - else |
309 | - setArrays((Vec3d*)vertexArr.constData(), (Vec2f*)texCoordArr.constData()); |
310 | + setArrays((Vec3d*)vertexArr.constData(), (Vec2f*)texCoordArr.constData()); |
311 | drawFromArray(Triangles, indiceArr.size(), 0, true, indiceArr.constData()); |
312 | } |
313 | |
314 | @@ -1682,14 +1475,10 @@ |
315 | t=1.f; |
316 | } |
317 | |
318 | - const float drho = M_PI / stacks; |
319 | - Q_ASSERT(stacks<=MAX_STACKS); |
320 | - ComputeCosSinRho(drho,stacks); |
321 | - float* cos_sin_rho_p; |
322 | + const float* cos_sin_rho = StelUtils::ComputeCosSinRho(stacks); |
323 | + const float* cos_sin_rho_p; |
324 | |
325 | - const float dtheta = 2.f * M_PI / slices; |
326 | - Q_ASSERT(slices<=MAX_SLICES); |
327 | - ComputeCosSinTheta(dtheta,slices); |
328 | + const float* cos_sin_theta = StelUtils::ComputeCosSinTheta(slices); |
329 | const float *cos_sin_theta_p; |
330 | |
331 | // texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y axis |
332 | @@ -1726,8 +1515,6 @@ |
333 | t -= dt; |
334 | } |
335 | return result; |
336 | - //setArrays((Vec3d*)vertexArr.constData(), (Vec2f*)texCoordArr.constData()); |
337 | - //drawFromArray(Triangles, indiceArr.size(), 0, true, indiceArr.constData()); |
338 | } |
339 | |
340 | // Reimplementation of gluCylinder : glu is overrided for non standard projection |
341 | @@ -2018,7 +1805,6 @@ |
342 | else |
343 | { |
344 | qDebug() << "Unhandled parameters." << texCoordArray.enabled << colorArray.enabled << normalArray.enabled; |
345 | - qDebug() << "Light: " << light.isEnabled(); |
346 | Q_ASSERT(0); |
347 | return; |
348 | } |
349 | @@ -2092,42 +1878,3 @@ |
350 | return ret; |
351 | } |
352 | |
353 | -// Light methods |
354 | - |
355 | -void StelPainterLight::setPosition(const Vec4f& v) |
356 | -{ |
357 | - position = v; |
358 | -} |
359 | - |
360 | -void StelPainterLight::setDiffuse(const Vec4f& v) |
361 | -{ |
362 | - diffuse = v; |
363 | -} |
364 | - |
365 | -void StelPainterLight::setSpecular(const Vec4f& v) |
366 | -{ |
367 | - specular = v; |
368 | -} |
369 | - |
370 | -void StelPainterLight::setAmbient(const Vec4f& v) |
371 | -{ |
372 | - ambient = v; |
373 | -} |
374 | - |
375 | -void StelPainterLight::setEnable(bool v) |
376 | -{ |
377 | - if (v) |
378 | - enable(); |
379 | - else |
380 | - disable(); |
381 | -} |
382 | - |
383 | -void StelPainterLight::enable() |
384 | -{ |
385 | - enabled = true; |
386 | -} |
387 | - |
388 | -void StelPainterLight::disable() |
389 | -{ |
390 | - enabled = false; |
391 | -} |
392 | |
393 | === modified file 'src/core/StelPainter.hpp' |
394 | --- src/core/StelPainter.hpp 2014-05-23 22:05:02 +0000 |
395 | +++ src/core/StelPainter.hpp 2014-06-04 22:13:44 +0000 |
396 | @@ -30,38 +30,6 @@ |
397 | |
398 | class QOpenGLShaderProgram; |
399 | |
400 | -class StelPainterLight |
401 | -{ |
402 | -public: |
403 | - StelPainterLight(int alight=0) : light(alight), enabled(false) {} |
404 | - |
405 | - void setPosition(const Vec4f& v); |
406 | - Vec4f& getPosition() {return position;} |
407 | - |
408 | - void setDiffuse(const Vec4f& v); |
409 | - Vec4f& getDiffuse() {return diffuse;} |
410 | - |
411 | - void setSpecular(const Vec4f& v); |
412 | - Vec4f& getSpecular() {return specular;} |
413 | - |
414 | - void setAmbient(const Vec4f& v); |
415 | - Vec4f& getAmbient() {return ambient;} |
416 | - |
417 | - void setEnable(bool v); |
418 | - void enable(); |
419 | - void disable(); |
420 | - bool isEnabled() const {return enabled;} |
421 | - |
422 | -private: |
423 | - int light; |
424 | - Vec4f position; |
425 | - Vec4f diffuse; |
426 | - Vec4f specular; |
427 | - Vec4f ambient; |
428 | - bool enabled; |
429 | -}; |
430 | - |
431 | - |
432 | //! @class StelPainter |
433 | //! Provides functions for performing openGL drawing operations. |
434 | //! All coordinates are converted using the StelProjector instance passed at construction. |
435 | @@ -225,9 +193,6 @@ |
436 | //! @param texCoordArr the vertex array in which the resulting texture coordinates are returned. |
437 | static void computeFanDisk(float radius, int innerFanSlices, int level, QVector<double>& vertexArr, QVector<float>& texCoordArr); |
438 | |
439 | - //! Draw a ring with a radial texturing. |
440 | - void sRing(const float rMin, const float rMax, int slices, const int stacks, const int orientInside); |
441 | - |
442 | //! Draw a fisheye texture in a sphere. |
443 | void sSphereMap(const float radius, const int slices, const int stacks, const float textureFov = 2.f*M_PI, const int orientInside = 0); |
444 | |
445 | @@ -240,9 +205,6 @@ |
446 | //! Get the color currently used for drawing. |
447 | Vec4f getColor() const; |
448 | |
449 | - //! Get the light |
450 | - StelPainterLight& getLight() {return light;} |
451 | - |
452 | //! Get the font metrics for the current font. |
453 | QFontMetrics getFontMetrics() const; |
454 | |
455 | @@ -404,9 +366,6 @@ |
456 | ArrayDesc normalArray; |
457 | //! The descriptor for the current opengl color array |
458 | ArrayDesc colorArray; |
459 | - |
460 | - //! the single light used by the painter |
461 | - StelPainterLight light; |
462 | }; |
463 | |
464 | #endif // _STELPAINTER_HPP_ |
465 | |
466 | === modified file 'src/core/StelTexture.cpp' |
467 | --- src/core/StelTexture.cpp 2014-05-23 22:05:02 +0000 |
468 | +++ src/core/StelTexture.cpp 2014-06-04 22:13:44 +0000 |
469 | @@ -108,12 +108,12 @@ |
470 | Bind the texture so that it can be used for openGL drawing (calls glBindTexture) |
471 | *************************************************************************/ |
472 | |
473 | -bool StelTexture::bind() |
474 | +bool StelTexture::bind(int slot) |
475 | { |
476 | if (id != 0) |
477 | { |
478 | // The texture is already fully loaded, just bind and return true; |
479 | - glActiveTexture(GL_TEXTURE0); |
480 | + glActiveTexture(GL_TEXTURE0 + slot); |
481 | glBindTexture(GL_TEXTURE_2D, id); |
482 | return true; |
483 | } |
484 | |
485 | === modified file 'src/core/StelTexture.hpp' |
486 | --- src/core/StelTexture.hpp 2014-05-23 22:05:02 +0000 |
487 | +++ src/core/StelTexture.hpp 2014-06-04 22:13:44 +0000 |
488 | @@ -65,7 +65,7 @@ |
489 | //! If the texture is lazyly loaded, this starts the loading and return false immediately. |
490 | //! @return true if the binding successfully occured, false if the texture is not yet loaded. |
491 | |
492 | - bool bind(); |
493 | + bool bind(int slot=0); |
494 | |
495 | //! Return whether the texture can be binded, i.e. it is fully loaded |
496 | bool canBind() const {return id!=0;} |
497 | |
498 | === modified file 'src/core/StelUtils.cpp' |
499 | --- src/core/StelUtils.cpp 2014-05-23 22:05:02 +0000 |
500 | +++ src/core/StelUtils.cpp 2014-06-04 22:13:44 +0000 |
501 | @@ -1780,5 +1780,105 @@ |
502 | return sigma; |
503 | } |
504 | |
505 | + |
506 | +// Arrays to keep cos/sin of angles and multiples of angles. rho and theta are delta angles, and these arrays |
507 | +#define MAX_STACKS 4096 |
508 | +static float cos_sin_rho[2*(MAX_STACKS+1)]; |
509 | +#define MAX_SLICES 4096 |
510 | +static float cos_sin_theta[2*(MAX_SLICES+1)]; |
511 | + |
512 | +//! Compute cosines and sines around a circle which is split in "segments" parts. |
513 | +//! Values are stored in the global static array cos_sin_theta. |
514 | +//! Used for the sin/cos values along a latitude circle, equator, etc. for a spherical mesh. |
515 | +//! @param slices number of partitions (elsewhere called "segments") for the circle |
516 | +float* ComputeCosSinTheta(const int slices) |
517 | +{ |
518 | + Q_ASSERT(slices<=MAX_SLICES); |
519 | + |
520 | + // Difference angle between the stops. Always use 2*M_PI/slices! |
521 | + const float dTheta = 2.f * M_PI / slices; |
522 | + float *cos_sin = cos_sin_theta; |
523 | + float *cos_sin_rev = cos_sin + 2*(slices+1); |
524 | + const float c = std::cos(dTheta); |
525 | + const float s = std::sin(dTheta); |
526 | + *cos_sin++ = 1.f; |
527 | + *cos_sin++ = 0.f; |
528 | + *--cos_sin_rev = -cos_sin[-1]; |
529 | + *--cos_sin_rev = cos_sin[-2]; |
530 | + *cos_sin++ = c; |
531 | + *cos_sin++ = s; |
532 | + *--cos_sin_rev = -cos_sin[-1]; |
533 | + *--cos_sin_rev = cos_sin[-2]; |
534 | + while (cos_sin < cos_sin_rev) // compares array address indices only! |
535 | + { |
536 | + // avoid expensive trig functions by use of the addition theorem. |
537 | + cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s; |
538 | + cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c; |
539 | + cos_sin += 2; |
540 | + *--cos_sin_rev = -cos_sin[-1]; |
541 | + *--cos_sin_rev = cos_sin[-2]; |
542 | + } |
543 | + return cos_sin_theta; |
544 | +} |
545 | + |
546 | +//! Compute cosines and sines around a half-circle which is split in "segments" parts. |
547 | +//! Values are stored in the global static array cos_sin_rho. |
548 | +//! Used for the sin/cos values along a meridian for a spherical mesh. |
549 | +//! @param segments number of partitions (elsewhere called "stacks") for the half-circle |
550 | +float* ComputeCosSinRho(const int segments) |
551 | +{ |
552 | + Q_ASSERT(segments<=MAX_STACKS); |
553 | + |
554 | + // Difference angle between the stops. Always use M_PI/segments! |
555 | + const float dRho = M_PI / segments; |
556 | + float *cos_sin = cos_sin_rho; |
557 | + float *cos_sin_rev = cos_sin + 2*(segments+1); |
558 | + const float c = std::cos(dRho); |
559 | + const float s = std::sin(dRho); |
560 | + *cos_sin++ = 1.f; |
561 | + *cos_sin++ = 0.f; |
562 | + *--cos_sin_rev = cos_sin[-1]; |
563 | + *--cos_sin_rev = -cos_sin[-2]; |
564 | + *cos_sin++ = c; |
565 | + *cos_sin++ = s; |
566 | + *--cos_sin_rev = cos_sin[-1]; |
567 | + *--cos_sin_rev = -cos_sin[-2]; |
568 | + while (cos_sin < cos_sin_rev) // compares array address indices only! |
569 | + { |
570 | + // avoid expensive trig functions by use of the addition theorem. |
571 | + cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s; |
572 | + cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c; |
573 | + cos_sin += 2; |
574 | + *--cos_sin_rev = cos_sin[-1]; |
575 | + *--cos_sin_rev = -cos_sin[-2]; |
576 | + } |
577 | + |
578 | + return cos_sin_rho; |
579 | +} |
580 | + |
581 | +//! Compute cosines and sines around part of a circle (from top to bottom) which is split in "segments" parts. |
582 | +//! Values are stored in the global static array cos_sin_rho. |
583 | +//! Used for the sin/cos values along a meridian. |
584 | +//! GZ: allow leaving away pole caps. The array now contains values for the region minAngle+segments*phi |
585 | +//! @param dRho a difference angle between the stops |
586 | +//! @param segments number of segments |
587 | +//! @param minAngle start angle inside the half-circle. maxAngle=minAngle+segments*phi |
588 | +float *ComputeCosSinRhoZone(const float dRho, const int segments, const float minAngle) |
589 | +{ |
590 | + float *cos_sin = cos_sin_rho; |
591 | + const float c = cos(dRho); |
592 | + const float s = sin(dRho); |
593 | + *cos_sin++ = cos(minAngle); |
594 | + *cos_sin++ = sin(minAngle); |
595 | + for (int i=0; i<segments; ++i) // we cannot mirror this, it may be unequal. |
596 | + { // efficient computation, avoid expensive trig functions by use of the addition theorem. |
597 | + cos_sin[0] = cos_sin[-2]*c - cos_sin[-1]*s; |
598 | + cos_sin[1] = cos_sin[-2]*s + cos_sin[-1]*c; |
599 | + cos_sin += 2; |
600 | + } |
601 | + return cos_sin_rho; |
602 | +} |
603 | + |
604 | + |
605 | } // end of the StelUtils namespace |
606 | |
607 | |
608 | === modified file 'src/core/StelUtils.hpp' |
609 | --- src/core/StelUtils.hpp 2014-05-23 22:05:02 +0000 |
610 | +++ src/core/StelUtils.hpp 2014-06-04 22:13:44 +0000 |
611 | @@ -36,6 +36,7 @@ |
612 | // speed of light (km/sec) |
613 | #define SPEED_OF_LIGHT 299792.458 |
614 | |
615 | + |
616 | //! @namespace StelUtils contains general purpose utility functions. |
617 | namespace StelUtils |
618 | { |
619 | @@ -570,6 +571,27 @@ |
620 | template <typename T> int sign(T val) { |
621 | return (T(0) < val) - (val < T(0)); |
622 | } |
623 | + |
624 | + //! Compute cosines and sines around a circle which is split in "segments" parts. |
625 | + //! Values are stored in the global static array cos_sin_theta. |
626 | + //! Used for the sin/cos values along a latitude circle, equator, etc. for a spherical mesh. |
627 | + //! @param slices number of partitions (elsewhere called "segments") for the circle |
628 | + float *ComputeCosSinTheta(const int slices); |
629 | + |
630 | + //! Compute cosines and sines around a half-circle which is split in "segments" parts. |
631 | + //! Values are stored in the global static array cos_sin_rho. |
632 | + //! Used for the sin/cos values along a meridian for a spherical mesh. |
633 | + //! @param segments number of partitions (elsewhere called "stacks") for the half-circle |
634 | + float *ComputeCosSinRho(const int segments); |
635 | + |
636 | + //! Compute cosines and sines around part of a circle (from top to bottom) which is split in "segments" parts. |
637 | + //! Values are stored in the global static array cos_sin_rho. |
638 | + //! Used for the sin/cos values along a meridian. |
639 | + //! GZ: allow leaving away pole caps. The array now contains values for the region minAngle+segments*phi |
640 | + //! @param dRho a difference angle between the stops |
641 | + //! @param segments number of segments |
642 | + //! @param minAngle start angle inside the half-circle. maxAngle=minAngle+segments*phi |
643 | + float* ComputeCosSinRhoZone(const float dRho, const int segments, const float minAngle); |
644 | } |
645 | |
646 | #endif // _STELUTILS_HPP_ |
647 | |
648 | === modified file 'src/core/modules/Comet.cpp' |
649 | --- src/core/modules/Comet.cpp 2014-04-14 15:40:40 +0000 |
650 | +++ src/core/modules/Comet.cpp 2014-06-04 22:13:44 +0000 |
651 | @@ -368,7 +368,6 @@ |
652 | |
653 | void Comet::drawTail(StelCore* core, StelProjector::ModelViewTranformP transfo, bool gas) |
654 | { |
655 | - |
656 | // Find rotation matrix from 0/0/1 to eclipticPosition: crossproduct for axis (normal vector), dotproduct for angle. |
657 | Vec3d eclposNrm=eclipticPos; eclposNrm.normalize(); |
658 | Mat4d tailrot=Mat4d::rotation(Vec3d(0.0, 0.0, 1.0)^(eclposNrm), std::acos(Vec3d(0.0, 0.0, 1.0).dot(eclposNrm)) ); |
659 | @@ -388,7 +387,6 @@ |
660 | transfo2->combine(dustTailYrot); |
661 | } |
662 | StelPainter* sPainter = new StelPainter(core->getProjection(transfo2)); |
663 | - sPainter->getLight().disable(); |
664 | glEnable(GL_BLEND); |
665 | glBlendFunc(GL_ONE, GL_ONE); |
666 | glDisable(GL_CULL_FACE); |
667 | @@ -439,14 +437,12 @@ |
668 | |
669 | void Comet::drawComa(StelCore* core, StelProjector::ModelViewTranformP transfo) |
670 | { |
671 | - |
672 | // Find rotation matrix from 0/0/1 to viewdirection! crossproduct for axis (normal vector), dotproduct for angle. |
673 | Vec3d eclposNrm=eclipticPos - core->getObserverHeliocentricEclipticPos() ; eclposNrm.normalize(); |
674 | Mat4d comarot=Mat4d::rotation(Vec3d(0.0, 0.0, 1.0)^(eclposNrm), std::acos(Vec3d(0.0, 0.0, 1.0).dot(eclposNrm)) ); |
675 | StelProjector::ModelViewTranformP transfo2 = transfo->clone(); |
676 | transfo2->combine(comarot); |
677 | StelPainter* sPainter = new StelPainter(core->getProjection(transfo2)); |
678 | - sPainter->getLight().disable(); |
679 | |
680 | glEnable(GL_BLEND); |
681 | glBlendFunc(GL_ONE, GL_ONE); |
682 | @@ -460,7 +456,6 @@ |
683 | float magFactor=std::pow(0.6f , magDrop); |
684 | magFactor=qMin(magFactor, 2.0f); // Limit excessively bright display. |
685 | |
686 | - |
687 | comaTexture->bind(); |
688 | sPainter->setColor(magFactor,magFactor,0.6f*magFactor); |
689 | sPainter->setArrays((Vec3d*)comaVertexArr.constData(), (Vec2f*)comaTexCoordArr.constData()); |
690 | |
691 | === modified file 'src/core/modules/Planet.cpp' |
692 | --- src/core/modules/Planet.cpp 2014-05-23 22:05:02 +0000 |
693 | +++ src/core/modules/Planet.cpp 2014-06-04 22:13:44 +0000 |
694 | @@ -40,11 +40,58 @@ |
695 | #include <QString> |
696 | #include <QDebug> |
697 | #include <QVarLengthArray> |
698 | +#include <QOpenGLShader> |
699 | + |
700 | +#ifndef NDEBUG |
701 | +static const char* get_gl_error_text(int code) { |
702 | + switch (code) { |
703 | + case GL_INVALID_ENUM: |
704 | + return "GL_INVALID_ENUM"; |
705 | + case GL_INVALID_FRAMEBUFFER_OPERATION: |
706 | + return "GL_INVALID_FRAMEBUFFER_OPERATION"; |
707 | + case GL_INVALID_VALUE: |
708 | + return "GL_INVALID_VALUE"; |
709 | + case GL_INVALID_OPERATION: |
710 | + return "GL_INVALID_OPERATION"; |
711 | + case GL_OUT_OF_MEMORY: |
712 | + return "GL_OUT_OF_MEMORY"; |
713 | + default: |
714 | + return "undefined error"; |
715 | + } |
716 | +} |
717 | + |
718 | +int check_gl_errors(const char *file, int line) |
719 | +{ |
720 | + int errors = 0; |
721 | + while (true) |
722 | + { |
723 | + GLenum x = glGetError(); |
724 | + if (x == GL_NO_ERROR) |
725 | + return errors; |
726 | + printf("%s:%d: OpenGL error: %d (%s)\n", |
727 | + file, line, x, get_gl_error_text(x)); |
728 | + errors++; |
729 | + } |
730 | +} |
731 | +#endif |
732 | + |
733 | +#ifndef NDEBUG |
734 | +# define GL(line) do { \ |
735 | + line; \ |
736 | + if (check_gl_errors(__FILE__, __LINE__)) \ |
737 | + exit(-1); \ |
738 | + } while(0) |
739 | +#else |
740 | +# define GL(line) line |
741 | +#endif |
742 | |
743 | Vec3f Planet::labelColor = Vec3f(0.4,0.4,0.8); |
744 | Vec3f Planet::orbitColor = Vec3f(1,0.6,1); |
745 | StelTextureSP Planet::hintCircleTex; |
746 | StelTextureSP Planet::texEarthShadow; |
747 | +QOpenGLShaderProgram* Planet::shaderProgram=NULL; |
748 | +Planet::ShaderVars Planet::shaderVars; |
749 | + |
750 | Planet::Planet(const QString& englishName, |
751 | int flagLighting, |
752 | double radius, |
753 | @@ -316,6 +363,50 @@ |
754 | return re.obliquity; |
755 | } |
756 | |
757 | + |
758 | +bool willCastShadow(const Planet* thisPlanet, const Planet* p) |
759 | +{ |
760 | + Vec3d thisPos = thisPlanet->getHeliocentricEclipticPos(); |
761 | + Vec3d planetPos = p->getHeliocentricEclipticPos(); |
762 | + |
763 | + // If the planet p is farther from the sun than this planet, it can't cast shadow on it. |
764 | + if (planetPos.lengthSquared()>thisPos.lengthSquared()) |
765 | + return false; |
766 | + |
767 | + Vec3d ppVector = planetPos; |
768 | + ppVector.normalize(); |
769 | + |
770 | + double shadowDistance = ppVector * thisPos; |
771 | + static const double sunRadius = 696000./AU; |
772 | + double d = planetPos.length() / (p->getRadius()/sunRadius+1); |
773 | + double penumbraRadius = (shadowDistance-d)/d*sunRadius; |
774 | + |
775 | + double penumbraCenterToThisPlanetCenterDistance = (ppVector*shadowDistance-thisPos).length(); |
776 | + |
777 | + if (penumbraCenterToThisPlanetCenterDistance<penumbraRadius+thisPlanet->getRadius()) |
778 | + return true; |
779 | + return false; |
780 | +} |
781 | + |
782 | +QVector<const Planet*> Planet::getCandidatesForShadow() const |
783 | +{ |
784 | + QVector<const Planet*> res; |
785 | + const SolarSystem *ssystem=GETSTELMODULE(SolarSystem); |
786 | + const Planet* sun = ssystem->getSun().data(); |
787 | + if (this==sun || (parent.data()==sun && satellites.empty())) |
788 | + return res; |
789 | + |
790 | + foreach (const PlanetP& planet, satellites) |
791 | + { |
792 | + if (willCastShadow(this, planet.data())) |
793 | + res.append(planet.data()); |
794 | + } |
795 | + if (willCastShadow(this, parent.data())) |
796 | + res.append(parent.data()); |
797 | + |
798 | + return res; |
799 | +} |
800 | + |
801 | void Planet::computePosition(const double date) |
802 | { |
803 | |
804 | @@ -822,8 +913,7 @@ |
805 | // Draw the rings if we are located on a planet with rings, but not the planet itself. |
806 | if (rings) |
807 | { |
808 | - StelPainter sPainter(core->getProjection(transfo)); |
809 | - rings->draw(&sPainter,transfo,1000.0); |
810 | + draw3dModel(core, transfo, 1024, true); |
811 | } |
812 | return; |
813 | } |
814 | @@ -861,7 +951,191 @@ |
815 | return; |
816 | } |
817 | |
818 | -void Planet::draw3dModel(StelCore* core, StelProjector::ModelViewTranformP transfo, float screenSz) |
819 | +class StelPainterLight |
820 | +{ |
821 | +public: |
822 | + Vec3f position; |
823 | + Vec3f diffuse; |
824 | + Vec3f ambient; |
825 | +}; |
826 | +static StelPainterLight light; |
827 | + |
828 | +void Planet::initShader() |
829 | +{ |
830 | + // Default planet texture shader program |
831 | + QOpenGLShader vshader(QOpenGLShader::Vertex); |
832 | + const char *vsrc = |
833 | + "attribute highp vec3 vertex;\n" |
834 | + "attribute highp vec3 unprojectedVertex;\n" |
835 | + "attribute mediump vec2 texCoord;\n" |
836 | + "uniform highp mat4 projectionMatrix;\n" |
837 | + "uniform highp vec3 lightPos;\n" |
838 | + "varying mediump vec2 texc;\n" |
839 | + "varying mediump float lambert;\n" |
840 | + "varying highp vec3 P;\n" |
841 | + "\n" |
842 | + "void main()\n" |
843 | + "{\n" |
844 | + " gl_Position = projectionMatrix * vec4(vertex, 1.);\n" |
845 | + " texc = texCoord;\n" |
846 | + " vec3 normal = normalize(unprojectedVertex);\n" |
847 | + " float c = lightPos.x * normal.x +\n" |
848 | + " lightPos.y * normal.y +\n" |
849 | + " lightPos.z * normal.z;\n" |
850 | + " lambert = clamp(c, 0.0, 1.0);\n" |
851 | + "\n" |
852 | + " P = unprojectedVertex;\n" |
853 | + "}\n" |
854 | + "\n"; |
855 | + vshader.compileSourceCode(vsrc); |
856 | + if (!vshader.log().isEmpty()) { qWarning() << "Planet: Warnings while compiling vshader: " << vshader.log(); } |
857 | + |
858 | + QOpenGLShader fshader(QOpenGLShader::Fragment); |
859 | + |
860 | + const char *fsrc = |
861 | + "varying mediump vec2 texc;\n" |
862 | + "varying mediump float lambert;\n" |
863 | + "uniform sampler2D tex;\n" |
864 | + "uniform mediump vec3 ambientLight;\n" |
865 | + "uniform mediump vec3 diffuseLight;\n" |
866 | + "uniform highp vec4 sunInfo;\n" |
867 | + "\n" |
868 | + "varying highp vec3 P;\n" |
869 | + "\n" |
870 | + "uniform int shadowCount;\n" |
871 | + "uniform highp mat4 shadowData;\n" |
872 | + "\n" |
873 | + "uniform bool ring;\n" |
874 | + "uniform highp float outerRadius;\n" |
875 | + "uniform highp float innerRadius;\n" |
876 | + "uniform sampler2D ringS;\n" |
877 | + "uniform bool isRing;\n" |
878 | + "\n" |
879 | + "uniform bool isMoon;\n" |
880 | + "uniform sampler2D earthShadow;\n" |
881 | + "\n" |
882 | + "void main()\n" |
883 | + "{\n" |
884 | + " float final_illumination = 1.0;\n" |
885 | + " if(lambert > 0.0 || isRing)\n" |
886 | + " {\n" |
887 | + " vec3 sunPosition = sunInfo.xyz;\n" |
888 | + " if(ring && !isRing)\n" |
889 | + " {\n" |
890 | + " vec3 ray = normalize(sunPosition);\n" |
891 | + " float u = - P.z / ray.z;\n" |
892 | + " if(u > 0.0 && u < 1e10)\n" |
893 | + " {\n" |
894 | + " float ring_radius = length(P + u * ray);\n" |
895 | + " if(ring_radius > innerRadius && ring_radius < outerRadius)\n" |
896 | + " {\n" |
897 | + " ring_radius = (ring_radius - innerRadius) / (outerRadius - innerRadius);\n" |
898 | + " float ringAlpha = texture2D(ringS, vec2(ring_radius, 0.5)).w;\n" |
899 | + " final_illumination = 1.0 - ringAlpha;\n" |
900 | + " }\n" |
901 | + " }\n" |
902 | + " }\n" |
903 | + "\n" |
904 | + " float sunRadius = sunInfo.w;\n" |
905 | + " float L = length(sunPosition - P);\n" |
906 | + " float R = asin(sunRadius / L);\n" |
907 | + " for (int i = 0; i < shadowCount; ++i)\n" |
908 | + " {\n" |
909 | + " vec3 satellitePosition = shadowData[i].xyz;\n" |
910 | + " float satelliteRadius = shadowData[i].w;\n" |
911 | + " float l = length(satellitePosition - P);\n" |
912 | + " float r = asin(satelliteRadius / l);\n" |
913 | + " float d = acos(min(1.0, dot(normalize(sunPosition - P), normalize(satellitePosition - P))));\n" |
914 | + "\n" |
915 | + " float illumination = 1.0;\n" |
916 | + "\n" |
917 | + " // distance too far\n" |
918 | + " if(d >= R + r)\n" |
919 | + " {\n" |
920 | + " illumination = 1.0;\n" |
921 | + " }\n" |
922 | + " // umbra\n" |
923 | + " else if(r >= R + d)\n" |
924 | + " {\n" |
925 | + " if(isMoon)\n" |
926 | + " illumination = d / (r - R) * 0.6;\n" |
927 | + " else" |
928 | + " illumination = 0.0;\n" |
929 | + " }\n" |
930 | + " // penumbra completely inside\n" |
931 | + " else if(d + r <= R)\n" |
932 | + " {\n" |
933 | + " illumination = 1.0 - r * r / (R * R);\n" |
934 | + " }\n" |
935 | + " // penumbra partially inside\n" |
936 | + " else\n" |
937 | + " {\n" |
938 | + " if(isMoon)\n" |
939 | + " illumination = ((d - abs(R-r)) / (R + r - abs(R-r))) * 0.4 + 0.6;\n" |
940 | + " else\n" |
941 | + " {\n" |
942 | + " float x = (R * R + d * d - r * r) / (2.0 * d);\n" |
943 | + " float alpha = acos(x / R);\n" |
944 | + " float beta = acos((d - x) / r);\n" |
945 | + " float AR = R * R * (alpha - 0.5 * sin(2.0 * alpha));\n" |
946 | + " float Ar = r * r * (beta - 0.5 * sin(2.0 * beta));\n" |
947 | + " float AS = R * R * 2.0 * 1.57079633;\n" |
948 | + " illumination = 1.0 - (AR + Ar) / AS;\n" |
949 | + " }\n" |
950 | + " }\n" |
951 | + "\n" |
952 | + " if(illumination < final_illumination)\n" |
953 | + " final_illumination = illumination;\n" |
954 | + " }\n" |
955 | + " }\n" |
956 | + "\n" |
957 | + " vec4 litColor = vec4((isRing ? 1.0 : lambert) * final_illumination * diffuseLight + ambientLight, 1.0);\n" |
958 | + " if(isMoon && final_illumination < 1.0)\n" |
959 | + " {\n" |
960 | + " vec4 shadowColor = texture2D(earthShadow, vec2(final_illumination, 0.5));\n" |
961 | + " gl_FragColor = mix(texture2D(tex, texc) * litColor, shadowColor, shadowColor.a);\n" |
962 | + " }\n" |
963 | + " else\n" |
964 | + " gl_FragColor = texture2D(tex, texc) * litColor;\n" |
965 | + "}\n" |
966 | + "\n"; |
967 | + fshader.compileSourceCode(fsrc); |
968 | + if (!fshader.log().isEmpty()) { qWarning() << "Planet: Warnings while compiling fshader: " << fshader.log(); } |
969 | + |
970 | + shaderProgram = new QOpenGLShaderProgram(QOpenGLContext::currentContext()); |
971 | + shaderProgram->addShader(&vshader); |
972 | + shaderProgram->addShader(&fshader); |
973 | + GL(StelPainter::linkProg(shaderProgram, "planetShaderProgram")); |
974 | + GL(shaderProgram->bind()); |
975 | + GL(shaderVars.projectionMatrix = shaderProgram->uniformLocation("projectionMatrix")); |
976 | + GL(shaderVars.texCoord = shaderProgram->attributeLocation("texCoord")); |
977 | + GL(shaderVars.unprojectedVertex = shaderProgram->attributeLocation("unprojectedVertex")); |
978 | + GL(shaderVars.vertex = shaderProgram->attributeLocation("vertex")); |
979 | + GL(shaderVars.texture = shaderProgram->uniformLocation("tex")); |
980 | + |
981 | + GL(shaderVars.lightPos = shaderProgram->uniformLocation("lightPos")); |
982 | + GL(shaderVars.diffuseLight = shaderProgram->uniformLocation("diffuseLight")); |
983 | + GL(shaderVars.ambientLight = shaderProgram->uniformLocation("ambientLight")); |
984 | + GL(shaderVars.shadowCount = shaderProgram->uniformLocation("shadowCount")); |
985 | + GL(shaderVars.shadowData = shaderProgram->uniformLocation("shadowData")); |
986 | + GL(shaderVars.sunInfo = shaderProgram->uniformLocation("sunInfo")); |
987 | + GL(shaderVars.isRing = shaderProgram->uniformLocation("isRing")); |
988 | + GL(shaderVars.ring = shaderProgram->uniformLocation("ring")); |
989 | + GL(shaderVars.outerRadius = shaderProgram->uniformLocation("outerRadius")); |
990 | + GL(shaderVars.innerRadius = shaderProgram->uniformLocation("innerRadius")); |
991 | + GL(shaderVars.ringS = shaderProgram->uniformLocation("ringS")); |
992 | + GL(shaderVars.isMoon = shaderProgram->uniformLocation("isMoon")); |
993 | + GL(shaderVars.earthShadow = shaderProgram->uniformLocation("earthShadow")); |
994 | + GL(shaderProgram->release()); |
995 | +} |
996 | + |
997 | +void Planet::deinitShader() |
998 | +{ |
999 | + delete shaderProgram; |
1000 | + shaderProgram = NULL; |
1001 | +} |
1002 | + |
1003 | +void Planet::draw3dModel(StelCore* core, StelProjector::ModelViewTranformP transfo, float screenSz, bool drawOnlyRing) |
1004 | { |
1005 | // This is the main method drawing a planet 3d model |
1006 | // Some work has to be done on this method to make the rendering nicer |
1007 | @@ -872,39 +1146,33 @@ |
1008 | StelProjector::ModelViewTranformP transfo2 = transfo->clone(); |
1009 | transfo2->combine(Mat4d::zrotation(M_PI/180*(axisRotation + 90.))); |
1010 | StelPainter* sPainter = new StelPainter(core->getProjection(transfo2)); |
1011 | - |
1012 | + |
1013 | if (flagLighting) |
1014 | { |
1015 | - sPainter->getLight().enable(); |
1016 | - |
1017 | // Set the main source of light to be the sun |
1018 | Vec3d sunPos(0); |
1019 | core->getHeliocentricEclipticModelViewTransform()->forward(sunPos); |
1020 | - sPainter->getLight().setPosition(Vec4f(sunPos[0],sunPos[1],sunPos[2],1.f)); |
1021 | + light.position=Vec4f(sunPos[0],sunPos[1],sunPos[2],1.f); |
1022 | |
1023 | // Set the light parameters taking sun as the light source |
1024 | - static Vec4f diffuse = Vec4f(1.f,1.f,1.f,1.f); |
1025 | - static Vec4f zero = Vec4f(0.f,0.f,0.f,0.f); |
1026 | - static Vec4f ambient = Vec4f(0.02f,0.02f,0.02f,0.02f); |
1027 | + light.diffuse = Vec4f(1.f,1.f,1.f); |
1028 | + light.ambient = Vec4f(0.02f,0.02f,0.02f); |
1029 | |
1030 | if (this==ssm->getMoon()) |
1031 | { |
1032 | // Special case for the Moon (maybe better use 1.5,1.5,1.5,1.0 ?) |
1033 | - diffuse = Vec4f(1.6f,1.6f,1.6f,1.f); |
1034 | + light.diffuse = Vec4f(1.6f,1.6f,1.6f,1.f); |
1035 | } |
1036 | - |
1037 | - sPainter->getLight().setAmbient(ambient); |
1038 | - sPainter->getLight().setDiffuse(diffuse); |
1039 | - sPainter->getLight().setSpecular(zero); |
1040 | } |
1041 | else |
1042 | { |
1043 | - sPainter->getLight().disable(); |
1044 | sPainter->setColor(albedo,albedo,albedo); |
1045 | } |
1046 | |
1047 | if (rings) |
1048 | { |
1049 | + // The planet has rings, we need to use depth buffer and adjust the clipping planes to avoid |
1050 | + // reaching the maximum resolution of the depth buffer |
1051 | const double dist = getEquinoxEquatorialPos(core).length(); |
1052 | double z_near = 0.9*(dist - rings->getSize()); |
1053 | double z_far = 1.1*(dist + rings->getSize()); |
1054 | @@ -912,48 +1180,22 @@ |
1055 | double n,f; |
1056 | core->getClippingPlanes(&n,&f); // Save clipping planes |
1057 | core->setClippingPlanes(z_near,z_far); |
1058 | - glDepthMask(GL_TRUE); |
1059 | - glClear(GL_DEPTH_BUFFER_BIT); |
1060 | - glEnable(GL_DEPTH_TEST); |
1061 | + |
1062 | + drawSphere(sPainter, screenSz, drawOnlyRing); |
1063 | + |
1064 | + core->setClippingPlanes(n,f); // Restore old clipping planes |
1065 | + } |
1066 | + else |
1067 | + { |
1068 | + // Normal planet |
1069 | drawSphere(sPainter, screenSz); |
1070 | - glDepthMask(GL_FALSE); |
1071 | - sPainter->getLight().disable(); |
1072 | - rings->draw(sPainter,transfo,screenSz); |
1073 | - sPainter->getLight().enable(); |
1074 | - glDisable(GL_DEPTH_TEST); |
1075 | - core->setClippingPlanes(n,f); // Restore old clipping planes |
1076 | - } |
1077 | - else |
1078 | - { |
1079 | - if (this==ssm->getMoon() && core->getCurrentLocation().planetName=="Earth" && ssm->nearLunarEclipse()) |
1080 | - { |
1081 | - // Draw earth shadow over moon using stencil buffer if appropriate |
1082 | - // This effect curently only looks right from earth viewpoint |
1083 | - // TODO: moon magnitude label during eclipse isn't accurate... |
1084 | - glClearStencil(0x0); |
1085 | - glClear(GL_STENCIL_BUFFER_BIT); |
1086 | - glStencilFunc(GL_ALWAYS, 0x1, 0x1); |
1087 | - glStencilOp(GL_ZERO, GL_REPLACE, GL_REPLACE); |
1088 | - glEnable(GL_STENCIL_TEST); |
1089 | - drawSphere(sPainter, screenSz); |
1090 | - glDisable(GL_STENCIL_TEST); |
1091 | - |
1092 | - sPainter->getLight().disable(); |
1093 | - drawEarthShadow(core, sPainter); |
1094 | - } |
1095 | - else |
1096 | - { |
1097 | - // Normal planet |
1098 | - drawSphere(sPainter, screenSz); |
1099 | - } |
1100 | - } |
1101 | - if (sPainter) |
1102 | - delete sPainter; |
1103 | + } |
1104 | + delete sPainter; |
1105 | sPainter=NULL; |
1106 | } |
1107 | |
1108 | // Draw the halo if it enabled in the ssystem.ini file (+ special case for backward compatible for the Sun) |
1109 | - if (hasHalo() || getEnglishName().contains("Sun")) |
1110 | + if (hasHalo() || this==ssm->getSun()) |
1111 | { |
1112 | // Prepare openGL lighting parameters according to luminance |
1113 | float surfArcMin2 = getSpheroidAngularSize(core)*60; |
1114 | @@ -965,8 +1207,120 @@ |
1115 | } |
1116 | } |
1117 | |
1118 | - |
1119 | -void Planet::drawSphere(StelPainter* painter, float screenSz) |
1120 | +struct Planet3DModel |
1121 | +{ |
1122 | + QVector<float> vertexArr; |
1123 | + QVector<float> texCoordArr; |
1124 | + QVector<unsigned short> indiceArr; |
1125 | +}; |
1126 | + |
1127 | +void sSphere(Planet3DModel* model, const float radius, const float oneMinusOblateness, const int slices, const int stacks) |
1128 | +{ |
1129 | + model->indiceArr.resize(0); |
1130 | + model->vertexArr.resize(0); |
1131 | + model->texCoordArr.resize(0); |
1132 | + |
1133 | + GLfloat x, y, z; |
1134 | + GLfloat s=0.f, t=1.f; |
1135 | + GLint i, j; |
1136 | + |
1137 | + const float* cos_sin_rho = StelUtils::ComputeCosSinRho(stacks); |
1138 | + const float* cos_sin_theta = StelUtils::ComputeCosSinTheta(slices); |
1139 | + |
1140 | + const float* cos_sin_rho_p; |
1141 | + const float *cos_sin_theta_p; |
1142 | + |
1143 | + // texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y axis |
1144 | + // t goes from -1.0/+1.0 at z = -radius/+radius (linear along longitudes) |
1145 | + // cannot use triangle fan on texturing (s coord. at top/bottom tip varies) |
1146 | + // If the texture is flipped, we iterate the coordinates backward. |
1147 | + const GLfloat ds = 1.f / slices; |
1148 | + const GLfloat dt = 1.f / stacks; // from inside texture is reversed |
1149 | + |
1150 | + // draw intermediate as quad strips |
1151 | + for (i = 0,cos_sin_rho_p = cos_sin_rho; i < stacks; ++i,cos_sin_rho_p+=2) |
1152 | + { |
1153 | + s = 0.f; |
1154 | + for (j = 0,cos_sin_theta_p = cos_sin_theta; j<=slices;++j,cos_sin_theta_p+=2) |
1155 | + { |
1156 | + x = -cos_sin_theta_p[1] * cos_sin_rho_p[1]; |
1157 | + y = cos_sin_theta_p[0] * cos_sin_rho_p[1]; |
1158 | + z = cos_sin_rho_p[0]; |
1159 | + model->texCoordArr << s << t; |
1160 | + model->vertexArr << x * radius << y * radius << z * oneMinusOblateness * radius; |
1161 | + x = -cos_sin_theta_p[1] * cos_sin_rho_p[3]; |
1162 | + y = cos_sin_theta_p[0] * cos_sin_rho_p[3]; |
1163 | + z = cos_sin_rho_p[2]; |
1164 | + model->texCoordArr << s << t - dt; |
1165 | + model->vertexArr << x * radius << y * radius << z * oneMinusOblateness * radius; |
1166 | + s += ds; |
1167 | + } |
1168 | + unsigned int offset = i*(slices+1)*2; |
1169 | + for (j = 2;j<slices*2+2;j+=2) |
1170 | + { |
1171 | + model->indiceArr << offset+j-2 << offset+j-1 << offset+j; |
1172 | + model->indiceArr << offset+j << offset+j-1 << offset+j+1; |
1173 | + } |
1174 | + t -= dt; |
1175 | + } |
1176 | +} |
1177 | + |
1178 | +struct Ring3DModel |
1179 | +{ |
1180 | + QVector<float> vertexArr; |
1181 | + QVector<float> texCoordArr; |
1182 | + QVector<unsigned short> indiceArr; |
1183 | +}; |
1184 | + |
1185 | + |
1186 | +void sRing(Ring3DModel* model, const float rMin, const float rMax, int slices, const int stacks) |
1187 | +{ |
1188 | + float x,y; |
1189 | + |
1190 | + const float dr = (rMax-rMin) / stacks; |
1191 | + const float* cos_sin_theta = StelUtils::ComputeCosSinTheta(slices); |
1192 | + const float* cos_sin_theta_p; |
1193 | + |
1194 | + model->vertexArr.resize(0); |
1195 | + model->texCoordArr.resize(0); |
1196 | + model->indiceArr.resize(0); |
1197 | + |
1198 | + float r = rMin; |
1199 | + for (int i=0; i<=stacks; ++i) |
1200 | + { |
1201 | + const float tex_r0 = (r-rMin)/(rMax-rMin); |
1202 | + int j; |
1203 | + for (j=0,cos_sin_theta_p=cos_sin_theta; j<=slices; ++j,cos_sin_theta_p+=2) |
1204 | + { |
1205 | + x = r*cos_sin_theta_p[0]; |
1206 | + y = r*cos_sin_theta_p[1]; |
1207 | + model->texCoordArr << tex_r0 << 0.5f; |
1208 | + model->vertexArr << x << y << 0.f; |
1209 | + } |
1210 | + r+=dr; |
1211 | + } |
1212 | + for (int i=0; i<stacks; ++i) |
1213 | + { |
1214 | + for (int j=0; j<slices; ++j) |
1215 | + { |
1216 | + model->indiceArr << i*slices+j << (i+1)*slices+j << i*slices+j+1; |
1217 | + model->indiceArr << i*slices+j+1 << (i+1)*slices+j << (i+1)*slices+j+1; |
1218 | + } |
1219 | + } |
1220 | +} |
1221 | + |
1222 | +void Planet::computeModelMatrix(Mat4d &result) const |
1223 | +{ |
1224 | + result = Mat4d::translation(eclipticPos) * rotLocalToParent * Mat4d::zrotation(M_PI/180*(axisRotation + 90.)); |
1225 | + PlanetP p = parent; |
1226 | + while (p && p->parent) |
1227 | + { |
1228 | + result = Mat4d::translation(p->eclipticPos) * result * p->rotLocalToParent; |
1229 | + p = p->parent; |
1230 | + } |
1231 | +} |
1232 | + |
1233 | +void Planet::drawSphere(StelPainter* painter, float screenSz, bool drawOnlyRing) |
1234 | { |
1235 | if (texMap) |
1236 | { |
1237 | @@ -976,119 +1330,166 @@ |
1238 | return; |
1239 | } |
1240 | } |
1241 | - //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GZ deactivated. 2013-12-27. If disabling blend, who cares which one? |
1242 | - painter->setColor(1.f, 1.f, 1.f); |
1243 | - |
1244 | painter->enableTexture2d(true); |
1245 | glDisable(GL_BLEND); |
1246 | glEnable(GL_CULL_FACE); |
1247 | |
1248 | // Draw the spheroid itself |
1249 | // Adapt the number of facets according with the size of the sphere for optimization |
1250 | - int nb_facet = (int)(screenSz * 40/50); // 40 facets for 1024 pixels diameter on screen |
1251 | + int nb_facet = (int)(screenSz * 40.f/50.f); // 40 facets for 1024 pixels diameter on screen |
1252 | if (nb_facet<10) nb_facet = 10; |
1253 | - if (nb_facet>40) nb_facet = 40; |
1254 | - // Rotate and add an extra quarter rotation so that the planet texture map |
1255 | - // fits to the observers position. No idea why this is necessary, |
1256 | - // perhaps some openGl strangeness, or confusing sin/cos. |
1257 | - |
1258 | - painter->sSphere(radius*sphereScale, oneMinusOblateness, nb_facet, nb_facet); |
1259 | + if (nb_facet>100) nb_facet = 100; |
1260 | + |
1261 | + // Generates the vertice |
1262 | + Planet3DModel model; |
1263 | + sSphere(&model, radius*sphereScale, oneMinusOblateness, nb_facet, nb_facet); |
1264 | + |
1265 | + QVector<float> projectedVertexArr; |
1266 | + projectedVertexArr.resize(model.vertexArr.size()); |
1267 | + for (int i=0;i<model.vertexArr.size()/3;++i) |
1268 | + painter->getProjector()->project(*((Vec3f*)(model.vertexArr.constData()+i*3)), *((Vec3f*)(projectedVertexArr.data()+i*3))); |
1269 | + |
1270 | + if (englishName=="Sun") |
1271 | + { |
1272 | + texMap->bind(); |
1273 | + painter->setColor(2, 2, 2); |
1274 | + painter->setArrays((Vec3f*)projectedVertexArr.constData(), (Vec2f*)model.texCoordArr.constData()); |
1275 | + painter->drawFromArray(StelPainter::Triangles, model.indiceArr.size(), 0, false, model.indiceArr.constData()); |
1276 | + return; |
1277 | + } |
1278 | + |
1279 | + if (shaderProgram==NULL) |
1280 | + Planet::initShader(); |
1281 | + Q_ASSERT(shaderProgram!=NULL); |
1282 | + GL(shaderProgram->bind()); |
1283 | + |
1284 | + const Mat4f& m = painter->getProjector()->getProjectionMatrix(); |
1285 | + const QMatrix4x4 qMat(m[0], m[4], m[8], m[12], m[1], m[5], m[9], m[13], m[2], m[6], m[10], m[14], m[3], m[7], m[11], m[15]); |
1286 | + shaderProgram->setUniformValue(shaderVars.projectionMatrix, qMat); |
1287 | + |
1288 | + Mat4d modelMatrix; |
1289 | + computeModelMatrix(modelMatrix); |
1290 | + // TODO explain this |
1291 | + const Mat4d mTarget = modelMatrix.inverse(); |
1292 | + |
1293 | + QMatrix4x4 shadowCandidatesData; |
1294 | + QVector<const Planet*> shadowCandidates = getCandidatesForShadow(); |
1295 | + // Our shader doesn't support more than 4 planets creating shadow |
1296 | + if (shadowCandidates.size()>4) |
1297 | + shadowCandidates.resize(4); |
1298 | + for (int i=0;i<shadowCandidates.size();++i) |
1299 | + { |
1300 | + shadowCandidates.at(i)->computeModelMatrix(modelMatrix); |
1301 | + const Vec4d position = mTarget * modelMatrix.getColumn(3); |
1302 | + shadowCandidatesData(0, i) = position[0]; |
1303 | + shadowCandidatesData(1, i) = position[1]; |
1304 | + shadowCandidatesData(2, i) = position[2]; |
1305 | + shadowCandidatesData(3, i) = shadowCandidates.at(i)->getRadius(); |
1306 | + } |
1307 | + |
1308 | + const StelProjectorP& projector = painter->getProjector(); |
1309 | + |
1310 | + Vec3f lightPos3; |
1311 | + lightPos3.set(light.position[0], light.position[1], light.position[2]); |
1312 | + Vec3f tmpv(0.f); |
1313 | + projector->getModelViewTransform()->forward(tmpv); |
1314 | + projector->getModelViewTransform()->getApproximateLinearTransfo().transpose().multiplyWithoutTranslation(Vec3d(lightPos3[0], lightPos3[1], lightPos3[2])); |
1315 | + projector->getModelViewTransform()->backward(lightPos3); |
1316 | + lightPos3.normalize(); |
1317 | + |
1318 | + GL(shaderProgram->setUniformValue(shaderVars.lightPos, lightPos3[0], lightPos3[1], lightPos3[2])); |
1319 | + GL(shaderProgram->setUniformValue(shaderVars.diffuseLight, light.diffuse[0], light.diffuse[1], light.diffuse[2])); |
1320 | + GL(shaderProgram->setUniformValue(shaderVars.ambientLight, light.ambient[0], light.ambient[1], light.ambient[2])); |
1321 | + GL(shaderProgram->setUniformValue(shaderVars.texture, 0)); |
1322 | + GL(shaderProgram->setUniformValue(shaderVars.shadowCount, shadowCandidates.size())); |
1323 | + GL(shaderProgram->setUniformValue(shaderVars.shadowData, shadowCandidatesData)); |
1324 | + |
1325 | + const SolarSystem* ssm = GETSTELMODULE(SolarSystem); |
1326 | + GL(shaderProgram->setUniformValue(shaderVars.sunInfo, mTarget[12], mTarget[13], mTarget[14], ssm->getSun()->getRadius())); |
1327 | + GL(shaderProgram->setUniformValue(shaderVars.isRing, false)); |
1328 | + |
1329 | + GL(shaderProgram->setUniformValue(shaderVars.ring, rings!=NULL)); |
1330 | + if (rings!=NULL) |
1331 | + { |
1332 | + rings->tex->bind(2); |
1333 | + GL(shaderProgram->setUniformValue(shaderVars.outerRadius, rings->radiusMax)); |
1334 | + GL(shaderProgram->setUniformValue(shaderVars.innerRadius, rings->radiusMin)); |
1335 | + GL(shaderProgram->setUniformValue(shaderVars.ringS, rings ? 2 : 0)); |
1336 | + } |
1337 | + |
1338 | + const bool isMoon = (this==ssm->getMoon()); |
1339 | + if (isMoon) |
1340 | + texEarthShadow->bind(3); |
1341 | + GL(shaderProgram->setUniformValue(shaderVars.isMoon, isMoon)); |
1342 | + GL(shaderProgram->setUniformValue(shaderVars.earthShadow, isMoon ? 3: 0)); |
1343 | + |
1344 | + GL(texMap->bind(1)); |
1345 | + |
1346 | + GL(shaderProgram->setAttributeArray(shaderVars.vertex, (const GLfloat*)projectedVertexArr.constData(), 3)); |
1347 | + GL(shaderProgram->enableAttributeArray(shaderVars.vertex)); |
1348 | + GL(shaderProgram->setAttributeArray(shaderVars.unprojectedVertex, (const GLfloat*)model.vertexArr.constData(), 3)); |
1349 | + GL(shaderProgram->enableAttributeArray(shaderVars.unprojectedVertex)); |
1350 | + GL(shaderProgram->setAttributeArray(shaderVars.texCoord, (const GLfloat*)model.texCoordArr.constData(), 2)); |
1351 | + GL(shaderProgram->enableAttributeArray(shaderVars.texCoord)); |
1352 | + |
1353 | + if (rings) |
1354 | + { |
1355 | + glDepthMask(GL_TRUE); |
1356 | + glClear(GL_DEPTH_BUFFER_BIT); |
1357 | + glEnable(GL_DEPTH_TEST); |
1358 | + } |
1359 | + |
1360 | + if (!drawOnlyRing) |
1361 | + GL(glDrawElements(GL_TRIANGLES, model.indiceArr.size(), GL_UNSIGNED_SHORT, model.indiceArr.constData())); |
1362 | + |
1363 | + if (rings) |
1364 | + { |
1365 | + // Draw the rings just after the planet |
1366 | + |
1367 | + glDepthMask(GL_FALSE); |
1368 | + |
1369 | + // Normal transparency mode |
1370 | + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
1371 | + glEnable(GL_BLEND); |
1372 | + |
1373 | + Ring3DModel ringModel; |
1374 | + sRing(&ringModel, rings->radiusMin, rings->radiusMax, 128, 32); |
1375 | + |
1376 | + GL(shaderProgram->setUniformValue(shaderVars.isRing, true)); |
1377 | + GL(shaderProgram->setUniformValue(shaderVars.texture, 2)); |
1378 | + |
1379 | + computeModelMatrix(modelMatrix); |
1380 | + const Vec4d position = mTarget * modelMatrix.getColumn(3); |
1381 | + shadowCandidatesData(0, 0) = position[0]; |
1382 | + shadowCandidatesData(1, 0) = position[1]; |
1383 | + shadowCandidatesData(2, 0) = position[2]; |
1384 | + shadowCandidatesData(3, 0) = getRadius(); |
1385 | + GL(shaderProgram->setUniformValue(shaderVars.shadowCount, 1)); |
1386 | + GL(shaderProgram->setUniformValue(shaderVars.shadowData, shadowCandidatesData)); |
1387 | + |
1388 | + projectedVertexArr.resize(ringModel.vertexArr.size()); |
1389 | + for (int i=0;i<ringModel.vertexArr.size()/3;++i) |
1390 | + painter->getProjector()->project(*((Vec3f*)(ringModel.vertexArr.constData()+i*3)), *((Vec3f*)(projectedVertexArr.data()+i*3))); |
1391 | + |
1392 | + GL(shaderProgram->setAttributeArray(shaderVars.vertex, (const GLfloat*)projectedVertexArr.constData(), 3)); |
1393 | + GL(shaderProgram->enableAttributeArray(shaderVars.vertex)); |
1394 | + GL(shaderProgram->setAttributeArray(shaderVars.unprojectedVertex, (const GLfloat*)ringModel.vertexArr.constData(), 3)); |
1395 | + GL(shaderProgram->enableAttributeArray(shaderVars.unprojectedVertex)); |
1396 | + GL(shaderProgram->setAttributeArray(shaderVars.texCoord, (const GLfloat*)ringModel.texCoordArr.constData(), 2)); |
1397 | + GL(shaderProgram->enableAttributeArray(shaderVars.texCoord)); |
1398 | + |
1399 | + glDisable(GL_CULL_FACE); |
1400 | + |
1401 | + GL(glDrawElements(GL_TRIANGLES, ringModel.indiceArr.size(), GL_UNSIGNED_SHORT, ringModel.indiceArr.constData())); |
1402 | + |
1403 | + glDisable(GL_DEPTH_TEST); |
1404 | + } |
1405 | + |
1406 | + GL(shaderProgram->release()); |
1407 | + |
1408 | glDisable(GL_CULL_FACE); |
1409 | } |
1410 | |
1411 | -// draws earth shadow overlapping the moon using stencil buffer |
1412 | -// umbra and penumbra are sized separately for accuracy |
1413 | -void Planet::drawEarthShadow(StelCore* core, StelPainter* sPainter) |
1414 | -{ |
1415 | - SolarSystem* ssm = GETSTELMODULE(SolarSystem); |
1416 | - Vec3d e = ssm->getEarth()->getEclipticPos(); |
1417 | - Vec3d m = ssm->getMoon()->getEclipticPos(); // relative to earth |
1418 | - Vec3d mh = ssm->getMoon()->getHeliocentricEclipticPos(); // relative to sun |
1419 | - float mscale = ssm->getMoon()->getSphereScale(); |
1420 | - |
1421 | - // shadow location at earth + moon distance along earth vector from sun |
1422 | - Vec3d en = e; |
1423 | - en.normalize(); |
1424 | - Vec3d shadow = en * (e.length() + m.length()); |
1425 | - |
1426 | - // find shadow radii in AU |
1427 | - double r_penumbra = shadow.length()*702378.1/AU/e.length() - 696000./AU; |
1428 | - double r_umbra = 6378.1/AU - m.length()*(689621.9/AU/e.length()); |
1429 | - |
1430 | - // find vector orthogonal to sun-earth vector using cross product with |
1431 | - // a non-parallel vector |
1432 | - Vec3d rpt = shadow^Vec3d(0,0,1); |
1433 | - rpt.normalize(); |
1434 | - Vec3d upt = rpt*r_umbra*mscale*1.02; // point on umbra edge |
1435 | - rpt *= r_penumbra*mscale; // point on penumbra edge |
1436 | - |
1437 | - // modify shadow location for scaled moon |
1438 | - Vec3d mdist = shadow - mh; |
1439 | - if (mdist.length() > r_penumbra + 2000./AU) |
1440 | - return; // not visible so don't bother drawing |
1441 | - |
1442 | - shadow = mh + mdist*mscale; |
1443 | - |
1444 | - StelProjectorP saveProj = sPainter->getProjector(); |
1445 | - sPainter->setProjector(core->getProjection(StelCore::FrameHeliocentricEcliptic)); |
1446 | - |
1447 | - sPainter->enableTexture2d(true); |
1448 | - glEnable(GL_BLEND); |
1449 | - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
1450 | - sPainter->setColor(1,1,1); |
1451 | - |
1452 | - glEnable(GL_STENCIL_TEST); |
1453 | - // We draw only where the stencil buffer is at 1, i.e. where the moon was drawn |
1454 | - glStencilFunc(GL_EQUAL, 0x1, 0x1); |
1455 | - // Don't change stencil buffer value |
1456 | - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); |
1457 | - |
1458 | - // shadow radial texture |
1459 | - texEarthShadow->bind(); |
1460 | - |
1461 | - Vec3d r; |
1462 | - |
1463 | - // Draw umbra first |
1464 | - QVector<Vec2f> texCoordArray; |
1465 | - QVector<Vec3d> vertexArray; |
1466 | - texCoordArray.reserve(210); |
1467 | - vertexArray.reserve(210); |
1468 | - texCoordArray << Vec2f(0.f, 0.5f); |
1469 | - // johannes: work-around for nasty ATI rendering bug: use y-texture coordinate of 0.5 instead of 0.0 |
1470 | - vertexArray << shadow; |
1471 | - |
1472 | - const Mat4d& rotMat = Mat4d::rotation(shadow, 2.*M_PI/100.); |
1473 | - r = upt; |
1474 | - for (int i=1; i<=101; ++i) |
1475 | - { |
1476 | - // position in texture of umbra edge |
1477 | - texCoordArray << Vec2f(0.6f, 0.5f); |
1478 | - r.transfo4d(rotMat); |
1479 | - vertexArray << shadow + r; |
1480 | - } |
1481 | - sPainter->setArrays(vertexArray.constData(), texCoordArray.constData()); |
1482 | - sPainter->drawFromArray(StelPainter::TriangleFan, 102); |
1483 | - |
1484 | - // now penumbra |
1485 | - vertexArray.resize(0); |
1486 | - texCoordArray.resize(0); |
1487 | - Vec3d u; |
1488 | - r = rpt; |
1489 | - u = upt; |
1490 | - for (int i=0; i<=200; i+=2) |
1491 | - { |
1492 | - r.transfo4d(rotMat); |
1493 | - u.transfo4d(rotMat); |
1494 | - texCoordArray << Vec2f(0.6f, 0.5f) << Vec2f(1.f, 0.5f); // position in texture of umbra edge |
1495 | - vertexArray << shadow + u << shadow + r; |
1496 | - } |
1497 | - sPainter->setArrays(vertexArray.constData(), texCoordArray.constData()); |
1498 | - sPainter->drawFromArray(StelPainter::TriangleStrip, 202); |
1499 | - glDisable(GL_STENCIL_TEST); |
1500 | - glClearStencil(0x0); |
1501 | - glClear(GL_STENCIL_BUFFER_BIT); // Clean again to let a clean buffer for later Qt display |
1502 | - sPainter->setProjector(saveProj); |
1503 | -} |
1504 | |
1505 | void Planet::drawHints(const StelCore* core, const QFont& planetNameFont) |
1506 | { |
1507 | @@ -1118,44 +1519,12 @@ |
1508 | sPainter.drawSprite2dMode(screenPos[0], screenPos[1], 11); |
1509 | } |
1510 | |
1511 | -Ring::Ring(double radiusMin,double radiusMax,const QString &texname) |
1512 | +Ring::Ring(float radiusMin, float radiusMax, const QString &texname) |
1513 | :radiusMin(radiusMin),radiusMax(radiusMax) |
1514 | { |
1515 | tex = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/"+texname); |
1516 | } |
1517 | |
1518 | -Ring::~Ring(void) |
1519 | -{ |
1520 | -} |
1521 | - |
1522 | -void Ring::draw(StelPainter* sPainter,StelProjector::ModelViewTranformP transfo,double screenSz) |
1523 | -{ |
1524 | - screenSz -= 50; |
1525 | - screenSz /= 250.0; |
1526 | - if (screenSz < 0.0) screenSz = 0.0; |
1527 | - else if (screenSz > 1.0) screenSz = 1.0; |
1528 | - const int slices = 128+(int)((256-128)*screenSz); |
1529 | - const int stacks = 8+(int)((32-8)*screenSz); |
1530 | - |
1531 | - // Normal transparency mode |
1532 | - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
1533 | - sPainter->setColor(1.f, 1.f, 1.f); |
1534 | - sPainter->enableTexture2d(true); |
1535 | - glEnable(GL_CULL_FACE); |
1536 | - glEnable(GL_BLEND); |
1537 | - |
1538 | - if (tex) tex->bind(); |
1539 | - |
1540 | - Mat4d mat = transfo->getApproximateLinearTransfo(); |
1541 | - // solve the ring wraparound by culling: |
1542 | - // decide if we are above or below the ring plane |
1543 | - const double h = mat.r[ 8]*mat.r[12] |
1544 | - + mat.r[ 9]*mat.r[13] |
1545 | - + mat.r[10]*mat.r[14]; |
1546 | - sPainter->sRing(radiusMin,radiusMax,(h<0.0)?slices:-slices,stacks, 0); |
1547 | - glDisable(GL_CULL_FACE); |
1548 | -} |
1549 | - |
1550 | |
1551 | // draw orbital path of Planet |
1552 | void Planet::drawOrbit(const StelCore* core) |
1553 | |
1554 | === modified file 'src/core/modules/Planet.hpp' |
1555 | --- src/core/modules/Planet.hpp 2014-05-23 22:05:02 +0000 |
1556 | +++ src/core/modules/Planet.hpp 2014-06-04 22:13:44 +0000 |
1557 | @@ -43,13 +43,6 @@ |
1558 | class StelPainter; |
1559 | class StelTranslator; |
1560 | |
1561 | -struct TrailPoint |
1562 | -{ |
1563 | - Vec3d point; |
1564 | - double date; |
1565 | -}; |
1566 | - |
1567 | - |
1568 | // Class used to store orbital elements |
1569 | class RotationElements |
1570 | { |
1571 | @@ -68,13 +61,10 @@ |
1572 | class Ring |
1573 | { |
1574 | public: |
1575 | - Ring(double radiusMin,double radiusMax,const QString &texname); |
1576 | - ~Ring(void); |
1577 | - void draw(StelPainter* painter, StelProjector::ModelViewTranformP transfo, double screenSz); |
1578 | + Ring(float radiusMin, float radiusMax,const QString &texname); |
1579 | double getSize(void) const {return radiusMax;} |
1580 | -private: |
1581 | - const double radiusMin; |
1582 | - const double radiusMax; |
1583 | + const float radiusMin; |
1584 | + const float radiusMax; |
1585 | StelTextureSP tex; |
1586 | }; |
1587 | |
1588 | @@ -241,20 +231,22 @@ |
1589 | static void setOrbitColor(const Vec3f& oc) {orbitColor = oc;} |
1590 | static const Vec3f& getOrbitColor() {return orbitColor;} |
1591 | |
1592 | + //! Return the list of planets which project some shadow on this planet |
1593 | + QVector<const Planet*> getCandidatesForShadow() const; |
1594 | + |
1595 | protected: |
1596 | static StelTextureSP texEarthShadow; // for lunar eclipses |
1597 | |
1598 | - // draw earth shadow on moon for lunar eclipses |
1599 | - void drawEarthShadow(StelCore* core, StelPainter* sPainter); |
1600 | - |
1601 | + void computeModelMatrix(Mat4d &result) const; |
1602 | + |
1603 | // Return the information string "ready to print" :) |
1604 | QString getSkyLabel(const StelCore* core) const; |
1605 | |
1606 | // Draw the 3d model. Call the proper functions if there are rings etc.. |
1607 | - void draw3dModel(StelCore* core, StelProjector::ModelViewTranformP transfo, float screenSz); |
1608 | + void draw3dModel(StelCore* core, StelProjector::ModelViewTranformP transfo, float screenSz, bool drawOnlyRing=false); |
1609 | |
1610 | // Draw the 3D sphere |
1611 | - void drawSphere(StelPainter* painter, float screenSz); |
1612 | + void drawSphere(StelPainter* painter, float screenSz, bool drawOnlyRing=false); |
1613 | |
1614 | // Draw the circle and name of the Planet |
1615 | void drawHints(const StelCore* core, const QFont& planetNameFont); |
1616 | @@ -299,6 +291,34 @@ |
1617 | |
1618 | static Vec3f labelColor; |
1619 | static StelTextureSP hintCircleTex; |
1620 | + |
1621 | + // Shader-related variables |
1622 | + struct ShaderVars { |
1623 | + int projectionMatrix; |
1624 | + int texCoord; |
1625 | + int unprojectedVertex; |
1626 | + int vertex; |
1627 | + int texture; |
1628 | + |
1629 | + int lightPos; |
1630 | + int diffuseLight; |
1631 | + int ambientLight; |
1632 | + int shadowCount; |
1633 | + int shadowData; |
1634 | + int sunInfo; |
1635 | + int isRing; |
1636 | + int ring; |
1637 | + int outerRadius; |
1638 | + int innerRadius; |
1639 | + int ringS; |
1640 | + int isMoon; |
1641 | + int earthShadow; |
1642 | + }; |
1643 | + static ShaderVars shaderVars; |
1644 | + |
1645 | + static void initShader(); |
1646 | + static void deinitShader(); |
1647 | + static class QOpenGLShaderProgram* shaderProgram; |
1648 | }; |
1649 | |
1650 | #endif // _PLANET_HPP_ |
1651 | |
1652 | === modified file 'src/core/modules/SolarSystem.cpp' |
1653 | --- src/core/modules/SolarSystem.cpp 2014-05-23 22:05:02 +0000 |
1654 | +++ src/core/modules/SolarSystem.cpp 2014-06-04 22:13:44 +0000 |
1655 | @@ -147,7 +147,7 @@ |
1656 | |
1657 | texPointer = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/pointeur4.png"); |
1658 | Planet::hintCircleTex = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/planet-indicator.png"); |
1659 | - |
1660 | + |
1661 | StelApp *app = &StelApp::getInstance(); |
1662 | connect(app, SIGNAL(languageChanged()), this, SLOT(updateI18n())); |
1663 | connect(app, SIGNAL(colorSchemeChanged(const QString&)), this, SLOT(setStelStyle(const QString&))); |
1664 | @@ -158,6 +158,11 @@ |
1665 | addAction("actionShow_Planets_Trails", displayGroup, N_("Planet trails"), "trailsDisplayed", "Shift+T"); |
1666 | } |
1667 | |
1668 | +void SolarSystem::deinit() |
1669 | +{ |
1670 | + Planet::deinitShader(); |
1671 | +} |
1672 | + |
1673 | void SolarSystem::recreateTrails() |
1674 | { |
1675 | // Create a trail group containing all the planets orbiting the sun (not including satellites) |
1676 | |
1677 | === modified file 'src/core/modules/SolarSystem.hpp' |
1678 | --- src/core/modules/SolarSystem.hpp 2014-05-23 22:05:02 +0000 |
1679 | +++ src/core/modules/SolarSystem.hpp 2014-06-04 22:13:44 +0000 |
1680 | @@ -69,6 +69,8 @@ |
1681 | //! - set display options from application settings |
1682 | virtual void init(); |
1683 | |
1684 | + virtual void deinit(); |
1685 | + |
1686 | //! Draw SolarSystem objects (planets). |
1687 | //! @param core The StelCore object. |
1688 | //! @return The maximum squared distance in pixels that any SolarSystem object |
This code give strange effect on the Sun in the moment of solar eclipse.