inline void ParametricSurface::GenerateVertices(vector<float>& vertices, unsigned char flags) const { int floatsPerVertex = 3; if (flags & VertexFlagsNormals) floatsPerVertex += 3; if (flags & VertexFlagsTexCoords) floatsPerVertex += 2; vertices.resize(GetVertexCount() * floatsPerVertex); float* attribute = &vertices[0]; for (int j = 0; j < m_divisions.y; j++) { for (int i = 0; i < m_divisions.x; i++) { // Compute Position vec2 domain = ComputeDomain(i, j); vec3 range = Evaluate(domain); attribute = range.Write(attribute); // Compute Normal if (flags & VertexFlagsNormals) { float s = i, t = j; // Nudge the point if the normal is indeterminate. if (i == 0) s += 0.01f; if (i == m_divisions.x - 1) s -= 0.01f; if (j == 0) t += 0.01f; if (j == m_divisions.y - 1) t -= 0.01f; // Compute the tangents and their cross product. vec3 p = Evaluate(ComputeDomain(s, t)); vec3 u = Evaluate(ComputeDomain(s + 0.01f, t)) - p; vec3 v = Evaluate(ComputeDomain(s, t + 0.01f)) - p; vec3 normal = u.Cross(v).Normalized(); if (InvertNormal(domain)) normal = -normal; attribute = normal.Write(attribute); } // Compute Texture Coordinates if (flags & VertexFlagsTexCoords) { float s = m_textureCount.x * i / m_slices.x; float t = m_textureCount.y * j / m_slices.y; attribute = vec2(s, t).Write(attribute); } } } }
void MinimizeN<Real>::GetMinimum (const Real* t0, const Real* t1, const Real* tInitial, Real* tMin, Real& fMin) { // For 1D function callback. mMinimizer.SetUserData(this); // The initial guess. size_t numBytes = mDimensions*sizeof(Real); mFCurr = mFunction(tInitial, mUserData); memcpy(mTSave, tInitial, numBytes); memcpy(mTCurr, tInitial, numBytes); // Initialize the direction set to the standard Euclidean basis. size_t numBasisBytes = numBytes*(mDimensions + 1); memset(mDirectionStorage, 0, numBasisBytes); int i; for (i = 0; i < mDimensions; ++i) { mDirection[i][i] = (Real)1; } Real ell0, ell1, ellMin; for (int iter = 0; iter < mMaxIterations; iter++) { // Find minimum in each direction and update current location. for (i = 0; i < mDimensions; ++i) { mDCurr = mDirection[i]; ComputeDomain(t0, t1, ell0, ell1); mMinimizer.GetMinimum(ell0, ell1, (Real)0, ellMin, mFCurr); for (int j = 0; j < mDimensions; ++j) { mTCurr[j] += ellMin*mDCurr[j]; } } // Estimate a unit-length conjugate direction. Real length = (Real)0; for (i = 0; i < mDimensions; ++i) { mDConj[i] = mTCurr[i] - mTSave[i]; length += mDConj[i]*mDConj[i]; } const Real epsilon = (Real)1e-06; length = Math<Real>::Sqrt(length); if (length < epsilon) { // New position did not change significantly from old one. // Should there be a better convergence criterion here? break; } Real invlength = ((Real)1)/length; for (i = 0; i < mDimensions; ++i) { mDConj[i] *= invlength; } // Minimize in conjugate direction. mDCurr = mDConj; ComputeDomain(t0, t1, ell0, ell1); mMinimizer.GetMinimum(ell0, ell1, (Real)0, ellMin, mFCurr); for (i = 0; i < mDimensions; ++i) { mTCurr[i] += ellMin*mDCurr[i]; } // Cycle the directions and add conjugate direction to set. mDConj = mDirection[0]; for (i = 0; i < mDimensions; ++i) { mDirection[i] = mDirection[i+1]; } // Set parameters for next pass. memcpy(mTSave, mTCurr, numBytes); } memcpy(tMin, mTCurr, numBytes); fMin = mFCurr; }