-------------------------------------------------------------------------------------- Description: Implements ITr2GenericParticleConstraint interface. Checks for collision between a particle and a sphere. If collision is detected optionally applies physical response to particle position and/or velocity and run generators to re-generate particle data components. This method can be called asyncrono
| 97 | // dt - Frame time. |
| 98 | // -------------------------------------------------------------------------------------- |
| 99 | void Tr2SphereConstraint::ApplyConstraint( const ITr2GenericEmitter::UpdateArguments& arguments, float** particles, unsigned* strides, unsigned count, float dt ) |
| 100 | { |
| 101 | if( !m_isValid ) |
| 102 | { |
| 103 | return; |
| 104 | } |
| 105 | |
| 106 | Tr2ParallelFor( |
| 107 | Tr2BlockedRange<size_t>( 0, count, 100 ), |
| 108 | [=]( const Tr2BlockedRange<size_t>& range ) -> void { |
| 109 | XMVECTOR refPosition = m_position; |
| 110 | XMVECTOR refRadius = XMVectorReplicate( m_radius ); |
| 111 | XMVECTOR invert = XMVectorReplicate( m_invertSphere ? -1.f : 1.f ); |
| 112 | XMVECTOR radiusCmp = XMVectorMultiply( invert, XMVectorMultiply( refRadius, refRadius ) ); |
| 113 | XMVECTOR particleRadiusCoefficient = m_particleRadiusCoefficient; |
| 114 | |
| 115 | Tr2ParticleStreamIterator<XMFLOAT3> position( particles, strides, m_positionElement ); |
| 116 | position += int( range.begin() ); |
| 117 | Tr2ParticleStreamIterator<XMFLOAT4> radiusStream( particles, strides, m_radiusElement ); |
| 118 | radiusStream += int( range.begin() ); |
| 119 | Tr2ParticleStreamIterator<XMFLOAT3> velocity( particles, strides, m_velocityElement ); |
| 120 | velocity += int( range.begin() ); |
| 121 | |
| 122 | for( auto i = range.begin(); i < range.end(); ++i, ++position, ++radiusStream, ++velocity ) |
| 123 | { |
| 124 | XMVECTOR radius = refRadius; |
| 125 | if( m_radiusElement.m_offset != -1 ) |
| 126 | { |
| 127 | if( m_invertSphere ) |
| 128 | { |
| 129 | radius = XMVectorSubtract( radius, XMVector4Dot( XMLoadFloat4( radiusStream ), particleRadiusCoefficient ) ); |
| 130 | } |
| 131 | else |
| 132 | { |
| 133 | radius = XMVectorAdd( radius, XMVector4Dot( XMLoadFloat4( radiusStream ), particleRadiusCoefficient ) ); |
| 134 | } |
| 135 | } |
| 136 | XMVECTOR curPosition = XMLoadFloat3( position ); |
| 137 | XMVECTOR curVelocity = XMLoadFloat3( velocity ); |
| 138 | XMVECTOR offset = XMVectorSubtract( curPosition, refPosition ); |
| 139 | XMVECTOR offsetLengthSq = XMVector3LengthSq( offset ); |
| 140 | |
| 141 | // Check if the particle is inside the "prohibited space" |
| 142 | if( XMVectorGetIntX( XMVectorLess( XMVectorMultiply( offsetLengthSq, invert ), radiusCmp ) ) ) |
| 143 | { |
| 144 | if( m_affectPosition ) |
| 145 | { |
| 146 | offset = XMVectorMultiply( offset, XMVectorReciprocal( XMVectorSqrt( offsetLengthSq ) ) ); |
| 147 | XMVECTOR newPosition = XMVectorMultiplyAdd( offset, radius, refPosition ); |
| 148 | XMStoreFloat3( position, newPosition ); |
| 149 | |
| 150 | if( m_affectVelocity && m_velocityElement.m_offset != -1 ) |
| 151 | { |
| 152 | offset = XMVectorMultiply( offset, invert ); |
| 153 | |
| 154 | XMVECTOR velocityDot = XMVector3Dot( curVelocity, offset ); |
| 155 | if( XMVectorGetIntX( XMVectorLess( velocityDot, XMVectorZero() ) ) ) |
| 156 | { |
nothing calls this directly
no test coverage detected