Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
proceduralskytexturedata.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4/*
5 Based on "sky.cpp" from the Godot engine v3
6 Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.
7 Copyright (c) 2014-2022 Godot Engine contributors.
8*/
9
11#include <QtQuick3DRuntimeRender/private/qssgrendertexturedata_p.h>
12#include <QtQuick3DRuntimeRender/private/qssgrenderimage_p.h>
13
15
118{
119 scheduleTextureUpdate();
120}
121
125
127{
128 return m_skyTopColor;
129}
130
132{
133 return m_skyHorizonColor;
134}
135
137{
138 return m_skyCurve;
139}
140
142{
143 return m_skyEnergy;
144}
145
147{
148 return m_groundBottomColor;
149}
150
152{
153 return m_groundHorizonColor;
154}
155
157{
158 return m_groundCurve;
159}
160
162{
163 return m_groundEnergy;
164}
165
167{
168 return m_sunColor;
169}
170
172{
173 return m_sunLatitude;
174}
175
177{
178 return m_sunLongitude;
179}
180
182{
183 return m_sunAngleMin;
184}
185
187{
188 return m_sunAngleMax;
189}
190
192{
193 return m_sunCurve;
194}
195
197{
198 return m_sunEnergy;
199}
200
205
207{
208 if (m_skyTopColor == skyTopColor)
209 return;
210
211 m_skyTopColor = skyTopColor;
212 emit skyTopColorChanged(m_skyTopColor);
213 scheduleTextureUpdate();
214}
215
217{
218 if (m_skyHorizonColor == skyHorizonColor)
219 return;
220
221 m_skyHorizonColor = skyHorizonColor;
222 emit skyHorizonColorChanged(m_skyHorizonColor);
223 scheduleTextureUpdate();
224}
225
227{
228 if (qFuzzyCompare(m_skyCurve, skyCurve))
229 return;
230
231 m_skyCurve = skyCurve;
232 emit skyCurveChanged(m_skyCurve);
233 scheduleTextureUpdate();
234}
235
237{
238 if (qFuzzyCompare(m_skyEnergy, skyEnergy))
239 return;
240
241 m_skyEnergy = skyEnergy;
242 emit skyEnergyChanged(m_skyEnergy);
243 scheduleTextureUpdate();
244}
245
247{
248 if (m_groundBottomColor == groundBottomColor)
249 return;
250
251 m_groundBottomColor = groundBottomColor;
252 emit groundBottomColorChanged(m_groundBottomColor);
253 scheduleTextureUpdate();
254}
255
257{
258 if (m_groundHorizonColor == groundHorizonColor)
259 return;
260
261 m_groundHorizonColor = groundHorizonColor;
262 emit groundHorizonColorChanged(m_groundHorizonColor);
263 scheduleTextureUpdate();
264}
265
267{
268 if (qFuzzyCompare(m_groundCurve, groundCurve))
269 return;
270
271 m_groundCurve = groundCurve;
272 emit groundCurveChanged(m_groundCurve);
273 scheduleTextureUpdate();
274}
275
277{
278 if (qFuzzyCompare(m_groundEnergy, groundEnergy))
279 return;
280
281 m_groundEnergy = groundEnergy;
282 emit groundEnergyChanged(m_groundEnergy);
283 scheduleTextureUpdate();
284}
285
287{
288 if (m_sunColor == sunColor)
289 return;
290
291 m_sunColor = sunColor;
292 emit sunColorChanged(m_sunColor);
293 scheduleTextureUpdate();
294}
295
297{
298 if (qFuzzyCompare(m_sunLatitude, sunLatitude))
299 return;
300
301 m_sunLatitude = sunLatitude;
302 emit sunLatitudeChanged(m_sunLatitude);
303 scheduleTextureUpdate();
304}
305
307{
308 if (qFuzzyCompare(m_sunLongitude, sunLongitude))
309 return;
310
311 m_sunLongitude = sunLongitude;
312 emit sunLongitudeChanged(m_sunLongitude);
313 scheduleTextureUpdate();
314}
315
317{
318 if (qFuzzyCompare(m_sunAngleMin, sunAngleMin))
319 return;
320
321 m_sunAngleMin = sunAngleMin;
322 emit sunAngleMinChanged(m_sunAngleMin);
323 scheduleTextureUpdate();
324}
325
327{
328 if (qFuzzyCompare(m_sunAngleMax, sunAngleMax))
329 return;
330
331 m_sunAngleMax = sunAngleMax;
332 emit sunAngleMaxChanged(m_sunAngleMax);
333 scheduleTextureUpdate();
334}
335
337{
338 if (qFuzzyCompare(m_sunCurve, sunCurve))
339 return;
340
341 m_sunCurve = sunCurve;
342 emit sunCurveChanged(m_sunCurve);
343 scheduleTextureUpdate();
344}
345
347{
348 if (qFuzzyCompare(m_sunEnergy, sunEnergy))
349 return;
350
351 m_sunEnergy = sunEnergy;
352 emit sunEnergyChanged(m_sunEnergy);
353 scheduleTextureUpdate();
354}
355
357{
358 if (m_textureQuality == textureQuality)
359 return;
360
361 m_textureQuality = textureQuality;
362 emit textureQualityChanged(m_textureQuality);
363 scheduleTextureUpdate();
364}
365
367{
368 int size = 0;
369 switch (m_textureQuality) {
371 size = 512;
372 break;
374 size = 1024;
375 break;
377 size = 2048;
378 break;
380 size = 4096;
381 break;
382 }
383
384 const int width = size;
385 const int height = width / 2;
388 setHasTransparency(false);
389 const int dataSize = width * height * 4 * 2; // 2 bytes per channel
392 generateSkyTexture(width, height, imageData, false);
394}
395
396QByteArray ProceduralSkyTextureData::generateSkyTexture(int width, int height, QByteArray &imageData, bool isRGBE) const
397{
398 quint32 *data = reinterpret_cast<quint32 *>(imageData.data());
399
400 LinearColor skyTopLinear(m_skyTopColor);
401 LinearColor skyHorizonLinear(m_skyHorizonColor);
402 LinearColor groundBottomLinear(m_groundBottomColor);
403 LinearColor groundHorizonLinear(m_groundHorizonColor);
404 LinearColor sunLinear(m_sunColor);
405 sunLinear.r *= m_sunEnergy;
406 sunLinear.g *= m_sunEnergy;
407 sunLinear.b *= m_sunEnergy;
408
409 QVector3D sun(0, 0, -1);
410
411 sun = QQuaternion::fromAxisAndAngle(QVector3D(1, 0, 0), m_sunLatitude) * sun;
412 sun = QQuaternion::fromAxisAndAngle(QVector3D(0, 1, 0), m_sunLongitude) * sun;
413 sun.normalize();
414
415 auto clamp = [](float value, float min, float max) {
416 if (value < min)
417 return min;
418 else if (value > max)
419 return max;
420 return value;
421 };
422
423 auto ease = [](float x, float c) {
424 if (x < 0.0f)
425 x = 0.0f;
426 else if (x > 1.0f)
427 x = 1.0f;
428 if (c > 0.0f) {
429 if (c < 1.0f) {
430 return 1.0f - qPow(1.0f - x, 1.0f / c);
431 } else {
432 return qPow(x, c);
433 }
434 } else if (c < 0.0f) {
435 if (x < 0.5f) {
436 return qPow(x * 2.0f, -c) * 0.5f;
437 } else {
438 return (1.0f - qPow(1.0f - (x - 0.5f) * 2.0f, -c)) * 0.5f + 0.5f;
439 }
440 } else
441 return 0.0f;
442 };
443
444 for (int i = 0; i < width; i++) {
445
446 float u = float(i) / (width - 1);
447 float phi = u * 2.0 * M_PI;
448
449 for (int j = 0; j < height; j++) {
450 float v = float(j) / (height - 1);
451 float theta = v * M_PI;
452
453 QVector3D normal(qSin(phi) * qSin(theta) * -1.0,
454 qCos(theta),
455 qCos(phi) * qSin(theta) * -1.0);
456 normal.normalize();
457 float vAngle = qAcos(clamp(normal.y(), -1.0, 1.0));
458 LinearColor color;
459
460 if (normal.y() < 0) {
461 // Ground color
462 float c = (vAngle - (M_PI * 0.5f)) / (M_PI * 0.5f);
463 color = groundHorizonLinear.interpolate(groundBottomLinear, ease(c, m_groundCurve));
464 color.r *= m_groundEnergy;
465 color.g *= m_groundEnergy;
466 color.b *= m_groundEnergy;
467 } else {
468 // Sky color
469 float c = vAngle / (M_PI * 0.5f);
470 color = skyHorizonLinear.interpolate(skyTopLinear, ease(1.0 - c, m_skyCurve));
471 color.r *= m_skyEnergy;
472 color.g *= m_skyEnergy;
473 color.b *= m_skyEnergy;
474
475 float sunAngle = qRadiansToDegrees(qAcos(clamp(QVector3D::dotProduct(sun, normal), -1.0f, 1.0f)));
476 if (sunAngle < m_sunAngleMin) {
477 color = color.blend(sunLinear);
478 } else if (sunAngle < m_sunAngleMax) {
479 float c2 = (sunAngle - m_sunAngleMin) / (m_sunAngleMax - m_sunAngleMin);
480 c2 = ease(c2, m_sunCurve);
481 color = color.blend(sunLinear).interpolate(color, c2);
482 }
483 }
484
485 // Write from bottom to top
486 if (isRGBE) {
487 data[(height - j - 1) * width + i] = color.toRGBE8();
488 } else {
489 // RGBA16F
490 const int offset = ((height - j - 1) * width + i) * 2;
491 qfloat16 *fData = reinterpret_cast<qfloat16 *>(data + offset);
492 float pixel[4] = {color.r, color.g, color.b, color.a };
493 qFloatToFloat16(fData, pixel, 4);
494 }
495 }
496 }
497
498 return imageData;
499}
500
501void ProceduralSkyTextureData::scheduleTextureUpdate()
502{
504}
505
506ProceduralSkyTextureData::LinearColor::LinearColor(const QColor &color)
507{
508 const float red = color.redF();
509 const float green = color.greenF();
510 const float blue = color.blueF();
511 const float alpha = color.alphaF();
512
513 r = red < 0.04045 ? red * (1.0 / 12.92) : qPow((red + 0.055) * (1.0 / (1 + 0.055)), 2.4),
514 g = green < 0.04045 ? green * (1.0 / 12.92) : qPow((green + 0.055) * (1.0 / (1 + 0.055)), 2.4),
515 b = blue < 0.04045 ? blue * (1.0 / 12.92) : qPow((blue + 0.055) * (1.0 / (1 + 0.055)), 2.4),
516 a = alpha;
517}
518
519ProceduralSkyTextureData::LinearColor ProceduralSkyTextureData::LinearColor::interpolate(const ProceduralSkyTextureData::LinearColor &color, float value) const
520{
521 LinearColor copy = *this;
522
523 copy.r += (value * (color.r - r));
524 copy.g += (value * (color.g - g));
525 copy.b += (value * (color.b - b));
526 copy.a += (value * (color.a - a));
527
528 return copy;
529}
530
531ProceduralSkyTextureData::LinearColor ProceduralSkyTextureData::LinearColor::blend(const ProceduralSkyTextureData::LinearColor &color) const
532{
533 LinearColor copy;
534 float sa = 1.0 - color.a;
535 copy.a = a * sa + color.a;
536 if (copy.a == 0) {
537 return LinearColor();
538 } else {
539 copy.r = (r * a * sa + color.r * color.a) / copy.a;
540 copy.g = (g * a * sa + color.g * color.a) / copy.a;
541 copy.b = (b * a * sa + color.b * color.a) / copy.a;
542 }
543 return copy;
544}
545
546quint32 ProceduralSkyTextureData::LinearColor::toRGBA8() const
547{
548 return (quint32(lrintf(r)) & 0xFF) |
549 ((quint32(lrintf(g)) & 0xFF) << 8) |
550 ((quint32(lrintf(b)) & 0xFF) << 16) |
551 ((quint32(lrintf(a)) & 0xFF) << 24);
552}
553
554quint32 ProceduralSkyTextureData::LinearColor::toRGBE8() const
555{
556 float v = 0.0f;
557 int exp = 0;
558
559 v = r;
560 if (g > v)
561 v = g;
562 if (b > v)
563 v = b;
564
565 v = frexp(v, &exp) * 256.0f / v;
566 quint32 result = 0;
567 quint8 *components = reinterpret_cast<quint8*>(&result);
568 components[0] = quint8(r * v);
569 components[1] = quint8(g * v);
570 components[2] = quint8(b * v);
571 components[3] = quint8(exp + 128);
572 return result;
573}
574
575quint32 ProceduralSkyTextureData::LinearColor::toRGBE9995() const
576{
577 const float pow2to9 = 512.0f;
578 const float B = 15.0f;
579 const float N = 9.0f;
580
581 float sharedExp = 65408.000f;
582
583 float cRed = qMax(0.0f, qMin(sharedExp, r));
584 float cGreen = qMax(0.0f, qMin(sharedExp, g));
585 float cBlue = qMax(0.0f, qMin(sharedExp, b));
586
587 float cMax = qMax(cRed, qMax(cGreen, cBlue));
588
589 float expp = qMax(-B - 1.0f, floor(std::log(cMax) / M_LN2)) + 1.0f + B;
590
591 float sMax = (float)floor((cMax / qPow(2.0f, expp - B - N)) + 0.5f);
592
593 float exps = expp + 1.0f;
594
595 if (0.0 <= sMax && sMax < pow2to9) {
596 exps = expp;
597 }
598
599 float sRed = qFloor((cRed / pow(2.0f, exps - B - N)) + 0.5f);
600 float sGreen = qFloor((cGreen / pow(2.0f, exps - B - N)) + 0.5f);
601 float sBlue = qFloor((cBlue / pow(2.0f, exps - B - N)) + 0.5f);
602
603 return (quint32(lrintf(sRed)) & 0x1FF) |
604 ((quint32(lrintf(sGreen)) & 0x1FF) << 9) |
605 ((quint32(lrintf(sBlue)) & 0x1FF) << 18) |
606 ((quint32(lrintf(exps)) & 0x1F) << 27);
607}
608
void groundHorizonColorChanged(QColor groundHorizonColor)
void setGroundHorizonColor(QColor groundHorizonColor)
void sunCurveChanged(float sunCurve)
void setGroundBottomColor(QColor groundBottomColor)
void setSunAngleMax(float sunAngleMax)
void groundCurveChanged(float groundCurve)
void setGroundEnergy(float groundEnergy)
void groundEnergyChanged(float groundEnergy)
void skyEnergyChanged(float skyEnergy)
void setSkyHorizonColor(QColor skyHorizonColor)
void sunAngleMinChanged(float sunAngleMin)
void sunColorChanged(QColor sunColor)
void sunEnergyChanged(float sunEnergy)
void skyCurveChanged(float skyCurve)
void setGroundCurve(float groundCurve)
void sunLatitudeChanged(float sunLatitude)
void textureQualityChanged(SkyTextureQuality textureQuality)
void setTextureQuality(SkyTextureQuality textureQuality)
void setSunLatitude(float sunLatitude)
void sunLongitudeChanged(float sunLongitude)
ProceduralSkyTextureData()
\qmltype ProceduralSkyTextureData \inqmlmodule QtQuick3D.Helpers \inherits TextureData
void setSunAngleMin(float sunAngleMin)
void skyHorizonColorChanged(QColor skyHorizonColor)
void skyTopColorChanged(QColor skyTopColor)
void groundBottomColorChanged(QColor groundBottomColor)
void setSkyTopColor(QColor skyTopColor)
void setSunLongitude(float sunLongitude)
void sunAngleMaxChanged(float sunAngleMax)
\inmodule QtCore
Definition qbytearray.h:57
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
Definition qbytearray.h:611
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
void setSize(const QSize &size)
Sets the size of the texture data in pixels.
void setTextureData(const QByteArray &data)
Sets the texture data.
void setHasTransparency(bool hasTransparency)
Set hasTransparency to true if the texture data has an active alpha channel with non-opaque values.
QSize size() const
Returns the size of the texture data in pixels.
void setFormat(Format format)
Sets the format of the texture data.
\inmodule QtCore
Definition qsize.h:25
The QVector3D class represents a vector or vertex in 3D space.
Definition qvectornd.h:171
static constexpr float dotProduct(QVector3D v1, QVector3D v2) noexcept
Returns the dot product of v1 and v2.
Definition qvectornd.h:770
\keyword 16-bit Floating Point Support\inmodule QtCore \inheaderfile QFloat16
Definition qfloat16.h:47
Combined button and popup list for selecting options.
static jboolean copy(JNIEnv *, jobject)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:333
Q_CORE_EXPORT void qFloatToFloat16(qfloat16 *, const float *, qsizetype length) noexcept
constexpr float qRadiansToDegrees(float radians)
Definition qmath.h:281
auto qAcos(T v)
Definition qmath.h:72
#define M_LN2
Definition qmath.h:201
auto qPow(T1 x, T2 y)
Definition qmath.h:180
int qFloor(T v)
Definition qmath.h:42
auto qCos(T v)
Definition qmath.h:60
#define M_PI
Definition qmath.h:209
auto qSin(T v)
Definition qmath.h:54
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLint GLsizei GLsizei height
GLboolean GLboolean GLboolean GLboolean a
[7]
GLint GLenum GLint components
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLenum GLsizei dataSize
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLsizei width
GLuint color
[2]
GLfloat GLfloat clamp
GLenum GLuint GLintptr offset
GLboolean GLboolean g
GLbyte GLbyte blue
Definition qopenglext.h:385
const GLubyte * c
GLuint64EXT * result
[6]
GLfloat GLfloat GLfloat alpha
Definition qopenglext.h:418
GLbyte green
Definition qopenglext.h:385
#define emit
unsigned int quint32
Definition qtypes.h:50
unsigned char quint8
Definition qtypes.h:46
MyCustomStruct c2
QByteArray imageData
[15]
QGraphicsSvgItem * red