/** Given a matrix transform and a set of points returns an orthogonal projection matrix that maps coordinates of transformed points between -1 and 1. * \param transform a transform matrix. * \param pointsInside a vector of point in 3d space. */ core::matrix4 getTighestFitOrthoProj(const core::matrix4 &transform, const std::vector<vector3df> &pointsInside) { float xmin = std::numeric_limits<float>::infinity(); float xmax = -std::numeric_limits<float>::infinity(); float ymin = std::numeric_limits<float>::infinity(); float ymax = -std::numeric_limits<float>::infinity(); float zmin = std::numeric_limits<float>::infinity(); float zmax = -std::numeric_limits<float>::infinity(); for (unsigned i = 0; i < pointsInside.size(); i++) { vector3df TransformedVector; transform.transformVect(TransformedVector, pointsInside[i]); xmin = MIN2(xmin, TransformedVector.X); xmax = MAX2(xmax, TransformedVector.X); ymin = MIN2(ymin, TransformedVector.Y); ymax = MAX2(ymax, TransformedVector.Y); zmin = MIN2(zmin, TransformedVector.Z); zmax = MAX2(zmax, TransformedVector.Z); } float left = xmin; float right = xmax; float up = ymin; float down = ymax; core::matrix4 tmp_matrix; // Prevent Matrix without extend if (left == right || up == down) return tmp_matrix; tmp_matrix.buildProjectionMatrixOrthoLH(left, right, down, up, 30, zmax); return tmp_matrix; }
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
// ---------------------------------------------------------------------------- void STKParticle::stimulateHeightMap(float dt, unsigned int active_count, std::vector<CPUParticle>* out) { assert(m_hm != NULL); const core::matrix4 cur_matrix = AbsoluteTransformation; 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 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; bool reset = false; const int px = core::clamp((int)(256.0f * (particle_position.X - m_hm->m_x) / m_hm->m_x_len), 0, 255); const int py = core::clamp((int)(256.0f * (particle_position.Z - m_hm->m_z) / m_hm->m_z_len), 0, 255); const float h = particle_position.Y - m_hm->m_array[px][py]; reset = h < 0.0f; core::vector3df initial_position, initial_new_position; cur_matrix.transformVect(initial_position, particle_position_initial); cur_matrix.transformVect(initial_new_position, particle_position_initial + particle_direction_initial); core::vector3df adjusted_initial_direction = initial_new_position - initial_position; float adjusted_lifetime = lifetime + (dt / lifetime_initial); reset = reset || adjusted_lifetime > 1.0f; reset = reset || lifetime < 0.0f; new_particle_position = !reset ? (particle_position + particle_direction * dt) : initial_position; new_lifetime = !reset ? adjusted_lifetime : 0.0f; new_particle_direction = !reset ? particle_direction : adjusted_initial_direction; new_size = !reset ? glslMix(size_initial, size_initial * m_size_increase_factor, adjusted_lifetime) : 0.0f; 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); } } } } // stimulateHeightMap