//---------------------------------------------------------------------------- void NodeBillboard::UpdateWorldData(Double appTime, Bool updateControllers) { // Compute billboard's world transforms based on its parent's world // transform and its local transforms. Notice that you should not call // Node::UpdateWorldData since that function updates its children. The // children of a NodeBillboard cannot be updated until the billboard is // aligned with the camera. Spatial::UpdateWorldData(appTime, updateControllers); if (mspCamera) { // Inverse-transform the camera to the model space of the billboard. Vector3F camLocation = World.ApplyInverse(mspCamera->GetLocation()); // To align the billboard, the projection of the camera to the // xz-plane of the billboard's model space determines the angle of // rotation about the billboard's model y-axis. If the projected // camera is on the model axis (x = 0 and z = 0), ATan2 returns zero // (rather than NaN), so there is no need to trap this degenerate // case and handle it separately. Float angle = MathF::ATan2(camLocation.X(), camLocation.Z()); Matrix34F orientation(Vector3F::UNIT_Y, angle); World.SetRotate(World.GetMatrix() * orientation); } // update the children now that the billboard orientation is known for (UInt i = 0; i < mChildren.GetQuantity(); i++) { Spatial* pChild = mChildren[i]; if (pChild) { pChild->UpdateGS(appTime, false, updateControllers); } } }
float grinliz::PointBetweenPoints( const Vector3F& p0, const Vector3F& p1, const Vector3F& pi ) { float validCount = 0.0f; float t = 0.0f; // p0.x + t*(p1.x-p0.x) = pi.x for( int i=0; i<3; ++i ) { float denom = p1.X(i) - p0.X(i); if ( !Equal( denom, 0.0f, 0.001f ) ) { float t0 = ( pi.X(i) - p0.X(i) ) / denom; GLASSERT( t0 >= 0.0f && t0 <= 1.0f ); t += t0; validCount += 1.0f; } } t /= validCount; GLASSERT( t >= 0.0f && t <= 1.0f ); return t; }
//---------------------------------------------------------------------------- void Game::DrawWarning(Double time) { GetRenderer()->DisableLighting(); Float f = (MathF::Sin(MathF::FMod(static_cast<Float>(time*5), MathF::TWO_PI)) + 1) * 0.5F; ColorRGB color(1, f, f); mspWarningText->Clear(color); mspWarningText->Append("Aim at the screen!"); mspWarningText->Update(GetRenderer()); Vector3F center = mspWarningText->GetMesh()->GetModelBound()->GetCenter(); center.Y() -= static_cast<Float>(mpRenderer->GetHeight()) * 0.5F; center.X() -= static_cast<Float>(mpRenderer->GetWidth()) * 0.5F; Transformation translate; translate.SetTranslate(-center); GetRenderer()->Draw(mspWarningText, translate); }
int grinliz::IntersectRayPlane( const Vector3F& origin, const Vector3F& dir, int plane, float x, Vector3F* intersect ) { GLASSERT( plane >=0 && plane < 3 ); if ( dir.X(plane) > -EPSILON && dir.X(plane) < EPSILON ) return REJECT; if ( dir.X(plane) > 0.0f && origin.X(plane) >= x ) return REJECT; if ( dir.X(plane) < 0.0f && origin.X(plane) <= x ) return REJECT; float t = ( x - origin.X(plane) ) / dir.X(plane); if ( intersect ) { intersect->x = origin.x + dir.x * t; intersect->y = origin.y + dir.y * t; intersect->z = origin.z + dir.z * t; } return INTERSECT; }
int grinliz::IntersectionRayAABB( const Ray& ray, const Rectangle3F& aabb, Rectangle3F* result ) { bool hasStart = false; bool hasEnd = false; Vector3F start, end; GLASSERT( Equal( ray.direction.Length(), 1.0f, 0.001f ) ); if ( aabb.Contains( ray.origin ) ) { hasStart = true; start = ray.origin; } // Check for an intersection with each face. If t>0 and it is a // positive dot then it is an 'end'. If t>0 and it is a negative // dot, then it is a 'start'. Vector3F at; float t; for( int k=0; k<=1; ++k ) { Vector3F originToPlane; if ( k == 0 ) { // min originToPlane.Set( aabb.min.x - ray.origin.x, aabb.min.y - ray.origin.y, aabb.min.z - ray.origin.z ); } else { // max originToPlane.Set( aabb.max.x - ray.origin.x, aabb.max.y - ray.origin.y, aabb.max.z - ray.origin.z ); } for ( int i=0; i<3 && !(hasEnd && hasStart); ++i ) { int i1 = (i + 1)%3; int i2 = (i + 2)%3; Vector3F planeNormal = { 0.0f, 0.0f, 0.0f }; planeNormal.X(i) = ( k == 0 ) ? -1.0f : 1.0f; float dot = DotProduct( originToPlane, planeNormal ); int hit = IntersectRayAAPlane( ray.origin, ray.direction, i, (k==0) ? aabb.min.X(i) : aabb.max.X(i), &at, &t ); if ( hit == INTERSECT && t > 0.0f && InRange( at.X(i1), aabb.min.X(i1), aabb.max.X(i1) ) && InRange( at.X(i2), aabb.min.X(i2), aabb.max.X(i2) ) ) { // We have hit a face of the AABB if ( dot > 0.0f ) { GLASSERT( !hasEnd ); hasEnd = true; if ( t > ray.length ) end = ray.origin + ray.direction*t; else end = at; } else if ( dot < 0.0f ) { GLASSERT( !hasStart ); hasStart = true; if ( t > ray.length ) { return REJECT; // the start never gets to the AABB } start = at; } } } } if( !hasStart || !hasEnd ) { return REJECT; } for( int i=0; i<3; ++i ) { result->min.X(i) = Min( start.X(i), end.X(i) ); result->max.X(i) = Max( start.X(i), end.X(i) ); } return INTERSECT; }