RGBColor Transmittance::SampleF(const Vector& wi, Vector& wo, const Normal& n) const { float eta = ior; Normal ns = n; float nDotWi = Dot(wo, ns); if (nDotWi > 0.0f) //Uhel je tupy (jdeme zevnitr ven) { eta = 1.f / ior; ns = -ns; } float w = -(nDotWi) / (wi.Length() * n.Length()); float r = eta; float k = sqrtf(1 + (w - r)*(w + r)); wo = r*wi + (w - k)*n; return c; }
// Function for the upper bound on error Spectrum ErrorBound(Point p, Normal n, Point bb_low, Point bb_high, Point l, Spectrum brdf, Spectrum intensities) { double err = 1; bool inf = false; int i; double dist = 0; // Calculate minimum distance from bounding box for(i = 0; i < 3; i++) { if(p[i] < bb_low[i]) dist += (p[i] - bb_low[i])*(p[i] - bb_low[i]); else if(p[i] > bb_high[i]) dist += (p[i] - bb_high[i])*(p[i] - bb_high[i]); else { inf = true; break; } } // Infinite error bound if p is inside the bounding box if(inf || dist < 0.001) { return -1 * intensities; } // Bound of the geometric term err *= 1.0 / dist; n /= n.Length(); // To bound the cosine term, align normal to the z-axis // and take maximum z-coordinate and minimum absolute values of x and y coordinates. float M[3][3]; //Rotation matrix from normal to z-axis float v[3][3]; float vsq[3][3]; int j; for(i = 0; i < 3; i++) { for(j = 0; j < 3; j++) { if(i == j) M[i][j] = 1; else M[i][j] = 0; v[i][j] = 0; vsq[i][j] = 0; } } float vx = n[1]; float vy = -(n[0]); float s = sqrtf(vx*vx + vy*vy); float c = n[2]; Point bb_low2, bb_high2; for(i = 0; i < 3; i++) { bb_low2[i] = bb_low[i] - p[i]; bb_high2[i] = bb_high[i] - p[i]; } int k; if(fabsf(s) < 0.001) { if(c < 0) { M[2][2] = -1; } } else { v[0][2] = vy; M[0][2] += vy; v[1][2] = -vx; M[1][2] += -vx; v[2][0] = -vy; M[2][0] += -vy; v[2][1] = vx; M[2][1] += vx; float temp = (1 - c) / (s * s); for(i = 0; i < 3; i++) { for(j = 0; j < 3; j++) { for(k = 0; k < 3; k++) { vsq[i][j] += v[i][k] * v[k][j]; } M[i][j] += vsq[i][j] * temp; } } } // Rotation Matrix computed Point bb_low3, bb_high3; // Transform and align normal to the z-axis // Apply the transform to the bounding box points for(i = 0; i < 3; i++) { for(k = 0; k < 3; k++) { bb_low3[i] += M[i][k]*bb_low2[k]; bb_high3[i] += M[i][k]*bb_high2[k]; } } // For cos theta bound, use maximum z and minimum absolute x and y float max_z = bb_high3[2]; if(bb_low3[2] > max_z) max_z = bb_low3[2]; // Negative maximum z means that none of the light sources are in the reflection hemisphere. Bound is 0. if(max_z < 0.001) return 0 * intensities; float min_x, min_y; if((bb_low3[0] < 0 && bb_high3[0] > 0) || (bb_high3[0] < 0 && bb_low3[0] > 0)) min_x = 0; else min_x = min(fabsf(bb_low3[0]), fabsf(bb_high3[0])); if((bb_low3[1] < 0 && bb_high3[1] > 0) || (bb_high3[1] < 0 && bb_low3[1] > 0)) min_y = 0; else min_y = min(fabsf(bb_low3[1]), fabsf(bb_high3[1])); err *= max_z / sqrtf((max_z * max_z) + (min_y * min_y) + (min_x * min_x)); // Multiply by the cosine bound return err * brdf * intensities; // Multiply by the constant lambertian brdf and the sum of light intensities }
void MeshBaryTriangle::GetShadingGeometry(const Transform &obj2world, const DifferentialGeometry &dg, DifferentialGeometry *dgShading) const { if (!mesh->n) { *dgShading = dg; return; } // Use _n_ to compute shading tangents for triangle, _ss_ and _ts_ const Normal nsi = dg.iData.baryTriangle.coords[0] * mesh->n[v[0]] + dg.iData.baryTriangle.coords[1] * mesh->n[v[1]] + dg.iData.baryTriangle.coords[2] * mesh->n[v[2]]; const Normal ns = Normalize(nsi); Vector ss, ts; Vector tangent, bitangent; float btsign; // if we got a generated tangent space, use that if (mesh->t) { // length of these vectors is essential for sampled normal mapping // they should be normalized at vertex level, and NOT normalized after interpolation tangent = dg.iData.baryTriangle.coords[0] * mesh->t[v[0]] + dg.iData.baryTriangle.coords[1] * mesh->t[v[1]] + dg.iData.baryTriangle.coords[2] * mesh->t[v[2]]; // only degenerate triangles will have different vertex signs bitangent = Cross(nsi, tangent); // store sign, and also magnitude of interpolated normal so we can recover it btsign = (mesh->btsign[v[0]] ? 1.f : -1.f) * nsi.Length(); ss = Normalize(tangent); ts = Normalize(bitangent); } else { ts = Normalize(Cross(ns, dg.dpdu)); ss = Cross(ts, ns); ts *= Dot(dg.dpdv, ts) > 0.f ? 1.f : -1.f; tangent = ss; bitangent = ts; btsign = (Dot(ts, ns) > 0.f ? 1.f : -1.f); } // the length of dpdu/dpdv can be important for bumpmapping ss *= dg.dpdu.Length(); ts *= dg.dpdv.Length(); Normal dndu, dndv; // Compute \dndu and \dndv for triangle shading geometry float uvs[3][2]; GetUVs(uvs); // Compute deltas for triangle partial derivatives of normal const float du1 = uvs[0][0] - uvs[2][0]; const float du2 = uvs[1][0] - uvs[2][0]; const float dv1 = uvs[0][1] - uvs[2][1]; const float dv2 = uvs[1][1] - uvs[2][1]; const Normal dn1 = mesh->n[v[0]] - mesh->n[v[2]]; const Normal dn2 = mesh->n[v[1]] - mesh->n[v[2]]; const float determinant = du1 * dv2 - dv1 * du2; if (determinant == 0.f) dndu = dndv = Normal(0, 0, 0); else { const float invdet = 1.f / determinant; dndu = ( dv2 * dn1 - dv1 * dn2) * invdet; dndv = (-du2 * dn1 + du1 * dn2) * invdet; } *dgShading = DifferentialGeometry(dg.p, ns, ss, ts, dndu, dndv, tangent, bitangent, btsign, dg.u, dg.v, this); dgShading->iData = dg.iData; }