//---------------------------------------------------------------------------- bool HelixTubeSurface::MoveCamera () { APoint position = mCurve->GetPosition(mCurveTime); AVector tangent = mCurve->GetTangent(mCurveTime); AVector binormal = tangent.UnitCross(AVector::UNIT_Z); AVector normal = binormal.UnitCross(tangent); mCamera->SetFrame(position, tangent, normal, binormal); mCuller.ComputeVisibleSet(mScene); return true; }
//---------------------------------------------------------------------------- void AmbientRegionActor::_UpdateDirLightCamera() { AVector dir = AVector::AnglesToDirection(Mathf::DEG_TO_RAD*mHorAngle, Mathf::DEG_TO_RAD*mVerAngle); dir.Normalize(); Scene *scene = DynamicCast<Scene>(GetTopestParent()); if (scene) { EnvirParam *envirParam = scene->GetEnvirParam(); Light *lightDir = envirParam->GetLight_Dir(); Projector *projector = envirParam->GetLight_Dir_Projector(); lightDir->Ambient = Float4(mAmbientColor[0], mAmbientColor[1], mAmbientColor[2], mIntensity); lightDir->Intensity = mIntensity; lightDir->Diffuse = Float4(mDiffuseColor[0], mDiffuseColor[1], mDiffuseColor[2], 1.0f); lightDir->Specular = Float4(mSpecularColor[0], mSpecularColor[1], mSpecularColor[2], mSpecularPow); float upDot = dir.Dot(-AVector::UNIT_Z); if (upDot >= 0.99f) { } else { AVector upTemp = AVector::UNIT_Z; AVector right = dir.UnitCross(upTemp); AVector up = right.UnitCross(dir); lightDir->DVector = dir; lightDir->UVector = up; lightDir->RVector = right; APoint camPos = mLightCameraLookPosition - dir*mLightCameraLookDistance; projector->SetFrame(camPos, lightDir->DVector, lightDir->UVector, lightDir->RVector); } if (!projector->IsPerspective()) { projector->SetFrustum(0.1f, 100.0f, -mLightCameraExtent, mLightCameraExtent, -mLightCameraExtent, mLightCameraExtent); } else { projector->SetFrustum(mLightCameraExtent, 1.0f, 1.0f, 100.0f); } } }
//---------------------------------------------------------------------------- void CameraActor::LookAt(const APoint &pos) { APoint localPos = LocalTransform.GetTranslate(); AVector dir = pos - localPos; float length = dir.Normalize(); if (length > 0.0f) { AVector right = dir.UnitCross(AVector::UNIT_Z); AVector up = right.UnitCross(dir); LocalTransform.SetRotate(HMatrix(right, dir, up, AVector::ZERO, true)); } }
//---------------------------------------------------------------------------- void PhysicsModule::GetData (APoint& center, HMatrix& incrRot) const { // Position is a point exactly on the hill. APoint position; position[0] = (float)(A1*mState[0]); position[1] = (float)(A2*mState[2]); position[2] = (float)(A3 - mState[0]*mState[0] - mState[2]*mState[2]); // Lift this point off the hill in the normal direction by the radius of // the ball so that the ball just touches the hill. The hill is // implicitly specified by F(x,y,z) = z - [a3 - (x/a1)^2 - (y/a2)^2] // where (x,y,z) is the position on the hill. The gradient of F is a // normal vector, Grad(F) = (2*x/a1^2,2*y/a2^2,1). AVector normal; normal[0] = 2.0f*position[0]/(float)mAux[0]; normal[1] = 2.0f*position[1]/(float)mAux[1]; normal[2] = 1.0f; normal.Normalize(); center = position + ((float)Radius)*normal; // Let the ball rotate as it rolls down hill. The axis of rotation is // the perpendicular to hill normal and ball velocity. The angle of // rotation from the last position is A = speed*deltaTime/radius. AVector velocity; velocity[0] = (float)(A1*mState[1]); velocity[1] = (float)(A1*mState[3]); velocity[2] = -2.0f*(velocity[0]*(float)mState[0] + velocity[1]*(float)mState[2]); float speed = velocity.Normalize(); float angle = speed*((float)mDeltaTime)/((float)Radius); AVector axis = normal.UnitCross(velocity); incrRot = HMatrix(axis, angle); }
//---------------------------------------------------------------------------- void SurfacePatch::GetFrame (float u, float v, APoint& position, AVector& tangent0, AVector& tangent1, AVector& normal) const { position = P(u, v); tangent0 = PU(u, v); tangent1 = PV(u, v); tangent0.Normalize(); normal = tangent0.UnitCross(tangent1); // The normalized first derivatives are not necessarily orthogonal. // Recompute T1 so that {T0,T1,N} is an orthonormal set. tangent1 = normal.Cross(tangent0); }
//---------------------------------------------------------------------------- void SurfacePatch::ComputePrincipalCurvatureInfo (float u, float v, float& curv0, float& curv1, AVector& dir0, AVector& dir1) { // Tangents: T0 = dP/du = (x_u,y_u,z_u), T1 = dP/dv = (x_v,y_v,z_v) // Normal: N = Cross(T0,T1)/Length(Cross(T0,T1)) // Metric Tensor: G = +- -+ // | Dot(T0,T0) Dot(T0,T1) | // | Dot(T1,T0) Dot(T1,T1) | // +- -+ // // Curvature Tensor: B = +- -+ // | -Dot(N,T0_u) -Dot(N,T0_v) | // | -Dot(N,T1_u) -Dot(N,T1_v) | // +- -+ // // Principal curvatures k are the generalized eigenvalues of // // Bw = kGw // // If k is a curvature and w=(a,b) is the corresponding solution to // Bw = kGw, then the principal direction as a 3D vector is d = a*U+b*V. // // Let k1 and k2 be the principal curvatures. The mean curvature // is (k1+k2)/2 and the Gaussian curvature is k1*k2. // Compute the derivatives. AVector derU = PU(u, v); AVector derV = PV(u, v); AVector derUU = PUU(u, v); AVector derUV = PUV(u, v); AVector derVV = PVV(u, v); // Compute the metric tensor. float metricTensor[2][2]; metricTensor[0][0] = derU.Dot(derU); metricTensor[0][1] = derU.Dot(derV); metricTensor[1][0] = metricTensor[0][1]; metricTensor[1][1] = derV.Dot(derV); // Compute the curvature tensor. AVector normal = derU.UnitCross(derV); float curvatureTensor[2][2]; curvatureTensor[0][0] = -normal.Dot(derUU); curvatureTensor[0][1] = -normal.Dot(derUV); curvatureTensor[1][0] = curvatureTensor[0][1]; curvatureTensor[1][1] = -normal.Dot(derVV); // Characteristic polynomial is 0 = det(B-kG) = c2*k^2+c1*k+c0. float c0 = curvatureTensor[0][0]*curvatureTensor[1][1] - curvatureTensor[0][1]*curvatureTensor[1][0]; float c1 = 2.0f*curvatureTensor[0][1]* metricTensor[0][1] - curvatureTensor[0][0]*metricTensor[1][1] - curvatureTensor[1][1]*metricTensor[0][0]; float c2 = metricTensor[0][0]*metricTensor[1][1] - metricTensor[0][1]*metricTensor[1][0]; // Principal curvatures are roots of characteristic polynomial. float temp = Mathf::Sqrt(Mathf::FAbs(c1*c1 - 4.0f*c0*c2)); curv0 = -0.5f*(c1+temp); curv1 = 0.5f*(-c1+temp); // Principal directions are solutions to (B-kG)w = 0, // w1 = (b12-k1*g12,-(b11-k1*g11)) OR (b22-k1*g22,-(b12-k1*g12)) float a0 = curvatureTensor[0][1] - curv0*metricTensor[0][1]; float a1 = curv0*metricTensor[0][0] - curvatureTensor[0][0]; float length = Mathf::Sqrt(a0*a0 + a1*a1); if (length >= Mathf::ZERO_TOLERANCE) { dir0 = a0*derU + a1*derV; } else { a0 = curvatureTensor[1][1] - curv0*metricTensor[1][1]; a1 = curv0*metricTensor[0][1] - curvatureTensor[0][1]; length = Mathf::Sqrt(a0*a0 + a1*a1); if (length >= Mathf::ZERO_TOLERANCE) { dir0 = a0*derU + a1*derV; } else { // Umbilic (surface is locally sphere, any direction principal). dir0 = derU; } } dir0.Normalize(); // Second tangent is cross product of first tangent and normal. dir1 = dir0.Cross(normal); }
//---------------------------------------------------------------------------- void Triangles::UpdateModelTangentsUseTCoords (VertexBufferAccessor& vba) { // Each vertex can be visited multiple times, so compute the tangent // space only on the first visit. Use the zero vector as a flag for the // tangent vector not being computed. const int numVertices = vba.GetNumVertices(); bool hasTangent = vba.HasTangent(); Float3 zero(0.0f, 0.0f, 0.0f); int i; if (hasTangent) { for (i = 0; i < numVertices; ++i) { vba.Tangent<Float3>(i) = zero; } } else { for (i = 0; i < numVertices; ++i) { vba.Binormal<Float3>(i) = zero; } } const int numTriangles = GetNumTriangles(); for (i = 0; i < numTriangles; i++) { // Get the triangle vertices' positions, normals, tangents, and // texture coordinates. int v0, v1, v2; if (!GetTriangle(i, v0, v1, v2)) { continue; } APoint locPosition[3] = { vba.Position<Float3>(v0), vba.Position<Float3>(v1), vba.Position<Float3>(v2) }; AVector locNormal[3] = { vba.Normal<Float3>(v0), vba.Normal<Float3>(v1), vba.Normal<Float3>(v2) }; AVector locTangent[3] = { (hasTangent ? vba.Tangent<Float3>(v0) : vba.Binormal<Float3>(v0)), (hasTangent ? vba.Tangent<Float3>(v1) : vba.Binormal<Float3>(v1)), (hasTangent ? vba.Tangent<Float3>(v2) : vba.Binormal<Float3>(v2)) }; Float2 locTCoord[3] = { vba.TCoord<Float2>(0, v0), vba.TCoord<Float2>(0, v1), vba.TCoord<Float2>(0, v2) }; for (int curr = 0; curr < 3; ++curr) { Float3 currLocTangent = (Float3)locTangent[curr]; if (currLocTangent != zero) { // This vertex has already been visited. continue; } // Compute the tangent space at the vertex. AVector norvec = locNormal[curr]; int prev = ((curr + 2) % 3); int next = ((curr + 1) % 3); AVector tanvec = ComputeTangent( locPosition[curr], locTCoord[curr], locPosition[next], locTCoord[next], locPosition[prev], locTCoord[prev]); // Project T into the tangent plane by projecting out the surface // normal N, and then making it unit length. tanvec -= norvec.Dot(tanvec)*norvec; tanvec.Normalize(); // Compute the bitangent B, another tangent perpendicular to T. AVector binvec = norvec.UnitCross(tanvec); if (vba.HasTangent()) { locTangent[curr] = tanvec; if (vba.HasBinormal()) { vba.Binormal<Float3>(curr) = binvec; } } else { vba.Binormal<Float3>(curr) = tanvec; } } } }