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
|
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef QQUICK3DPARTICLERANDOMIZER_H
#define QQUICK3DPARTICLERANDOMIZER_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QRandomGenerator>
#include <QList>
#include <private/qglobal_p.h>
QT_BEGIN_NAMESPACE
/*
Simple helper to get pseudo-random numbers which remain the same per particle & user.
Particles don't need strong randomization and the ability to seed can be useful.
Based on brief testing on my laptop, getting 1.000.000 random numbers:
1) Using QRandomGenerator::global()->generateDouble()
-> ~120ms
2) Using QPRand::get(), with m_size 4096
-> ~8ms
3) Using QPRand::get(i, j), with m_size 4096
-> ~10ms
4) Using QPRand::get(i, j), with m_size 100000
-> ~10ms
So QPRand seems fast and increasing keys amount doesn't notably affect the performance,
just the memory usage. With more particles m_size should be relatively big to make sure
particles appear random enough.
Bounded usage tips:
- qrg->bounded(4.0) == QPRand::get() * 4.0
- qrg->bounded(4) == int(QPRand::get() * 4)
*/
class QPRand
{
public:
// Add here new enums for diferent "users".
// This way e.g. particle can vary little on colors but more on sizes.
enum UserType {
Default = 0,
WanderXPS, // PaceStart
WanderYPS,
WanderZPS,
WanderXPV, // PaceVariation
WanderYPV,
WanderZPV,
WanderXAV, // AmountVariation
WanderYAV,
WanderZAV,
AttractorDurationV,
AttractorPosVX,
AttractorPosVY,
AttractorPosVZ,
Shape1, // Shape
Shape2,
Shape3,
Shape4,
SpriteAnimationI,
DeterministicSeparator, // Note: Enums before this must always be
// deterministic based on the particle index
LifeSpanV, // Emitter
ScaleV,
ScaleEV,
RotXV,
RotYV,
RotZV,
RotXVV,
RotYVV,
RotZVV,
ColorRV,
ColorGV,
ColorBV,
ColorAV,
TDirPosXV, // TargetDirection
TDirPosYV,
TDirPosZV,
TDirMagV,
VDirXV, // VectorDirection
VDirYV,
VDirZV,
SpriteAnimationV
};
void init(quint32 seed, int size = 65536) {
m_size = size;
m_generator.seed(seed);
m_randomList.clear();
m_randomList.reserve(m_size);
for (int i = 0; i < m_size; i++)
m_randomList << float(m_generator.generateDouble());
}
void setDeterministic(bool deterministic) {
m_deterministic = deterministic;
}
// Return float 0.0 - 1.0
// With the same input values, returns always the same output.
inline float get(int particleIndex, UserType user = Default) {
if (!m_deterministic && user > DeterministicSeparator)
return get();
int i = (particleIndex + user) % m_size;
return m_randomList.at(i);
}
// Return float 0.0 - 1.0 from random list
// Note: Not deterministic between runs
inline float get() {
m_index = (m_index < m_size - 1) ? m_index + 1 : 0;
return m_randomList.at(m_index);
}
QRandomGenerator generator() const
{
return m_generator;
}
private:
QRandomGenerator m_generator;
int m_size = 0;
int m_index = 0;
bool m_deterministic = false;
QList<float> m_randomList;
};
QT_END_NAMESPACE
#endif // QQUICK3DPARTICLERANDOMIZER_H
|