GeometryRayTestResult Intersects(const Sphere& Ball, const Ray& Cast) { // Code in this function is based on the equivalent in Ogre const Vector3 CastDir = Cast.GetNormal(); const Vector3 CastOrigin = Cast.GetOrigin() - Ball.Center; // Makes math easier to do this in sphere local coordinates const Real Radius = Ball.Radius; // Build coefficients for our formula // t = (-b +/- sqrt(b*b + 4ac)) / 2a Real ACoEff = CastDir.DotProduct(CastDir); Real BCoEff = 2 * CastOrigin.DotProduct(CastDir); Real CCoEff = CastOrigin.DotProduct(CastOrigin) - ( Radius * Radius ); // Get the Determinate Real Determinate = ( BCoEff * BCoEff ) - ( 4 * ACoEff * CCoEff ); if( Determinate < 0 ) { return GeometryRayTestResult(false,Ray()); }else{ Real NearDist = ( -BCoEff - MathTools::Sqrt( Determinate ) ) / ( 2 * ACoEff ); Real FarDist = ( -BCoEff + MathTools::Sqrt( Determinate ) ) / ( 2 * ACoEff ); Ray Ret( Cast.GetOrigin() + (CastDir * NearDist), Cast.GetOrigin() + (CastDir * FarDist) ); return GeometryRayTestResult(true,Ret); } }
float Ray::HitDistance(const Sphere& sphere) const { Vector3 centeredOrigin = origin_ - sphere.center_; float squaredRadius = sphere.radius_ * sphere.radius_; // Check if ray originates inside the sphere if (centeredOrigin.LengthSquared() <= squaredRadius) return 0.0f; // Calculate intersection by quadratic equation float a = direction_.DotProduct(direction_); float b = 2.0f * centeredOrigin.DotProduct(direction_); float c = centeredOrigin.DotProduct(centeredOrigin) - squaredRadius; float d = b * b - 4.0f * a * c; // No solution if (d < 0.0f) return M_INFINITY; // Get the nearer solution float dSqrt = sqrtf(d); float dist = (-b - dSqrt) / (2.0f * a); if (dist >= 0.0f) return dist; else return (-b + dSqrt) / (2.0f * a); }
//--------------------------- // //--------------------------- void Matrix44::SetView( const Vector3& vPos, const Vector3& vDir_, const Vector3& vUp_ ) { Vector3 vDir; Vector3 vUp; Vector3 vCross; vDir = vDir_.Normal(); vCross = vUp_.CrossProduct( vDir ); vCross.Normalize(); vUp = vDir.CrossProduct( vCross ); _11 = vCross.x; _12 = vUp.x; _13 = vDir.x; _14 = 0.0F; _21 = vCross.y; _22 = vUp.y; _23 = vDir.y; _24 = 0.0F; _31 = vCross.z; _32 = vUp.z; _33 = vDir.z; _34 = 0.0F; _41 = -vPos.DotProduct( vCross ); _42 = -vPos.DotProduct( vUp ); _43 = -vPos.DotProduct( vDir ); _44 = 1.0F; } //Matrix44::SetView
void Matrix44::SetView( const Vector3& pos, const Vector3& dir0, const Vector3& up0 ) { Vector3 vDir; Vector3 vUp; Vector3 vCross; vDir = dir0.Normal(); vCross = up0.CrossProduct( vDir ); vCross.Normalize(); vUp = vDir.CrossProduct( vCross ); _11 = vCross.x; _12 = vUp.x; _13 = vDir.x; _14 = 0.0f; _21 = vCross.y; _22 = vUp.y; _23 = vDir.y; _24 = 0.0f; _31 = vCross.z; _32 = vUp.z; _33 = vDir.z; _34 = 0.0f; _41 = -pos.DotProduct( vCross ); _42 = -pos.DotProduct( vUp ); _43 = -pos.DotProduct( vDir ); _44 = 1.0f; }
/** * @brief * Calculate the intersection of a ray and a triangle */ dFloat BodyTerrain::RayCastTriangle(const Vector3 &p0, const Vector3 &dp, const Vector3 &origin, const Vector3 &e1, const Vector3 &e2) { dFloat t; dFloat b0; dFloat b1; dFloat b00; dFloat b11; dFloat a00; dFloat a10; dFloat a11; dFloat det; dFloat dot; dFloat tol; // Clip line again first triangle Vector3 normal(e2.CrossProduct(e1)); dot = normal.DotProduct(dp); if (dot <= 1.0e-6f) { t = ((origin - p0).DotProduct(normal)) / dot; if (t > 0.0f) { if (t < 1.0f) { Vector3 q = p0 + dp*t; a00 = e1.DotProduct(e1); a11 = e2.DotProduct(e2); a10 = e1.DotProduct(e2); det = a00*a11 - a10*a10; // det must be positive and different than zero // _ASSERTE(det > 0.0f); Vector3 q0p0 = q - origin; b0 = q0p0.DotProduct(e1); b1 = q0p0.DotProduct(e2); tol = -det*1.0e-3f; b00 = b0*a11 - b1*a10; if (b00 >= tol) { b11 = b1*a00 - b0*a10; if (b11 >= tol) { if ((b00 + b11) <= (det*1.001f)) { // Found a hit return this value return t; } } } } } } // If it come here the there no intersection return 1.2f; }
void IK::DefineM(const Vector3 p, const Vector3 d) { Vector3 mX,mY,mZ; // Minv defines a coordinate system whose x axis contains P, so X = unit(P). mX = p.Normalized(); // The y axis of Minv is perpendicular to P, so Y = unit( D - X(D·X) ). float dDOTx = d.DotProduct(mX); mY.x_ = d.x_ - dDOTx * mX.x_; mY.y_ = d.y_ - dDOTx * mX.y_; mY.z_ = d.z_ - dDOTx * mX.z_; mY.Normalize(); // The z axis of Minv is perpendicular to both X and Y, so Z = X×Y. mZ=mX.CrossProduct(mY); Minv = Matrix3(mX.x_,mX.y_,mX.z_,mY.x_,mY.y_,mY.z_,mZ.x_,mZ.y_,mZ.z_); //Minv = Minv.Transpose(); Mfwd = Minv.Transpose(); // Mfwd = (Minv)T, since transposing inverts a rotation matrix. }
Vector3 Vector3::Refract(const Vector3& n, double r_coeff) const { Vector3 result; //TODO: Calculate the refraction of this vector given the input normal n and the refractive coefficient r_index //Store the result in result //Refraction is governed by the Snell's law // DONE double cosI = n.DotProduct(*this) * -1; // if cosI is negative then the normal is pointing the wrong way if (cosI < 0) { cosI *= -1; } double sinT2 = r_coeff * r_coeff * (1.0 - cosI * cosI); double cosT = sqrt(1.0 - sinT2); result = *this * r_coeff + n * (r_coeff * cosI - cosT); return result; }
void Quaternion::FromRotationTo(const Vector3& start, const Vector3& end) { Vector3 normStart = start.Normalized(); Vector3 normEnd = end.Normalized(); float d = normStart.DotProduct(normEnd); if (d > -1.0f + M_EPSILON) { Vector3 c = normStart.CrossProduct(normEnd); float s = sqrtf((1.0f + d) * 2.0f); float invS = 1.0f / s; x_ = c.x_ * invS; y_ = c.y_ * invS; z_ = c.z_ * invS; w_ = 0.5f * s; } else { Vector3 axis = Vector3::RIGHT.CrossProduct(normStart); if (axis.Length() < M_EPSILON) axis = Vector3::UP.CrossProduct(normStart); FromAngleAxis(180.f, axis); } }
void OptimizeLigandGeomety(Conformer& ligand, double chi_increment, std::vector<double> chi_stdev, std::string lp_atom, double unit_cell_length, double angle_tolerance, std::string output_dir) { if (ligand.parent()->conformer_states() == NULL) Log->error(FLERR, "There are no conformer states for the ligand!"); const std::vector<Linkage<std::string> >& chi_names = ligand.parent()->conformer_states()->degrees_of_freedom(); std::vector<double> chi_values = GetChiValues(ligand); //adjust chi to values between [0, 360] for (size_t i = 0; i < chi_values.size(); ++i) { chi_values[i] = (chi_values[i] < 0 ? chi_values[i] += 360 : chi_values[i]); } //loop through the possible chi angles, filling the ligand geometry map std::map<std::vector<double>, std::vector<double> > ligand_geometry; for(double chi1 = floor(chi_values[0] - chi_stdev[0]); chi1 < ceil(chi_values[0] + chi_stdev[0]); chi1 += chi_increment) { for(double chi2 = floor(chi_values[1] - chi_stdev[1]); chi2 < ceil(chi_values[1] + chi_stdev[1]); chi2 += chi_increment) { ligand.AdjustLinkage(chi_names[0], chi1); ligand.AdjustLinkage(chi_names[1], chi2); std::vector<double> chis; chis.push_back(chi1); chis.push_back(chi2); Vector3 v = CalculateLonePairDirection(ligand, lp_atom); //Calculate the dot product of v and z axis unit vector //cos(q) = v*w / (|v|*|w|) double angle_z = RADIANS_TO_DEGREES * acos(v.DotProduct(Vector3(0, 0, 1)) / v.Length()); //Calculate the dot product of v and the vector from the N to the metal (where the C4 symmetry axis is) Atom* N = ligand.Find(lp_atom); Vector3 N_metal(unit_cell_length - N->x(), - N->y(), 0); double angle_metal = RADIANS_TO_DEGREES * acos(v.DotProduct(N_metal) / (v.Length() * N_metal.Length())); if ((angle_z < (90.0 + angle_tolerance) && angle_z > (90.0 - angle_tolerance)) && (angle_metal < angle_tolerance)) { ligand_geometry[chis].push_back(angle_z); ligand_geometry[chis].push_back(angle_metal); //OutputStructure(ligand.parent()->parent()->parent()->parent()->parent()->parent(), chis, lp_atom, output_dir); Log->print("Optimized Cu binding PDB with chi1 " + Log->to_str(chi1) + ", chi2 " + Log->to_str(chi2)); OutputLatticeStructure(ligand.parent()->parent()->parent()->parent()->parent()->parent(), chis, unit_cell_length, lp_atom, output_dir); } } } OutputStat(ligand_geometry, lp_atom, output_dir); }
Matrix4& Matrix4::LookAtLH( const Vector3& eye, const Vector3& at, const Vector3& up ) { Vector3 zaxis = at - eye; zaxis.Normalize(); Vector3 nup = up; nup.Normalize(); Vector3 xaxis = zaxis.CrossProduct( nup ); Vector3 yaxis = xaxis.CrossProduct( zaxis ); A[0][0] = xaxis.X; A[1][0] = xaxis.Y; A[2][0] = xaxis.Z; A[3][0] = 0.0f; A[0][1] = yaxis.X; A[1][1] = yaxis.Y; A[2][1] = yaxis.Z; A[3][1] = 0.0f; A[0][2] = zaxis.X; A[1][2] = zaxis.Y; A[2][2] = zaxis.Z; A[3][2] = 0.0f; A[0][3] = -xaxis.DotProduct( eye ); A[1][3] = -yaxis.DotProduct( eye ); A[2][3] = -zaxis.DotProduct( eye ); A[3][3] = 1.0f; return *this; }
bool Plane3::isPointOnPlane( const Vector3& pointToCheck ) const { if( pointToCheck.DotProduct( normal ) == distanceFromOrigin ) { return true; } return false; }
bool Collider::Check(const OrientedBoundingBox2D &OBB2D, const Sphere &SP) { Vector3 pt = OBB2D.ClosestPoint(SP.position); Vector3 v = pt - SP.position; return v.DotProduct(v) <= SP.radious*SP.radious; }
Vector3 CalculateLonePairDirection(Conformer& ligand, std::string LP_atom) { Atom* NE = ligand.Find("NE2"); Atom* ND = ligand.Find("ND1"); Atom* CG = ligand.Find("CG"); Atom* CD = ligand.Find("CD2"); Atom* CE = ligand.Find("CE1"); if (NE == NULL || ND == NULL || CG == NULL || CD == NULL || CE == NULL) Log->error(FLERR, "Check the atom names in the ligand"); Vector3 v; if (LP_atom == "NE2") { //define theta Vector3 r1(*CE, *NE); Vector3 r2(*CD, *NE); double theta = acos(r1.DotProduct(r2) / (r1.Length() * r2.Length())); //define gamma, gamma = 0.5 * theta Point middle; double a = 0.49969; middle.set_x(a * ND->x() + (1 - a) * CG->x()); middle.set_y(a * ND->y() + (1 - a) * CG->y()); middle.set_z(a * ND->z() + (1 - a) * CG->z()); v = Vector3(middle, *NE); double gamma = acos(v.DotProduct(r2) / (v.Length() * r2.Length())); } else if (LP_atom == "ND1") { //define theta Vector3 r1(*CE, *ND); Vector3 r2(*CG, *ND); double theta = acos(r1.DotProduct(r2) / (r1.Length() * r2.Length())); //define gamma, gamma = 0.5 * theta Point middle; double a = 0.495; middle.set_x(a * NE->x() + (1 - a) * CD->x()); middle.set_y(a * NE->y() + (1 - a) * CD->y()); middle.set_z(a * NE->z() + (1 - a) * CD->z()); v = Vector3(middle, *ND); double gamma = acos(v.DotProduct(r2) / (v.Length() * r2.Length())); } return v; }
void Quaternion::SetRotationArc(const Vector3& v0, const Vector3& v1, const Vector3 &norm) { Vector3 vCross = v0.CrossProduct(v1); const float len = vCross.Length(); if (len <= 0.01f) { // v0 - v1 벡터가 정확히 반대 방향이거나, 정확히 같은 방향을 가르킬때, // 두 벡터에 직교하는 벡터 norm 에서 180도 회전하거나, 회전하지 않거나 // 결정한다. *this = Quaternion(norm, v0.DotProduct(v1) > 0 ? 0 : MATH_PI); return; } float fDot = v0.DotProduct(v1); float s = (float)sqrtf((1.0f + fDot) * 2.0f); x = vCross.x / s; y = vCross.y / s; z = vCross.z / s; w = s * 0.5f; } //Quaternion::SetRotationArc
// ---------------------------------------------------------------------------- Vector3 Face::Intersect(const Vector3& origin, const Vector3& direction) const { #define NO_INTERSECTION Vector3(-1, -1, -1) #define DO_CULL 0 // Algorithm taken from: // "Fast, Minimum Storage Ray/Triangle Intersection" // See doc/research/ Vector3 edge1 = vertex_[1]->position_ - vertex_[0]->position_; Vector3 edge2 = vertex_[2]->position_ - vertex_[0]->position_; Vector3 p = direction.CrossProduct(edge2); float determinant = p.DotProduct(edge1); #if DO_CULL if(determinant == 0.0f) return NO_INTERSECTION; #endif Vector3 ray = origin - vertex_[0]->position_; float u = p.DotProduct(ray); #if DO_CULL if(u < 0.0f || u > determinant) return NO_INTERSECTION; #endif Vector3 q = ray.CrossProduct(edge1); float v = q.DotProduct(direction); #if DO_CULL if(v < 0.0f || v > determinant) return NO_INTERSECTION; #endif determinant = 1.0f / determinant; u *= determinant; v *= determinant; return Vector3(1.0f - u - v, u, v); }
Colour RayTracer::CalculateSpecularLighting(Vector3 &surfacePoint, Vector3 &surfaceNormal, Vector3 &lightPosition, Vector3 &cameraPosition, Light &light, Material &material) { Colour specular; Vector3 halfVector = Vector3::HalfVector(cameraPosition, surfacePoint, lightPosition); double angle = halfVector.DotProduct(surfaceNormal); double power = powf(angle, material.GetSpecPower()); specular.red = light.GetLightColour().red * material.GetSpecularColour().red * power; specular.green = light.GetLightColour().green * material.GetSpecularColour().green * power; specular.blue = light.GetLightColour().blue * material.GetSpecularColour().blue * power; return specular; }
Colour RayTracer::CalculateDiffuseLighting(Vector3 &lightNormal, Vector3 &surfaceNormal, Light &light, Material &material) { Colour diffuse; double angle = lightNormal.DotProduct(surfaceNormal); if (angle > 0.0) { diffuse.red = light.GetLightColour().red * material.GetDiffuseColour().red * angle; diffuse.green = light.GetLightColour().red * material.GetDiffuseColour().green * angle; diffuse.blue = light.GetLightColour().red * material.GetDiffuseColour().blue * angle; } return diffuse; }
VCNBool VCNRay::Intersects( const VCNSphere& sphere, VCNFloat& t ) const { Vector3 w = sphere.GetCenter() - m_vcOrig; VCNFloat c = w.Length(); VCNFloat v = w.DotProduct(m_vcDir); VCNFloat d = (sphere.GetRadius() * sphere.GetRadius()) - (c*c - v*v); t = -1.0f; // If there was no intersection, return -1 if (d < 0.0f) return false; // Return the distance to the [first] intersecting point t = v - sqrt(d); return true; }
//! test a sphere against the frustum Frustum::E_TestResult Frustum::Test(const Vector3& vCenter, f32 fRadius) const { for(u32 i=0; i<P_Count; ++i) { f32 fDist = vCenter.DotProduct(m_Planes[i].Normal) - m_Planes[i].D; if(fDist > fRadius) { return TR_Out; } if(Math::FAbs(fDist) < fRadius) { return TR_Intersect; } } return TR_In; }
//! returns the closest point on a line segment [A B] Vector3 Math::GetClosestPointOnLine(const Vector3& vPoint, const Vector3& vA, const Vector3& vB) { Vector3 vC = vPoint-vA; Vector3 vD = vB-vA; float fLength = vD.GetLength(); vD = vD / fLength; float t = vD.DotProduct(vC); if(t < 0.0f) { return vA; } else if(t > fLength) { return vB; } return vA + vD*t; }
//-------------------------------- // //-------------------------------- void Quaternion::SetRotationArc( const Vector3& v0, const Vector3& v1 ) { Vector3 vCross = v0.CrossProduct( v1 ); float fDot = v0.DotProduct( v1 ); float s = (float)sqrt( ( 1.0F + fDot ) * 2.0F ); if( 0.1f > s ) { x = 0; y = 1; z = 0; w = 0; return; } x = vCross.x / s; y = vCross.y / s; z = vCross.z / s; w = s * 0.5F; } //Quaternion::SetRotationArc
// 광선 orig, dir 에 충돌된 면이 있다면 true 를 리턴하고, 충돌 위치를 out에 // 저장해서 리턴한다. bool cGrid2::Pick( const Vector3 &orig, const Vector3 &dir, Vector3 &out ) { bool isFirst = true; sVertexNormTex *vertices = (sVertexNormTex*)m_vtxBuff.Lock(); WORD *indices = (WORD*)m_idxBuff.Lock(); RETV(!vertices || !indices, false); for (int i=0; i < m_idxBuff.GetFaceCount()*3; i+=3) { const Vector3 &p1 = vertices[ indices[ i]].p; const Vector3 &p2 = vertices[ indices[ i+1]].p; const Vector3 &p3 = vertices[ indices[ i+2]].p; const Triangle tri(p1, p2, p3); const Plane p(p1, p2, p3); const float dot = dir.DotProduct( p.N ); if (dot >= 0) continue; float t; if (tri.Intersect(orig, dir, &t)) { if (isFirst) { isFirst = false; out = orig + dir * t; } else { const Vector3 v = orig + dir * t; if (orig.LengthRoughly(v) < orig.LengthRoughly(out)) out = v; } } } m_vtxBuff.Unlock(); m_idxBuff.Unlock(); return !isFirst; }
void CollisionShape2D::OnMarkedDirty(Node* node) { Vector3 newWorldScale = node_->GetWorldScale(); Vector3 delta = newWorldScale - cachedWorldScale_; if (delta.DotProduct(delta) < 0.01f) return; // Physics operations are not safe from worker threads Scene* scene = GetScene(); if (scene && scene->IsThreadedUpdate()) { scene->DelayedMarkedDirty(this); return; } cachedWorldScale_ = newWorldScale; if (fixture_) ApplyNodeWorldScale(); }
//-------------------------------- // //-------------------------------- void Quaternion::SetRotationArc( const Vector3& v0, const Vector3& v1 ) { Vector3 vCross = v0.CrossProduct(v1); const float len = vCross.Length(); if (len <= 0.01f) { x = 0; y = 0; z = 0; w = 1; return; } float fDot = v0.DotProduct( v1 ); float s = (float)sqrtf((1.0f + fDot) * 2.0f); //if (0.1f > s) //{ // x = 0; y = 1; z = 0; w = 0; // return; //} x = vCross.x / s; y = vCross.y / s; z = vCross.z / s; w = s * 0.5f; } //Quaternion::SetRotationArc
//THIS NEEDS TESTING MAJORLY void Sphere::ResolveCollision(Sphere& rhs, const float& time){ //Calculate the depth of the penetration float penDepth = this->radius + rhs.radius - this->position.GetDistance(rhs.position); //Calculate the contact normal Vector3 conNormal = (this->position - rhs.position).GetNormalised(); //Calculate the point of contact Vector3 conPoint = this->position - conNormal * (this->radius - penDepth); //Calculate the rough combined elasticity of the two spheres in //the collision. An application of the smoke and mirrors technique! float elasticity = (this->elasticity + rhs.elasticity) * 0.5f; //Calculate the velocities of both spheres Vector3 va = this->getVelocity(time); Vector3 vb = rhs.getVelocity(time); //Calculate the Vn of the collision float veloNormal = (va - vb).DotProduct(conNormal); //Calculate the impulse of the collision float impulse = ( -(1 + elasticity) * veloNormal ) / conNormal.DotProduct(conNormal * ( (1 / this->mass) + (1 / rhs.mass) )); //Calculate the resultant velocties of the collision Vector3 vaAfter = va + ((impulse/this->mass) * conNormal); Vector3 vbAfter = vb - ((impulse/rhs.mass) * conNormal); //Translate the shapes out of contact with each other this->translate(conNormal * (penDepth*0.5f)); rhs.translate(0.0f - (conNormal * (penDepth*0.5f))); //Apply the calculated velocties to them this->setVelocity(vaAfter, time); rhs.setVelocity(vbAfter, time); }
//! 3D sphere vs ray intersection check bool CollisionUtils::SphereIntersectsWithRay(const Vector3& vCenter, f32 fRadius, const Vector3& vRayStart, const Vector3& vRayDir, f32* fRayLength /*= 0*/, f32* fDistToIntersection /*= 0*/) { Vector3 vToSphere = vCenter-vRayStart; f32 fDist = vToSphere.GetLength(); f32 fV = vToSphere.DotProduct(vRayDir); f32 fD = fRadius*fRadius - (fDist*fDist - fV*fV); f32 _fDistToIntersection = fV - Math::SquareRoot(fD); if(fD < 0.0f || _fDistToIntersection < 0.0f) { return false; } if(fRayLength && (*fRayLength < _fDistToIntersection)) { return false; } if(fDistToIntersection) { *fDistToIntersection = _fDistToIntersection; } return true; }
/** * @brief * Called when the scene node needs to be updated */ void PGLeaf::OnUpdate() { // If this scene node wasn't drawn at the last frame, we can skip some update stuff if ((GetFlags() & ForceUpdate) || m_bUpdate) { m_bUpdate = false; // If there are free particles, create new particles Particle *pParticle = AddParticle(); while (pParticle) { InitParticle(*pParticle); // Next particle, please pParticle = AddParticle(); } { // Update particles float fTimeDiff = Timing::GetInstance()->GetTimeDifference(); Iterator<Particle> cIterator = GetParticleIterator(); while (cIterator.HasNext()) { Particle &cParticle = cIterator.Next(); // Update forces // One: gravity cParticle.vVelocity[1] -= fTimeDiff*(cParticle.vPos[1]-FloorHeight)/5; // Two wind (dot wind vector normal) Vector3 vRot; EulerAngles::FromQuaternion(*cParticle.pRot, vRot.x, vRot.y, vRot.z); vRot.x *= static_cast<float>(Math::RadToDeg); vRot.y *= static_cast<float>(Math::RadToDeg); vRot.z *= static_cast<float>(Math::RadToDeg); cParticle.vVelocity += Wind.Get()*fTimeDiff*Math::Abs(vRot.DotProduct(Wind.Get())); // Four collision (just check whether leaf would end up on wrong side) if (cParticle.vPos.y + cParticle.vVelocity.y*fTimeDiff < FloorHeight) { // Random bouncy and some friction cParticle.vVelocity.y *= -1.0; cParticle.vVelocity.z *= Math::GetRandNegFloat(); cParticle.vVelocity.x *= Math::GetRandNegFloat(); cParticle.nCustom1 = ((static_cast<int>(Math::GetRandNegFloat()*255.0f*8.0f))<<8) | (cParticle.nCustom1&0xff); } // Five check whether particle has left area and can die... if it is outside, let it die float fDistx = GetTransform().GetPosition().x - cParticle.vPos.x; float fDisty = GetTransform().GetPosition().z - cParticle.vPos.z; float fDistToCenter = fDistx*fDistx + fDisty*fDisty; uint32 nStart = cParticle.nCustom1 & 0xff; if (nStart < 0xff) { // It is being spawned nStart += static_cast<uint32>(fTimeDiff*512.0f + 0.5f); if (nStart > 0xff) nStart = 0xff; // Clamp cParticle.nCustom1 = (cParticle.nCustom1&0xffffff00)|nStart; // Write to lower 8 bits } if (fDistToCenter > Radius*Radius) { // Start dying... set alpha according to how far it is away fDistToCenter = 255 - (Math::Sqrt(fDistToCenter) - Radius)*3.0f; cParticle.fSize = static_cast<float>(static_cast<int>(fDistToCenter*(cParticle.nCustom1 & 0xff))>>8)/255*cParticle.fCustom1; if (cParticle.fSize < 0.2f) InitParticle(cParticle); } else { cParticle.fSize = static_cast<float>(cParticle.nCustom1 &0xff)/255*cParticle.fCustom1; } // Update position cParticle.vPos += cParticle.vVelocity*fTimeDiff*cParticle.fSize/2; // Update spin Vector3 vAxis = cParticle.vVelocity; vAxis.SetLength(1); // Transform normal and distortion vAxis *= ((static_cast<float>(cParticle.nCustom1>>8))/255.0f)*fTimeDiff/10; Quaternion qRotInc; EulerAngles::ToQuaternion(static_cast<float>(vAxis.x*Math::DegToRad), static_cast<float>(vAxis.y*Math::DegToRad), static_cast<float>(vAxis.z*Math::DegToRad), qRotInc); *cParticle.pRot *= qRotInc; Vector3 d = cParticle.vDistortion; d.SetLength(cParticle.fSize); cParticle.vDistortion = (*cParticle.pRot)*d; // Update color EulerAngles::FromQuaternion(*cParticle.pRot, vRot.x, vRot.y, vRot.z); vRot.x *= static_cast<float>(Math::RadToDeg); vRot.y *= static_cast<float>(Math::RadToDeg); vRot.z *= static_cast<float>(Math::RadToDeg); vAxis = vRot.Normalize(); fDistx = vAxis.x+vAxis.y*2+vAxis.z*3; if (fDistx > 1.0f) fDistx = 1.0f; if (fDistx < 0.5f) fDistx = 0.5f; cParticle.vColor[0] = cParticle.vFixPos.x*fDistx; cParticle.vColor[1] = cParticle.vFixPos.y*fDistx; cParticle.vColor[2] = cParticle.vFixPos.z*fDistx; }
void Terrain::CreatePatchGeometry(TerrainPatch* patch) { URHO3D_PROFILE(CreatePatchGeometry); unsigned row = (unsigned)(patchSize_ + 1); VertexBuffer* vertexBuffer = patch->GetVertexBuffer(); Geometry* geometry = patch->GetGeometry(); Geometry* maxLodGeometry = patch->GetMaxLodGeometry(); Geometry* occlusionGeometry = patch->GetOcclusionGeometry(); if (vertexBuffer->GetVertexCount() != row * row) vertexBuffer->SetSize(row * row, MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1 | MASK_TANGENT); SharedArrayPtr<unsigned char> cpuVertexData(new unsigned char[row * row * sizeof(Vector3)]); SharedArrayPtr<unsigned char> occlusionCpuVertexData(new unsigned char[row * row * sizeof(Vector3)]); float* vertexData = (float*)vertexBuffer->Lock(0, vertexBuffer->GetVertexCount()); float* positionData = (float*)cpuVertexData.Get(); float* occlusionData = (float*)occlusionCpuVertexData.Get(); BoundingBox box; unsigned occlusionLevel = occlusionLodLevel_; if (occlusionLevel > numLodLevels_ - 1) occlusionLevel = numLodLevels_ - 1; if (vertexData) { const IntVector2& coords = patch->GetCoordinates(); int lodExpand = (1 << (occlusionLevel)) - 1; int halfLodExpand = (1 << (occlusionLevel)) / 2; for (int z = 0; z <= patchSize_; ++z) { for (int x = 0; x <= patchSize_; ++x) { int xPos = coords.x_ * patchSize_ + x; int zPos = coords.y_ * patchSize_ + z; // Position Vector3 position((float)x * spacing_.x_, GetRawHeight(xPos, zPos), (float)z * spacing_.z_); *vertexData++ = position.x_; *vertexData++ = position.y_; *vertexData++ = position.z_; *positionData++ = position.x_; *positionData++ = position.y_; *positionData++ = position.z_; box.Merge(position); // For vertices that are part of the occlusion LOD, calculate the minimum height in the neighborhood // to prevent false positive occlusion due to inaccuracy between occlusion LOD & visible LOD float minHeight = position.y_; if (halfLodExpand > 0 && (x & lodExpand) == 0 && (z & lodExpand) == 0) { int minX = Max(xPos - halfLodExpand, 0); int maxX = Min(xPos + halfLodExpand, numVertices_.x_ - 1); int minZ = Max(zPos - halfLodExpand, 0); int maxZ = Min(zPos + halfLodExpand, numVertices_.y_ - 1); for (int nZ = minZ; nZ <= maxZ; ++nZ) { for (int nX = minX; nX <= maxX; ++nX) minHeight = Min(minHeight, GetRawHeight(nX, nZ)); } } *occlusionData++ = position.x_; *occlusionData++ = minHeight; *occlusionData++ = position.z_; // Normal Vector3 normal = GetRawNormal(xPos, zPos); *vertexData++ = normal.x_; *vertexData++ = normal.y_; *vertexData++ = normal.z_; // Texture coordinate Vector2 texCoord((float)xPos / (float)numVertices_.x_, 1.0f - (float)zPos / (float)numVertices_.y_); *vertexData++ = texCoord.x_; *vertexData++ = texCoord.y_; // Tangent Vector3 xyz = (Vector3::RIGHT - normal * normal.DotProduct(Vector3::RIGHT)).Normalized(); *vertexData++ = xyz.x_; *vertexData++ = xyz.y_; *vertexData++ = xyz.z_; *vertexData++ = 1.0f; } } vertexBuffer->Unlock(); vertexBuffer->ClearDataLost(); } patch->SetBoundingBox(box); if (drawRanges_.Size()) { unsigned occlusionDrawRange = occlusionLevel << 4; geometry->SetIndexBuffer(indexBuffer_); geometry->SetDrawRange(TRIANGLE_LIST, drawRanges_[0].first_, drawRanges_[0].second_, false); geometry->SetRawVertexData(cpuVertexData, MASK_POSITION); maxLodGeometry->SetIndexBuffer(indexBuffer_); maxLodGeometry->SetDrawRange(TRIANGLE_LIST, drawRanges_[0].first_, drawRanges_[0].second_, false); maxLodGeometry->SetRawVertexData(cpuVertexData, MASK_POSITION); occlusionGeometry->SetIndexBuffer(indexBuffer_); occlusionGeometry->SetDrawRange(TRIANGLE_LIST, drawRanges_[occlusionDrawRange].first_, drawRanges_[occlusionDrawRange].second_, false); occlusionGeometry->SetRawVertexData(occlusionCpuVertexData, MASK_POSITION); } patch->ResetLod(); }
void DecalSet::GetFace(Vector<PODVector<DecalVertex> >& faces, Drawable* target, unsigned batchIndex, unsigned i0, unsigned i1, unsigned i2, const unsigned char* positionData, const unsigned char* normalData, const unsigned char* skinningData, unsigned positionStride, unsigned normalStride, unsigned skinningStride, const Frustum& frustum, const Vector3& decalNormal, float normalCutoff) { bool hasNormals = normalData != 0; bool hasSkinning = skinned_ && skinningData != 0; const Vector3& v0 = *((const Vector3*)(&positionData[i0 * positionStride])); const Vector3& v1 = *((const Vector3*)(&positionData[i1 * positionStride])); const Vector3& v2 = *((const Vector3*)(&positionData[i2 * positionStride])); // Calculate unsmoothed face normals if no normal data Vector3 faceNormal = Vector3::ZERO; if (!hasNormals) { Vector3 dist1 = v1 - v0; Vector3 dist2 = v2 - v0; faceNormal = (dist1.CrossProduct(dist2)).Normalized(); } const Vector3& n0 = hasNormals ? *((const Vector3*)(&normalData[i0 * normalStride])) : faceNormal; const Vector3& n1 = hasNormals ? *((const Vector3*)(&normalData[i1 * normalStride])) : faceNormal; const Vector3& n2 = hasNormals ? *((const Vector3*)(&normalData[i2 * normalStride])) : faceNormal; const unsigned char* s0 = hasSkinning ? &skinningData[i0 * skinningStride] : (const unsigned char*)0; const unsigned char* s1 = hasSkinning ? &skinningData[i1 * skinningStride] : (const unsigned char*)0; const unsigned char* s2 = hasSkinning ? &skinningData[i2 * skinningStride] : (const unsigned char*)0; // Check if face is too much away from the decal normal if (decalNormal.DotProduct((n0 + n1 + n2) / 3.0f) < normalCutoff) return; // Check if face is culled completely by any of the planes for (unsigned i = PLANE_FAR; i < NUM_FRUSTUM_PLANES; --i) { const Plane& plane = frustum.planes_[i]; if (plane.Distance(v0) < 0.0f && plane.Distance(v1) < 0.0f && plane.Distance(v2) < 0.0f) return; } faces.Resize(faces.Size() + 1); PODVector<DecalVertex>& face = faces.Back(); if (!hasSkinning) { face.Reserve(3); face.Push(DecalVertex(v0, n0)); face.Push(DecalVertex(v1, n1)); face.Push(DecalVertex(v2, n2)); } else { const float* bw0 = (const float*)s0; const float* bw1 = (const float*)s1; const float* bw2 = (const float*)s2; const unsigned char* bi0 = s0 + sizeof(float) * 4; const unsigned char* bi1 = s1 + sizeof(float) * 4; const unsigned char* bi2 = s2 + sizeof(float) * 4; unsigned char nbi0[4]; unsigned char nbi1[4]; unsigned char nbi2[4]; // Make sure all bones are found and that there is room in the skinning matrices if (!GetBones(target, batchIndex, bw0, bi0, nbi0) || !GetBones(target, batchIndex, bw1, bi1, nbi1) || !GetBones(target, batchIndex, bw2, bi2, nbi2)) return; face.Reserve(3); face.Push(DecalVertex(v0, n0, bw0, nbi0)); face.Push(DecalVertex(v1, n1, bw1, nbi1)); face.Push(DecalVertex(v2, n2, bw2, nbi2)); } }
double DotProduct( Vector3 const& i_lhs, Vector3 const& i_rhs ) { return i_lhs.DotProduct( i_rhs ); }