//----------------------------------------------------------------------------- // Установка углов поворота объекта //----------------------------------------------------------------------------- void CSpaceObject::SetRotation(VECTOR3D NewRotation) { // вызываем родительскую функцию ::CObject3D::SetRotation(NewRotation); if (GFX != 0) for (int i=0; i<GFXQuantity; i++) { Matrix33CalcPoint(&(GFXLocation[i]), OldInvRotationMat); Matrix33CalcPoint(&(GFXLocation[i]), CurrentRotationMat); if (GFX[i] != 0) { if (GFX[i]->SpeedOnCreation == -1.0f) { GFX[i]->MoveSystem(GFXLocation[i] + Location); GFX[i]->SetStartLocation(GFXLocation[i] + Location); GFX[i]->RotateSystemAndParticlesByAngle(Rotation); } else { GFX[i]->MoveSystemLocation(GFXLocation[i] + Location); GFX[i]->RotateSystemByAngle(Rotation); } } } }
//----------------------------------------------------------------------------- // Проверка столкновений Sphere-Mesh //----------------------------------------------------------------------------- bool vw_SphereMeshCollision(VECTOR3D Object1Location, eObjectBlock *Object1DrawObjectList, float Object1RotationMatrix[9], float Object2Radius, VECTOR3D Object2Location, VECTOR3D Object2PrevLocation, VECTOR3D *CollisionLocation) { // если не передали геометрию - делать тут нечего if (Object1DrawObjectList == 0) return false; // делаем матрицу перемещения точек, для геометрии float TransMat[16]; TransMat[0] = Object1RotationMatrix[0]; TransMat[1] = Object1RotationMatrix[1]; TransMat[2] = Object1RotationMatrix[2]; TransMat[3] = 0.0f; TransMat[4] = Object1RotationMatrix[3]; TransMat[5] = Object1RotationMatrix[4]; TransMat[6] = Object1RotationMatrix[5]; TransMat[7] = 0.0f; TransMat[8] = Object1RotationMatrix[6]; TransMat[9] = Object1RotationMatrix[7]; TransMat[10] = Object1RotationMatrix[8]; TransMat[11] = 0.0f; TransMat[12] = Object1Location.x; TransMat[13] = Object1Location.y; TransMat[14] = Object1Location.z; TransMat[15] = 1.0f; // находим точку локального положения объекта в моделе VECTOR3D LocalLocation(Object1DrawObjectList->Location); Matrix33CalcPoint(&LocalLocation, Object1RotationMatrix); // если нужно - создаем матрицу, иначе - копируем ее if (Object1DrawObjectList->Rotation.x != 0.0f || Object1DrawObjectList->Rotation.y != 0.0f || Object1DrawObjectList->Rotation.z != 0.0f) { float TransMatTMP[16]; Matrix44Identity(TransMatTMP); Matrix44CreateRotate(TransMatTMP, Object1DrawObjectList->Rotation); Matrix44Translate(TransMatTMP, LocalLocation); // и умножаем на основную матрицу, со сведениями по всему объекту Matrix44Mult(TransMat, TransMatTMP); } else { Matrix44Translate(TransMat, LocalLocation); } // проверяем все треугольники объекта for (int i=0; i<Object1DrawObjectList->VertexCount; i+=3) { // находим 3 точки треугольника (с учетом индекс буфера) int j2; if (Object1DrawObjectList->IndexBuffer != 0) j2 = Object1DrawObjectList->IndexBuffer[Object1DrawObjectList->RangeStart+i]*Object1DrawObjectList->VertexStride; else j2 = (Object1DrawObjectList->RangeStart+i)*Object1DrawObjectList->VertexStride; // находим точки триугольника VECTOR3D Point1; Point1.x = Object1DrawObjectList->VertexBuffer[j2]; Point1.y = Object1DrawObjectList->VertexBuffer[j2+1]; Point1.z = Object1DrawObjectList->VertexBuffer[j2+2]; Matrix44CalcPoint(&Point1, TransMat); if (Object1DrawObjectList->IndexBuffer != 0) j2 = Object1DrawObjectList->IndexBuffer[Object1DrawObjectList->RangeStart+i+1]*Object1DrawObjectList->VertexStride; else j2 = (Object1DrawObjectList->RangeStart+i+1)*Object1DrawObjectList->VertexStride; VECTOR3D Point2; Point2.x = Object1DrawObjectList->VertexBuffer[j2]; Point2.y = Object1DrawObjectList->VertexBuffer[j2+1]; Point2.z = Object1DrawObjectList->VertexBuffer[j2+2]; Matrix44CalcPoint(&Point2, TransMat); if (Object1DrawObjectList->IndexBuffer != 0) j2 = Object1DrawObjectList->IndexBuffer[Object1DrawObjectList->RangeStart+i+2]*Object1DrawObjectList->VertexStride; else j2 = (Object1DrawObjectList->RangeStart+i+2)*Object1DrawObjectList->VertexStride; VECTOR3D Point3; Point3.x = Object1DrawObjectList->VertexBuffer[j2]; Point3.y = Object1DrawObjectList->VertexBuffer[j2+1]; Point3.z = Object1DrawObjectList->VertexBuffer[j2+2]; Matrix44CalcPoint(&Point3, TransMat); // находим 2 вектора, образующих плоскость VECTOR3D PlaneVector1 = Point2 - Point1; VECTOR3D PlaneVector2 = Point3 - Point1; // находим нормаль плоскости VECTOR3D NormalVector = PlaneVector1; NormalVector.Multiply(PlaneVector2); NormalVector.Normalize(); // проверка, сферы // - в сфере или нет?, т.е. расстояние от плоскости до центра сферы // - по нормале находим точку на плоскости // - точка принадлежит треугольнику? // находим расстояние от точки до плоскости float Distance = (Object2Location - Point1)*NormalVector; // если точка дальше радиуса - нам тут делать нечего, берем следующую точку if (fabsf(Distance) <= Object2Radius) { // находим реальную точку пересечения с плоскостью VECTOR3D IntercPoint = Object2Location - (NormalVector^Distance); // передаем точку и флаг успешной коллизии if (vw_PointInTriangle(IntercPoint, Point1, Point2, Point3)) { *CollisionLocation = IntercPoint; return true; } } // проверка, сферы // если от точек до текущего положения расстояние меньше float Object2Radius2 = Object2Radius*Object2Radius; // находим расстояние VECTOR3D DistancePoint1 = Object2Location - Point1; float Distance2Point1 = DistancePoint1.x*DistancePoint1.x + DistancePoint1.y*DistancePoint1.y + DistancePoint1.z*DistancePoint1.z; if (Distance2Point1 <= Object2Radius2) { *CollisionLocation = Point1; return true; } // находим расстояние VECTOR3D DistancePoint2 = Object2Location - Point2; float Distance2Point2 = DistancePoint2.x*DistancePoint2.x + DistancePoint2.y*DistancePoint2.y + DistancePoint2.z*DistancePoint2.z; if (Distance2Point2 <= Object2Radius2) { *CollisionLocation = Point2; return true; } // находим расстояние VECTOR3D DistancePoint3 = Object2Location - Point3; float Distance2Point3 = DistancePoint3.x*DistancePoint3.x + DistancePoint3.y*DistancePoint3.y + DistancePoint3.z*DistancePoint3.z; if (Distance2Point3 <= Object2Radius2) { *CollisionLocation = Point3; return true; } // проверка луч, старое положение - новое положение объекта // - пересекает плоскость (обе точки с одной стороны? знак, или ноль) // - точка пересечения плоскости // - принадлежит треугольнику? // проверка, если это фронт-часть, нормально... иначе - берем следующую VECTOR3D vDir1 = Point1 - Object2PrevLocation; float d1 = vDir1*NormalVector; if (d1>0.001f) continue; // находим расстояние от плоскости до точки float originDistance = NormalVector*Point1; // пересечение прямой с плоскостью VECTOR3D vLineDir = Object2Location - Object2PrevLocation; // может и не нужно этого делать... т.к. все и так хорошо работает в нашем случае //vLineDir.Normalize(); float Numerator = - (NormalVector.x * Object2PrevLocation.x + // Use the plane equation with the normal and the line NormalVector.y * Object2PrevLocation.y + NormalVector.z * Object2PrevLocation.z - originDistance); float Denominator = NormalVector*vLineDir; if( Denominator == 0.0) continue; float dist = Numerator / Denominator; // зная расстояние, находим точку пересечения с плоскостью VECTOR3D IntercPoint = Object2PrevLocation + (vLineDir ^ dist); // проверяем, на отрезке или нет (до этого работали с прямой/лучем) if ((Object2PrevLocation-IntercPoint)*(Object2Location-IntercPoint) >= 0.0f) continue; // передаем точку и флаг успешной коллизии if (vw_PointInTriangle(IntercPoint, Point1, Point2, Point3)) { *CollisionLocation = IntercPoint; return true; } } return false; }
//----------------------------------------------------------------------------- // Проверка столкновений Sphere-OBB //----------------------------------------------------------------------------- bool vw_SphereOBBCollision(VECTOR3D Object1OBB[8], VECTOR3D Object1OBBLocation, VECTOR3D Object1Location, float Object1RotationMatrix[9], float Object2Radius, VECTOR3D Object2Location, VECTOR3D Object2PrevLocation) { // параметры OBB VECTOR3D TMPMax = Object1OBB[0]; VECTOR3D TMPMin = Object1OBB[6]; // точки VECTOR3D TMPPoint1 = Object2Location - (Object1Location+Object1OBBLocation); VECTOR3D TMPPoint2 = Object2PrevLocation - (Object1Location+Object1OBBLocation); // строим матрицу, чтобы развернуть точки float TMPInvRotationMatrix[9]; memcpy(TMPInvRotationMatrix, Object1RotationMatrix, 9*sizeof(float)); Matrix33InverseRotate(TMPInvRotationMatrix); // перемещаем в общие координаты Matrix33CalcPoint(&TMPMax, TMPInvRotationMatrix); Matrix33CalcPoint(&TMPMin, TMPInvRotationMatrix); Matrix33CalcPoint(&TMPPoint1, TMPInvRotationMatrix); Matrix33CalcPoint(&TMPPoint2, TMPInvRotationMatrix); // и как в Sphere-AABB bool Result = true; // если максимальная точка сферы меньше минимума - не входит if (TMPPoint1.x + Object2Radius < TMPMin.x) Result = false; if (TMPPoint1.y + Object2Radius < TMPMin.y) Result = false; if (TMPPoint1.z + Object2Radius < TMPMin.z) Result = false; // если минимальная точка сферы больше максимальной AABB - тоже не входит if (TMPPoint1.x - Object2Radius > TMPMax.x) Result = false; if (TMPPoint1.y - Object2Radius > TMPMax.y) Result = false; if (TMPPoint1.z - Object2Radius > TMPMax.z) Result = false; // проверим прямую, чтобы перехватить быстро летящих... if (!Result) { // средняя точка линии VECTOR3D mid = (Object2Location + Object2PrevLocation) / 2.0f; // направление линии VECTOR3D dir = Object2Location - Object2PrevLocation; // полудлина линии float hl = dir.Length()/2.0f; dir.Normalize(); VECTOR3D T = Object1Location - mid; // проверяем, является ли одна из осей X,Y,Z разделяющей if ( (fabs(T.x) > TMPMax.x + hl*fabs(dir.x)) || (fabs(T.y) > TMPMax.y + hl*fabs(dir.y)) || (fabs(T.z) > TMPMax.z + hl*fabs(dir.z)) ) return false; // проверяем X ^ dir float r = TMPMax.y*fabs(dir.z) + TMPMax.z*fabs(dir.y); if ( fabs(T.y*dir.z - T.z*dir.y) > r ) return false; // проверяем Y ^ dir r = TMPMax.x*fabs(dir.z) + TMPMax.z*fabs(dir.x); if ( fabs(T.z*dir.x - T.x*dir.z) > r ) return false; // проверяем Z ^ dir r = TMPMax.x*fabs(dir.y) + TMPMax.y*fabs(dir.x); if ( fabs(T.x*dir.y - T.y*dir.x) > r ) return false; return true; } return Result; }
//----------------------------------------------------------------------------- // инициализация класса //----------------------------------------------------------------------------- CSpaceStars::CSpaceStars() { Age = 0.0f; TimeLastUpdate = -1.0f; // положение системы Location = VECTOR3D( 0.0f, 0.0f, 0.0f); Size = 0.003f; CreationSize = VECTOR3D(5.21f,5.21f,5.21f); Texture = vw_FindTextureByName("DATA/GFX/flare1.tga"); DeadZone = 5.2f; if (Setup.UseGLSL) { GLSL = vw_FindShaderByName("SpaceStars"); UniformLocations[0] = vw_GetUniformLocation(GLSL, "ParticleTexture"); UniformLocations[1] = vw_GetUniformLocation(GLSL, "ParticleAge"); } // начальные установки для мартиц поворотов Matrix33Identity(CurrentRotationMat); Matrix33Identity(OldInvRotationMat); // настройка массива Start = 0; End = 0; unsigned int ParticlesCreated = 10000 - 4000*Setup.VisualEffectsQuality; // пока не создадим все необходимые частицы while (ParticlesCreated > 0) { // создаем новую частицу CStar *NewParticle = 0; NewParticle = new CStar; if (NewParticle == 0) return; // считаем значение альфы NewParticle->Alpha = 0.5f + 0.5f * vw_Randf1; // убираем переполнение Clamp( NewParticle->Alpha, 0.0f, 1.0f ); // считаем дельту альфы NewParticle->AlphaDelta = (1.5f + 1.5f * vw_Randf1) / 3.0f; // выпускаем частицу возле места нахождения системы // в сфере VECTOR3D tmp; float minDist = CreationSize.x*CreationSize.x+CreationSize.y*CreationSize.y+CreationSize.z*CreationSize.z; // если зона больше чем радиус излучения - выключаем ее if (minDist <= DeadZone*DeadZone) DeadZone = 0.0f; // прибавляем к рандому, чтобы избежать вероятности появления всех трех нулей и деления на ноль в дальнейшем tmp.x = (vw_Randf0 + 0.00001f) * CreationSize.x; tmp.y = vw_Randf0 * CreationSize.y; tmp.z = vw_Randf0 * CreationSize.z; float ParticleDist = tmp.x*tmp.x + tmp.y*tmp.y + tmp.z*tmp.z; while (ParticleDist > minDist || ParticleDist < DeadZone*DeadZone) { if (ParticleDist > minDist) { // ум. радиус VECTOR3D tmp1 = tmp; tmp1.Normalize(); tmp1 = tmp1^(1/100.0f); tmp = tmp - tmp1; } if ( ParticleDist < DeadZone*DeadZone) { // ув. радиус VECTOR3D tmp1 = tmp; tmp1.Normalize(); tmp1 = tmp1^(1/100.0f); tmp = tmp + tmp1; if (tmp.x > 0.0f) {if (tmp.x > CreationSize.x) tmp.x = CreationSize.x;} else {if (tmp.x < -CreationSize.x) tmp.x = -CreationSize.x;} if (tmp.y > 0.0f) {if (tmp.y > CreationSize.y) tmp.y = CreationSize.y;} else {if (tmp.y < -CreationSize.y) tmp.y = -CreationSize.y;} if (tmp.z > 0.0f) {if (tmp.z > CreationSize.z) tmp.z = CreationSize.z;} else {if (tmp.z < -CreationSize.z) tmp.z = -CreationSize.z;} } ParticleDist = tmp.x*tmp.x + tmp.y*tmp.y + tmp.z*tmp.z; } Matrix33CalcPoint(&tmp, CurrentRotationMat); NewParticle->Location = Location + tmp; // подключаем частицу к системе Attach(NewParticle); // уменьшаем необходимое количество частиц ParticlesCreated--; } list = 0; tmpDATA = 0; VBO = 0; LastCameraAngleX = LastCameraAngleY = LastCameraAngleZ = 0.0f; }