Bonjour,
Je suis en train de travailler sur les systèmes de particules sur GPU. J'ai donc trouvé ce tuto pour effectuer une simulation uniquement sur GPU.
Je pense que je me mélange un peut les pinceaux entre les buffers.
Il y a deux type de particules, les génératrices et les autres.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 GLuint transformFeedbackBuffer; GLuint particleBuffer[2]; GLuint VAO[2];
D'après l'objet Query, mon nombre de particules augmentent. Le problème c'est que j'en est qu'une qui est affiché si ma première particule génératrice génère des particules normales. Par contre si elle génère des particules de type génératrice, elles sont affiché mais ne subissent pas le feedback.
Voici le geometry shader du tuto pour l'update des particules :
Je l'ai modifié pour qu'il puisse simplement faire monter les particules.
Si j'ai bien compris, on génère iNumToGenerate particule de type 1 (donc pas génératrice).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 void main() { vLocalSeed = vRandomSeed; // gl_Position doesn't matter now, as rendering is discarded, so I don't set it at all vPositionOut = vPositionPass[0] + vec3(0.0, 0.01, 0.0); vVelocityOut = vVelocityPass[0]; if(iTypePass[0] != 0)vPositionOut += /*vVelocityOut*fTimePassed + */vec3(0.0, 0.05, 0.0); if(iTypePass[0] != 0)vVelocityOut += vGenGravityVector*fTimePassed; vColorOut = vColorPass[0]; fLifeTimeOut = fLifeTimePass[0]-fTimePassed; fSizeOut = fSizePass[0]; iTypeOut = iTypePass[0]; if(iTypeOut == 0) { EmitVertex(); EndPrimitive(); for(int i = 0; i < iNumToGenerate; i++) { vPositionOut = vec3(0.0, -1.0, 0.0); vVelocityOut = vGenVelocityMin+vec3(vGenVelocityRange.x*randZeroOne(), vGenVelocityRange.y*randZeroOne(), vGenVelocityRange.z*randZeroOne()); vVelocityOut = vec3(0.0, 0.1, 0.0); vColorOut = vGenColor; fLifeTimeOut = fGenLifeMin+fGenLifeRange*randZeroOne(); fSizeOut = fGenSize; iTypeOut = 1; EmitVertex(); EndPrimitive(); } } else /*if(fLifeTimeOut > 0.0) */ { EmitVertex(); EndPrimitive(); } }
Je vous joint mon code. Je doit vous avouer que je ne vois pas d’où viens le problème.
Le point d'entré de cette classe est la fonction apply qui est appelé à chaque frame.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 #ifndef PARTICLESYSTEMTRANSFORMFEEDBACK_H #define PARTICLESYSTEMTRANSFORMFEEDBACK_H #include <GL/glew.h> #include <SFML/OpenGL.hpp> #include <glm.hpp> #include "Shader.h" #include "GraphicComponant.h" enum PARTICLETYPE { PARTICLE_TYPE_GENERATOR = 0, PARTICLE_TYPE_BASIC }; class ParticleTransformFeedback { public: glm::vec3 vPosition; glm::vec3 vVelocity; glm::vec3 vColor; float fLifeTime; float fSize; int iType; }; class ParticleSystemTransformFeedback : public GraphicComponant { private: bool initialized; bool first; GLuint transformFeedbackBuffer; GLuint particleBuffer[2]; GLuint VAO[2]; GLuint query; GLuint texture; int currentBuffer; int nbParticles; glm::vec3 quad1, quad2; float previousTime; float elapsedTime; float nextGenerationTime; glm::vec3 genPosition; glm::vec3 genVelocityMin, genVelocityRange; glm::vec3 genGravity; glm::vec3 genColor; float genLifeMin, genLifeRange; float genSize; int nbToGenerate; Shader* renderShader; Shader* updateShader; public: ParticleSystemTransformFeedback(); bool initializeParticleSystem(); void renderParticles(GlobalInformation* globalInformation); void updateParticles(float timePassed); void setGeneratorProperty(glm::vec3 genPosition, glm::vec3 genVelocityMin, glm::vec3 genVelocityMax, glm::vec3 genGravityVector, glm::vec3 genColor, float genLifeMin, float genLifeMax, float genSize, float every, int numToGenerate); void clearAllParticles(); bool releaseParticleSystem(); virtual void apply(float time, glm::vec3* position, glm::mat3* rotation, glm::vec3* scale, GlobalInformation* globalInformation); int getNbParticles(); ~ParticleSystemTransformFeedback(); }; #endifUpdate Shader :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212 #include "ParticleSystemTransformFeedback.h" ParticleSystemTransformFeedback::ParticleSystemTransformFeedback() { this->initialized = false; this->first = true; this->currentBuffer = 0; setGeneratorProperty(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(-0.5, 0, -0.5), glm::vec3(0.5, 0.20, 0.5), glm::vec3(0, -0.0, 0), glm::vec3(0.0f, 0.5f, 1.0f), 2000.0f, 3000.0f, 0.05f, 2000.0f, 30); } bool ParticleSystemTransformFeedback::initializeParticleSystem() { if (this->initialized) return false; const char* sVaryings[6] = { "vPositionOut", "vVelocityOut", "vColorOut", "fLifeTimeOut", "fSizeOut", "iTypeOut", }; this->updateShader = new Shader("../IN55-Project/res/shaders/particles_update.vert", "../IN55-Project/res/shaders/particles_update.geo", "../IN55-Project/res/shaders/particles_update.frag"); this->renderShader = new Shader("../IN55-Project/res/shaders/particles_render.vert", "../IN55-Project/res/shaders/particles_render.geo", "../IN55-Project/res/shaders/particles_render.frag"); glTransformFeedbackVaryings(this->updateShader->getProgramID(), 6, sVaryings, GL_INTERLEAVED_ATTRIBS); this->updateShader->linkProgram(); glGenTransformFeedbacks(1, &this->transformFeedbackBuffer); glGenQueries(1, &this->query); glGenBuffers(2, this->particleBuffer); glGenVertexArrays(2, this->VAO); ParticleTransformFeedback particleInitialisation[10000]; memset(particleInitialisation, 0, sizeof(particleInitialisation)); particleInitialisation[0].iType = PARTICLE_TYPE_GENERATOR; for (int i=0; i<2; ++i) { glBindVertexArray(this->VAO[i]); glBindBuffer(GL_ARRAY_BUFFER, this->particleBuffer[i]); glBufferData(GL_ARRAY_BUFFER, sizeof(particleInitialisation), particleInitialisation, GL_DYNAMIC_DRAW); for (int j=0; j<6; ++j) glEnableVertexAttribArray(j); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(ParticleTransformFeedback), (const GLvoid*)0); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(ParticleTransformFeedback), (const GLvoid*)12); glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(ParticleTransformFeedback), (const GLvoid*)24); glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, sizeof(ParticleTransformFeedback), (const GLvoid*)36); glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, sizeof(ParticleTransformFeedback), (const GLvoid*)40); glVertexAttribPointer(5, 1, GL_INT, GL_FALSE, sizeof(ParticleTransformFeedback), (const GLvoid*)44); } this->currentBuffer = 0; this->nbParticles = 1; this->initialized = true; return true; } void ParticleSystemTransformFeedback::renderParticles(GlobalInformation* globalInformation) { if (!this->initialized) return; glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); glDepthMask(0); glDisable(GL_RASTERIZER_DISCARD); GLuint programID = this->renderShader->getProgramID(); glUseProgram(programID); glUniformMatrix4fv(glGetUniformLocation(programID, "matrices.mView"), 1, GL_FALSE, &globalInformation->getCurrentCamera()->getView()[0][0]); glUniformMatrix4fv(glGetUniformLocation(programID, "matrices.mProj"), 1, GL_FALSE, &globalInformation->getCurrentCamera()->getProjection()[0][0]); glUniform3f(glGetUniformLocation(programID, "vQuad1"), this->quad1.x, this->quad1.y, this->quad1.z); glUniform3f(glGetUniformLocation(programID, "vQuad2"), this->quad2.x, this->quad2.y, this->quad2.z); glBindVertexArray(this->VAO[this->currentBuffer]); glDisableVertexAttribArray(1); glDrawTransformFeedback(GL_POINTS, this->transformFeedbackBuffer); glDepthMask(1); glDisable(GL_BLEND); glUseProgram(0); } float grandf(float fMin, float fAdd) { float fRandom = float(rand()%(RAND_MAX+1))/float(RAND_MAX); return fMin+fAdd*fRandom; } void ParticleSystemTransformFeedback::updateParticles(float timePassed) { if (!this->initialized) return; GLuint programID = this->updateShader->getProgramID(); glUseProgram(programID); glUniform1f(glGetUniformLocation(programID, "fTimePassed"), timePassed); glUniform3f(glGetUniformLocation(programID, "vGenPosition"), this->genPosition.x, this->genPosition.y, this->genPosition.z); glUniform3f(glGetUniformLocation(programID, "vGenVelocityMin"), this->genVelocityMin.x, this->genVelocityMin.y, this->genVelocityMin.z); glUniform3f(glGetUniformLocation(programID, "vGenVelocityRange"), this->genVelocityRange.x, this->genVelocityRange.y, this->genVelocityRange.z); glUniform3f(glGetUniformLocation(programID, "vGenColor"), this->genColor.x, this->genColor.y, this->genColor.z); glUniform3f(glGetUniformLocation(programID, "vGenGravityVector"), this->genGravity.x, this->genGravity.y, this->genGravity.z); glUniform1f(glGetUniformLocation(programID, "fGenLifeMin"), this->genLifeMin); glUniform1f(glGetUniformLocation(programID, "fGenLifeRange"), this->genLifeRange); glUniform1f(glGetUniformLocation(programID, "fGenSize"), this->genSize); glUniform1i(glGetUniformLocation(programID, "iNumToGenerate"), 0); this->elapsedTime += timePassed; if (this->elapsedTime > this->nextGenerationTime) { glUniform1i(glGetUniformLocation(programID, "iNumToGenerate"), this->nbToGenerate); this->elapsedTime -= this->nextGenerationTime; glm::vec3 randSpeed = glm::vec3(grandf(-0.10f, 0.20f), grandf(-0.10f, 0.20f), grandf(-0.10f, 0.20f)); glUniform3f(glGetUniformLocation(programID, "vRandomSeed"), randSpeed.x, randSpeed.y, randSpeed.z); } glEnable(GL_RASTERIZER_DISCARD); glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, this->transformFeedbackBuffer); glBindVertexArray(this->VAO[this->currentBuffer]); glEnableVertexAttribArray(1); glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, this->particleBuffer[1-this->currentBuffer]); glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, this->query); glBeginTransformFeedback(GL_POINTS); if (this->first) { glDrawArrays(GL_POINTS, 0, this->nbParticles); this->first = false; } else glDrawTransformFeedback(GL_POINTS, this->transformFeedbackBuffer); glEndTransformFeedback(); glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN); glGetQueryObjectiv(this->query, GL_QUERY_RESULT, &this->nbParticles); std::cout<<this->nbParticles<<std::endl; this->currentBuffer = 1 - this->currentBuffer; glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0); glUseProgram(0); } void ParticleSystemTransformFeedback::setGeneratorProperty(glm::vec3 genPosition, glm::vec3 genVelocityMin, glm::vec3 genVelocityMax, glm::vec3 genGravityVector, glm::vec3 genColor, float genLifeMin, float genLifeMax, float genSize, float every, int numToGenerate) { this->genPosition = genPosition; this->genVelocityMin = genVelocityMin; this->genVelocityRange = genVelocityMax - genVelocityMin; this->genGravity = genGravity; this->genColor = genColor; this->genSize = genSize; this->genLifeMin = genLifeMin; this->genLifeRange = genLifeMax - genLifeMin; this->nextGenerationTime = every; this->elapsedTime = 0.8f; this->nbToGenerate = numToGenerate; } void ParticleSystemTransformFeedback::clearAllParticles() { } bool ParticleSystemTransformFeedback::releaseParticleSystem() { return true; } void ParticleSystemTransformFeedback::apply(float time, glm::vec3* position, glm::mat3* rotation, glm::vec3* scale, GlobalInformation* globalInformation) { this->updateParticles(time - previousTime); this->previousTime = time; glm::vec3 view = globalInformation->getCurrentCamera()->getFocus() - globalInformation->getCurrentCamera()->getPostion(); view = glm::normalize(view); this->quad1 = glm::cross(view, globalInformation->getCurrentCamera()->getUpVector()); this->quad1 = glm::normalize(this->quad1); this->quad2 = glm::cross(view, this->quad1); this->quad2 = glm::normalize(this->quad2); renderParticles(globalInformation); } int ParticleSystemTransformFeedback::getNbParticles() { return this->nbParticles; } ParticleSystemTransformFeedback::~ParticleSystemTransformFeedback() { }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 #version 330 layout (location = 0) in vec3 vPosition; layout (location = 1) in vec3 vVelocity; layout (location = 2) in vec3 vColor; layout (location = 3) in float fLifeTime; layout (location = 4) in float fSize; layout (location = 5) in int iType; out vec3 vPositionPass; out vec3 vVelocityPass; out vec3 vColorPass; out float fLifeTimePass; out float fSizePass; out int iTypePass; void main() { vPositionPass = vPosition; vVelocityPass = vVelocity; vColorPass = vColor; fLifeTimePass = fLifeTime; fSizePass = fSize; iTypePass = iType; }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 #version 330 layout(points) in; layout(points) out; layout(max_vertices = 40) out; // All that we get from vertex shader in vec3 vPositionPass[]; in vec3 vVelocityPass[]; in vec3 vColorPass[]; in float fLifeTimePass[]; in float fSizePass[]; in int iTypePass[]; // All that we send further out vec3 vPositionOut; out vec3 vVelocityOut; out vec3 vColorOut; out float fLifeTimeOut; out float fSizeOut; out int iTypeOut; uniform vec3 vGenPosition; // Position where new particles are spawned uniform vec3 vGenGravityVector; // Gravity vector for particles - updates velocity of particles uniform vec3 vGenVelocityMin; // Velocity of new particle - from min to (min+range) uniform vec3 vGenVelocityRange; uniform vec3 vGenColor; uniform float fGenSize; uniform float fGenLifeMin, fGenLifeRange; // Life of new particle - from min to (min+range) uniform float fTimePassed; // Time passed since last frame uniform vec3 vRandomSeed; // Seed number for our random number function vec3 vLocalSeed; uniform int iNumToGenerate; // How many particles will be generated next time, if greater than zero, particles are generated // This function returns random number from zero to one float randZeroOne() { uint n = floatBitsToUint(vLocalSeed.y * 214013.0 + vLocalSeed.x * 2531011.0 + vLocalSeed.z * 141251.0); n = n * (n * n * 15731u + 789221u); n = (n >> 9u) | 0x3F800000u; float fRes = 2.0 - uintBitsToFloat(n); vLocalSeed = vec3(vLocalSeed.x + 147158.0 * fRes, vLocalSeed.y*fRes + 415161.0 * fRes, vLocalSeed.z + 324154.0*fRes); return fRes; } void main() { vLocalSeed = vRandomSeed; // gl_Position doesn't matter now, as rendering is discarded, so I don't set it at all vPositionOut = vPositionPass[0] + vec3(0.0, 0.01, 0.0); vVelocityOut = vVelocityPass[0]; if(iTypePass[0] != 0)vPositionOut += /*vVelocityOut*fTimePassed + */vec3(0.0, 0.05, 0.0); if(iTypePass[0] != 0)vVelocityOut += vGenGravityVector*fTimePassed; vColorOut = vColorPass[0]; fLifeTimeOut = fLifeTimePass[0]-fTimePassed; fSizeOut = fSizePass[0]; iTypeOut = iTypePass[0]; if(iTypeOut == 0) { EmitVertex(); EndPrimitive(); for(int i = 0; i < iNumToGenerate; i++) { vPositionOut = vec3(0.0, -1.0, 0.0); vVelocityOut = vGenVelocityMin+vec3(vGenVelocityRange.x*randZeroOne(), vGenVelocityRange.y*randZeroOne(), vGenVelocityRange.z*randZeroOne()); vVelocityOut = vec3(0.0, 0.1, 0.0); vColorOut = vGenColor; fLifeTimeOut = fGenLifeMin+fGenLifeRange*randZeroOne(); fSizeOut = fGenSize; iTypeOut = 1; EmitVertex(); EndPrimitive(); } } else /*if(fLifeTimeOut > 0.0) */ { EmitVertex(); EndPrimitive(); } }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 #version 330 out vec4 vColor; void main() { vColor = vec4(1.0, 1.0, 1.0, 1.0); }
Render Shader :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 #version 330 layout (location = 0) in vec3 vPosition; layout (location = 2) in vec3 vColor; layout (location = 3) in float fLifeTime; layout (location = 4) in float fSize; layout (location = 5) in int iType; out vec3 vColorPass; out float fLifeTimePass; out float fSizePass; out int iTypePass; uniform struct Matrices { mat4 mProj; mat4 mView; } matrices; void main() { gl_Position = vec4(vPosition, 1.0); vColorPass = vColor; fSizePass = fSize; fLifeTimePass = fLifeTime; iTypePass = iType; }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 #version 330 uniform struct Matrices { mat4 mProj; mat4 mView; } matrices; uniform vec3 vQuad1, vQuad2; layout(points) in; layout(triangle_strip) out; layout(max_vertices = 4) out; in vec3 vColorPass[]; in float fLifeTimePass[]; in float fSizePass[]; in int iTypePass[]; smooth out vec2 vTexCoord; flat out vec4 vColorPart; void main() { if(iTypePass[0] == 0) { vec3 vPosOld = gl_in[0].gl_Position.xyz; float fSize = fSizePass[0]; mat4 mVP = matrices.mProj*matrices.mView; vColorPart = vec4(vColorPass[0], fLifeTimePass[0]); vec3 vPos = vPosOld; vTexCoord = vec2(0.0, 0.0); gl_Position = mVP*vec4(vPos, 1.0); EmitVertex(); vPos = vPosOld + vec3(0.0, 0.0, 0.1); vTexCoord = vec2(0.0, 1.0); gl_Position = mVP*vec4(vPos, 1.0); EmitVertex(); vPos = vPosOld + vec3(0.0, 0.1, 0.0); vTexCoord = vec2(1.0, 0.0); gl_Position = mVP*vec4(vPos, 1.0); EmitVertex(); vPos = vPosOld + vec3(0.0, 0.1, 0.1); vTexCoord = vec2(1.0, 1.0); gl_Position = mVP*vec4(vPos, 1.0); EmitVertex(); EndPrimitive(); } }Merci d'avance pour votre aide,
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 #version 330 uniform sampler2D gSampler; smooth in vec2 vTexCoord; flat in vec4 vColorPart; out vec4 FragColor; void main() { FragColor = vec4(1.0, 0.0, 0.0, 1.0); }
Robin
Partager