void Matrix::AxisRotate(const Vector3F& mvAxis, float angle) { Vector3F mvNormalizedAxis = mvAxis; mvNormalizedAxis.Normalize(); float c = cosf(angle); float s = sinf(angle); float x = mvNormalizedAxis.x, y = mvNormalizedAxis.y, z = mvNormalizedAxis.z; _11 = x * x * (1 - c) + c; _21 = x * y * (1 - c) - (z * s); _31 = x * z * (1 - c) + (y * s); _41 = 0; _12 = y * x * (1 - c) + (z * s); _22 = y * y * (1 - c) + c; _32 = y * z * (1 - c) - (x * s); _42 = 0; _13 = z * x * (1 - c) - (y * s); _23 = z * y * (1 - c) + (x * s); _33 = z * z * (1 - c) + c; _43 = 0; _14 = 0; _24 = 0; _34 = 0; _44 = 1; }
void Plane::ProjectToPlane( const Vector3F& _vector, Vector3F* projected ) const { // A || B = B x (Ax B / |B|) / |B| Vector3F vector = _vector; vector.Normalize(); Vector3F AcB; CrossProduct( vector, n, &AcB ); CrossProduct( n, AcB, projected ); projected->Normalize(); /* GLASSERT( Equal( n.Length(), 1.0f, EPSILON ) ); Vector3F vector = _vector; vector.Normalize(); Vector3F pn; CrossProduct( n, vector, &pn ); CrossProduct( pn, n, projected ); */ #ifdef DEBUG { float len = projected->Length(); GLASSERT( Equal( len, 1.0f, EPSILON ) ); Vector3F test = { 0.0f, 0.0f, Z( 0.0f, 0.0f ) }; test = test + (*projected); float z = Z( projected->x, projected->y ); GLASSERT( Equal( test.z, z, 0.0001f ) ); } #endif }
void Lilith3D::IntersectRayFromScreen( int x, int y, int flags, LilithObjectList* vec ) { double p0x, p0y, p0z, p1x, p1y, p1z; double modelView[ 16 ]; glGetDoublev( GL_MODELVIEW_MATRIX, modelView ); double projection[ 16 ]; glGetDoublev( GL_PROJECTION_MATRIX, projection ); int viewport[ 4 ]; glGetIntegerv( GL_VIEWPORT, viewport ); gluUnProject( (double) x, (double) ( viewport[3]-y ), 0, modelView, projection, viewport, &p0x, &p0y, &p0z ); gluUnProject( (double) x, (double) ( viewport[3]-y ), 1, modelView, projection, viewport, &p1x, &p1y, &p1z ); //GLOUTPUT( "ret0=%d ret1=%d\n", ret0, ret1 ); Vector3F point = { (float) p0x, (float) p0y, (float) p0z }; Vector3F dir = { (float) ( p1x-p0x ), (float) ( p1y-p0y ), float( p1z-p0z ) }; dir.Normalize(); Ray ray; ray.origin = point; ray.direction = dir; ray.length = FAR_PLANE_DISTANCE; IntersectRay( ray, flags, vec ); }
void Scene::MoveImpl(float dx, float dy, Engine* engine) { Camera& camera = engine->camera; const Vector3F* dir = camera.EyeDir3(); Vector3F right = dir[2]; Vector3F forward = dir[0]; right.y = 0; forward.y = 0; right.Normalize(); forward.Normalize(); Vector3F pos = camera.PosWC(); pos = pos + dx*right + dy*forward; camera.SetPosWC(pos); }
bool CPointGravityEntity::DoForceEnvelopeCollision(CBaseEntity * pCollidingEntity) { if (!m_pFoceEnvelopeBV) return 0; Vector3F cp, cn; if (m_pFoceEnvelopeBV->Intersect(pCollidingEntity->GetContactBV(), cp, cn)) { //Assume the the colliding entity is a CBSphere Vector3F dir = ((CBSphere*)m_pContactBV)->PosW() - ((CBSphere*)pCollidingEntity->GetContactBV())->PosW(); if(gravitySign != pCollidingEntity->gravitySign) { pCollidingEntity->AddToForce(m_fGravity*dir.Normalize()); } else { pCollidingEntity->AddToForce(-m_fGravity*dir.Normalize()); } } return 1; }
//---------------------------------------------------------------------------- void Player::UpdateShot(Double deltaTime, const Vector2F& rCursorPosition) { // If not shooting, exit if (mShoot < 1) { Float alpha = mShoot < 0 ? 0 : mShoot; mspMuzzleflashMaterialState->Ambient.A() = alpha; mspMuzzleflashLight->Color = mMuzzleflashLightColor * alpha; mShoot -= static_cast<Float>(deltaTime)*10.0F; return; } mShoot -= static_cast<Float>(deltaTime)*10.0F; Vector3F origin; Vector3F direction; mspCamera->GetPickRay(rCursorPosition, origin, direction); direction.Normalize(); btVector3 rayStart = PhysicsWorld::Convert(origin); btVector3 rayEnd = rayStart + PhysicsWorld::Convert(direction * mMaximumShootingDistance); btCollisionWorld::ClosestRayResultCallback hitCallback(rayStart, rayEnd); if (!mpPhysicsWorld) { return; } mpPhysicsWorld->Get()->rayTest(rayStart, rayEnd, hitCallback); if (hitCallback.hasHit()) { btCollisionObject* pColObj = hitCallback.m_collisionObject; if (!pColObj->isStaticOrKinematicObject()) { btRigidBody* pRigidBody = btRigidBody::upcast(pColObj); if (pRigidBody) { btVector3 y = hitCallback.m_hitPointWorld - pRigidBody->getCenterOfMassPosition(); pColObj->activate(true); pRigidBody->applyImpulse(PhysicsWorld::Convert(direction)*7.5F, y); } } ProbeRobot* pProbeRobotController = static_cast<ProbeRobot*>(hitCallback.m_collisionObject->getUserPointer()); if (pProbeRobotController) { pProbeRobotController->TakeDamage(5.0F); } } }
//---------------------------------------------------------------------------- void Player::UpdateGun(Double deltaTime) { Float width = Application::GetApplication()->GetWidthF(); Float height = Application::GetApplication()->GetHeightF(); Vector2F cursorPosition(mLookAt.X()*2/width, mLookAt.Y()*2/height); Matrix4F projectionMatrix = mspCamera->GetProjectionMatrix(); Vector3F pickDirection(-cursorPosition.X() / projectionMatrix(0, 0), cursorPosition.Y() / projectionMatrix(1, 1), 1); Vector3F tempUp(0, 1, 0); Vector3F right = pickDirection.Cross(tempUp); Vector3F up = right.Cross(pickDirection); pickDirection.Normalize(); right.Normalize(); up.Normalize(); Matrix3F mat(-right, up, pickDirection, true); // to reduce the Wiimote's tilt jitter we average the last few sampled // tilt values Float tilt = 0; if (mRolls.GetQuantity() > 0) { for (UInt i = 0; i < mRolls.GetQuantity(); i++) { tilt += mRolls[i]; } tilt /= mRolls.GetQuantity(); } Matrix3F roll(Vector3F(0, 0, 1), tilt); mpGun->Local.SetRotate(mat * roll); UpdateShot(deltaTime, cursorPosition); }
void BoltEffect::Draw( const Vector3F* eyeDir ) { if ( d1 > d0 && !done ) { Vector3F q0 = p0 + normal*d0; Vector3F q1 = p0 + normal*d1; Vector3F right; CrossProduct( eyeDir[Camera::NORMAL], q1-q0, &right ); right.Normalize(); float halfWidth = width*0.5f; // FIXME: hardcoded texture coordinates static const float tx = 0.50f; static const float ty = 0.0f; PTVertex pV[4]; pV[0].pos = q0 - right*halfWidth; pV[0].tex.Set( tx+0.0f, ty+0.0f ); pV[1].pos = q0 + right*halfWidth; pV[1].tex.Set( tx+0.25f, ty+0.0f ); pV[2].pos = q1 + right*halfWidth; pV[2].tex.Set( tx+0.25f, ty+0.25f ); pV[3].pos = q1 - right*halfWidth; pV[3].tex.Set( tx+0.0f, ty+0.25f ); static const U16 index[6] = { 0, 1, 2, 0, 2, 3 }; QuadParticleShader shader; shader.SetTexture0( TextureManager::Instance()->GetTexture( "particleQuad" ) ); GPUStream stream; stream.stride = sizeof( pV[0] ); stream.nPos = 3; stream.posOffset = 0; stream.nTexture0 = 2; stream.texture0Offset = 12; shader.SetColor( color ); shader.SetStream( stream, pV, 6, index ); shader.Draw(); } }
Vector3F ArcBallCameraController::Direction() const { //R v R' where v = (0,0,-1,0) //The equation can be reduced because we know the following things: // 1. We're using unit quaternions // 2. The initial aspect does not change //The reduced form of the same equation follows Vector3F dir = Vector3F::Zero(); dir.x = -2.0f * ((m_ArcBallOrientation.x * m_ArcBallOrientation.z) + (m_ArcBallOrientation.w * m_ArcBallOrientation.y)); dir.y = 2.0f * ((m_ArcBallOrientation.w * m_ArcBallOrientation.x) - (m_ArcBallOrientation.y * m_ArcBallOrientation.z)); dir.z = ((m_ArcBallOrientation.x * m_ArcBallOrientation.x) + (m_ArcBallOrientation.y * m_ArcBallOrientation.y)) - ((m_ArcBallOrientation.z * m_ArcBallOrientation.z) + (m_ArcBallOrientation.w * m_ArcBallOrientation.w)); dir.Normalize(); return dir; }
/// <summary> /// Sets up a quaternion & position from vector camera components /// and oriented the camera up /// </summary> /// <param name="eye">The camera position</param> /// <param name="lookAt">The camera's look-at point</param> /// <param name="up"></param> void ArcBallCameraController::SetCamera(Vector3F position, Vector3F target, Vector3F up) { m_bRecomputeViewMatrix = true; //Create a look at matrix, to simplify matters a bit Matrix4 temp; temp.LookAt(position, target, up); //invert the matrix, since we're determining the //orientation from the rotation matrix in RH coords temp.Invert(); //set the position m_Target = target; //set distance m_fDistance = (target - position).Length(); //create the new aspect from the look-at matrix m_ArcBallOrientation.FromMatrix(temp); //When setting a new eye-view direction //in one of the gamble-locked modes, the yaw and //pitch gimble must be calculated. //first, get the direction projected on the x/z plne Vector3F dir = Direction(); dir.y = 0.0f; if (dir.Length() == 0.0f) { dir = Vector3F::Forward(); } dir.Normalize(); //find the yaw of the direction on the x/z plane //and use the sign of the x-component since we have 360 degrees //of freedom m_fArcBallYaw = (acosf(-dir.z) * Sign(dir.x)); //Get the pitch from the angle formed by the Up vector and the //the forward direction, then subtracting Pi / 2, since //we pitch is zero at Forward, not Up. m_fArcBallPitch = -(acosf(Vector3F::Dot(Vector3F::Up(), Direction())) - MATH_PI_DIV_2); }
Bolt* LumosChitBag::NewBolt( const Vector3F& pos, const Vector3F& _dir, int effectFlags, int chitID, float damage, float speed, bool trail ) { GLASSERT(pos.y > 0); GLASSERT(pos.y < 4); Bolt* bolt = ChitBag::NewBolt(); Vector3F dir = _dir; dir.Normalize(); GLASSERT(Equal(dir.Length(), 1.0f)); bolt->head = pos + dir * 0.5f; bolt->len = 0.5f; bolt->dir = dir; const Game::Palette* palette = Game::GetMainPalette(); switch( effectFlags & (GameItem::EFFECT_FIRE | GameItem::EFFECT_SHOCK) ) { case 0: bolt->color = palette->Get4F( 1, PAL_GREEN ); break; case GameItem::EFFECT_FIRE: bolt->color = palette->Get4F( 1, PAL_RED ); break; case GameItem::EFFECT_SHOCK: bolt->color = palette->Get4F( 1, PAL_BLUE ); break; case GameItem::EFFECT_FIRE | GameItem::EFFECT_SHOCK: bolt->color = palette->Get4F( 1, PAL_PURPLE ); break; default: GLASSERT( 0 ); break; } bolt->chitID = chitID; bolt->damage = damage; bolt->effect = effectFlags; bolt->particle = trail; bolt->speed = speed; bolt->frameCount = 0; return bolt; }
void XenoAudio::SetChannelPos(int i) { if (!audioOn) return; if (sounds[i].pos.IsZero()) { Mix_SetPosition(i, 0, 0); } else { Vector3F delta = sounds[i].pos - listenerPos; float len = delta.Length(); float df = len / MAX_DISTANCE; int d = LRintf(df*255.0f); d = Clamp(d, 0, 255); if (delta.LengthSquared() > 0.001f) { delta.Normalize(); } else { delta.Set(0, 0, -1); } static const Vector3F UP = { 0, 1, 0 }; Vector3F listenerRight = CrossProduct(listenerDir, UP); float dotFront = DotProduct(delta, listenerDir); float dotRight = DotProduct(delta, listenerRight); // 0 is north, 90 is east, etc. WTF. float rad = atan2(dotRight, dotFront); float deg = rad * 180.0f / PI; int degi = int(deg); if (degi < 0) degi += 360; int result = Mix_SetPosition(i, degi, d); GLASSERT(result != 0); (void)result; } }
BridgeMorph::BridgeMorph( float width, float originX, float originY, float destX, float destY ) : TerrainMorph() { float a = ( destX - originX ); float b = ( destY - originY ); float half = width / 2.0f; Vector3F at; bool inWater; Lilith3D* lilith = Lilith3D::Instance(); float originH = lilith->GetTerrainMesh()->CalcHeight( originX, originY, &at, &inWater ); float destH = lilith->GetTerrainMesh()->CalcHeight( destX, destY, &at, &inWater ); Vector3F widthNormal = { -b, a }; widthNormal.Normalize(); LineLoop loop; loop.AddAtEnd( new LineNode( originX + widthNormal.x*half, originY + widthNormal.y*half, originH ) ); loop.AddAtEnd( new LineNode( originX - widthNormal.x*half, originY - widthNormal.y*half, originH ) ); loop.AddAtEnd( new LineNode( destX - widthNormal.x*half, destY - widthNormal.y*half, destH ) ); loop.AddAtEnd( new LineNode( destX + widthNormal.x*half, destY + widthNormal.y*half, destH ) ); GenerateHeightMap( &loop, 1.0f, 1.0f, &maxDelta ); startTime = Lilith3D::GetTimeClock()->Msec(); }
int grinliz::IntersectRayAllAABB( const Vector3F& origin, const Vector3F& dir, const Rectangle3F& aabb, int* inTest, Vector3F* inIntersect, int *outTest, Vector3F* outIntersect ) { // Could be more efficient, but looking for simplicity as I write this. float t; // First check if we hit the box at all, and that establishes in test. *inTest = IntersectRayAABB( origin, dir, aabb, inIntersect, &t ); if ( *inTest == grinliz::REJECT ) { *outTest = grinliz::REJECT; return grinliz::REJECT; } // Could get fancy and intersect from the inside. But that's hard, so I'll run // the ray out and shoot it backwards. float deltaLen = aabb.SizeX() + aabb.SizeY() + aabb.SizeZ(); Vector3F dirNormal = dir; dirNormal.Normalize(); Vector3F invOrigin = origin + dir*deltaLen; Vector3F invDir = -dirNormal; *outTest = IntersectRayAABB( invOrigin, invDir, aabb, outIntersect, &t ); GLASSERT( *outTest != grinliz::INSIDE ); // bad algorith. if ( *outTest == grinliz::REJECT ) { // some strange floating point thing. Hit a corner. Reject everything. *inTest = grinliz::REJECT; return grinliz::REJECT; } return grinliz::INTERSECT; }
int GravParticles::PrepareStreamOut() { // normal: from the particle to the camera. // right: the "to the right" vectior // up: an up vector, // upPrime: a vector at camera up // right = up X normal // upPrime = normal X right const Vector3F up = { 0.0f, 0.0f, 1.0f }; Lilith3D* lilith = Lilith3D::Instance(); Vector3F camera = lilith->GetCamera()->Eye(); Vector3F right; Vector3F upPrime; //Color4F c; int index = 0; for( int i=0; i<numParticle; ++i, index += 4 ) { Vector3F normal = { camera.x - particle[i].loc.x, camera.y - particle[i].loc.y, camera.z - particle[i].loc.z }; normal.Normalize(); CrossProduct( up, normal, &right ); CrossProduct( normal, right, &upPrime ); float halfSize = particle[i].size / 2.0f; GLASSERT( InRange( color[i*4].a, 0.0f, 1.0f ) ); // c.r = particle[i].color.r; // c.g = particle[i].color.g; // c.b = particle[i].color.b; // c.a = particle[i].energy; // // color[ index+0 ] = color[ index+1 ] = color[ index+2 ] = color[ index+3 ] = c; // texUV[ index+0 ].x = 0.0f; // texUV[ index+0 ].y = 0.0f; quads[ index+0 ].x = particle[i].loc.x - halfSize*right.x - halfSize*upPrime.x; quads[ index+0 ].y = particle[i].loc.y - halfSize*right.y - halfSize*upPrime.y; quads[ index+0 ].z = particle[i].loc.z - halfSize*right.z - halfSize*upPrime.z; // texUV[ index+1 ].x = 1.0f; // texUV[ index+1 ].y = 0.0f; quads[ index+1 ].x = particle[i].loc.x + halfSize*right.x - halfSize*upPrime.x; quads[ index+1 ].y = particle[i].loc.y + halfSize*right.y - halfSize*upPrime.y; quads[ index+1 ].z = particle[i].loc.z + halfSize*right.z - halfSize*upPrime.z; // texUV[ index+2 ].x = 1.0f; // texUV[ index+2 ].y = 1.0f; quads[ index+2 ].x = particle[i].loc.x + halfSize*right.x + halfSize*upPrime.x; quads[ index+2 ].y = particle[i].loc.y + halfSize*right.y + halfSize*upPrime.y; quads[ index+2 ].z = particle[i].loc.z + halfSize*right.z + halfSize*upPrime.z; // texUV[ index+3 ].x = 0.0f; // texUV[ index+3 ].y = 1.0f; quads[ index+3 ].x = particle[i].loc.x - halfSize*right.x + halfSize*upPrime.x; quads[ index+3 ].y = particle[i].loc.y - halfSize*right.y + halfSize*upPrime.y; quads[ index+3 ].z = particle[i].loc.z - halfSize*right.z + halfSize*upPrime.z; } GLASSERT( index <= MAX_PARTICLE*4 ); return index; }
Model* SpaceTree::QueryRay( const Vector3F& _origin, const Vector3F& _direction, int required, int excluded, const Model** ignore, HitTestMethod testType, Vector3F* intersection ) { //GLOUTPUT(( "query ray\n" )); modelRoot = 0; nodesVisited = 0; modelsFound = 0; requiredFlags = required; excludedFlags = excluded | Model::MODEL_HIDDEN_FROM_TREE; ++queryID; Vector3F dummy; if ( !intersection ) { intersection = &dummy; } Vector3F dir = _direction; dir.Normalize(); Rectangle3F aabb; aabb.min.Set( 0, yMin, 0 ); aabb.max.Set( Map::SIZE, yMax, Map::SIZE ); // Where does this ray enter and leave the spaceTree? // It enters at 'p0' and leaves at 'p1' int p0Test, p1Test; Vector3F p0, p1; int test = IntersectRayAllAABB( _origin, dir, aabb, &p0Test, &p0, &p1Test, &p1 ); if ( test != grinliz::INTERSECT ) { // Can click outside of AABB pretty commonly, actually. return 0; } Plane planes[6]; Rectangle3F rect; rect.FromPair( p0, p1 ); Plane::CreatePlanes( rect, planes ); Model* modelRoot = Query( planes, 6, required, excluded ); // We now have a batch of models. Are any of them a hit?? GLASSERT( testType == TEST_HIT_AABB || testType == TEST_TRI ); float close = FLT_MAX; Model* closeModel = 0; Vector3F testInt; float t; for( Model* root=modelRoot; root; root=root->next ) { if ( Ignore( root, ignore ) ) continue; //GLOUTPUT(( "Consider: %s\n", root->GetResource()->header.name )); int result = grinliz::REJECT; if ( testType == TEST_HIT_AABB ) { Rectangle3F modelAABB; root->CalcHitAABB( &modelAABB ); result = IntersectRayAABB( p0, dir, modelAABB, &testInt, &t ); } else if ( testType == TEST_TRI ) { t = FLT_MAX; result = root->IntersectRay( p0, dir, &testInt ); if ( result == grinliz::INTERSECT ) { Vector3F delta = p0 - testInt; t = delta.LengthSquared(); //GLOUTPUT(( "Hit: %s t=%.2f\n", root->GetResource()->header.name, t )); } } if ( result == grinliz::INTERSECT ) { // Ugly little bug: check for t>=0, else could collide with objects // that touch the bounding box but are before the ray starts. if ( t >= 0.0f && t < close ) { closeModel = root; *intersection = testInt; close = t; } } } if ( closeModel ) { return closeModel; } return 0; }
//---------------------------------------------------------------------------- void Mesh::GenerateNormals(Bool ignoreHardEdges) { VertexBuffer* pPositions = GetPositionBuffer(); if (!pPositions) { return; } VertexBuffer* pNormals = GetNormalBuffer(); if (!pNormals) { return; } UShort* const pIndices = mspIndexBuffer->GetData(); // collect the triangles each vertex is part of TArray<TArray<UInt> > buckets(pPositions->GetQuantity()); buckets.SetQuantity(pPositions->GetQuantity()); UInt triIndex = 0; for (UInt i = 0; i < mspIndexBuffer->GetQuantity(); i += 3) { buckets[pIndices[i]].Append(triIndex); buckets[pIndices[i+1]].Append(triIndex); buckets[pIndices[i+2]].Append(triIndex); triIndex++; } if (ignoreHardEdges) { for (UInt j = 0; j < pPositions->GetQuantity(); j++) { const Vector3F& vertex = pPositions->Position3(j); for (UInt i = j+1; i < pPositions->GetQuantity(); i++) { if (vertex == pPositions->Position3(i)) { UInt origCount = buckets[j].GetQuantity(); for (UInt k = 0; k < buckets[i].GetQuantity(); k++) { buckets[j].Append(buckets[i][k]); } for (UInt k = 0; k < origCount; k++) { buckets[i].Append(buckets[j][k]); } } } } } // calculate the normals of the individual triangles TArray<Vector3F> faceNormals(mspIndexBuffer->GetQuantity()/3); for (UInt i = 0; i < mspIndexBuffer->GetQuantity(); i +=3) { Vector3F v1 = pPositions->Position3(pIndices[i+1]) - pPositions-> Position3(pIndices[i]); Vector3F v2 = pPositions->Position3(pIndices[i+2]) - pPositions-> Position3(pIndices[i+1]); Vector3F normal = v2.Cross(v1); normal.Normalize(); faceNormals.Append(normal); } // calculate the normal of the vertex from the normals of its faces for (UInt i = 0; i < buckets.GetQuantity(); i++) { Vector3F normal(Vector3F::ZERO); for (UInt j = 0; j < buckets[i].GetQuantity(); j++) { normal += faceNormals[buckets[i][j]]; } if (buckets[i].GetQuantity() > 0) { normal /= static_cast<Float>(buckets[i].GetQuantity()); normal.Normalize(); } else { // vertex not used in mesh, use a default normal normal = Vector3F::UNIT_X; } pNormals->Normal3(i) = normal; } }