bool Sphere::Intersect(const Ray &r, Float *tHit, SurfaceInteraction *isect) const { Float phi; Point3f pHit; // Transform _Ray_ to object space Vector3f oErr, dErr; Ray ray = (*WorldToObject)(r, &oErr, &dErr); // Compute quadratic sphere coefficients // Initialize _EFloat_ ray coordinate values EFloat ox(ray.o.x, oErr.x), oy(ray.o.y, oErr.y), oz(ray.o.z, oErr.z); EFloat dx(ray.d.x, dErr.x), dy(ray.d.y, dErr.y), dz(ray.d.z, dErr.z); EFloat a = dx * dx + dy * dy + dz * dz; EFloat b = 2 * (dx * ox + dy * oy + dz * oz); EFloat c = ox * ox + oy * oy + oz * oz - EFloat(radius) * EFloat(radius); // Solve quadratic equation for _t_ values EFloat t0, t1; if (!Quadratic(a, b, c, &t0, &t1)) return false; // Check quadric shape _t0_ and _t1_ for nearest intersection if (t0.UpperBound() > ray.tMax || t1.LowerBound() <= 0) return false; EFloat tShapeHit = t0; if (t0.LowerBound() <= 0) { tShapeHit = t1; if (tShapeHit.UpperBound() > ray.tMax) return false; } // Compute sphere hit position and $\phi$ pHit = ray((Float)tShapeHit); // Refine sphere intersection point pHit *= radius / Distance(pHit, Point3f(0, 0, 0)); if (pHit.x == 0 && pHit.y == 0) pHit.x = 1e-5f * radius; phi = std::atan2(pHit.y, pHit.x); if (phi < 0) phi += 2 * Pi; // Test sphere intersection against clipping parameters if ((zMin > -radius && pHit.z < zMin) || (zMax < radius && pHit.z > zMax) || phi > phiMax) { if (tShapeHit == t1) return false; if (t1.UpperBound() > ray.tMax) return false; tShapeHit = t1; // Compute sphere hit position and $\phi$ pHit = ray((Float)tShapeHit); // Refine sphere intersection point pHit *= radius / Distance(pHit, Point3f(0, 0, 0)); if (pHit.x == 0 && pHit.y == 0) pHit.x = 1e-5f * radius; phi = std::atan2(pHit.y, pHit.x); if (phi < 0) phi += 2 * Pi; if ((zMin > -radius && pHit.z < zMin) || (zMax < radius && pHit.z > zMax) || phi > phiMax) return false; } // Find parametric representation of sphere hit Float u = phi / phiMax; Float theta = std::acos(Clamp(pHit.z / radius, -1, 1)); Float v = (theta - thetaMin) / (thetaMax - thetaMin); // Compute sphere $\dpdu$ and $\dpdv$ Float zRadius = std::sqrt(pHit.x * pHit.x + pHit.y * pHit.y); Float invZRadius = 1 / zRadius; Float cosPhi = pHit.x * invZRadius; Float sinPhi = pHit.y * invZRadius; Vector3f dpdu(-phiMax * pHit.y, phiMax * pHit.x, 0); Vector3f dpdv = (thetaMax - thetaMin) * Vector3f(pHit.z * cosPhi, pHit.z * sinPhi, -radius * std::sin(theta)); // Compute sphere $\dndu$ and $\dndv$ Vector3f d2Pduu = -phiMax * phiMax * Vector3f(pHit.x, pHit.y, 0); Vector3f d2Pduv = (thetaMax - thetaMin) * pHit.z * phiMax * Vector3f(-sinPhi, cosPhi, 0.); Vector3f d2Pdvv = -(thetaMax - thetaMin) * (thetaMax - thetaMin) * Vector3f(pHit.x, pHit.y, pHit.z); // Compute coefficients for fundamental forms Float E = Dot(dpdu, dpdu); Float F = Dot(dpdu, dpdv); Float G = Dot(dpdv, dpdv); Vector3f N = Normalize(Cross(dpdu, dpdv)); Float e = Dot(N, d2Pduu); Float f = Dot(N, d2Pduv); Float g = Dot(N, d2Pdvv); // Compute $\dndu$ and $\dndv$ from fundamental form coefficients Float invEGF2 = 1 / (E * G - F * F); Normal3f dndu = Normal3f((f * F - e * G) * invEGF2 * dpdu + (e * F - f * E) * invEGF2 * dpdv); Normal3f dndv = Normal3f((g * F - f * G) * invEGF2 * dpdu + (f * F - g * E) * invEGF2 * dpdv); // Compute error bounds for sphere intersection Vector3f pError = gamma(5) * Abs((Vector3f)pHit); // Initialize _SurfaceInteraction_ from parametric information *isect = (*ObjectToWorld)(SurfaceInteraction(pHit, pError, Point2f(u, v), -ray.d, dpdu, dpdv, dndu, dndv, ray.time, this)); // Update _tHit_ for quadric intersection *tHit = (Float)tShapeHit; return true; }
void COctree::DrawOctree(COctree *pNode) { // We should already have the octree created before we call this function. // This only goes through the nodes that are in our frustum, then renders those // vertices stored in their end nodes. Before we draw a node we check to // make sure it is a subdivided node (from m_bSubdivided). If it is, then // we haven't reaches the end and we need to keep recursing through the tree. // Once we get to a node that isn't subdivided we draw it's vertices. // Make sure a valid node was passed in, otherwise go back to the last node if(!pNode) return; /////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// * // Before we do any checks with the current node, let's make sure we even need too. // We want to check if this node's cube is even in our frustum first. // To do that we pass in our center point of the node and 1/2 it's width to our // CubeInFrustum() function. This will return "true" if it is inside the frustum // (camera's view), otherwise return false. else if(g_Frustum.CubeInFrustum(pNode->m_vCenter.x, pNode->m_vCenter.y, pNode->m_vCenter.z, pNode->m_Width / 2)) /////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// * // Check if this node is subdivided. If so, then we need to recurse and draw it's nodes if(pNode->IsSubDivided()) { // Recurse to the bottom of these nodes and draw the end node's vertices // Like creating the octree, we need to recurse through each of the 8 nodes. DrawOctree(pNode->m_pOctreeNodes[TOP_LEFT_FRONT]); DrawOctree(pNode->m_pOctreeNodes[TOP_LEFT_BACK]); DrawOctree(pNode->m_pOctreeNodes[TOP_RIGHT_BACK]); DrawOctree(pNode->m_pOctreeNodes[TOP_RIGHT_FRONT]); DrawOctree(pNode->m_pOctreeNodes[BOTTOM_LEFT_FRONT]); DrawOctree(pNode->m_pOctreeNodes[BOTTOM_LEFT_BACK]); DrawOctree(pNode->m_pOctreeNodes[BOTTOM_RIGHT_BACK]); DrawOctree(pNode->m_pOctreeNodes[BOTTOM_RIGHT_FRONT]); } else { // Increase the amount of nodes in our viewing frustum (camera's view) g_TotalNodesDrawn++; // Make sure we have valid vertices assigned to this node if(!pNode->m_pVertices) return; // Render the world data with triangles glBegin(GL_TRIANGLES); // Turn the polygons green glColor3ub(0, 255, 0); // Store the vertices in a local pointer to keep code more clean CVector3 *pVertices = pNode->m_pVertices; // Go through all of the vertices (the number of triangles * 3) for(int i = 0; i < pNode->GetTriangleCount() * 3; i += 3) { // Before we render the vertices we want to calculate the face normal // of the current polygon. That way when lighting is turned on we can // see the definition of the terrain more clearly. In reality you wouldn't do this. // Here we get a vector from each side of the triangle CVector3 vVector1 = pVertices[i + 1] - pVertices[i]; CVector3 vVector2 = pVertices[i + 2] - pVertices[i]; // Then we need to get the cross product of those 2 vectors (The normal's direction) CVector3 vNormal = Cross(vVector1, vVector2); // Now we normalize the normal so it is a unit vector (length of 1) vNormal = Normalize(vNormal); // Pass in the normal for this triangle so we can see better depth in the scene glNormal3f(vNormal.x, vNormal.y, vNormal.z); // Render the first point in the triangle glVertex3f(pVertices[i].x, pVertices[i].y, pVertices[i].z); // Render the next point in the triangle glVertex3f(pVertices[i + 1].x, pVertices[i + 1].y, pVertices[i + 1].z); // Render the last point in the triangle to form the current triangle glVertex3f(pVertices[i + 2].x, pVertices[i + 2].y, pVertices[i + 2].z); } // Quit Drawing glEnd(); } }
float3 Polygon::EdgeNormal(int edgeIndex) const { return Cross(Edge(edgeIndex).Dir(), PlaneCCW().normal).Normalized(); }
void TesselateBezierPatch(u8 *&dest, int &count, const BezierPatch &patch, u32 origVertType) { const float third = 1.0f / 3.0f; if (g_Config.bLowQualitySplineBezier) { // Fast and easy way - just draw the control points, generate some very basic normal vector subsitutes. // Very inaccurate though but okay for Loco Roco. Maybe should keep it as an option. float u_base = patch.u_index / 3.0f; float v_base = patch.v_index / 3.0f; for (int tile_v = 0; tile_v < 3; tile_v++) { for (int tile_u = 0; tile_u < 3; tile_u++) { int point_index = tile_u + tile_v * 4; SimpleVertex v0 = *patch.points[point_index]; SimpleVertex v1 = *patch.points[point_index+1]; SimpleVertex v2 = *patch.points[point_index+4]; SimpleVertex v3 = *patch.points[point_index+5]; // Generate UV. TODO: Do this even if UV specified in control points? if ((origVertType & GE_VTYPE_TC_MASK) == 0) { float u = u_base + tile_u * third; float v = v_base + tile_v * third; v0.uv[0] = u; v0.uv[1] = v; v1.uv[0] = u + third; v1.uv[1] = v; v2.uv[0] = u; v2.uv[1] = v + third; v3.uv[0] = u + third; v3.uv[1] = v + third; } // Generate normal if lighting is enabled (otherwise there's no point). // This is a really poor quality algorithm, we get facet normals. if (gstate.isLightingEnabled()) { Vec3f norm = Cross(v1.pos - v0.pos, v2.pos - v0.pos); norm.Normalize(); if (gstate.patchfacing & 1) norm *= -1.0f; v0.nrm = norm; v1.nrm = norm; v2.nrm = norm; v3.nrm = norm; } CopyQuad(dest, &v0, &v1, &v2, &v3); count += 6; } } } else { // Full correct tesselation of bezier patches. // Note: Does not handle splines correctly. int tess_u = gstate.getPatchDivisionU(); int tess_v = gstate.getPatchDivisionV(); // First compute all the vertices and put them in an array SimpleVertex *vertices = new SimpleVertex[(tess_u + 1) * (tess_v + 1)]; Vec3f *horiz = new Vec3f[(tess_u + 1) * 4]; Vec3f *horiz2 = horiz + (tess_u + 1) * 1; Vec3f *horiz3 = horiz + (tess_u + 1) * 2; Vec3f *horiz4 = horiz + (tess_u + 1) * 3; // Precompute the horizontal curves to we only have to evaluate the vertical ones. for (int i = 0; i < tess_u + 1; i++) { float u = ((float)i / (float)tess_u); horiz[i] = Bernstein3D(patch.points[0]->pos, patch.points[1]->pos, patch.points[2]->pos, patch.points[3]->pos, u); horiz2[i] = Bernstein3D(patch.points[4]->pos, patch.points[5]->pos, patch.points[6]->pos, patch.points[7]->pos, u); horiz3[i] = Bernstein3D(patch.points[8]->pos, patch.points[9]->pos, patch.points[10]->pos, patch.points[11]->pos, u); horiz4[i] = Bernstein3D(patch.points[12]->pos, patch.points[13]->pos, patch.points[14]->pos, patch.points[15]->pos, u); } bool computeNormals = gstate.isLightingEnabled(); for (int tile_v = 0; tile_v < tess_v + 1; ++tile_v) { for (int tile_u = 0; tile_u < tess_u + 1; ++tile_u) { float u = ((float)tile_u / (float)tess_u); float v = ((float)tile_v / (float)tess_v); float bu = u; float bv = v; // TODO: Should be able to precompute the four curves per U, then just Bernstein per V. Will benefit large tesselation factors. const Vec3f &pos1 = horiz[tile_u]; const Vec3f &pos2 = horiz2[tile_u]; const Vec3f &pos3 = horiz3[tile_u]; const Vec3f &pos4 = horiz4[tile_u]; SimpleVertex &vert = vertices[tile_v * (tess_u + 1) + tile_u]; if (computeNormals) { Vec3f derivU1 = Bernstein3DDerivative(patch.points[0]->pos, patch.points[1]->pos, patch.points[2]->pos, patch.points[3]->pos, bu); Vec3f derivU2 = Bernstein3DDerivative(patch.points[4]->pos, patch.points[5]->pos, patch.points[6]->pos, patch.points[7]->pos, bu); Vec3f derivU3 = Bernstein3DDerivative(patch.points[8]->pos, patch.points[9]->pos, patch.points[10]->pos, patch.points[11]->pos, bu); Vec3f derivU4 = Bernstein3DDerivative(patch.points[12]->pos, patch.points[13]->pos, patch.points[14]->pos, patch.points[15]->pos, bu); Vec3f derivU = Bernstein3D(derivU1, derivU2, derivU3, derivU4, bv); Vec3f derivV = Bernstein3DDerivative(pos1, pos2, pos3, pos4, bv); // TODO: Interpolate normals instead of generating them, if available? vert.nrm = Cross(derivU, derivV).Normalized(); if (gstate.patchfacing & 1) vert.nrm *= -1.0f; } else { vert.nrm.SetZero(); } vert.pos = Bernstein3D(pos1, pos2, pos3, pos4, bv); if ((origVertType & GE_VTYPE_TC_MASK) == 0) { // Generate texcoord vert.uv[0] = u + patch.u_index * third; vert.uv[1] = v + patch.v_index * third; } else { // Sample UV from control points patch.sampleTexUV(u, v, vert.uv[0], vert.uv[1]); } if (origVertType & GE_VTYPE_COL_MASK) { patch.sampleColor(u, v, vert.color); } else { memcpy(vert.color, patch.points[0]->color, 4); } } } delete [] horiz; // Tesselate. TODO: Use indices so we only need to emit 4 vertices per pair of triangles instead of six. for (int tile_v = 0; tile_v < tess_v; ++tile_v) { for (int tile_u = 0; tile_u < tess_u; ++tile_u) { float u = ((float)tile_u / (float)tess_u); float v = ((float)tile_v / (float)tess_v); const SimpleVertex *v0 = &vertices[tile_v * (tess_u + 1) + tile_u]; const SimpleVertex *v1 = &vertices[tile_v * (tess_u + 1) + tile_u + 1]; const SimpleVertex *v2 = &vertices[(tile_v + 1) * (tess_u + 1) + tile_u]; const SimpleVertex *v3 = &vertices[(tile_v + 1) * (tess_u + 1) + tile_u + 1]; CopyQuad(dest, v0, v1, v2, v3); count += 6; } } delete [] vertices; } }
vec Polygon::BasisV() const { if (p.size() < 2) return vec::unitY; return Cross(PlaneCCW().normal, BasisU()).Normalized(); }
void Manifold::ApplyImpulse( void ) { // Early out and positional correct if both objects have infinite mass if(Equal( A->im + B->im, 0 )) { InfiniteMassCorrection( ); return; } for(uint32 i = 0; i < contact_count; ++i) { // Calculate radii from COM to contact Vec2 ra = contacts[i] - A->position; Vec2 rb = contacts[i] - B->position; // Relative velocity Vec2 rv = B->velocity + Cross( B->angularVelocity, rb ) - A->velocity - Cross( A->angularVelocity, ra ); // Relative velocity along the normal real contactVel = Dot( rv, normal ); // Do not resolve if velocities are separating if(contactVel > 0) return; real raCrossN = Cross( ra, normal ); real rbCrossN = Cross( rb, normal ); real invMassSum = A->im + B->im + Sqr( raCrossN ) * A->iI + Sqr( rbCrossN ) * B->iI; // Calculate impulse scalar real j = -(1.0f + e) * contactVel; j /= invMassSum; j /= (real)contact_count; // Apply impulse Vec2 impulse = normal * j; A->ApplyImpulse( -impulse, ra ); B->ApplyImpulse( impulse, rb ); // Friction impulse rv = B->velocity + Cross( B->angularVelocity, rb ) - A->velocity - Cross( A->angularVelocity, ra ); Vec2 t = rv - (normal * Dot( rv, normal )); t.Normalize( ); // j tangent magnitude real jt = -Dot( rv, t ); jt /= invMassSum; jt /= (real)contact_count; // Don't apply tiny friction impulses if(Equal( jt, 0.0f )) return; // Coulumb's law Vec2 tangentImpulse; if(std::abs( jt ) < j * sf) tangentImpulse = t * jt; else tangentImpulse = t * -j * df; // Apply friction impulse A->ApplyImpulse( -tangentImpulse, ra ); B->ApplyImpulse( tangentImpulse, rb ); } }
void NaiadTriangle::GetShadingGeometry(const Transform &obj2world, const DifferentialGeometry &dg, DifferentialGeometry *dgShading) const { if (!mesh->n && !mesh->s) { *dgShading = dg; return; } // Initialize _NaiadTriangle_ shading geometry with _n_ and _s_ // Compute barycentric coordinates for point float b[3]; // Initialize _A_ and _C_ matrices for barycentrics float uv[3][2]; GetUVs(uv); float A[2][2] = { { uv[1][0] - uv[0][0], uv[2][0] - uv[0][0] }, { uv[1][1] - uv[0][1], uv[2][1] - uv[0][1] } }; float C[2] = { dg.u - uv[0][0], dg.v - uv[0][1] }; if (!SolveLinearSystem2x2(A, C, &b[1], &b[2])) { // Handle degenerate parametric mapping b[0] = b[1] = b[2] = 1.f/3.f; } else b[0] = 1.f - b[1] - b[2]; // Use _n_ and _s_ to compute shading tangents for NaiadTriangle, _ss_ and _ts_ Normal ns; Vector ss, ts; if (mesh->n) ns = Normalize(obj2world(b[0] * mesh->n[v[0]] + b[1] * mesh->n[v[1]] + b[2] * mesh->n[v[2]])); else ns = dg.nn; if (mesh->s) ss = Normalize(obj2world(b[0] * mesh->s[v[0]] + b[1] * mesh->s[v[1]] + b[2] * mesh->s[v[2]])); else ss = Normalize(dg.dpdu); ts = Cross(ss, ns); if (ts.LengthSquared() > 0.f) { ts = Normalize(ts); ss = Cross(ts, ns); } else CoordinateSystem((Vector)ns, &ss, &ts); Normal dndu, dndv; // Compute $\dndu$ and $\dndv$ for NaiadTriangle shading geometry if (mesh->n) { float uvs[3][2]; GetUVs(uvs); // Compute deltas for NaiadTriangle partial derivatives of normal float du1 = uvs[0][0] - uvs[2][0]; float du2 = uvs[1][0] - uvs[2][0]; float dv1 = uvs[0][1] - uvs[2][1]; float dv2 = uvs[1][1] - uvs[2][1]; Normal dn1 = mesh->n[v[0]] - mesh->n[v[2]]; Normal dn2 = mesh->n[v[1]] - mesh->n[v[2]]; float determinant = du1 * dv2 - dv1 * du2; if (determinant == 0.f) dndu = dndv = Normal(0,0,0); else { float invdet = 1.f / determinant; dndu = ( dv2 * dn1 - dv1 * dn2) * invdet; dndv = (-du2 * dn1 + du1 * dn2) * invdet; } } else dndu = dndv = Normal(0,0,0); *dgShading = DifferentialGeometry(dg.p, ss, ts, (*ObjectToWorld)(dndu), (*ObjectToWorld)(dndv), dg.u, dg.v, dg.shape); dgShading->dudx = dg.dudx; dgShading->dvdx = dg.dvdx; dgShading->dudy = dg.dudy; dgShading->dvdy = dg.dvdy; dgShading->dpdx = dg.dpdx; dgShading->dpdy = dg.dpdy; }
bool Triangle::Intersect(const Ray &ray, Float *tHit, SurfaceInteraction *isect, bool testAlphaTexture) const { ProfilePhase p(Prof::TriIntersect); ++nTests; // Get triangle vertices in _p0_, _p1_, and _p2_ const Point3f &p0 = mesh->p[v[0]]; const Point3f &p1 = mesh->p[v[1]]; const Point3f &p2 = mesh->p[v[2]]; // Perform ray--triangle intersection test // Transform triangle vertices to ray coordinate space // Translate vertices based on ray origin Point3f p0t = p0 - Vector3f(ray.o); Point3f p1t = p1 - Vector3f(ray.o); Point3f p2t = p2 - Vector3f(ray.o); // Permute components of triangle vertices and ray direction int kz = MaxDimension(Abs(ray.d)); int kx = kz + 1; if (kx == 3) kx = 0; int ky = kx + 1; if (ky == 3) ky = 0; Vector3f d = Permute(ray.d, kx, ky, kz); p0t = Permute(p0t, kx, ky, kz); p1t = Permute(p1t, kx, ky, kz); p2t = Permute(p2t, kx, ky, kz); // Apply shear transformation to translated vertex positions Float Sx = -d.x / d.z; Float Sy = -d.y / d.z; Float Sz = 1.f / d.z; p0t.x += Sx * p0t.z; p0t.y += Sy * p0t.z; p1t.x += Sx * p1t.z; p1t.y += Sy * p1t.z; p2t.x += Sx * p2t.z; p2t.y += Sy * p2t.z; // Compute edge function coefficients _e0_, _e1_, and _e2_ Float e0 = p1t.x * p2t.y - p1t.y * p2t.x; Float e1 = p2t.x * p0t.y - p2t.y * p0t.x; Float e2 = p0t.x * p1t.y - p0t.y * p1t.x; // Fall back to double precision test at triangle edges if (sizeof(Float) == sizeof(float) && (e0 == 0.0f || e1 == 0.0f || e2 == 0.0f)) { double p2txp1ty = (double)p2t.x * (double)p1t.y; double p2typ1tx = (double)p2t.y * (double)p1t.x; e0 = (float)(p2typ1tx - p2txp1ty); double p0txp2ty = (double)p0t.x * (double)p2t.y; double p0typ2tx = (double)p0t.y * (double)p2t.x; e1 = (float)(p0typ2tx - p0txp2ty); double p1txp0ty = (double)p1t.x * (double)p0t.y; double p1typ0tx = (double)p1t.y * (double)p0t.x; e2 = (float)(p1typ0tx - p1txp0ty); } // Perform triangle edge and determinant tests if ((e0 < 0 || e1 < 0 || e2 < 0) && (e0 > 0 || e1 > 0 || e2 > 0)) return false; Float det = e0 + e1 + e2; if (det == 0) return false; // Compute scaled hit distance to triangle and test against ray $t$ range p0t.z *= Sz; p1t.z *= Sz; p2t.z *= Sz; Float tScaled = e0 * p0t.z + e1 * p1t.z + e2 * p2t.z; if (det < 0 && (tScaled >= 0 || tScaled < ray.tMax * det)) return false; else if (det > 0 && (tScaled <= 0 || tScaled > ray.tMax * det)) return false; // Compute barycentric coordinates and $t$ value for triangle intersection Float invDet = 1 / det; Float b0 = e0 * invDet; Float b1 = e1 * invDet; Float b2 = e2 * invDet; Float t = tScaled * invDet; // Ensure that computed triangle $t$ is conservatively greater than zero // Compute $\delta_z$ term for triangle $t$ error bounds Float maxZt = MaxComponent(Abs(Vector3f(p0t.z, p1t.z, p2t.z))); Float deltaZ = gamma(3) * maxZt; // Compute $\delta_x$ and $\delta_y$ terms for triangle $t$ error bounds Float maxXt = MaxComponent(Abs(Vector3f(p0t.x, p1t.x, p2t.x))); Float maxYt = MaxComponent(Abs(Vector3f(p0t.y, p1t.y, p2t.y))); Float deltaX = gamma(5) * (maxXt + maxZt); Float deltaY = gamma(5) * (maxYt + maxZt); // Compute $\delta_e$ term for triangle $t$ error bounds Float deltaE = 2 * (gamma(2) * maxXt * maxYt + deltaY * maxXt + deltaX * maxYt); // Compute $\delta_t$ term for triangle $t$ error bounds and check _t_ Float maxE = MaxComponent(Abs(Vector3f(e0, e1, e2))); Float deltaT = 3 * (gamma(3) * maxE * maxZt + deltaE * maxZt + deltaZ * maxE) * std::abs(invDet); if (t <= deltaT) return false; // Compute triangle partial derivatives Vector3f dpdu, dpdv; Point2f uv[3]; GetUVs(uv); // Compute deltas for triangle partial derivatives Vector2f duv02 = uv[0] - uv[2], duv12 = uv[1] - uv[2]; Vector3f dp02 = p0 - p2, dp12 = p1 - p2; Float determinant = duv02[0] * duv12[1] - duv02[1] * duv12[0]; if (determinant == 0) { // Handle zero determinant for triangle partial derivative matrix CoordinateSystem(Normalize(Cross(p2 - p0, p1 - p0)), &dpdu, &dpdv); } else { Float invdet = 1 / determinant; dpdu = (duv12[1] * dp02 - duv02[1] * dp12) * invdet; dpdv = (-duv12[0] * dp02 + duv02[0] * dp12) * invdet; } // Compute error bounds for triangle intersection Float xAbsSum = (std::abs(b0 * p0.x) + std::abs(b1 * p1.x) + std::abs(b2 * p2.x)); Float yAbsSum = (std::abs(b0 * p0.y) + std::abs(b1 * p1.y) + std::abs(b2 * p2.y)); Float zAbsSum = (std::abs(b0 * p0.z) + std::abs(b1 * p1.z) + std::abs(b2 * p2.z)); Vector3f pError = gamma(7) * Vector3f(xAbsSum, yAbsSum, zAbsSum); // Interpolate $(u,v)$ parametric coordinates and hit point Point3f pHit = b0 * p0 + b1 * p1 + b2 * p2; Point2f uvHit = b0 * uv[0] + b1 * uv[1] + b2 * uv[2]; // Test intersection against alpha texture, if present if (testAlphaTexture && mesh->alphaMask) { SurfaceInteraction isectLocal(pHit, Vector3f(0, 0, 0), uvHit, -ray.d, dpdu, dpdv, Normal3f(0, 0, 0), Normal3f(0, 0, 0), ray.time, this); if (mesh->alphaMask->Evaluate(isectLocal) == 0) return false; } // Fill in _SurfaceInteraction_ from triangle hit *isect = SurfaceInteraction(pHit, pError, uvHit, -ray.d, dpdu, dpdv, Normal3f(0, 0, 0), Normal3f(0, 0, 0), ray.time, this); // Override surface normal in _isect_ for triangle isect->n = isect->shading.n = Normal3f(Normalize(Cross(dp02, dp12))); if (mesh->n || mesh->s) { // Initialize _Triangle_ shading geometry // Compute shading normal _ns_ for triangle Normal3f ns; if (mesh->n) { ns = (b0 * mesh->n[v[0]] + b1 * mesh->n[v[1]] + b2 * mesh->n[v[2]]); if (ns.LengthSquared() > 0) ns = Normalize(ns); else ns = isect->n; } else ns = isect->n; // Compute shading tangent _ss_ for triangle Vector3f ss; if (mesh->s) { ss = (b0 * mesh->s[v[0]] + b1 * mesh->s[v[1]] + b2 * mesh->s[v[2]]); if (ss.LengthSquared() > 0) ss = Normalize(ss); else ss = Normalize(isect->dpdu); } else ss = Normalize(isect->dpdu); // Compute shading bitangent _ts_ for triangle and adjust _ss_ Vector3f ts = Cross(ss, ns); if (ts.LengthSquared() > 0.f) { ts = Normalize(ts); ss = Cross(ts, ns); } else CoordinateSystem((Vector3f)ns, &ss, &ts); // Compute $\dndu$ and $\dndv$ for triangle shading geometry Normal3f dndu, dndv; if (mesh->n) { // Compute deltas for triangle partial derivatives of normal Vector2f duv02 = uv[0] - uv[2]; Vector2f duv12 = uv[1] - uv[2]; Normal3f dn1 = mesh->n[v[0]] - mesh->n[v[2]]; Normal3f dn2 = mesh->n[v[1]] - mesh->n[v[2]]; Float determinant = duv02[0] * duv12[1] - duv02[1] * duv12[0]; if (determinant == 0) dndu = dndv = Normal3f(0, 0, 0); else { Float invDet = 1 / determinant; dndu = (duv12[1] * dn1 - duv02[1] * dn2) * invDet; dndv = (-duv12[0] * dn1 + duv02[0] * dn2) * invDet; } } else dndu = dndv = Normal3f(0, 0, 0); isect->SetShadingGeometry(ss, ts, dndu, dndv, true); } // Ensure correct orientation of the geometric normal if (mesh->n) isect->n = Faceforward(isect->n, isect->shading.n); else if (reverseOrientation ^ transformSwapsHandedness) isect->n = isect->shading.n = -isect->n; *tHit = t; ++nHits; return true; }
bool Triangle::IntersectP(const Ray &ray, bool testAlphaTexture) const { ProfilePhase p(Prof::TriIntersectP); ++nTests; // Get triangle vertices in _p0_, _p1_, and _p2_ const Point3f &p0 = mesh->p[v[0]]; const Point3f &p1 = mesh->p[v[1]]; const Point3f &p2 = mesh->p[v[2]]; // Perform ray--triangle intersection test // Transform triangle vertices to ray coordinate space // Translate vertices based on ray origin Point3f p0t = p0 - Vector3f(ray.o); Point3f p1t = p1 - Vector3f(ray.o); Point3f p2t = p2 - Vector3f(ray.o); // Permute components of triangle vertices and ray direction int kz = MaxDimension(Abs(ray.d)); int kx = kz + 1; if (kx == 3) kx = 0; int ky = kx + 1; if (ky == 3) ky = 0; Vector3f d = Permute(ray.d, kx, ky, kz); p0t = Permute(p0t, kx, ky, kz); p1t = Permute(p1t, kx, ky, kz); p2t = Permute(p2t, kx, ky, kz); // Apply shear transformation to translated vertex positions Float Sx = -d.x / d.z; Float Sy = -d.y / d.z; Float Sz = 1.f / d.z; p0t.x += Sx * p0t.z; p0t.y += Sy * p0t.z; p1t.x += Sx * p1t.z; p1t.y += Sy * p1t.z; p2t.x += Sx * p2t.z; p2t.y += Sy * p2t.z; // Compute edge function coefficients _e0_, _e1_, and _e2_ Float e0 = p1t.x * p2t.y - p1t.y * p2t.x; Float e1 = p2t.x * p0t.y - p2t.y * p0t.x; Float e2 = p0t.x * p1t.y - p0t.y * p1t.x; // Fall back to double precision test at triangle edges if (sizeof(Float) == sizeof(float) && (e0 == 0.0f || e1 == 0.0f || e2 == 0.0f)) { double p2txp1ty = (double)p2t.x * (double)p1t.y; double p2typ1tx = (double)p2t.y * (double)p1t.x; e0 = (float)(p2typ1tx - p2txp1ty); double p0txp2ty = (double)p0t.x * (double)p2t.y; double p0typ2tx = (double)p0t.y * (double)p2t.x; e1 = (float)(p0typ2tx - p0txp2ty); double p1txp0ty = (double)p1t.x * (double)p0t.y; double p1typ0tx = (double)p1t.y * (double)p0t.x; e2 = (float)(p1typ0tx - p1txp0ty); } // Perform triangle edge and determinant tests if ((e0 < 0 || e1 < 0 || e2 < 0) && (e0 > 0 || e1 > 0 || e2 > 0)) return false; Float det = e0 + e1 + e2; if (det == 0) return false; // Compute scaled hit distance to triangle and test against ray $t$ range p0t.z *= Sz; p1t.z *= Sz; p2t.z *= Sz; Float tScaled = e0 * p0t.z + e1 * p1t.z + e2 * p2t.z; if (det < 0 && (tScaled >= 0 || tScaled < ray.tMax * det)) return false; else if (det > 0 && (tScaled <= 0 || tScaled > ray.tMax * det)) return false; // Compute barycentric coordinates and $t$ value for triangle intersection Float invDet = 1 / det; Float b0 = e0 * invDet; Float b1 = e1 * invDet; Float b2 = e2 * invDet; Float t = tScaled * invDet; // Ensure that computed triangle $t$ is conservatively greater than zero // Compute $\delta_z$ term for triangle $t$ error bounds Float maxZt = MaxComponent(Abs(Vector3f(p0t.z, p1t.z, p2t.z))); Float deltaZ = gamma(3) * maxZt; // Compute $\delta_x$ and $\delta_y$ terms for triangle $t$ error bounds Float maxXt = MaxComponent(Abs(Vector3f(p0t.x, p1t.x, p2t.x))); Float maxYt = MaxComponent(Abs(Vector3f(p0t.y, p1t.y, p2t.y))); Float deltaX = gamma(5) * (maxXt + maxZt); Float deltaY = gamma(5) * (maxYt + maxZt); // Compute $\delta_e$ term for triangle $t$ error bounds Float deltaE = 2 * (gamma(2) * maxXt * maxYt + deltaY * maxXt + deltaX * maxYt); // Compute $\delta_t$ term for triangle $t$ error bounds and check _t_ Float maxE = MaxComponent(Abs(Vector3f(e0, e1, e2))); Float deltaT = 3 * (gamma(3) * maxE * maxZt + deltaE * maxZt + deltaZ * maxE) * std::abs(invDet); if (t <= deltaT) return false; // Test shadow ray intersection against alpha texture, if present if (testAlphaTexture && (mesh->alphaMask || mesh->shadowAlphaMask)) { // Compute triangle partial derivatives Vector3f dpdu, dpdv; Point2f uv[3]; GetUVs(uv); // Compute deltas for triangle partial derivatives Vector2f duv02 = uv[0] - uv[2], duv12 = uv[1] - uv[2]; Vector3f dp02 = p0 - p2, dp12 = p1 - p2; Float determinant = duv02[0] * duv12[1] - duv02[1] * duv12[0]; if (determinant == 0) { // Handle zero determinant for triangle partial derivative matrix CoordinateSystem(Normalize(Cross(p2 - p0, p1 - p0)), &dpdu, &dpdv); } else { Float invdet = 1 / determinant; dpdu = (duv12[1] * dp02 - duv02[1] * dp12) * invdet; dpdv = (-duv12[0] * dp02 + duv02[0] * dp12) * invdet; } // Interpolate $(u,v)$ parametric coordinates and hit point Point3f pHit = b0 * p0 + b1 * p1 + b2 * p2; Point2f uvHit = b0 * uv[0] + b1 * uv[1] + b2 * uv[2]; SurfaceInteraction isectLocal(pHit, Vector3f(0, 0, 0), uvHit, -ray.d, dpdu, dpdv, Normal3f(0, 0, 0), Normal3f(0, 0, 0), ray.time, this); if (mesh->alphaMask && mesh->alphaMask->Evaluate(isectLocal) == 0) return false; if (mesh->shadowAlphaMask && mesh->shadowAlphaMask->Evaluate(isectLocal) == 0) return false; } ++nHits; return true; }
void FVoronoiDiagramSite::GenerateCentroid(FIntRect Bounds) { TArray<FVector2D> SortedVertices; // Gather all vertices from the edges // Solve for corners bool bHas_X_Min = false; bool bHas_X_Max = false; bool bHas_Min_Y = false; bool bHas_Max_Y = false; for(auto Itr(Edges.CreateConstIterator()); Itr; ++Itr) { TSharedPtr<FVoronoiDiagramEdge, ESPMode::ThreadSafe> CurrentEdge = (*Itr); // Don't add edge that is (0,0) -> (0,0). Increment Index if no edge is removed, otherwise the remove should do this shifting for us if( FMath::IsNearlyEqual(CurrentEdge->LeftClippedEndPoint.X, FLT_MIN) && FMath::IsNearlyEqual(CurrentEdge->LeftClippedEndPoint.Y, FLT_MIN) && FMath::IsNearlyEqual(CurrentEdge->RightClippedEndPoint.X, FLT_MIN) && FMath::IsNearlyEqual(CurrentEdge->RightClippedEndPoint.Y, FLT_MIN) ) { continue; } FVector2D LeftEndPoint = CurrentEdge->LeftClippedEndPoint; FVector2D RightEndPoint = CurrentEdge->RightClippedEndPoint; // (x, Min) if(FMath::IsNearlyZero(LeftEndPoint.Y, NOT_REALLY_KINDA_SMALL_NUMBER) || FMath::IsNearlyZero(RightEndPoint.Y, NOT_REALLY_KINDA_SMALL_NUMBER)) { bHas_X_Min = true; } // (x, Max) if(FMath::IsNearlyEqual(LeftEndPoint.Y, Bounds.Height(), NOT_REALLY_KINDA_SMALL_NUMBER) || FMath::IsNearlyEqual(RightEndPoint.Y, Bounds.Height(), NOT_REALLY_KINDA_SMALL_NUMBER)) { bHas_X_Max = true; } // (Min, y) if(FMath::IsNearlyZero(LeftEndPoint.X, NOT_REALLY_KINDA_SMALL_NUMBER) || FMath::IsNearlyZero(RightEndPoint.X, NOT_REALLY_KINDA_SMALL_NUMBER)) { bHas_Min_Y = true; } // (Max, y) if(FMath::IsNearlyEqual(LeftEndPoint.X, Bounds.Width(), NOT_REALLY_KINDA_SMALL_NUMBER) || FMath::IsNearlyEqual(RightEndPoint.X, Bounds.Width(), NOT_REALLY_KINDA_SMALL_NUMBER)) { bHas_Max_Y = true; } SortedVertices.Add(LeftEndPoint); SortedVertices.Add(RightEndPoint); } // Add corners if applicable // (x, Min) -> (Min, y) // Min, Min Corner if(bHas_X_Min && bHas_Min_Y) { SortedVertices.Add(FVector2D(0.0f, 0.0f)); bIsCorner = true; } // x, Min -> Max, y // Min, Max Corner if(bHas_X_Min && bHas_Max_Y) { SortedVertices.Add(FVector2D(Bounds.Width(), 0.0f)); bIsCorner = true; } // x, Max -> Min, y // Max, Min Corner if(bHas_X_Max && bHas_Min_Y) { SortedVertices.Add(FVector2D(0.0f, static_cast<float>(Bounds.Height()))); bIsCorner = true; } // x, Max -> Max, y // Max, Max Corner if(bHas_X_Max && bHas_Max_Y) { SortedVertices.Add(FVector2D(static_cast<float>(Bounds.Width()), static_cast<float>(Bounds.Height()))); bIsCorner = true; } if(bHas_X_Min || bHas_X_Max || bHas_Min_Y || bHas_Max_Y) { bIsEdge = true; } // Monotone Chain // Sort the vertices lexigraphically by X and then Y struct FSortVertex { bool operator()(const FVector2D& A, const FVector2D& B) const { if(A.X < B.X) { return true; } if(A.X > B.X) { return false; } if(A.Y < B.Y) { return true; } if(A.Y > B.Y) { return false; } return false; } }; SortedVertices.Sort(FSortVertex()); TArray<FVector2D> LowerHull; for(int32 i = 0; i < SortedVertices.Num(); ++i) { while(LowerHull.Num() >= 2 && (Cross( LowerHull[ LowerHull.Num() - 2 ], LowerHull[ LowerHull.Num() - 1 ], SortedVertices[i]) < 0.0f || FMath::IsNearlyZero(Cross( LowerHull[ LowerHull.Num() - 2 ], LowerHull[ LowerHull.Num() - 1 ], SortedVertices[i])))) { LowerHull.RemoveAt(LowerHull.Num() - 1); } LowerHull.Add(SortedVertices[i]); } TArray<FVector2D> UpperHull; for(int32 i = SortedVertices.Num() - 1; i >= 0; --i) { while(UpperHull.Num() >= 2 && (Cross( UpperHull[ UpperHull.Num() - 2 ], UpperHull[ UpperHull.Num() - 1 ], SortedVertices[i]) < 0.0f || FMath::IsNearlyZero(Cross( UpperHull[ UpperHull.Num() - 2 ], UpperHull[ UpperHull.Num() - 1 ], SortedVertices[i])))) { UpperHull.RemoveAt(UpperHull.Num() - 1); } UpperHull.Add(SortedVertices[i]); } // Remove last point because they are represented in the other list UpperHull.RemoveAt(UpperHull.Num() - 1); LowerHull.RemoveAt(LowerHull.Num() - 1); SortedVertices.Empty(); SortedVertices.Append(LowerHull); SortedVertices.Append(UpperHull); // Calculate Centroid Centroid = FVector2D::ZeroVector; Vertices.Empty(); Vertices.Append(SortedVertices); FVector2D CurrentVertex; FVector2D NextVertex; float SignedArea = 0.0f; float PartialArea; // Use all vertices except the last one for(int32 Index = 0; Index < SortedVertices.Num() - 1; ++Index) { CurrentVertex = FVector2D(SortedVertices[Index]); NextVertex = FVector2D(SortedVertices[Index + 1]); PartialArea = CurrentVertex.X * NextVertex.Y - NextVertex.X * CurrentVertex.Y; SignedArea += PartialArea; Centroid = FVector2D(Centroid.X + (CurrentVertex.X + NextVertex.X) * PartialArea, Centroid.Y + (CurrentVertex.Y + NextVertex.Y) * PartialArea); } // Process last vertex CurrentVertex = SortedVertices[SortedVertices.Num() - 1]; NextVertex = SortedVertices[0]; PartialArea = (CurrentVertex.X * NextVertex.Y - NextVertex.X * CurrentVertex.Y); SignedArea += PartialArea; Centroid = FVector2D(Centroid.X + (CurrentVertex.X + NextVertex.X) * PartialArea, Centroid.Y + (CurrentVertex.Y + NextVertex.Y) * PartialArea); SignedArea *= 0.5f; Centroid = FVector2D( Centroid.X / (6.0f * SignedArea), Centroid.Y / (6.0f * SignedArea) ); // UE_LOG(LogVoronoiDiagram, Log, TEXT("Centroid (%f, %f)"), Centroid.X, Centroid.Y); // if(Centroid.X == NAN || Centroid.Y == NAN) // { // UE_LOG(LogVoronoiDiagram, Log, TEXT("Centroid (%f, %f)"), Centroid.X, Centroid.Y); // for(auto Itr(SortedVertices.CreateConstIterator()); Itr; ++Itr) // { // UE_LOG(LogVoronoiDiagram, Log, TEXT("Vertex (%f, %f)"), (*Itr).X, (*Itr).Y); // } // } }
void NURBS::Refine(vector<Reference<Shape> > &refined) const { // Compute NURBS dicing rates int diceu = 30, dicev = 30; float *ueval = new float[diceu]; float *veval = new float[dicev]; Point *evalPs = new Point[diceu*dicev]; Normal *evalNs = new Normal[diceu*dicev]; int i; for (i = 0; i < diceu; ++i) ueval[i] = Lerp((float)i / (float)(diceu-1), umin, umax); for (i = 0; i < dicev; ++i) veval[i] = Lerp((float)i / (float)(dicev-1), vmin, vmax); // Evaluate NURBS over grid of points memset(evalPs, 0, diceu*dicev*sizeof(Point)); memset(evalNs, 0, diceu*dicev*sizeof(Point)); float *uvs = new float[2*diceu*dicev]; // Turn NURBS into triangles Homogeneous3 *Pw = (Homogeneous3 *)P; if (!isHomogeneous) { Pw = (Homogeneous3 *)alloca(nu*nv*sizeof(Homogeneous3)); for (int i = 0; i < nu*nv; ++i) { Pw[i].x = P[3*i]; Pw[i].y = P[3*i+1]; Pw[i].z = P[3*i+2]; Pw[i].w = 1.; } } for (int v = 0; v < dicev; ++v) { for (int u = 0; u < diceu; ++u) { uvs[2*(v*diceu+u)] = ueval[u]; uvs[2*(v*diceu+u)+1] = veval[v]; Vector dPdu, dPdv; Point pt = NURBSEvaluateSurface(uorder, uknot, nu, ueval[u], vorder, vknot, nv, veval[v], Pw, &dPdu, &dPdv); evalPs[v*diceu + u].x = pt.x; evalPs[v*diceu + u].y = pt.y; evalPs[v*diceu + u].z = pt.z; evalNs[v*diceu + u] = Normal(Normalize(Cross(dPdu, dPdv))); } } // Generate points-polygons mesh int nTris = 2*(diceu-1)*(dicev-1); int *vertices = new int[3 * nTris]; int *vertp = vertices; // Compute the vertex offset numbers for the triangles for (int v = 0; v < dicev-1; ++v) { for (int u = 0; u < diceu-1; ++u) { #define VN(u,v) ((v)*diceu+(u)) *vertp++ = VN(u, v); *vertp++ = VN(u+1, v); *vertp++ = VN(u+1, v+1); *vertp++ = VN(u, v); *vertp++ = VN(u+1, v+1); *vertp++ = VN(u, v+1); #undef VN } } int nVerts = diceu*dicev; ParamSet paramSet; paramSet.AddInt("indices", vertices, 3*nTris); paramSet.AddPoint("P", evalPs, nVerts); paramSet.AddFloat("uv", uvs, 2 * nVerts); paramSet.AddNormal("N", evalNs, nVerts); refined.push_back(MakeShape("trianglemesh", ObjectToWorld, reverseOrientation, paramSet)); // Cleanup from NURBS refinement delete[] uvs; delete[] ueval; delete[] veval; delete[] evalPs; delete[] evalNs; delete[] vertices; }
bool Shade(Path* path, Geometry *geometry, BVHAccel *bvh, const RayHit& rayHit) { uint tracedShadowRayCount; if (rayHit.index == 0xffffffffu) { return false; } // Something was hit unsigned int currentTriangleIndex = rayHit.index; RGB triInterpCol = geometry->triangles[currentTriangleIndex].InterpolateColor( geometry->vertColors, rayHit.b1, rayHit.b2); Normal shadeN = geometry->triangles[currentTriangleIndex].InterpolateNormal( geometry->vertNormals, rayHit.b1, rayHit.b2); // Calculate next step path->depth++; // Check if I have to stop if (path->depth >= MAX_PATH_DEPTH) { // Too depth, terminate the path return false; } else if (path->depth > 2) { // Russian Rulette, maximize cos const float p = min(1.f, triInterpCol.filter() * AbsDot(shadeN, path->pathRay.d)); if (p > getFloatRNG(&path->seed)) path->throughput /= p; else { // Terminate the path return false; } } //-------------------------------------------------------------------------- // Build the shadow ray //-------------------------------------------------------------------------- // Check if it is a light source float RdotShadeN = Dot(path->pathRay.d, shadeN); if (geometry->IsLight(currentTriangleIndex)) { // Check if we are on the right side of the light source if ((path->depth == 1) && (RdotShadeN < 0.f)) path->radiance += triInterpCol * path->throughput; // Terminate the path return false; } if (RdotShadeN > 0.f) { // Flip shade normal shadeN = -shadeN; } else RdotShadeN = -RdotShadeN; path->throughput *= RdotShadeN * triInterpCol; // Trace shadow rays const Point hitPoint = path->pathRay(rayHit.t); tracedShadowRayCount = 0; const float lightStrategyPdf = static_cast<float> (SHADOWRAY) / static_cast<float> (geometry->nLights); float lightPdf[SHADOWRAY]; RGB lightColor[SHADOWRAY]; Ray shadowRay[SHADOWRAY]; for (unsigned int i = 0; i < SHADOWRAY; ++i) { // Select the light to sample const unsigned int currentLightIndex = geometry->SampleLights(getFloatRNG(&path->seed)); // const TriangleLight &light = scene->lights[currentLightIndex]; // Select a point on the surface lightColor[tracedShadowRayCount] = Sample_L(currentLightIndex, geometry, hitPoint, shadeN, getFloatRNG(&path->seed), getFloatRNG(&path->seed), &lightPdf[tracedShadowRayCount], &shadowRay[tracedShadowRayCount]); // Scale light pdf for ONE_UNIFORM strategy lightPdf[tracedShadowRayCount] *= lightStrategyPdf; // Using 0.1 instead of 0.0 to cut down fireflies if (lightPdf[tracedShadowRayCount] > 0.1f) tracedShadowRayCount++; } RayHit* rh = new RayHit[tracedShadowRayCount]; for (unsigned int i = 0; i < tracedShadowRayCount; ++i) Intersect(shadowRay[i], rh[i], bvh->bvhTree, geometry->triangles, geometry->vertices); if ((tracedShadowRayCount > 0)) { for (unsigned int i = 0; i < tracedShadowRayCount; ++i) { const RayHit *shadowRayHit = &rh[i]; if (shadowRayHit->index == 0xffffffffu) { // Nothing was hit, light is visible path->radiance += path->throughput * lightColor[i] / lightPdf[i]; } } } //-------------------------------------------------------------------------- // Build the next vertex path ray //-------------------------------------------------------------------------- // Calculate exit direction float r1 = 2.f * M_PI * getFloatRNG(&path->seed); float r2 = getFloatRNG(&path->seed); float r2s = sqrt(r2); const Vector w(shadeN); Vector u; if (fabsf(shadeN.x) > .1f) { const Vector a(0.f, 1.f, 0.f); u = Cross(a, w); } else { const Vector a(1.f, 0.f, 0.f); u = Cross(a, w); } u = Normalize(u); Vector v = Cross(w, u); Vector newDir = u * (cosf(r1) * r2s) + v * (sinf(r1) * r2s) + w * sqrtf(1.f - r2); newDir = Normalize(newDir); path->pathRay.o = hitPoint; path->pathRay.d = newDir; return true; }
Point GetLineIntersection(const Point& P, const Point& v, const Point& Q, const Point& w) { Vector u = P-Q; double t = Cross(w, u) / Cross(v, w); return P+v*t; }
void Extrude(const Vec3* points, int numPoints, std::vector<Vec3>& vertices, std::vector<Vec3>& normals, std::vector<int>& triangles, float radius, int resolution, int smoothing) { if (numPoints < 2) return; Vec3 u, v; Vec3 w = SafeNormalize(Vec3(points[1])-Vec3(points[0]), Vec3(0.0f, 1.0f, 0.0f)); BasisFromVector(w, &u, &v); Matrix44 frame; frame.SetCol(0, Vec4(u.x, u.y, u.z, 0.0f)); frame.SetCol(1, Vec4(v.x, v.y, v.z, 0.0f)); frame.SetCol(2, Vec4(w.x, w.y, w.z, 0.0f)); frame.SetCol(3, Vec4(0.0f, 0.0f, 0.0f, 1.0f)); for (int i=0; i < numPoints -1; ++i) { Vec3 next; if (i < numPoints -1) next = Normalize(Vec3(points[i+1])-Vec3(points[i-1])); else next = Normalize(Vec3(points[i])-Vec3(points[i-1])); int a = Max(i-1, 0); int b = i; int c = Min(i+1, numPoints -1); int d = Min(i+2, numPoints -1); Vec3 p1 = Vec3(points[b]); Vec3 p2 = Vec3(points[c]); Vec3 m1 = 0.5f*(Vec3(points[c]) - Vec3(points[a])); Vec3 m2 = 0.5f*(Vec3(points[d]) - Vec3(points[b])); // ensure last segment handled correctly int segments = (i < numPoints-2)?smoothing:smoothing+1; for (int s=0; s < segments; ++s) { Vec3 pos = HermiteInterpolate(p1, p2, m1, m2, s/float(smoothing)); Vec3 dir = Normalize(HermiteTangent(p1, p2, m1, m2, s/float(smoothing))); Vec3 cur = frame.GetAxis(2); const float angle = acosf(Dot(cur, dir)); // if parallel then don't need to do anything if (fabsf(angle) > 0.001f) frame = RotationMatrix(angle, SafeNormalize(Cross(cur, dir)))*frame; int startIndex = vertices.size(); for (int c=0; c < resolution; ++c) { float angle = k2Pi / resolution; // transform position and normal to world space Vec4 v = frame*Vec4(cosf(angle*c), sinf(angle*c), 0.0f, 0.0f); vertices.push_back(Vec3(v)*radius + pos); normals.push_back(Vec3(v)); } // output triangles if (startIndex != 0) { for (int i=0; i < resolution; ++i) { int curIndex = startIndex + i; int nextIndex = startIndex + (i+1)%resolution; triangles.push_back(curIndex); triangles.push_back(curIndex-resolution); triangles.push_back(nextIndex-resolution); triangles.push_back(nextIndex-resolution); triangles.push_back(nextIndex); triangles.push_back(curIndex); } } } } }
void InitLists( ) { glutSetWindow( MainWindow ); // Create the helicopter: HeliList = glGenLists( 1 ); glNewList( HeliList, GL_COMPILE ); if(!HELI_SOLID){ int i; struct edge *ep; struct point *p0, *p1; glPushMatrix( ); glTranslatef( 0., -1., 0. ); glRotatef( 97., 0., 1., 0. ); glRotatef( -15., 0., 0., 1. ); glBegin( GL_LINES ); for( i=0, ep = Heliedges; i < Helinedges; i++, ep++ ) { p0 = &Helipoints[ ep->p0 ]; p1 = &Helipoints[ ep->p1 ]; glVertex3f( p0->x, p0->y, p0->z ); glVertex3f( p1->x, p1->y, p1->z ); } glEnd( ); glPopMatrix( ); }else{ int i; struct point *p0, *p1, *p2; struct tri *tp; float p01[3], p02[3], n[3]; glPushMatrix( ); glTranslatef( 0., -1., 0. ); glRotatef( 97., 0., 1., 0. ); glRotatef( -15., 0., 0., 1. ); glBegin( GL_TRIANGLES ); for( i=0, tp = Helitris; i < Helintris; i++, tp++ ) { p0 = &Helipoints[ tp->p0 ]; p1 = &Helipoints[ tp->p1 ]; p2 = &Helipoints[ tp->p2 ]; /* fake "lighting" from above: */ p01[0] = p1->x - p0->x; p01[1] = p1->y - p0->y; p01[2] = p1->z - p0->z; p02[0] = p2->x - p0->x; p02[1] = p2->y - p0->y; p02[2] = p2->z - p0->z; Cross( p01, p02, n ); Unit( n, n ); n[1] = fabs( n[1] ); n[1] += .25; if( n[1] > 1. ) n[1] = 1.; glColor3f( 0., n[1], 0. ); glVertex3f( p0->x, p0->y, p0->z ); glVertex3f( p1->x, p1->y, p1->z ); glVertex3f( p2->x, p2->y, p2->z ); } glEnd( ); glPopMatrix( ); } glEndList( ); // draw the helicopter blade with radius BLADE_RADIUS and // width BLADE_WIDTH centered at (0.,0.,0.) in the XY plane BladeList = glGenLists( 1 ); glNewList( BladeList, GL_COMPILE ); glPushMatrix( ); glBegin( GL_TRIANGLES ); glVertex2f( BLADE_RADIUS, BLADE_WIDTH/2. ); glVertex2f( 0., 0. ); glVertex2f( BLADE_RADIUS, -BLADE_WIDTH/2. ); glVertex2f( -BLADE_RADIUS, -BLADE_WIDTH/2. ); glVertex2f( 0., 0. ); glVertex2f( -BLADE_RADIUS, BLADE_WIDTH/2. ); glEnd( ); glPopMatrix( ); glEndList( ); // Draw the world WorldList = glGenLists( 1 ); glNewList( WorldList, GL_COMPILE ); glPushMatrix( ); glColor3f( 0.2, 0.2, 1. ); glBegin( GL_QUADS ); glVertex3f(WORLD_APOTHEM, WORLD_HEIGHT, WORLD_APOTHEM); glVertex3f(WORLD_APOTHEM, WORLD_HEIGHT, -WORLD_APOTHEM); glVertex3f(-WORLD_APOTHEM, WORLD_HEIGHT, -WORLD_APOTHEM); glVertex3f(-WORLD_APOTHEM, WORLD_HEIGHT, WORLD_APOTHEM); glEnd( ); glPopMatrix( ); glEndList( ); // Draw the object ObjectList = glGenLists( 1 ); glNewList( ObjectList, GL_COMPILE ); int rotations = 6; float length = PI*2*rotations; int steps = 200; float start_r = 0.25, start_g = 0., start_b = 0.25; float end_r = 0., end_g = 1., end_b = 0.75; // Draw the helix glPushMatrix( ); glBegin( GL_TRIANGLE_STRIP ); // Rotate in a circle for(float s; s < steps; s++){ float p = s / steps; float r = (start_r * (1-p)) + (end_r * p); float g = (start_g * (1-p)) + (end_g * p); float b = (start_b * (1-p)) + (end_b * p); glColor3f(r, g, b); float a = (s - steps/2) * (length / steps); glVertex3f(cos(a), a/10 + WORLD_HEIGHT+2, sin(a) - OBJECT_DISTANCE); glVertex3f(cos(a), a/10 + WORLD_HEIGHT+2+0.2, sin(a) - OBJECT_DISTANCE); } glEnd( ); glPopMatrix( ); glEndList( ); // create the axes: AxesList = glGenLists( 1 ); glNewList( AxesList, GL_COMPILE ); glLineWidth( AXES_WIDTH ); Axes( 3. ); glLineWidth( 1. ); glEndList( ); }
std::vector<std::shared_ptr<Shape>> CreateTriangleMeshShape( const Transform *o2w, const Transform *w2o, bool reverseOrientation, const ParamSet ¶ms, std::map<std::string, std::shared_ptr<Texture<Float>>> *floatTextures) { int nvi, npi, nuvi, nsi, nni; const int *vi = params.FindInt("indices", &nvi); const Point3f *P = params.FindPoint3f("P", &npi); const Point2f *uvs = params.FindPoint2f("uv", &nuvi); if (!uvs) uvs = params.FindPoint2f("st", &nuvi); std::vector<Point2f> tempUVs; if (!uvs) { const Float *fuv = params.FindFloat("uv", &nuvi); if (!fuv) fuv = params.FindFloat("st", &nuvi); if (fuv) { nuvi /= 2; tempUVs.reserve(nuvi); for (int i = 0; i < nuvi; ++i) tempUVs.push_back(Point2f(fuv[2 * i], fuv[2 * i + 1])); uvs = &tempUVs[0]; } } bool discardDegenerateUVs = params.FindOneBool("discarddegenerateUVs", false); if (uvs) { if (nuvi < npi) { Error( "Not enough of \"uv\"s for triangle mesh. Expencted %d, " "found %d. Discarding.", npi, nuvi); uvs = nullptr; } else if (nuvi > npi) Warning( "More \"uv\"s provided than will be used for triangle " "mesh. (%d expcted, %d found)", npi, nuvi); } if (!vi) { Error( "Vertex indices \"indices\" not provided with triangle mesh shape"); return std::vector<std::shared_ptr<Shape>>(); } if (!P) { Error("Vertex positions \"P\" not provided with triangle mesh shape"); return std::vector<std::shared_ptr<Shape>>(); } const Vector3f *S = params.FindVector3f("S", &nsi); if (S && nsi != npi) { Error("Number of \"S\"s for triangle mesh must match \"P\"s"); S = nullptr; } const Normal3f *N = params.FindNormal3f("N", &nni); if (N && nni != npi) { Error("Number of \"N\"s for triangle mesh must match \"P\"s"); N = nullptr; } if (discardDegenerateUVs && uvs && N) { // if there are normals, check for bad uv's that // give degenerate mappings; discard them if so const int *vp = vi; for (int i = 0; i < nvi; i += 3, vp += 3) { Float area = .5f * Cross(P[vp[0]] - P[vp[1]], P[vp[2]] - P[vp[1]]).Length(); if (area < 1e-7) continue; // ignore degenerate tris. if ((uvs[vp[0]].x == uvs[vp[1]].x && uvs[vp[0]].y == uvs[vp[1]].y) || (uvs[vp[1]].x == uvs[vp[2]].x && uvs[vp[1]].y == uvs[vp[2]].y) || (uvs[vp[2]].x == uvs[vp[0]].x && uvs[vp[2]].y == uvs[vp[0]].y)) { Warning( "Degenerate uv coordinates in triangle mesh. Discarding " "all uvs."); uvs = nullptr; break; } } } for (int i = 0; i < nvi; ++i) if (vi[i] >= npi) { Error( "trianglemesh has out of-bounds vertex index %d (%d \"P\" " "values were given", vi[i], npi); return std::vector<std::shared_ptr<Shape>>(); } std::shared_ptr<Texture<Float>> alphaTex; std::string alphaTexName = params.FindTexture("alpha"); if (alphaTexName != "") { if (floatTextures->find(alphaTexName) != floatTextures->end()) alphaTex = (*floatTextures)[alphaTexName]; else Error("Couldn't find float texture \"%s\" for \"alpha\" parameter", alphaTexName.c_str()); } else if (params.FindOneFloat("alpha", 1.f) == 0.f) alphaTex.reset(new ConstantTexture<Float>(0.f)); std::shared_ptr<Texture<Float>> shadowAlphaTex; std::string shadowAlphaTexName = params.FindTexture("shadowalpha"); if (shadowAlphaTexName != "") { if (floatTextures->find(shadowAlphaTexName) != floatTextures->end()) shadowAlphaTex = (*floatTextures)[shadowAlphaTexName]; else Error( "Couldn't find float texture \"%s\" for \"shadowalpha\" " "parameter", shadowAlphaTexName.c_str()); } else if (params.FindOneFloat("shadowalpha", 1.f) == 0.f) shadowAlphaTex.reset(new ConstantTexture<Float>(0.f)); return CreateTriangleMesh(o2w, w2o, reverseOrientation, nvi / 3, vi, npi, P, S, N, uvs, alphaTex, shadowAlphaTex); }
double CalcTetBadnessGrad (const Point3d & p1, const Point3d & p2, const Point3d & p3, const Point3d & p4, double h, int pi, Vec<3> & grad) { double vol, l, ll, lll; double err; const Point3d *pp1, *pp2, *pp3, *pp4; pp1 = &p1; pp2 = &p2; pp3 = &p3; pp4 = &p4; switch (pi) { case 2: { swap (pp1, pp2); swap (pp3, pp4); break; } case 3: { swap (pp1, pp3); swap (pp2, pp4); break; } case 4: { swap (pp1, pp4); swap (pp3, pp2); break; } } Vec3d v1 (*pp1, *pp2); Vec3d v2 (*pp1, *pp3); Vec3d v3 (*pp1, *pp4); Vec3d v4 (*pp2, *pp3); Vec3d v5 (*pp2, *pp4); Vec3d v6 (*pp3, *pp4); vol = -Determinant (v1, v2, v3) / 6; Vec3d gradvol; Cross (v5, v4, gradvol); gradvol *= (-1.0/6.0); double ll1 = v1.Length2(); double ll2 = v2.Length2(); double ll3 = v3.Length2(); double ll4 = v4.Length2(); double ll5 = v5.Length2(); double ll6 = v6.Length2(); ll = ll1 + ll2 + ll3 + ll4 + ll5 + ll6; l = sqrt (ll); lll = l * ll; if (vol <= 1e-24 * lll) { grad = Vec3d (0, 0, 0); return 1e24; } Vec3d gradll1 (*pp2, *pp1); Vec3d gradll2 (*pp3, *pp1); Vec3d gradll3 (*pp4, *pp1); gradll1 *= 2; gradll2 *= 2; gradll3 *= 2; Vec3d gradll (gradll1); gradll += gradll2; gradll += gradll3; /* Vec3d gradll; gradll = v1+v2+v3; gradll *= -2; */ err = 0.0080187537 * lll / vol; gradll *= (0.0080187537 * 1.5 * l / vol); Vec3d graderr(gradll); gradvol *= ( -0.0080187537 * lll / (vol * vol) ); graderr += gradvol; if (h > 0) { /* Vec3d gradll1 (*pp2, *pp1); Vec3d gradll2 (*pp3, *pp1); Vec3d gradll3 (*pp4, *pp1); gradll1 *= 2; gradll2 *= 2; gradll3 *= 2; */ err += ll / (h*h) + h*h * ( 1 / ll1 + 1 / ll2 + 1 / ll3 + 1 / ll4 + 1 / ll5 + 1 / ll6 ) - 12; graderr += (1/(h*h) - h*h/(ll1*ll1)) * gradll1; graderr += (1/(h*h) - h*h/(ll2*ll2)) * gradll2; graderr += (1/(h*h) - h*h/(ll3*ll3)) * gradll3; cout << "?"; } double errpow; if (teterrpow == 2) { errpow = err*err; grad = (2 * err) * graderr; } else { errpow = pow (err, teterrpow); grad = (teterrpow * errpow / err) * graderr; } return errpow; }
bool Curve::recursiveIntersect(const Ray &ray, Float *tHit, SurfaceInteraction *isect, const Point3f cp[4], const Transform &rayToObject, Float u0, Float u1, int depth) const { // Try to cull curve segment versus ray // Compute bounding box of curve segment, _curveBounds_ Bounds3f curveBounds = Union(Bounds3f(cp[0], cp[1]), Bounds3f(cp[2], cp[3])); Float maxWidth = std::max(Lerp(u0, common->width[0], common->width[1]), Lerp(u1, common->width[0], common->width[1])); curveBounds = Expand(curveBounds, 0.5 * maxWidth); // Compute bounding box of ray, _rayBounds_ Float rayLength = ray.d.Length(); Float zMax = rayLength * ray.tMax; Bounds3f rayBounds(Point3f(0, 0, 0), Point3f(0, 0, zMax)); if (Overlaps(curveBounds, rayBounds) == false) return false; if (depth > 0) { // Split curve segment into sub-segments and test for intersection Float uMid = 0.5f * (u0 + u1); Point3f cpSplit[7]; SubdivideBezier(cp, cpSplit); return (recursiveIntersect(ray, tHit, isect, &cpSplit[0], rayToObject, u0, uMid, depth - 1) || recursiveIntersect(ray, tHit, isect, &cpSplit[3], rayToObject, uMid, u1, depth - 1)); } else { // Intersect ray with curve segment // Test ray against segment endpoint boundaries // Test sample point against tangent perpendicular at curve start Float edge = (cp[1].y - cp[0].y) * -cp[0].y + cp[0].x * (cp[0].x - cp[1].x); if (edge < 0) return false; // Test sample point against tangent perpendicular at curve end edge = (cp[2].y - cp[3].y) * -cp[3].y + cp[3].x * (cp[3].x - cp[2].x); if (edge < 0) return false; // Compute line $w$ that gives minimum distance to sample point Vector2f segmentDirection = Point2f(cp[3]) - Point2f(cp[0]); Float denom = segmentDirection.LengthSquared(); if (denom == 0) return false; Float w = Dot(-Vector2f(cp[0]), segmentDirection) / denom; // Compute $u$ coordinate of curve intersection point and _hitWidth_ Float u = Clamp(Lerp(w, u0, u1), u0, u1); Float hitWidth = Lerp(u, common->width[0], common->width[1]); Normal3f nHit; if (common->type == CurveType::Ribbon) { // Scale _hitWidth_ based on ribbon orientation Float sin0 = std::sin((1 - u) * common->normalAngle) * common->invSinNormalAngle; Float sin1 = std::sin(u * common->normalAngle) * common->invSinNormalAngle; nHit = sin0 * common->n[0] + sin1 * common->n[1]; hitWidth *= AbsDot(nHit, ray.d) / rayLength; } // Test intersection point against curve width Vector3f dpcdw; Point3f pc = EvalBezier(cp, Clamp(w, 0, 1), &dpcdw); Float ptCurveDist2 = pc.x * pc.x + pc.y * pc.y; if (ptCurveDist2 > hitWidth * hitWidth * .25) return false; if (pc.z < 0 || pc.z > zMax) return false; // Compute $v$ coordinate of curve intersection point Float ptCurveDist = std::sqrt(ptCurveDist2); Float edgeFunc = dpcdw.x * -pc.y + pc.x * dpcdw.y; Float v = (edgeFunc > 0) ? 0.5f + ptCurveDist / hitWidth : 0.5f - ptCurveDist / hitWidth; // Compute hit _t_ and partial derivatives for curve intersection if (tHit != nullptr) { // FIXME: this tHit isn't quite right for ribbons... *tHit = pc.z / rayLength; // Compute error bounds for curve intersection Vector3f pError(2 * hitWidth, 2 * hitWidth, 2 * hitWidth); // Compute $\dpdu$ and $\dpdv$ for curve intersection Vector3f dpdu, dpdv; EvalBezier(common->cpObj, u, &dpdu); if (common->type == CurveType::Ribbon) dpdv = Normalize(Cross(nHit, dpdu)) * hitWidth; else { // Compute curve $\dpdv$ for flat and cylinder curves Vector3f dpduPlane = (Inverse(rayToObject))(dpdu); Vector3f dpdvPlane = Normalize(Vector3f(-dpduPlane.y, dpduPlane.x, 0)) * hitWidth; if (common->type == CurveType::Cylinder) { // Rotate _dpdvPlane_ to give cylindrical appearance Float theta = Lerp(v, -90., 90.); Transform rot = Rotate(-theta, dpduPlane); dpdvPlane = rot(dpdvPlane); } dpdv = rayToObject(dpdvPlane); } *isect = (*ObjectToWorld)(SurfaceInteraction( ray(pc.z), pError, Point2f(u, v), -ray.d, dpdu, dpdv, Normal3f(0, 0, 0), Normal3f(0, 0, 0), ray.time, this)); } ++nHits; return true; } }
bool NaiadTriangle::IntersectP(const Ray &ray) const { PBRT_RAY_TRIANGLE_INTERSECTIONP_TEST(const_cast<Ray *>(&ray), const_cast<NaiadTriangle *>(this)); // Compute $\VEC{s}_1$ // Get NaiadTriangle vertices in _p1_, _p2_, and _p3_ const Point &p1 = mesh->p[v[0]]; const Point &p2 = mesh->p[v[1]]; const Point &p3 = mesh->p[v[2]]; Vector e1 = p2 - p1; Vector e2 = p3 - p1; Vector s1 = Cross(ray.d, e2); float divisor = Dot(s1, e1); if (divisor == 0.) return false; float invDivisor = 1.f / divisor; // Compute first barycentric coordinate Vector d = ray.o - p1; float b1 = Dot(d, s1) * invDivisor; if (b1 < 0. || b1 > 1.) return false; // Compute second barycentric coordinate Vector s2 = Cross(d, e1); float b2 = Dot(ray.d, s2) * invDivisor; if (b2 < 0. || b1 + b2 > 1.) return false; // Compute _t_ to intersection point float t = Dot(e2, s2) * invDivisor; if (t < ray.mint || t > ray.maxt) return false; // Test shadow ray intersection against alpha texture, if present if (ray.depth != -1 && mesh->alphaTexture) { // Compute NaiadTriangle partial derivatives Vector dpdu, dpdv; float uvs[3][2]; GetUVs(uvs); // Compute deltas for NaiadTriangle partial derivatives float du1 = uvs[0][0] - uvs[2][0]; float du2 = uvs[1][0] - uvs[2][0]; float dv1 = uvs[0][1] - uvs[2][1]; float dv2 = uvs[1][1] - uvs[2][1]; Vector dp1 = p1 - p3, dp2 = p2 - p3; float determinant = du1 * dv2 - dv1 * du2; if (determinant == 0.f) { // Handle zero determinant for NaiadTriangle partial derivative matrix CoordinateSystem(Normalize(Cross(e2, e1)), &dpdu, &dpdv); } else { float invdet = 1.f / determinant; dpdu = ( dv2 * dp1 - dv1 * dp2) * invdet; dpdv = (-du2 * dp1 + du1 * dp2) * invdet; } // Interpolate $(u,v)$ NaiadTriangle parametric coordinates float b0 = 1 - b1 - b2; float tu = b0*uvs[0][0] + b1*uvs[1][0] + b2*uvs[2][0]; float tv = b0*uvs[0][1] + b1*uvs[1][1] + b2*uvs[2][1]; DifferentialGeometry dgLocal(ray(t), dpdu, dpdv, Normal(0,0,0), Normal(0,0,0), tu, tv, this); if (mesh->alphaTexture->Evaluate(dgLocal) == 0.f) return false; } PBRT_RAY_TRIANGLE_INTERSECTIONP_HIT(const_cast<Ray *>(&ray), t); return true; }
bool Heightfield2::TriangleIntersect(const Ray &ray, float *tHit, float *rayEpsilon, DifferentialGeometry *dg, int index[]) const{ PBRT_RAY_TRIANGLE_INTERSECTION_TEST(const_cast<Ray *>(&ray), const_cast<Triangle *>(this)); // Get triangle vertices in _p1_, _p2_, and _p3_ const Point &p1o = point[index[0]]; const Point &p2o = point[index[1]]; const Point &p3o = point[index[2]]; const Point &p1 = (*ObjectToWorld)(p1o); const Point &p2 = (*ObjectToWorld)(p2o); const Point &p3 = (*ObjectToWorld)(p3o); Vector e1 = p2 - p1; Vector e2 = p3 - p1; Vector s1 = Cross(ray.d, e2); float divisor = Dot(s1, e1); if (divisor == 0.) return false; float invDivisor = 1.f / divisor; // Compute first barycentric coordinate Vector s = ray.o - p1; float b1 = Dot(s, s1) * invDivisor; if (b1 < 0. || b1 > 1.) return false; // Compute second barycentric coordinate Vector s2 = Cross(s, e1); float b2 = Dot(ray.d, s2) * invDivisor; if (b2 < 0. || b1 + b2 > 1.) return false; // Compute _t_ to intersection point float t = Dot(e2, s2) * invDivisor; if (t < ray.mint || t > ray.maxt) return false; // Compute triangle partial derivatives Vector dpdu, dpdv; // Compute deltas for triangle partial derivatives float du1 = p1o.x - p3o.x; float du2 = p2o.x - p3o.x; float dv1 = p1o.y - p3o.y; float dv2 = p2o.y - p3o.y; Vector dp1 = p1 - p3, dp2 = p2 - p3; float determinant = du1 * dv2 - dv1 * du2; if (determinant == 0.f) { // Handle zero determinant for triangle partial derivative matrix CoordinateSystem(Normalize(Cross(e2, e1)), &dpdu, &dpdv); } else { float invdet = 1.f / determinant; dpdu = ( dv2 * dp1 - dv1 * dp2) * invdet; dpdv = (-du2 * dp1 + du1 * dp2) * invdet; } // Interpolate $(u,v)$ triangle parametric coordinates float b0 = 1 - b1 - b2; float tu = b0*p1o.x + b1*p2o.x + b2*p3o.x; float tv = b0*p1o.y + b1*p2o.y + b2*p3o.y; // Fill in _DifferentialGeometry_ from triangle hit *dg = DifferentialGeometry(ray(t), dpdu, dpdv, Normal(0,0,0), Normal(0,0,0), tu, tv, this); *tHit = t; *rayEpsilon = 1e-3f * *tHit; ray.maxt = t; PBRT_RAY_TRIANGLE_INTERSECTION_HIT(const_cast<Ray *>(&ray), t); return true; }
void TesselateSplinePatch(u8 *&dest, int &count, const SplinePatch &spatch, u32 origVertType) { const float third = 1.0f / 3.0f; if (g_Config.bLowQualitySplineBezier) { // Fast and easy way - just draw the control points, generate some very basic normal vector substitutes. // Very inaccurate but okay for Loco Roco. Maybe should keep it as an option because it's fast. const int tile_min_u = (spatch.type_u & START_OPEN) ? 0 : 1; const int tile_min_v = (spatch.type_v & START_OPEN) ? 0 : 1; const int tile_max_u = (spatch.type_u & END_OPEN) ? spatch.count_u - 1 : spatch.count_u - 2; const int tile_max_v = (spatch.type_v & END_OPEN) ? spatch.count_v - 1 : spatch.count_v - 2; for (int tile_v = tile_min_v; tile_v < tile_max_v; ++tile_v) { for (int tile_u = tile_min_u; tile_u < tile_max_u; ++tile_u) { int point_index = tile_u + tile_v * spatch.count_u; SimpleVertex v0 = *spatch.points[point_index]; SimpleVertex v1 = *spatch.points[point_index+1]; SimpleVertex v2 = *spatch.points[point_index+spatch.count_u]; SimpleVertex v3 = *spatch.points[point_index+spatch.count_u+1]; // Generate UV. TODO: Do this even if UV specified in control points? if ((origVertType & GE_VTYPE_TC_MASK) == 0) { float u = tile_u * third; float v = tile_v * third; v0.uv[0] = u; v0.uv[1] = v; v1.uv[0] = u + third; v1.uv[1] = v; v2.uv[0] = u; v2.uv[1] = v + third; v3.uv[0] = u + third; v3.uv[1] = v + third; } // Generate normal if lighting is enabled (otherwise there's no point). // This is a really poor quality algorithm, we get facet normals. if (gstate.isLightingEnabled()) { Vec3f norm = Cross(v1.pos - v0.pos, v2.pos - v0.pos); norm.Normalize(); if (gstate.patchfacing & 1) norm *= -1.0f; v0.nrm = norm; v1.nrm = norm; v2.nrm = norm; v3.nrm = norm; } CopyQuad(dest, &v0, &v1, &v2, &v3); count += 6; } } } else { // Full correct tessellation of spline patches. // Does not yet generate normals and is atrociously slow (see spline_s...) // First, generate knot vectors. int n = spatch.count_u - 1; int m = spatch.count_v - 1; float *knot_u = new float[n + 5]; float *knot_v = new float[m + 5]; spline_knot(n, spatch.type_u, knot_u); spline_knot(m, spatch.type_v, knot_v); int patch_div_s = gstate.getPatchDivisionU(); int patch_div_t = gstate.getPatchDivisionV(); // Increase tesselation based on the size. Should be approximately right? // JPCSP is wrong at least because their method results in square loco roco. patch_div_s = (spatch.count_u - 3) * patch_div_s / 3; patch_div_t = (spatch.count_v - 3) * patch_div_t / 3; if (patch_div_s == 0) patch_div_s = 1; if (patch_div_t == 0) patch_div_t = 1; // TODO: Remove this cap when spline_s has been optimized. if (patch_div_s > 64) patch_div_s = 64; if (patch_div_t > 64) patch_div_t = 64; // First compute all the vertices and put them in an array SimpleVertex *vertices = new SimpleVertex[(patch_div_s + 1) * (patch_div_t + 1)]; float tu_width = 1.0f + (spatch.count_u - 4) * 1.0f/3.0f; float tv_height = 1.0f + (spatch.count_v - 4) * 1.0f/3.0f; bool computeNormals = gstate.isLightingEnabled(); for (int tile_v = 0; tile_v < patch_div_t + 1; tile_v++) { float v = ((float)tile_v * (float)(m - 2) / (float)(patch_div_t + 0.00001f)); // epsilon to prevent division by 0 in spline_s for (int tile_u = 0; tile_u < patch_div_s + 1; tile_u++) { float u = ((float)tile_u * (float)(n - 2) / (float)(patch_div_s + 0.00001f)); SimpleVertex *vert = &vertices[tile_v * (patch_div_s + 1) + tile_u]; vert->pos.SetZero(); if (origVertType & GE_VTYPE_NRM_MASK) { vert->nrm.SetZero(); } else { vert->nrm.SetZero(); vert->nrm.z = 1.0f; } if (origVertType & GE_VTYPE_COL_MASK) { memset(vert->color, 0, 4); } else { memcpy(vert->color, spatch.points[0]->color, 4); } if (origVertType & GE_VTYPE_TC_MASK) { vert->uv[0] = 0.0f; vert->uv[1] = 0.0f; } else { vert->uv[0] = tu_width * ((float)tile_u / (float)patch_div_s); vert->uv[1] = tv_height * ((float)tile_v / (float)patch_div_t); } // Collect influences from surrounding control points. float u_weights[4]; float v_weights[4]; int iu = (int)u; int iv = (int)v; spline_n_4(iu, u, knot_u, u_weights); spline_n_4(iv, v, knot_v, v_weights); for (int ii = 0; ii < 4; ++ii) { for (int jj = 0; jj < 4; ++jj) { float u_spline = u_weights[ii]; float v_spline = v_weights[jj]; float f = u_spline * v_spline; if (f > 0.0f) { SimpleVertex *a = spatch.points[spatch.count_u * (iv + jj) + (iu + ii)]; vert->pos += a->pos * f; if (origVertType & GE_VTYPE_TC_MASK) { vert->uv[0] += a->uv[0] * f; vert->uv[1] += a->uv[1] * f; } if (origVertType & GE_VTYPE_COL_MASK) { vert->color[0] += a->color[0] * f; vert->color[1] += a->color[1] * f; vert->color[2] += a->color[2] * f; vert->color[3] += a->color[3] * f; } if (origVertType & GE_VTYPE_NRM_MASK) { vert->nrm += a->nrm * f; } } } } if (origVertType & GE_VTYPE_NRM_MASK) { vert->nrm.Normalize(); } } } delete [] knot_u; delete [] knot_v; // Hacky normal generation through central difference. if (gstate.isLightingEnabled() && (origVertType & GE_VTYPE_NRM_MASK) == 0) { for (int v = 0; v < patch_div_t + 1; v++) { for (int u = 0; u < patch_div_s + 1; u++) { int l = std::max(0, u - 1); int t = std::max(0, v - 1); int r = std::min(patch_div_s, u + 1); int b = std::min(patch_div_t, v + 1); const Vec3f &right = vertices[v * (patch_div_s + 1) + r].pos - vertices[v * (patch_div_s + 1) + l].pos; const Vec3f &down = vertices[b * (patch_div_s + 1) + u].pos - vertices[t * (patch_div_s + 1) + u].pos; vertices[v * (patch_div_s + 1) + u].nrm = Cross(right, down).Normalized(); if (gstate.patchfacing & 1) { vertices[v * (patch_div_s + 1) + u].nrm *= -1.0f; } } } } // Tesselate. TODO: Use indices so we only need to emit 4 vertices per pair of triangles instead of six. for (int tile_v = 0; tile_v < patch_div_t; ++tile_v) { for (int tile_u = 0; tile_u < patch_div_s; ++tile_u) { float u = ((float)tile_u / (float)patch_div_s); float v = ((float)tile_v / (float)patch_div_t); SimpleVertex *v0 = &vertices[tile_v * (patch_div_s + 1) + tile_u]; SimpleVertex *v1 = &vertices[tile_v * (patch_div_s + 1) + tile_u + 1]; SimpleVertex *v2 = &vertices[(tile_v + 1) * (patch_div_s + 1) + tile_u]; SimpleVertex *v3 = &vertices[(tile_v + 1) * (patch_div_s + 1) + tile_u + 1]; CopyQuad(dest, v0, v1, v2, v3); count += 6; } } delete [] vertices; } }
void Heightfield2::GetShadingGeometry(const Transform &obj2world, const DifferentialGeometry &dg, DifferentialGeometry *dgShading) const { // Initialize _Triangle_ shading geometry with _n_ and _s_ // *dgShading = dg; // return; Point p = Point(dg.u, dg.v, 0); int x = posToVoxel(p, 0); int y = posToVoxel(p, 1); int index1 = x + y*nx; int index2, index3; const Point &p1o = point[index1]; if((dg.u-p1o.x)*width[1] > (dg.v-p1o.y)*width[0]){ index2 = x+1 + y*nx; index3 = x+1 + (y+1)*nx; }else{ index2 = x+1 + (y+1)*nx; index3 = x + (y+1)*nx; } const Point &p2o = point[index2]; const Point &p3o = point[index3]; const Normal &normal0 = normal[index1]; const Normal &normal1 = normal[index2]; const Normal &normal2 = normal[index3]; // Compute barycentric coordinates for point float b[3]; // Initialize _A_ and _C_ matrices for barycentrics float A[2][2] = { { p2o.x - p1o.x, p3o.x - p1o.x }, { p2o.y - p1o.y, p3o.y - p1o.y } }; float C[2] = { dg.u - p1o.x, dg.v - p1o.y }; if (!SolveLinearSystem2x2(A, C, &b[1], &b[2])) { // Handle degenerate parametric mapping b[0] = b[1] = b[2] = 1.f/3.f; } else b[0] = 1.f - b[1] - b[2]; // Use _n_ and _s_ to compute shading tangents for triangle, _ss_ and _ts_ Normal ns; Vector ss, ts; ns = Normalize(obj2world(b[0] * normal0 + b[1] * normal1 + b[2] * normal2)); ss = Normalize(dg.dpdu); ts = Cross(ss, ns); if (ts.LengthSquared() > 0.f) { ts = Normalize(ts); ss = Cross(ts, ns); } else CoordinateSystem((Vector)ns, &ss, &ts); Normal dndu, dndv; // Compute $\dndu$ and $\dndv$ for triangle shading geometry // Compute deltas for triangle partial derivatives of normal float du1 = p1o.x - p3o.x; float du2 = p2o.x - p3o.x; float dv1 = p1o.y - p3o.y; float dv2 = p2o.y - p3o.y; Normal dn1 = normal0 - normal2; Normal dn2 = normal1 - normal2; float determinant = du1 * dv2 - dv1 * du2; if (determinant == 0.f) dndu = dndv = Normal(0,0,0); else { float invdet = 1.f / determinant; dndu = ( dv2 * dn1 - dv1 * dn2) * invdet; dndv = (-du2 * dn1 + du1 * dn2) * invdet; } *dgShading = DifferentialGeometry(dg.p, ss, ts, obj2world(dndu), obj2world(dndv), dg.u, dg.v, dg.shape); dgShading->dudx = dg.dudx; dgShading->dvdx = dg.dvdx; dgShading->dudy = dg.dudy; dgShading->dvdy = dg.dvdy; dgShading->dpdx = dg.dpdx; dgShading->dpdy = dg.dpdy; }
void Hull::ComputeInertia(const Transform& transform, Point3& centerOfMass, Matrix33& inertia, float totalMass) const { assert(totalMass > 0.0f); // order: 1, x, y, z, x^2, y^2, z^2, xy, yz, zx float integral[10] = {0,0,0,0,0,0,0,0,0,0}; // for each triangle for (short face = 0; face < m_numFaces; face++) { short edge = GetFaceFirstEdge(face); Point3 v0 = m_pVerts[ GetEdgeVertex0(face, edge) ] * transform; edge = GetFaceNextEdge(face, edge); Point3 v1 = m_pVerts[ GetEdgeVertex0(face, edge) ] * transform; for (edge = GetFaceNextEdge(face, edge); edge != -1; edge = GetFaceNextEdge(face, edge)) { Point3 v2 = m_pVerts[ GetEdgeVertex0(face, edge) ] * transform; // get cross product of triangle edges Vector3 d = Cross(v2 - v0, v1 - v0); // compute integral terms Vector3 w0 = Vector3(v0); Vector3 w1 = Vector3(v1); Vector3 w2 = Vector3(v2); Vector3 temp0 = w0 + w1; Vector3 f1 = temp0 + w2; Vector3 temp1 = w0 * w0; Vector3 temp2 = temp1 + w1 * temp0; Vector3 f2 = temp2 + w2 * f1; Vector3 f3 = w0 * temp1 + w1 * temp2 + w2 * f2; Vector3 g0 = f2 + w0 * (f1 + w0); Vector3 g1 = f2 + w1 * (f1 + w1); Vector3 g2 = f2 + w2 * (f1 + w2); // update integrals integral[0] += d[0] * f1[0]; integral[1] += d[0] * f2[0]; integral[2] += d[1] * f2[1]; integral[3] += d[2] * f2[2]; integral[4] += d[0] * f3[0]; integral[5] += d[1] * f3[1]; integral[6] += d[2] * f3[2]; integral[7] += d[0] * (v0[1] * g0[0] + v1[1] * g1[0] + v2[1] * g2[0]); integral[8] += d[1] * (v0[2] * g0[1] + v1[2] * g1[1] + v2[2] * g2[1]); integral[9] += d[2] * (v0[0] * g0[2] + v1[0] * g1[2] + v2[0] * g2[2]); // next edge v1 = v2; } } integral[0] *= 1.0f / 6.0f; integral[1] *= 1.0f / 24.0f; integral[2] *= 1.0f / 24.0f; integral[3] *= 1.0f / 24.0f; integral[4] *= 1.0f / 60.0f; integral[5] *= 1.0f / 60.0f; integral[6] *= 1.0f / 60.0f; integral[7] *= 1.0f / 120.0f; integral[8] *= 1.0f / 120.0f; integral[9] *= 1.0f / 120.0f; // scale all integrals to get desired total mass assert(integral[0] > 0.0f); float invMassRatio = totalMass / integral[0]; for (int i = 0; i < 10; i++) integral[i] *= invMassRatio; // center of mass centerOfMass = Point3(integral[1] / totalMass, integral[2] / totalMass, integral[3] / totalMass); // inertia relative to world inertia[0][0] = integral[5] + integral[6]; inertia[0][1] = -integral[7]; inertia[0][2] = -integral[9]; inertia[1][0] = -integral[7]; inertia[1][1] = integral[4] + integral[6]; inertia[1][2] = -integral[8]; inertia[2][0] = -integral[9]; inertia[2][1] = -integral[8]; inertia[2][2] = integral[5] + integral[5]; // inertia relative to center of mass inertia[0][0] -= totalMass * (centerOfMass[1] * centerOfMass[1] + centerOfMass[2] * centerOfMass[2]); inertia[0][1] += totalMass * centerOfMass[0] * centerOfMass[1]; inertia[0][2] += totalMass * centerOfMass[2] * centerOfMass[0]; inertia[1][0] += totalMass * centerOfMass[0] * centerOfMass[1]; inertia[1][1] -= totalMass * (centerOfMass[2] * centerOfMass[2] + centerOfMass[0] * centerOfMass[0]); inertia[1][2] += totalMass * centerOfMass[1] * centerOfMass[2]; inertia[2][0] += totalMass * centerOfMass[2] * centerOfMass[0]; inertia[2][1] += totalMass * centerOfMass[1] * centerOfMass[2]; inertia[2][2] -= totalMass * (centerOfMass[0] * centerOfMass[0] + centerOfMass[1] * centerOfMass[1]); }
// Heightfield2 Method Definitions Heightfield2::Heightfield2(const Transform *o2w, const Transform *w2o, bool ro, int x, int y, const float *zs) : Shape(o2w, w2o, ro) { nx = x; ny = y; z = new float[nx*ny]; point = new Point[nx*ny]; normal = new Normal[nx * ny]; memcpy(z, zs, nx*ny*sizeof(float)); nVoxels[0] = x-1; nVoxels[1] = y-1; bounds = ObjectBound(); for (int axis = 0; axis < 2; ++axis) { width[axis] = 1.f / nVoxels[axis]; invWidth[axis] = (width[axis] == 0.f) ? 0.f : 1.f / width[axis]; } int index = 0; for(int _y = 0; _y < y; _y++){ for(int _x = 0; _x < x; _x++){ point[index] = Point(_x * width[0], _y * width[1], z[index]); normal[index] = Normal(0, 0, 0); index++; } } for (int _y = 0; _y < nVoxels[1]; _y++) { for (int _x = 0; _x < nVoxels[0]; _x++) { int index1 = _x + _y*nx; int index2 = _x+1 + _y*nx; int index3 = _x+1 + (_y+1)*nx; int index4 = _x + (_y+1)*nx; const Point &p1 = point[index1]; const Point &p2 = point[index2]; const Point &p3 = point[index3]; const Point &p4 = point[index4]; Normal &normal1 = normal[index1]; Normal &normal2 = normal[index2]; Normal &normal3 = normal[index3]; Normal &normal4 = normal[index4]; Normal normal; normal = Normal(Normalize(Cross(p2 - p1, p3 - p1))); normal1 += normal; normal2 += normal; normal3 += normal; normal = Normal(Normalize(Cross(p3 - p1, p4 - p1))); normal1 += normal; normal3 += normal; normal4 += normal; } } for (int i = 0; i < nx*ny; i++) { normal[i] = Normalize(normal[i]); } }
void PlayerMC::Dispatch() { // set player to look at boss DE::Vector3 direction = ((Player*)m_pOwner)->GetBoss()->GetPosition() - m_pOwner->GetPosition(); if (!direction.iszero()) { float length = direction.Length(); DE::Vector3 cross = Cross(m_pOwner->GetTransform()->GetForward().Normal(), direction.Normal()); float dot = cross.Dot(DE::Vector3::UnitY); float theta = asinf(cross.Length()); int y = 1; if (dot < 0.0f) { y = -1; } float speedUp = (theta > PI) ? 3.0f : 1.0f; DE::Quaternion quat(DE::Vector3(0, y, 0), theta * m_fDeltaTime * speedUp); m_pOwner->TransformBy(quat.GetRotationMatrix()); } // only send new animation event when player is not being impacted if (((Player*)m_pOwner)->GetState() != Player::IMPACTING) { if (m_vTrans.iszero() && ((Player*)m_pOwner)->GetState() == Player::LOCOMOTION && m_bWalk) { DE::Handle h(sizeof(Player_Walk_END_Event)); new (h) Player_Walk_END_Event; DE::EventQueue::GetInstance()->Add(h, DE::GAME_EVENT); m_bWalk = false; } else if (m_bDodge && !m_vTrans.iszero() && ((Player*)m_pOwner)->GetStamina() >= 20.0f) { m_vDodgeDir = m_vTrans.Normal(); m_bDodge = false; ((Player*)m_pOwner)->SetState(Player::DOGDING); ((Player*)m_pOwner)->AddStamina(-20.0f); DE::Handle h(sizeof(Player_Dodge_START_Event)); new (h) Player_Dodge_START_Event; ((Player_Dodge_START_Event*)h.Raw())->m_vDir = m_vTrans.Normal(); DE::EventQueue::GetInstance()->Add(h, DE::GAME_EVENT); } else if (!m_vTrans.iszero() && ((Player*)m_pOwner)->GetState() == Player::LOCOMOTION) { Move(m_vTrans); m_bWalk = true; if (m_bRun) { if (!m_bRunLock && ((Player*)m_pOwner)->GetStamina() >= 4.0f) { ((Player*)m_pOwner)->AddStamina(-2.0f); } else { m_bRunLock = true; m_bRun = false; } } DE::Handle h(sizeof(Player_Walk_PLAYING_Event)); new (h) Player_Walk_PLAYING_Event; ((Player_Walk_PLAYING_Event*)h.Raw())->m_vDir = m_vTrans.Normal(); ((Player_Walk_PLAYING_Event*)h.Raw())->m_bRun = m_bRun; DE::EventQueue::GetInstance()->Add(h, DE::GAME_EVENT); } if (((Player*)m_pOwner)->GetState() == Player::DOGDING) { Move(m_vDodgeDir * m_fSpeed * m_fDeltaTime * 3.0f); } if (m_ComboSequence[0] || m_ComboSequence[1]) { m_fComboTime += m_fDeltaTime; } if (m_ComboSequence[2]) { DE::Vector3 vForward = DE::Vector3::UnitZ; Move(vForward * m_fSpeed * m_fDeltaTime * 0.5f); } } m_vTrans = DE::Vector3::Zero; m_bDodge = false; m_bRun = false; }
void ComputeNormals(Loader3ds *pt3ds) { int i,j,index; int shared=0; float v1x=0.0,v1y=0.0,v1z=0.0, v2x=0.0,v2y=0.0,v2z=0.0, vnx=0.0,vny=0.0,vnz=0.0, vp0x=0.0,vp0y=0.0,vp0z=0.0, vp1x=0.0,vp1y=0.0,vp1z=0.0, vp2x=0.0,vp2y=0.0,vp2z=0.0, *pNormals=NULL, *pTempNormals=NULL, vSumx = 0.0,vSumy = 0.0,vSumz = 0.0; Objects *cur_obj; // If there are no objects, we can skip this part if(pt3ds->NBobjects <= 0) return; // Go through each of the objects to calculate their normals cur_obj = pt3ds->objects; for(index = 0; index < pt3ds->NBobjects; index++) { pNormals = (float*)malloc(sizeof(float) *(3*cur_obj->NBFaces)); pTempNormals = (float*)malloc(sizeof(float) * (3*cur_obj->NBFaces)); cur_obj->Normal = (float*)malloc(sizeof(float) * (3*cur_obj->NBvert)); // Go though all of the faces of this object for(i=0; i < cur_obj->NBFaces; i++) { vp0x=cur_obj->vert[0+3*cur_obj->Faces[i*3]]; vp0y=cur_obj->vert[1+3*cur_obj->Faces[i*3]]; vp0z=cur_obj->vert[2+3*cur_obj->Faces[i*3]]; vp1x=cur_obj->vert[0+3*cur_obj->Faces[i*3+1]]; vp1y=cur_obj->vert[1+3*cur_obj->Faces[i*3+1]]; vp1z=cur_obj->vert[2+3*cur_obj->Faces[i*3+1]]; vp2x=cur_obj->vert[0+3*cur_obj->Faces[i*3+2]]; vp2y=cur_obj->vert[1+3*cur_obj->Faces[i*3+2]]; vp2z=cur_obj->vert[2+3*cur_obj->Faces[i*3+2]]; Vector( vp0x,vp0y,vp0z, vp2x,vp2y,vp2z, &v1x,&v1y,&v1z); // Get the vector of the polygon (we just need 2 sides for the normal) Vector( vp2x,vp2y,vp2z, vp1x,vp1y,vp1z, &v2x,&v2y,&v2z); // Get a second vector of the polygon Cross( v1x,v1y,v1z, v2x,v2y,v2z, &vnx,&vny,&vnz); // Return the cross product of the 2 vectors (normalize vector, but not a unit vector) pTempNormals[3*i] = vnx; // Save the un-normalized normal for the vertex normals pTempNormals[3*i+1] = vny; // Save the un-normalized normal for the vertex normals pTempNormals[3*i+2] = vnz; // Save the un-normalized normal for the vertex normals Normalize(&vnx,&vny,&vnz); // Normalize the cross product to give us the polygons normal pNormals[3*i] = vnx; // Assign the normal to the list of normals pNormals[3*i+1] = vny; // Assign the normal to the list of normals pNormals[3*i+2] = vnz; // Assign the normal to the list of normals } //////////////// Now Get The Vertex Normals ///////////////// vSumx = 0.0;vSumy = 0.0;vSumz = 0.0; shared=0; for (i = 0; i < cur_obj->NBvert; i++) // Go through all of the vertices { for (j = 0; j < cur_obj->NBFaces; j++) // Go through all of the triangles { // Check if the vertex is shared by another face if (cur_obj->Faces[j*3] == i || cur_obj->Faces[j*3+1] == i || cur_obj->Faces[j*3+2] == i) { AddVector( vSumx,vSumy,vSumz, pTempNormals[j*3],pTempNormals[j*3+1],pTempNormals[j*3+2], &vSumx,&vSumy,&vSumz);// Add the un-normalized normal of the shared face shared++; // Increase the number of shared triangles } } // Get the normal by dividing the sum by the shared. We negate the shared so it has the normals pointing out. DivideVectorByScaler( vSumx,vSumy,vSumz, &(cur_obj->Normal[i*3]), &(cur_obj->Normal[i*3+1]), &(cur_obj->Normal[i*3+2]), -(float)shared); // Normalize the normal for the final vertex normal Normalize( &(cur_obj->Normal[i*3]), &(cur_obj->Normal[i*3+1]), &(cur_obj->Normal[i*3+2])); vSumx = 0.0;vSumy = 0.0;vSumz = 0.0; // Reset the sum shared = 0; // Reset the shared } if (pNormals) free(pNormals); if (pTempNormals) free(pTempNormals); cur_obj=cur_obj->next; }//end for index }
float3 Polygon::BasisV() const { if (p.size() < 2) return float3::unitY; return Cross(BasisU(), PlaneCCW().normal).Normalized(); }
void Arrow( float tail[3], float head[3] ) { float u[3], v[3], w[3]; // arrow coordinate system // set w direction in u-v-w coordinate system: w[0] = head[0] - tail[0]; w[1] = head[1] - tail[1]; w[2] = head[2] - tail[2]; // determine major direction: int axis = X; float mag = fabs( w[0] ); if( fabs( w[1] ) > mag ) { axis = Y; mag = fabs( w[1] ); } if( fabs( w[2] ) > mag ) { axis = Z; mag = fabs( w[2] ); } // set size of wings and turn w into a Unit vector: float d = WINGS * Unit( w, w ); // draw the shaft of the arrow: glBegin( GL_LINE_STRIP ); glVertex3fv( tail ); glVertex3fv( head ); glEnd( ); // draw two sets of wings in the non-major directions: float x, y, z; if( axis != X ) { Cross( w, axx, v ); (void) Unit( v, v ); Cross( v, w, u ); x = head[0] + d * ( u[0] - w[0] ); y = head[1] + d * ( u[1] - w[1] ); z = head[2] + d * ( u[2] - w[2] ); glBegin( GL_LINE_STRIP ); glVertex3fv( head ); glVertex3f( x, y, z ); glEnd( ); x = head[0] + d * ( -u[0] - w[0] ); y = head[1] + d * ( -u[1] - w[1] ); z = head[2] + d * ( -u[2] - w[2] ); glBegin( GL_LINE_STRIP ); glVertex3fv( head ); glVertex3f( x, y, z ); glEnd( ); } if( axis != Y ) { Cross( w, ayy, v ); (void) Unit( v, v ); Cross( v, w, u ); x = head[0] + d * ( u[0] - w[0] ); y = head[1] + d * ( u[1] - w[1] ); z = head[2] + d * ( u[2] - w[2] ); glBegin( GL_LINE_STRIP ); glVertex3fv( head ); glVertex3f( x, y, z ); glEnd( ); x = head[0] + d * ( -u[0] - w[0] ); y = head[1] + d * ( -u[1] - w[1] ); z = head[2] + d * ( -u[2] - w[2] ); glBegin( GL_LINE_STRIP ); glVertex3fv( head ); glVertex3f( x, y, z ); glEnd( ); } if( axis != Z ) { Cross( w, azz, v ); (void) Unit( v, v ); Cross( v, w, u ); x = head[0] + d * ( u[0] - w[0] ); y = head[1] + d * ( u[1] - w[1] ); z = head[2] + d * ( u[2] - w[2] ); glBegin( GL_LINE_STRIP ); glVertex3fv( head ); glVertex3f( x, y, z ); glEnd( ); x = head[0] + d * ( -u[0] - w[0] ); y = head[1] + d * ( -u[1] - w[1] ); z = head[2] + d * ( -u[2] - w[2] ); glBegin( GL_LINE_STRIP ); glVertex3fv( head ); glVertex3f( x, y, z ); glEnd( ); } }
bool Terrain::LoadHeightmap(const char *filename, float heightScale) { img.LoadTga(filename); if (!img) return false; this->heightScale = heightScale; int w = img.GetWidth(); int h = img.GetHeight(); indicesCount = (w-1)*(h-1)*6; Vector3f *verts = new Vector3f[w * h]; Vector3f *norms = new Vector3f[w * h]; Vector2f *texs = new Vector2f[w * h]; UINT *inds = new UINT[indicesCount]; Vector3f *polygonNormals[2]; for (int i = 0; i < 2; i++) polygonNormals[i] = new Vector3f[(w-1)*(h-1)*2]; float hw = w * 0.5f; float hh = h * 0.5f; float k = 1.0f / 255.0f * heightScale; for (int i = 0; i < w; i++) for (int j = 0; j < h; j++) { int idx = i * h + j; verts[idx].x = i - hw; verts[idx].z = j - hh; verts[idx].y = img.GetPixel(i, j).r * k; texs[idx].x = i*0.3f; texs[idx].y = j*0.3f; } int n = 0; for (int i = 0; i < w - 1; i++) for (int j = 0; j < h - 1; j++) { inds[n] = i*h + j; inds[n+1] = i*h + (j+1); inds[n+2] = (i+1)*h + (j+1); inds[n+3] = inds[n]; inds[n+4] = inds[n+2]; inds[n+5] = (i+1)*h + j; Vector3f t1[3] = { verts[inds[n]], verts[inds[n+1]], verts[inds[n+2]] }; Vector3f t2[3] = { verts[inds[n+3]], verts[inds[n+4]], verts[inds[n+5]] }; polygonNormals[0][i*h + j] = Normalize(Cross(t1[0] - t1[1], t1[1] - t1[2])); polygonNormals[1][i*h + j] = Normalize(Cross(t2[0] - t2[1], t2[1] - t2[2])); n += 6; } for (int i = 0; i < w; i++) for (int j = 0; j < h; j++) { Vector3f &normal = norms[i*h + j]; if (i != 0 && j != 0) { for (int k = 0; k < 2; k++) normal += polygonNormals[k][(i-1)*h + (j-1)]; } if (i != w - 1 && j != h - 1) { for (int k = 0; k < 2; k++) normal += polygonNormals[k][i*h + j]; } if (i != 0 && j != h - 1) normal += polygonNormals[1][(i-1)*h + j]; if (j != 0 && i != w - 1) normal += polygonNormals[0][i*h + (j-1)]; normal.Normalize(); } vertices.SetData(w * h * sizeof(Vector3f), verts, GL_STATIC_DRAW); normals.SetData(w * h * sizeof(Vector3f), norms, GL_STATIC_DRAW); texCoords.SetData(w * h * sizeof(Vector2f), texs, GL_STATIC_DRAW); indices.SetData(indicesCount * sizeof(UINT), inds, GL_STATIC_DRAW); delete [] polygonNormals[0]; delete [] polygonNormals[1]; delete [] verts; delete [] norms; delete [] texs; delete [] inds; return true; }
// compute polygon list of edge plane intersections // // This is never called externally and could be private. // // The representation returned is not efficient, but it appears a // typical rendering only contains about 1k triangles. void TextureBrick::compute_polygons(Ray& view, double tmin, double tmax, double dt, vector<float>& vertex, vector<uint32_t>& index, vector<uint32_t>& size) { if (dt <= 0.0) return; Vector vv[12], tt[12]; // temp storage for vertices and texcoords uint32_t degree = 0; // find up and right vectors Vector vdir = view.direction(); view_vector_ = vdir; Vector up; Vector right; switch (MinIndex(fabs(vdir.x()), fabs(vdir.y()), fabs(vdir.z()))) { case 0: up.x(0.0); up.y(-vdir.z()); up.z(vdir.y()); break; case 1: up.x(-vdir.z()); up.y(0.0); up.z(vdir.x()); break; case 2: up.x(-vdir.y()); up.y(vdir.x()); up.z(0.0); break; } up.normalize(); right = Cross(vdir, up); bool order = TextureRenderer::get_update_order(); size_t vert_count = 0; for (double t = order ? tmin : tmax; order ? (t < tmax) : (t > tmin); t += order ? dt : -dt) { // we compute polys back to front // find intersections degree = 0; for (size_t j = 0; j < 12; j++) { double u; FLIVR::Vector vec = -view.direction(); FLIVR::Point pnt = view.parameter(t); bool intersects = edge_[j].planeIntersectParameter (vec, pnt, u); if (intersects && u >= 0.0 && u <= 1.0) { Point p; p = edge_[j].parameter(u); vv[degree] = (Vector)p; p = tex_edge_[j].parameter(u); tt[degree] = (Vector)p; degree++; } } if (degree < 3 || degree >6) continue; bool sorted = degree > 3; uint32_t idx[6]; if (sorted) { // compute centroids Vector vc(0.0, 0.0, 0.0), tc(0.0, 0.0, 0.0); for (int j = 0; j < degree; j++) { vc += vv[j]; tc += tt[j]; } vc /= (double)degree; tc /= (double)degree; // sort vertices double pa[6]; for (uint32_t i = 0; i < degree; i++) { double vx = Dot(vv[i] - vc, right); double vy = Dot(vv[i] - vc, up); // compute pseudo-angle pa[i] = vy / (fabs(vx) + fabs(vy)); if (vx < 0.0) pa[i] = 2.0 - pa[i]; else if (vy < 0.0) pa[i] = 4.0 + pa[i]; // init idx idx[i] = i; } Sort(pa, idx, degree); } // save all of the indices for (uint32_t j = 1; j < degree - 1; j++) { index.push_back(vert_count); index.push_back(vert_count + j); index.push_back(vert_count + j + 1); } // save all of the verts for (uint32_t j = 0; j < degree; j++) { vertex.push_back((sorted ? vv[idx[j]] : vv[j]).x()); vertex.push_back((sorted ? vv[idx[j]] : vv[j]).y()); vertex.push_back((sorted ? vv[idx[j]] : vv[j]).z()); vertex.push_back((sorted ? tt[idx[j]] : tt[j]).x()); vertex.push_back((sorted ? tt[idx[j]] : tt[j]).y()); vertex.push_back((sorted ? tt[idx[j]] : tt[j]).z()); vert_count++; } size.push_back(degree); } }