void BuildCylinder( core::array<video::S3DVertex>& vertexArray, core::array<u16>& indexArray, core::aabbox3d<f32>& boundingBox, f32 height, f32 startRadius, f32 endRadius, s32 radialSegments, const core::matrix4& transform, f32 startTCoordY = 0.0f, f32 endTCoordY = 1.0f, video::SColor startColor = video::SColor(255,255,255,255), video::SColor endColor = video::SColor(255,255,255,255) ) { u16 vertexIndex = vertexArray.size(); s32 radialVertices = radialSegments + 1; // We want one additional vertex to make the texture wraps correctly // Place bottom cap for ( s32 i=0; i<radialVertices; i++ ) { f32 angle = 2.0f * core::PI * i / (f32)( radialSegments ); core::vector3df dir; dir.X = cos(angle); dir.Z = sin(angle); core::vector3df pos; core::vector3df normal = dir; pos = dir * startRadius; // Place bottom vertex transform.transformVect( pos ); transform.rotateVect( normal ); core::vector2df tcoord; tcoord.X = (f32)( i ) / (f32)( radialSegments ); tcoord.Y = startTCoordY; vertexArray.push_back( video::S3DVertex( pos, normal, startColor, tcoord ) ); boundingBox.addInternalPoint( pos ); } // Place top cap and indices for ( s32 i=0; i<radialVertices; i++ ) { f32 angle = 2.0f * core::PI * i / (f32)( radialSegments ); core::vector3df dir; dir.X = cos(angle); dir.Z = sin(angle); core::vector3df normal = dir; core::vector3df pos = dir * endRadius; pos.Y = height; transform.transformVect( pos ); transform.rotateVect( normal ); core::vector2df tcoord; tcoord.X = (f32)( i ) / (f32)( radialSegments ); tcoord.Y = endTCoordY; vertexArray.push_back( video::S3DVertex( pos, normal, endColor, tcoord ) ); boundingBox.addInternalPoint(pos); // Add indices if ( i != radialVertices-1 ) { s32 i2 = (i+1)%radialVertices; // Place the indices indexArray.push_back ( vertexIndex + i ); indexArray.push_back ( vertexIndex + radialVertices + i ); indexArray.push_back ( vertexIndex + i2 ); indexArray.push_back ( vertexIndex + radialVertices + i ); indexArray.push_back ( vertexIndex + radialVertices + i2 ); indexArray.push_back ( vertexIndex + i2 ); } } }
// ---------------------------------------------------------------------------- void STKParticle::stimulateNormal(float dt, unsigned int active_count, std::vector<CPUParticle>* out) { const core::matrix4 cur_matrix = AbsoluteTransformation; core::vector3df previous_frame_position, current_frame_position, previous_frame_direction, current_frame_direction; for (unsigned i = 0; i < m_max_count; i++) { core::vector3df new_particle_position; core::vector3df new_particle_direction; float new_size = 0.0f; float new_lifetime = 0.0f; const core::vector3df particle_position = m_particles_generating[i].m_position; const float lifetime = m_particles_generating[i].m_lifetime; const core::vector3df particle_direction = m_particles_generating[i].m_direction; const float size = m_particles_generating[i].m_size; const core::vector3df particle_position_initial = m_initial_particles[i].m_position; const float lifetime_initial = m_initial_particles[i].m_lifetime; const core::vector3df particle_direction_initial = m_initial_particles[i].m_direction; const float size_initial = m_initial_particles[i].m_size; float updated_lifetime = lifetime + (dt / lifetime_initial); if (updated_lifetime > 1.0f) { if (i < active_count) { float dt_from_last_frame = glslFract(updated_lifetime) * lifetime_initial; float coeff = dt_from_last_frame / dt; m_previous_frame_matrix.transformVect(previous_frame_position, particle_position_initial); cur_matrix.transformVect(current_frame_position, particle_position_initial); core::vector3df updated_position = previous_frame_position .getInterpolated(current_frame_position, coeff); m_previous_frame_matrix.rotateVect(previous_frame_direction, particle_direction_initial); cur_matrix.rotateVect(current_frame_direction, particle_direction_initial); core::vector3df updated_direction = previous_frame_direction .getInterpolated(current_frame_direction, coeff); // + (current_frame_position - previous_frame_position) / dt; // To be accurate, emitter speed should be added. // But the simple formula // ( (current_frame_position - previous_frame_position) / dt ) // with a constant speed between 2 frames creates visual // artifacts when the framerate is low, and a more accurate // formula would need more complex computations. new_particle_position = updated_position + dt_from_last_frame * updated_direction; new_particle_direction = updated_direction; new_lifetime = glslFract(updated_lifetime); new_size = glslMix(size_initial, size_initial * m_size_increase_factor, glslFract(updated_lifetime)); } else { new_lifetime = glslFract(updated_lifetime); new_size = 0.0f; } } else { new_particle_position = particle_position + particle_direction * dt; new_particle_direction = particle_direction; new_lifetime = updated_lifetime; new_size = (size == 0.0f) ? 0.0f : glslMix(size_initial, size_initial * m_size_increase_factor, updated_lifetime); } m_particles_generating[i].m_position = new_particle_position; m_particles_generating[i].m_lifetime = new_lifetime; m_particles_generating[i].m_direction = new_particle_direction; m_particles_generating[i].m_size = new_size; if (out != NULL) { if (m_flips || new_size != 0.0f) { if (new_size != 0.0f) { Buffer->BoundingBox.addInternalPoint (new_particle_position); } out->emplace_back(new_particle_position, m_color_from, m_color_to, new_lifetime, new_size); } } } } // stimulateNormal