107 | | struct PrecipitationCullCallback : public virtual osg::Drawable::CullCallback |
108 | | { |
109 | | PrecipitationCullCallback() {} |
110 | | |
111 | | PrecipitationCullCallback(const PrecipitationCullCallback&,const osg::CopyOp&) {} |
112 | | |
113 | | META_Object(osg,PrecipitationCullCallback); |
114 | | |
115 | | /** do customized cull code, return true if drawable should be culled.*/ |
116 | | virtual bool cull(osg::NodeVisitor* nodeVisitor, osg::Drawable* drawable, osg::State* state) const |
117 | | { |
118 | | return false; |
119 | | } |
120 | | }; |
121 | | #endif |
122 | | |
123 | | class PrecipitationGeometry : public osg::Geometry |
124 | | { |
125 | | public: |
126 | | |
127 | | PrecipitationGeometry() |
128 | | { |
129 | | setSupportsDisplayList(false); |
130 | | |
131 | | // setCullCallback(new PrecipitationCullCallback()); |
132 | | } |
133 | | |
134 | | virtual bool supports(const osg::PrimitiveFunctor&) const { return false; } |
135 | | virtual void accept(osg::PrimitiveFunctor&) const {} |
136 | | virtual bool supports(const osg::PrimitiveIndexFunctor&) const { return false; } |
137 | | virtual void accept(osg::PrimitiveIndexFunctor&) const {} |
138 | | |
139 | | void setInternalGeometry(osg::Geometry* geometry) { _internalGeometry = geometry; } |
140 | | |
141 | | osg::Geometry* getInternalGeometry() { return _internalGeometry.get(); } |
142 | | |
143 | | void setPosition(const osg::Vec3& position) { _position = position; } |
144 | | const osg::Vec3& getPosition() const { return _position; } |
145 | | |
146 | | void setScale(const osg::Vec3& scale) { _scale = scale; } |
147 | | const osg::Vec3& getScale() const { return _scale; } |
148 | | |
149 | | void setStartTime(float time) { _startTime = time; } |
150 | | float getStartTime() const { return _startTime; } |
151 | | |
152 | | |
153 | | virtual void compileGLObjects(osg::State& state) const |
154 | | { |
155 | | if (!_internalGeometry) return; |
156 | | |
157 | | static bool s_interalGeometryCompiled = false; |
158 | | if (!s_interalGeometryCompiled) |
159 | | { |
160 | | _internalGeometry->compileGLObjects(state); |
161 | | s_interalGeometryCompiled = true; |
162 | | } |
163 | | } |
164 | | |
165 | | virtual void drawImplementation(osg::State& state) const |
166 | | { |
167 | | if (!_internalGeometry) return; |
168 | | |
169 | | const Extensions* extensions = getExtensions(state.getContextID(),true); |
170 | | |
171 | | glNormal3fv(_position.ptr()); |
172 | | extensions->glMultiTexCoord1f(GL_TEXTURE0+1, _startTime); |
173 | | |
174 | | glPushMatrix(); |
175 | | |
176 | | osg::Matrix modelview = state.getModelViewMatrix(); |
177 | | modelview.preMult(osg::Matrix::translate(_position)); |
178 | | modelview.preMult(osg::Matrix::scale(_scale)); |
179 | | |
180 | | bool isPoint = (_internalGeometry->getName()=="point"); |
181 | | |
182 | | glLoadMatrix(modelview.ptr()); |
183 | | |
184 | | if (!isPoint) |
185 | | { |
186 | | state.setActiveTextureUnit(0); |
187 | | glMatrixMode( GL_TEXTURE ); |
188 | | |
189 | | glPushMatrix(); |
190 | | |
191 | | glLoadMatrix(_previousModelView.ptr()); |
192 | | |
193 | | _previousModelView = modelview; |
194 | | } |
195 | | #if 0 |
196 | | else |
197 | | { |
198 | | state.setActiveTextureUnit(0); |
199 | | glMatrixMode( GL_TEXTURE ); |
200 | | |
201 | | glPushMatrix(); |
202 | | |
203 | | glLoadIdentity(); |
204 | | |
205 | | _previousModelView = modelview; |
206 | | } |
207 | | #endif |
208 | | _internalGeometry->draw(state); |
209 | | |
210 | | |
211 | | static int s_frameNumber = 0xffffffff; |
212 | | static unsigned int s_NumberQuads = 0; |
213 | | static unsigned int s_NumberQuadsVertices = 0; |
214 | | static unsigned int s_NumberLines = 0; |
215 | | static unsigned int s_NumberLinesVertices = 0; |
216 | | static unsigned int s_NumberPoints = 0; |
217 | | static unsigned int s_NumberPointsVertices = 0; |
218 | | |
219 | | if (s_frameNumber != state.getFrameStamp()->getFrameNumber()) |
220 | | { |
221 | | // std::cout<<"Frame "<< s_frameNumber<<"\tquads "<<s_NumberQuads<<", "<<s_NumberQuadsVertices<<" points "<<s_NumberPoints<<", "<<s_NumberPointsVertices<<std::endl; |
222 | | |
223 | | s_NumberQuads = 0; |
224 | | s_NumberLines = 0; |
225 | | s_NumberPoints = 0; |
226 | | s_NumberQuadsVertices = 0; |
227 | | s_NumberLinesVertices = 0; |
228 | | s_NumberPointsVertices = 0; |
229 | | |
230 | | s_frameNumber = state.getFrameStamp()->getFrameNumber(); |
231 | | } |
232 | | |
233 | | |
234 | | if (_internalGeometry->getName()=="quad") |
235 | | { |
236 | | s_NumberQuads++; |
237 | | s_NumberQuadsVertices+= _internalGeometry->getVertexArray()->getNumElements(); |
238 | | } |
239 | | else if (_internalGeometry->getName()=="line") |
240 | | { |
241 | | s_NumberLines++; |
242 | | s_NumberLinesVertices+= _internalGeometry->getVertexArray()->getNumElements(); |
243 | | } |
244 | | else if (_internalGeometry->getName()=="point") |
245 | | { |
246 | | s_NumberPoints++; |
247 | | s_NumberPointsVertices+= _internalGeometry->getVertexArray()->getNumElements(); |
248 | | } |
249 | | |
250 | | if (!isPoint) |
251 | | { |
252 | | glPopMatrix(); |
253 | | glMatrixMode( GL_MODELVIEW ); |
254 | | } |
255 | | |
256 | | glPopMatrix(); |
257 | | } |
258 | | |
259 | | virtual osg::BoundingBox computeBound() const |
260 | | { |
261 | | return osg::BoundingBox(); |
262 | | } |
263 | | |
264 | | protected: |
265 | | |
266 | | osg::Vec3 _position; |
267 | | osg::Vec3 _scale; |
268 | | float _startTime; |
269 | | osg::ref_ptr<osg::Geometry> _internalGeometry; |
270 | | mutable osg::Matrix _previousModelView; |
271 | | |
272 | | }; |
273 | | |
274 | | class CullCallback : public osg::NodeCallback |
275 | | { |
276 | | public: |
277 | | |
278 | | CullCallback(osg::Uniform* uniform): |
279 | | _previousFrame(0), |
280 | | _initialized(false), |
281 | | _uniform(uniform) |
282 | | { |
283 | | } |
284 | | |
285 | | virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) |
286 | | { |
287 | | osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv); |
288 | | if (cv) |
289 | | { |
290 | | if (!_initialized) |
291 | | { |
292 | | _previousModelViewMatrix = cv->getModelViewMatrix(); |
293 | | _previousFrame = nv->getFrameStamp()->getFrameNumber(); |
294 | | _initialized = true; |
295 | | } |
296 | | |
297 | | _uniform->set(_previousModelViewMatrix); |
298 | | |
299 | | // osg::notify(osg::NOTICE)<<"Updating uniform "<<_previousModelViewMatrix<<std::endl; |
300 | | |
301 | | traverse(node, nv); |
302 | | |
303 | | if (_previousFrame != nv->getFrameStamp()->getFrameNumber()) |
304 | | { |
305 | | _previousModelViewMatrix = cv->getModelViewMatrix(); |
306 | | _previousFrame = nv->getFrameStamp()->getFrameNumber(); |
307 | | } |
308 | | } |
309 | | else |
310 | | { |
311 | | traverse(node, nv); |
312 | | } |
313 | | } |
314 | | |
315 | | int _previousFrame; |
316 | | bool _initialized; |
317 | | osg::Matrix _previousModelViewMatrix; |
318 | | osg::ref_ptr<osg::Uniform> _uniform; |
319 | | }; |
320 | | |
321 | | void fillSpotLightImage(unsigned char* ptr, const osg::Vec4& centerColour, const osg::Vec4& backgroudColour, unsigned int size, float power) |
322 | | { |
323 | | float mid = (float(size)-1.0f)*0.5f; |
324 | | float div = 2.0f/float(size); |
325 | | for(unsigned int r=0;r<size;++r) |
326 | | { |
327 | | //unsigned char* ptr = image->data(0,r,0); |
328 | | for(unsigned int c=0;c<size;++c) |
329 | | { |
330 | | float dx = (float(c) - mid)*div; |
331 | | float dy = (float(r) - mid)*div; |
332 | | float r = powf(1.0f-sqrtf(dx*dx+dy*dy),power); |
333 | | if (r<0.0f) r=0.0f; |
334 | | osg::Vec4 color = centerColour*r+backgroudColour*(1.0f-r); |
335 | | *ptr++ = (unsigned char)((color[0])*255.0f); |
336 | | *ptr++ = (unsigned char)((color[1])*255.0f); |
337 | | *ptr++ = (unsigned char)((color[2])*255.0f); |
338 | | *ptr++ = (unsigned char)((color[3])*255.0f); |
339 | | } |
340 | | } |
341 | | } |
342 | | |
343 | | |
344 | | osg::Image* createSpotLightImage(const osg::Vec4& centerColour, const osg::Vec4& backgroudColour, unsigned int size, float power) |
345 | | { |
346 | | |
347 | | #if 0 |
348 | | osg::Image* image = new osg::Image; |
349 | | unsigned char* ptr = image->data(0,0,0); |
350 | | fillSpotLightImage(ptr, centerColour, backgroudColour, size, power); |
351 | | |
352 | | return image; |
353 | | #else |
354 | | osg::Image* image = new osg::Image; |
355 | | osg::Image::MipmapDataType mipmapData; |
356 | | unsigned int s = size; |
357 | | unsigned int totalSize = 0; |
358 | | unsigned i; |
359 | | for(i=0; s>0; s>>=1, ++i) |
360 | | { |
361 | | if (i>0) mipmapData.push_back(totalSize); |
362 | | totalSize += s*s*4; |
363 | | } |
364 | | |
365 | | unsigned char* ptr = new unsigned char[totalSize]; |
366 | | image->setImage(size, size, size, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, ptr, osg::Image::USE_NEW_DELETE,1); |
367 | | |
368 | | image->setMipmapLevels(mipmapData); |
369 | | |
370 | | s = size; |
371 | | for(i=0; s>0; s>>=1, ++i) |
372 | | { |
373 | | fillSpotLightImage(ptr, centerColour, backgroudColour, s, power); |
374 | | ptr += s*s*4; |
375 | | } |
376 | | |
377 | | return image; |
378 | | #endif |
379 | | } |
380 | | |
381 | | /** create quad, line and point geometry data all with consistent particle positions.*/ |
382 | | void createGeometry(unsigned int numParticles, |
383 | | osg::Geometry* quad_geometry, |
384 | | osg::Geometry* line_geometry, |
385 | | osg::Geometry* point_geometry) |
386 | | { |
387 | | // particle corner offsets |
388 | | osg::Vec2 offset00(0.0f,0.0f); |
389 | | osg::Vec2 offset10(1.0f,0.0f); |
390 | | osg::Vec2 offset01(0.0f,1.0f); |
391 | | osg::Vec2 offset11(1.0f,1.0f); |
392 | | |
393 | | osg::Vec2 offset0(0.5f,0.0f); |
394 | | osg::Vec2 offset1(0.5f,1.0f); |
395 | | |
396 | | osg::Vec2 offset(0.5f,0.5f); |
397 | | |
398 | | |
399 | | // configure quad_geometry; |
400 | | osg::Vec3Array* quad_vertices = 0; |
401 | | osg::Vec2Array* quad_offsets = 0; |
402 | | if (quad_geometry) |
403 | | { |
404 | | quad_geometry->setName("quad"); |
405 | | |
406 | | quad_vertices = new osg::Vec3Array(numParticles*4); |
407 | | quad_offsets = new osg::Vec2Array(numParticles*4); |
408 | | |
409 | | quad_geometry->setVertexArray(quad_vertices); |
410 | | quad_geometry->setTexCoordArray(0, quad_offsets); |
411 | | quad_geometry->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, numParticles*4)); |
412 | | } |
413 | | |
414 | | // configure line_geometry; |
415 | | osg::Vec3Array* line_vertices = 0; |
416 | | osg::Vec2Array* line_offsets = 0; |
417 | | if (line_geometry) |
418 | | { |
419 | | line_geometry->setName("line"); |
420 | | |
421 | | line_vertices = new osg::Vec3Array(numParticles*2); |
422 | | line_offsets = new osg::Vec2Array(numParticles*2); |
423 | | |
424 | | line_geometry->setVertexArray(line_vertices); |
425 | | line_geometry->setTexCoordArray(0, line_offsets); |
426 | | line_geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINES, 0, numParticles*2)); |
427 | | } |
428 | | |
429 | | // configure point_geometry; |
430 | | osg::Vec3Array* point_vertices = 0; |
431 | | osg::Vec2Array* point_offsets = 0; |
432 | | if (point_geometry) |
433 | | { |
434 | | point_geometry->setName("point"); |
435 | | |
436 | | point_vertices = new osg::Vec3Array(numParticles); |
437 | | point_offsets = new osg::Vec2Array(numParticles); |
438 | | |
439 | | point_geometry->setVertexArray(point_vertices); |
440 | | point_geometry->setTexCoordArray(0, point_offsets); |
441 | | point_geometry->addPrimitiveSet(new osg::DrawArrays(GL_POINTS, 0, numParticles)); |
442 | | } |
443 | | |
444 | | // set up vertex attribute data. |
445 | | for(unsigned int i=0; i< numParticles; ++i) |
446 | | { |
447 | | osg::Vec3 pos( random(0.0f, 1.0f), random(0.0f, 1.0f), random(0.0f, 1.0f)); |
448 | | |
449 | | // quad particles |
450 | | if (quad_vertices) |
451 | | { |
452 | | (*quad_vertices)[i*4] = pos; |
453 | | (*quad_vertices)[i*4+1] = pos; |
454 | | (*quad_vertices)[i*4+2] = pos; |
455 | | (*quad_vertices)[i*4+3] = pos; |
456 | | (*quad_offsets)[i*4] = offset00; |
457 | | (*quad_offsets)[i*4+1] = offset01; |
458 | | (*quad_offsets)[i*4+2] = offset11; |
459 | | (*quad_offsets)[i*4+3] = offset10; |
460 | | } |
461 | | |
462 | | // line particles |
463 | | if (line_vertices) |
464 | | { |
465 | | (*line_vertices)[i*2] = pos; |
466 | | (*line_vertices)[i*2+1] = pos; |
467 | | (*line_offsets)[i*2] = offset0; |
468 | | (*line_offsets)[i*2+1] = offset1; |
469 | | } |
470 | | |
471 | | // point particles |
472 | | if (point_vertices) |
473 | | { |
474 | | (*point_vertices)[i] = pos; |
475 | | (*point_offsets)[i] = offset; |
476 | | } |
477 | | } |
478 | | } |
479 | | |
480 | | |
481 | | static osg::ref_ptr<osg::Geometry> quad_geometry = 0; |
482 | | static osg::ref_ptr<osg::StateSet> quad_stateset = 0; |
483 | | |
484 | | static osg::ref_ptr<osg::Geometry> line_geometry = 0; |
485 | | static osg::ref_ptr<osg::StateSet> line_stateset = 0; |
486 | | |
487 | | static osg::ref_ptr<osg::Geometry> point_geometry = 0; |
488 | | static osg::ref_ptr<osg::StateSet> point_stateset = 0; |
489 | | |
490 | | void setUpGeometries(unsigned int numParticles) |
491 | | { |
492 | | unsigned int renderBin = 11; |
493 | | |
494 | | { |
495 | | quad_geometry = new osg::Geometry; |
496 | | quad_geometry->setUseVertexBufferObjects(true); |
497 | | |
498 | | quad_stateset = new osg::StateSet; |
499 | | osg::Program* program = new osg::Program; |
500 | | quad_stateset->setAttribute(program); |
501 | | quad_stateset->setRenderBinDetails(renderBin,"DepthSortedBin"); |
502 | | |
503 | | #ifdef USE_LOCAL_SHADERS |
504 | | char vertexShaderSource[] = |
505 | | "uniform float inversePeriod;\n" |
506 | | "uniform vec4 particleColour;\n" |
507 | | "uniform float particleSize;\n" |
508 | | "\n" |
509 | | "uniform float osg_FrameTime;\n" |
510 | | "uniform float osg_DeltaFrameTime;\n" |
511 | | "\n" |
512 | | "varying vec4 colour;\n" |
513 | | "varying vec2 texCoord;\n" |
514 | | "\n" |
515 | | "void main(void)\n" |
516 | | "{\n" |
517 | | " float offset = gl_Vertex.z;\n" |
518 | | " float startTime = gl_MultiTexCoord1.x;\n" |
519 | | " texCoord = gl_MultiTexCoord0.xy;\n" |
520 | | "\n" |
521 | | " vec4 v_previous = gl_Vertex;\n" |
522 | | " v_previous.z = fract( (osg_FrameTime - startTime)*inversePeriod - offset);\n" |
523 | | " \n" |
524 | | " vec4 v_current = v_previous;\n" |
525 | | " v_current.z += (osg_DeltaFrameTime*inversePeriod);\n" |
526 | | " \n" |
527 | | "\n" |
528 | | " colour = particleColour;\n" |
529 | | " \n" |
530 | | " vec4 v1 = gl_ModelViewMatrix * v_current;\n" |
531 | | " vec4 v2 = gl_TextureMatrix[0] * v_previous;\n" |
532 | | " \n" |
533 | | " vec3 dv = v2.xyz - v1.xyz;\n" |
534 | | " \n" |
535 | | " vec2 dv_normalized = normalize(dv.xy);\n" |
536 | | " dv.xy += dv_normalized * particleSize;\n" |
537 | | " vec2 dp = vec2( -dv_normalized.y, dv_normalized.x ) * particleSize;\n" |
538 | | " \n" |
539 | | " float area = length(dv.xy);\n" |
540 | | " colour.a = 0.05+(particleSize)/area;\n" |
541 | | " \n" |
542 | | "\n" |
543 | | " v1.xyz += dv*texCoord.y;\n" |
544 | | " v1.xy += dp*texCoord.x;\n" |
545 | | " \n" |
546 | | " gl_Position = gl_ProjectionMatrix * v1;\n" |
547 | | "}\n"; |
548 | | |
549 | | char fragmentShaderSource[] = |
550 | | "uniform sampler2D baseTexture;\n" |
551 | | "varying vec2 texCoord;\n" |
552 | | "varying vec4 colour;\n" |
553 | | "\n" |
554 | | "void main (void)\n" |
555 | | "{\n" |
556 | | " gl_FragColor = colour * texture2D( baseTexture, texCoord);\n" |
557 | | "}\n"; |
558 | | |
559 | | program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource)); |
560 | | program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource)); |
561 | | #else |
562 | | // get shaders from source |
563 | | program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("quad_rain.vert"))); |
564 | | program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("rain.frag"))); |
565 | | #endif |
566 | | } |
567 | | |
568 | | |
569 | | { |
570 | | line_geometry = new osg::Geometry; |
571 | | line_geometry->setUseVertexBufferObjects(true); |
572 | | |
573 | | line_stateset = new osg::StateSet; |
574 | | |
575 | | osg::Program* program = new osg::Program; |
576 | | line_stateset->setAttribute(program); |
577 | | line_stateset->setRenderBinDetails(renderBin,"DepthSortedBin"); |
578 | | |
579 | | #ifdef USE_LOCAL_SHADERS |
580 | | char vertexShaderSource[] = |
581 | | "uniform float inversePeriod;\n" |
582 | | "uniform vec4 particleColour;\n" |
583 | | "uniform float particleSize;\n" |
584 | | "\n" |
585 | | "uniform float osg_FrameTime;\n" |
586 | | "uniform float osg_DeltaFrameTime;\n" |
587 | | "uniform mat4 previousModelViewMatrix;\n" |
588 | | "\n" |
589 | | "varying vec4 colour;\n" |
590 | | "varying vec2 texCoord;\n" |
591 | | "\n" |
592 | | "void main(void)\n" |
593 | | "{\n" |
594 | | " float offset = gl_Vertex.z;\n" |
595 | | " float startTime = gl_MultiTexCoord1.x;\n" |
596 | | " texCoord = gl_MultiTexCoord0.xy;\n" |
597 | | "\n" |
598 | | " vec4 v_previous = gl_Vertex;\n" |
599 | | " v_previous.z = fract( (osg_FrameTime - startTime)*inversePeriod - offset);\n" |
600 | | " \n" |
601 | | " vec4 v_current = v_previous;\n" |
602 | | " v_current.z += (osg_DeltaFrameTime*inversePeriod);\n" |
603 | | " \n" |
604 | | " colour = particleColour;\n" |
605 | | " \n" |
606 | | " vec4 v1 = gl_ModelViewMatrix * v_current;\n" |
607 | | " vec4 v2 = gl_TextureMatrix[0] * v_previous;\n" |
608 | | " \n" |
609 | | " vec3 dv = v2.xyz - v1.xyz;\n" |
610 | | " \n" |
611 | | " vec2 dv_normalized = normalize(dv.xy);\n" |
612 | | " dv.xy += dv_normalized * particleSize;\n" |
613 | | " \n" |
614 | | " float area = length(dv.xy);\n" |
615 | | " colour.a = (particleSize)/area;\n" |
616 | | " \n" |
617 | | " v1.xyz += dv*texCoord.y;\n" |
618 | | " \n" |
619 | | " gl_Position = gl_ProjectionMatrix * v1;\n" |
620 | | "}\n"; |
621 | | |
622 | | char fragmentShaderSource[] = |
623 | | "uniform sampler2D baseTexture;\n" |
624 | | "varying vec2 texCoord;\n" |
625 | | "varying vec4 colour;\n" |
626 | | "\n" |
627 | | "void main (void)\n" |
628 | | "{\n" |
629 | | " gl_FragColor = colour * texture2D( baseTexture, texCoord);\n" |
630 | | "}\n"; |
631 | | |
632 | | program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource)); |
633 | | program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource)); |
634 | | #else |
635 | | // get shaders from source |
636 | | program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("line_rain.vert"))); |
637 | | program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("rain.frag"))); |
638 | | #endif |
639 | | } |
640 | | |
641 | | |
642 | | { |
643 | | point_geometry = new osg::Geometry; |
644 | | point_geometry->setUseVertexBufferObjects(true); |
645 | | |
646 | | point_stateset = new osg::StateSet; |
647 | | |
648 | | osg::Program* program = new osg::Program; |
649 | | point_stateset->setAttribute(program); |
650 | | |
651 | | #ifdef USE_LOCAL_SHADERS |
652 | | char vertexShaderSource[] = |
653 | | "uniform float inversePeriod;\n" |
654 | | "uniform vec4 particleColour;\n" |
655 | | "uniform float particleSize;\n" |
656 | | "\n" |
657 | | "uniform float osg_FrameTime;\n" |
658 | | "\n" |
659 | | "varying vec4 colour;\n" |
660 | | "\n" |
661 | | "void main(void)\n" |
662 | | "{\n" |
663 | | " float offset = gl_Vertex.z;\n" |
664 | | " float startTime = gl_MultiTexCoord1.x;\n" |
665 | | "\n" |
666 | | " vec4 v_current = gl_Vertex;\n" |
667 | | " v_current.z = fract( (osg_FrameTime - startTime)*inversePeriod - offset);\n" |
668 | | " \n" |
669 | | " colour = particleColour;\n" |
670 | | "\n" |
671 | | " gl_Position = gl_ModelViewProjectionMatrix * v_current;\n" |
672 | | "\n" |
673 | | " float pointSize = abs(1280.0*particleSize / gl_Position.w);\n" |
674 | | "\n" |
675 | | " //gl_PointSize = max(ceil(pointSize),2);\n" |
676 | | " gl_PointSize = ceil(pointSize);\n" |
677 | | " \n" |
678 | | " colour.a = 0.05+(pointSize*pointSize)/(gl_PointSize*gl_PointSize);\n" |
679 | | "}\n"; |
680 | | |
681 | | char fragmentShaderSource[] = |
682 | | "uniform sampler2D baseTexture;\n" |
683 | | "varying vec4 colour;\n" |
684 | | "\n" |
685 | | "void main (void)\n" |
686 | | "{\n" |
687 | | " gl_FragColor = colour * texture2D( baseTexture, gl_TexCoord[0]);\n" |
688 | | "}\n"; |
689 | | |
690 | | program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShaderSource)); |
691 | | program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource)); |
692 | | #else |
693 | | // get shaders from source |
694 | | program->addShader(osg::Shader::readShaderFile(osg::Shader::VERTEX, osgDB::findDataFile("point_rain.vert"))); |
695 | | program->addShader(osg::Shader::readShaderFile(osg::Shader::FRAGMENT, osgDB::findDataFile("point_rain.frag"))); |
696 | | #endif |
697 | | |
698 | | /// Setup the point sprites |
699 | | osg::PointSprite *sprite = new osg::PointSprite(); |
700 | | point_stateset->setTextureAttributeAndModes(0, sprite, osg::StateAttribute::ON); |
701 | | |
702 | | point_stateset->setMode(GL_VERTEX_PROGRAM_POINT_SIZE, osg::StateAttribute::ON); |
703 | | point_stateset->setRenderBinDetails(renderBin,"DepthSortedBin"); |
704 | | } |
705 | | |
706 | | createGeometry(numParticles, quad_geometry.get(), line_geometry.get(), point_geometry.get()); |
707 | | |
708 | | } |
709 | | |
710 | | |
711 | | osg::Node* createRainEffect(const osg::BoundingBox& bb, const PrecipatationParameters& parameters) |
712 | | { |
713 | | osg::LOD* lod = new osg::LOD; |
714 | | |
715 | | |
716 | | // distance between start point and end of cyclce |
717 | | osg::Vec3 position(bb.xMin(), bb.yMin(), bb.zMax()); |
718 | | |
719 | | // time taken to get from start to the end of cycle |
720 | | float period = fabs((bb.zMax()-bb.zMin()) / parameters.particleVelocity.z()); |
721 | | osg::Vec3 dv_i( bb.xMax()-bb.xMin(), 0.0f, 0.0f ); |
722 | | osg::Vec3 dv_j( 0.0f, bb.yMax()-bb.yMin(), 0.0f ); |
723 | | osg::Vec3 dv_k( parameters.particleVelocity * period ); |
724 | | |
725 | | osg::Vec3 scale( bb.xMax()-bb.xMin(), bb.yMax()-bb.yMin(), parameters.particleVelocity.z() * period); |
726 | | |
727 | | float startTime = random(0, period); |
728 | | |
729 | | // high res LOD. |
730 | | { |
731 | | osg::Geode* highres_geode = new osg::Geode; |
732 | | |
733 | | PrecipitationGeometry* geometry = new PrecipitationGeometry; |
734 | | |
735 | | highres_geode->addDrawable(geometry); |
736 | | |
737 | | geometry->setName("highres"); |
738 | | geometry->setPosition(position); |
739 | | geometry->setScale(scale); |
740 | | geometry->setStartTime(startTime); |
741 | | geometry->setInitialBound(bb); |
742 | | geometry->setInternalGeometry(quad_geometry.get()); |
743 | | geometry->setStateSet(quad_stateset.get()); |
744 | | |
745 | | lod->addChild( highres_geode, 0.0f, parameters.nearTransition ); |
746 | | } |
747 | | |
748 | | |
749 | | if (parameters.useFarLineSegments) |
750 | | { |
751 | | osg::Geode* lowres_geode = new osg::Geode; |
752 | | |
753 | | |
754 | | PrecipitationGeometry* geometry = new PrecipitationGeometry; |
755 | | |
756 | | lowres_geode->addDrawable(geometry); |
757 | | |
758 | | geometry->setName("lowres"); |
759 | | geometry->setPosition(position); |
760 | | geometry->setScale(scale); |
761 | | geometry->setStartTime(startTime); |
762 | | geometry->setInitialBound(bb); |
763 | | geometry->setInternalGeometry(line_geometry.get()); |
764 | | geometry->setStateSet(line_stateset.get()); |
765 | | |
766 | | lod->addChild( lowres_geode, parameters.nearTransition, parameters.farTransition ); |
767 | | } |
768 | | else |
769 | | { |
770 | | osg::Geode* lowres_geode = new osg::Geode; |
771 | | |
772 | | |
773 | | PrecipitationGeometry* geometry = new PrecipitationGeometry; |
774 | | |
775 | | lowres_geode->addDrawable(geometry); |
776 | | |
777 | | geometry->setName("lowres"); |
778 | | geometry->setPosition(position); |
779 | | geometry->setScale(scale); |
780 | | geometry->setStartTime(startTime); |
781 | | geometry->setInitialBound(bb); |
782 | | geometry->setInternalGeometry(point_geometry.get()); |
783 | | geometry->setStateSet(point_stateset.get()); |
784 | | |
785 | | lod->addChild( lowres_geode, parameters.nearTransition, parameters.farTransition ); |
786 | | } |
787 | | |
788 | | |
789 | | return lod; |
790 | | } |
791 | | |
792 | | osg::Node* createCellRainEffect(const PrecipatationParameters& parameters) |
793 | | { |
794 | | |
795 | | unsigned int numX = parameters.numberOfCellsX; |
796 | | unsigned int numY = parameters.numberOfCellsY; |
797 | | unsigned int numCells = numX*numY; |
798 | | unsigned int numParticlesPerCell = parameters.numberOfParticles/numCells; |
799 | | |
800 | | setUpGeometries(numParticlesPerCell); |
801 | | |
802 | | const osg::BoundingBox& bb = parameters.boundingBox; |
803 | | |
804 | | std::cout<<"Effect total number of particles = "<<parameters.numberOfParticles<<std::endl; |
805 | | std::cout<<"Number of cells = "<<numCells<<std::endl; |
806 | | std::cout<<"Number of particles per cell = "<<numParticlesPerCell<<std::endl; |
807 | | std::cout<<"Cell width = "<<(bb.xMax()-bb.xMin())/(float)(numX)<<std::endl; |
808 | | std::cout<<"Cell length = "<<(bb.yMax()-bb.yMin())/(float)(numY)<<std::endl; |
809 | | std::cout<<"Cell height = "<<(bb.zMax()-bb.zMin())<<std::endl; |
810 | | |
811 | | osg::Group* group = new osg::Group; |
812 | | for(unsigned int i=0; i<numX; ++i) |
813 | | { |
814 | | for(unsigned int j=0; j<numX; ++j) |
815 | | { |
816 | | osg::BoundingBox bbLocal(bb.xMin() + ((bb.xMax()-bb.xMin())*(float)i)/(float)(numX), |
817 | | bb.yMin() + ((bb.yMax()-bb.yMin())*(float)j)/(float)(numY), |
818 | | bb.zMin(), |
819 | | bb.xMin() + ((bb.xMax()-bb.xMin())*(float)(i+1))/(float)(numX), |
820 | | bb.yMin() + ((bb.yMax()-bb.yMin())*(float)(j+1))/(float)(numY), |
821 | | bb.zMax()); |
822 | | |
823 | | group->addChild(createRainEffect(bbLocal, parameters)); |
824 | | } |
825 | | } |
826 | | |
827 | | |
828 | | osgUtil::Optimizer::SpatializeGroupsVisitor sgv; |
829 | | group->accept(sgv); |
830 | | sgv.divide(); |
831 | | |
832 | | |
833 | | osg::StateSet* stateset = group->getOrCreateStateSet(); |
834 | | |
835 | | // time taken to get from start to the end of cycle |
836 | | float period = fabs((bb.zMax()-bb.zMin()) / parameters.particleVelocity.z()); |
837 | | |
838 | | // distance between start point and end of cyclce |
839 | | osg::Vec3 dv_i( (bb.xMax()-bb.xMin())/(float)(numX), 0.0f, 0.0f ); |
840 | | osg::Vec3 dv_j( 0.0f, (bb.yMax()-bb.yMin())/(float)(numY), 0.0f ); |
841 | | osg::Vec3 dv_k( parameters.particleVelocity * period ); |
842 | | |
843 | | |
844 | | osg::Uniform* inversePeriodUniform = new osg::Uniform("inversePeriod",1.0f/period); |
845 | | //osg::Uniform* startTime = new osg::Uniform("startTime",0.0f); |
846 | | |
847 | | stateset->addUniform(inversePeriodUniform); // float |
848 | | //stateset->addUniform(startTime); // float |
849 | | |
850 | | stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF); |
851 | | stateset->setMode(GL_BLEND, osg::StateAttribute::ON); |
852 | | |
853 | | osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0); |
854 | | stateset->addUniform(baseTextureSampler); |
855 | | |
856 | | osg::Texture2D* texture = new osg::Texture2D(createSpotLightImage(osg::Vec4(1.0f,1.0f,1.0f,1.0f),osg::Vec4(1.0f,1.0f,1.0f,0.0f),32,1.0)); |
857 | | stateset->setTextureAttribute(0, texture); |
858 | | |
859 | | stateset->addUniform(new osg::Uniform("particleColour", parameters.particleColour)); |
860 | | stateset->addUniform(new osg::Uniform("particleSize", parameters.particleSize)); |
861 | | |
862 | | // osg::Uniform* previousModelViewUniform = new osg::Uniform("previousModelViewMatrix",osg::Matrix()); |
863 | | // stateset->addUniform(previousModelViewUniform); |
864 | | |
865 | | // group->setCullCallback(new CullCallback(previousModelViewUniform)); |
866 | | |
867 | | |
868 | | return group; |
869 | | } |
870 | | |
871 | | osg::Node* createModel(osg::Node* loadedModel, PrecipatationParameters& parameters) |
| 31 | osg::Node* createModel(osg::Node* loadedModel, osgParticle::PrecipitationParameters& parameters) |