void BackgroundActor::UpdateUVs(float horizontal, float vertical) { Vector2 lowerLeft; Vector2 upperRight; GetUVs(lowerLeft, upperRight); lowerLeft.X += horizontal; lowerLeft.Y += vertical; upperRight.X += horizontal; upperRight.Y += vertical; SetUVs(lowerLeft, upperRight); }
void Triangle::GetShadingGeometry(const Transform &obj2world, const DifferentialGeometry &dg, DifferentialGeometry *dgShading) const { if (!mesh->n && !mesh->s) { *dgShading = dg; return; } // Initialize _Triangle_ 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 triangle, _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 triangle shading geometry if (mesh->n) { float uvs[3][2]; GetUVs(uvs); // Compute deltas for triangle 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::IntersectP(const Ray &ray) const { PBRT_RAY_TRIANGLE_INTERSECTIONP_TEST(const_cast<Ray *>(&ray), const_cast<Triangle *>(this)); // Compute $\VEC{s}_1$ // Get triangle 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 triangle partial derivatives Vector dpdu, dpdv; float uvs[3][2]; GetUVs(uvs); // Compute deltas for triangle 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 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*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 Triangle::Intersect(const Ray &ray, Float *distance, Float *rayEpsilon, DifferentialGeometry *dg) const { Point p1 = mMesh->p[mIndex[0]]; Point p2 = mMesh->p[mIndex[1]]; Point p3 = mMesh->p[mIndex[2]]; //这里使用质心坐标来计算 详见PBRT公式 Vector3f e1 = p2 - p1; //e1=p2-p1 Vector3f e2 = p3 - p1; //e2=p3-p1 Vector3f s1 = Cross(ray.d, e2); //s1=d x e2 Float divisor = Dot(s1, e1); if (divisor == 0.0f) return false; Float invDivisor = 1.f / divisor; //1/(s1.e1) // 计算第一个质心坐标 Vector3f s = ray.o - p1; //s = o - p1 Float b1 = Dot(s, s1) * invDivisor; //b1 = (s.s1)/(s1.e1) if (b1 < 0. || b1 > 1.) return false; // 计算第二个质心坐标 Vector3f s2 = Cross(s, e1); //s2 = s x e1 Float b2 = Dot(ray.d, s2) * invDivisor; // b2 = (d.s2)/(s1.e1) if (b2 < 0. || b1 + b2 > 1.) return false; // 计算参数t Float t = Dot(e2, s2) * invDivisor; if (t < ray.minT || t > ray.maxT) return false; Vector3f dpdu, dpdv; //p在u和v上的偏导 Float uvs[3][2]; GetUVs(uvs); //计算p在u和v上的偏导 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]; Vector3f dp1 = p1 - p3, dp2 = p2 - p3; Float determinant = du1 * dv2 - dv1 * du2; if (determinant == 0.f) { //行列式为0 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; } //这里是在计算参数坐标 用的也是质心坐标 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]; *dg = DifferentialGeometry(ray(t), dpdu, dpdv, Normal(0, 0, 0), Normal(0, 0, 0), tu, tv, this); *distance = t; *rayEpsilon = 1e-3f * *distance; //cout<<"射中三角"<<endl; return true; }
bool NaiadTriangle::Intersect(const Ray &ray, float *tHit, float *rayEpsilon, DifferentialGeometry *dg) const { if (!mesh.GetPtr()->foam_block && ray.zbuffer) return false; PBRT_RAY_TRIANGLE_INTERSECTION_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; // 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]; //printf("\nu: %f, v: %f\n",tu,tv); // Test intersection against alpha texture, if present if (ray.depth != -1) { if (mesh->alphaTexture) { 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; } } // Fill in _DifferentialGeometry_ from NaiadTriangle hit *dg = DifferentialGeometry(ray(t), dpdu, dpdv, Normal(0,0,0), Normal(0,0,0), tu, tv, this); *tHit = t; //If writing to Z buffer if (mesh.GetPtr()->foam_block ) { ray.zbuffer_depth = t; } *rayEpsilon = 1e-3f * *tHit; PBRT_RAY_TRIANGLE_INTERSECTION_HIT(const_cast<Ray *>(&ray), t); 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; }
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; }
std::shared_ptr<Mesh> FBXConverter::LoadMesh(FbxMesh* fbxMesh) { assert(fbxMesh->GetLayerCount() > 0); auto node = fbxMesh->GetNode(); auto layer = fbxMesh->GetLayer(0); if (layer->GetNormals() == nullptr) { fbxMesh->GenerateNormals(true); } auto uvs = layer->GetUVs(); auto vcolors = layer->GetVertexColors(); auto normals = layer->GetNormals(); auto binormals = layer->GetBinormals(); auto materials = layer->GetMaterials(); auto controlPoints = fbxMesh->GetControlPoints(); auto controlPointsCount = fbxMesh->GetControlPointsCount(); auto polygonCount = fbxMesh->GetPolygonCount(); std::vector<FbxFace> faces; // Load weights std::vector<BoneConnector> bcs_temp; std::vector<Vertex> vs_temp; LoadSkin(fbxMesh, bcs_temp, vs_temp); // generate face vertex int32_t vertexID = 0; for (int32_t polygonIndex = 0; polygonIndex < polygonCount; polygonIndex++) { int polygonPointCount = fbxMesh->GetPolygonSize(polygonIndex); FbxFace face; for (int32_t polygonPointIndex = 0; polygonPointIndex < polygonPointCount; polygonPointIndex++) { auto ctrlPointIndex = fbxMesh->GetPolygonVertex(polygonIndex, polygonPointIndex); Vertex v; v.Position = LoadPosition(fbxMesh, ctrlPointIndex); v.Weights = vs_temp[ctrlPointIndex].Weights; if (normals != nullptr) { v.Normal = LoadNormal(normals, vertexID, ctrlPointIndex); } if (uvs != nullptr) { v.UV = LoadUV(fbxMesh, uvs, vertexID, ctrlPointIndex, polygonIndex, polygonPointIndex); } else { // Auto generated v.UV[0] = v.Position[0] + v.Position[2]; v.UV[1] = v.Position[1]; } if (vcolors != nullptr) { v.VertexColor = LoadVertexColor(fbxMesh, vcolors, vertexID, ctrlPointIndex, polygonIndex, polygonPointIndex); } face.Vertecies.push_back(v); vertexID++; } faces.push_back(face); } // 面の表裏入れ替え for (auto& face : faces) { std::reverse(face.Vertecies.begin(), face.Vertecies.end()); } // メッシュで使用可能な形式に変換 // 頂点変換テーブル作成 int32_t vInd = 0; std::map<Vertex, int32_t> v2ind; std::map<int32_t, Vertex> ind2v; for (auto& face : faces) { for (int32_t vi = 0; vi < (int32_t)face.Vertecies.size(); vi++) { auto vertex = face.Vertecies[vi]; auto it = v2ind.find(vertex); if (it == v2ind.end()) { v2ind[vertex] = vInd; ind2v[vInd] = vertex; vInd++; } } } // 設定 auto mesh = std::make_shared<Mesh>(); mesh->Name = node->GetName(); mesh->BoneConnectors = bcs_temp; mesh->Vertexes.resize(vInd); for (auto& iv : ind2v) { mesh->Vertexes[iv.first] = iv.second; } for (auto& face : faces) { if (face.Vertecies.size() < 3) continue; if (face.Vertecies.size() == 3) { Face f; f.Index[0] = v2ind[face.Vertecies[0]]; f.Index[1] = v2ind[face.Vertecies[1]]; f.Index[2] = v2ind[face.Vertecies[2]]; mesh->Faces.push_back(f); } if (face.Vertecies.size() == 4) { Face f0; f0.Index[0] = v2ind[face.Vertecies[0]]; f0.Index[1] = v2ind[face.Vertecies[1]]; f0.Index[2] = v2ind[face.Vertecies[2]]; mesh->Faces.push_back(f0); Face f1; f1.Index[0] = v2ind[face.Vertecies[0]]; f1.Index[1] = v2ind[face.Vertecies[2]]; f1.Index[2] = v2ind[face.Vertecies[3]]; mesh->Faces.push_back(f1); } } // Binormal,Tangent計算 std::map<int32_t, VertexNormals> vInd2Normals; for (const auto& face : mesh->Faces) { FbxVector4 binormal, tangent; CalcTangentSpace( mesh->Vertexes[face.Index[0]], mesh->Vertexes[face.Index[1]], mesh->Vertexes[face.Index[2]], binormal, tangent); for (auto i = 0; i < 3; i++) { vInd2Normals[face.Index[i]].Binormal += binormal; vInd2Normals[face.Index[i]].Tangent += tangent; vInd2Normals[face.Index[i]].Count += 1; } } for (auto& vn : vInd2Normals) { vn.second.Binormal /= vn.second.Count; vn.second.Tangent /= vn.second.Count; } for (auto& vn : vInd2Normals) { mesh->Vertexes[vn.first].Binormal = vn.second.Binormal; mesh->Vertexes[vn.first].Tangent = vn.second.Tangent; // 適当な値を代入する if (mesh->Vertexes[vn.first].Binormal.Length() == 0.0f) { if (mesh->Vertexes[vn.first].Normal != FbxVector4(1, 0, 0)) { mesh->Vertexes[vn.first].Binormal = FbxVector4(1, 0, 0); mesh->Vertexes[vn.first].Tangent = FbxVector4(0, 1, 0); } else { mesh->Vertexes[vn.first].Binormal = FbxVector4(0, 1, 0); mesh->Vertexes[vn.first].Tangent = FbxVector4(1, 0, 0); } } } return mesh; }