Beispiel #1
0
Spectrum FresnelSpecular::Sample_f(const Vector3f &wo, Vector3f *wi,
                                   const Point2f &u, Float *pdf,
                                   BxDFType *sampledType) const {
    Float F = FrDielectric(CosTheta(wo), etaA, etaB);
    if (u[0] < F) {
        // Compute specular reflection for _FresnelSpecular_

        // Compute perfect specular reflection direction
        *wi = Vector3f(-wo.x, -wo.y, wo.z);
        if (sampledType)
            *sampledType = BxDFType(BSDF_SPECULAR | BSDF_REFLECTION);
        *pdf = F;
        return F * R / AbsCosTheta(*wi);
    } else {
        // Compute specular transmission for _FresnelSpecular_

        // Figure out which $\eta$ is incident and which is transmitted
        bool entering = CosTheta(wo) > 0;
        Float etaI = entering ? etaA : etaB;
        Float etaT = entering ? etaB : etaA;

        // Compute ray direction for specular transmission
        if (!Refract(wo, Faceforward(Normal3f(0, 0, 1), wo), etaI / etaT, wi))
            return 0;
        Spectrum ft = T * (1 - F);

        // Account for non-symmetry with transmission to different medium
        if (mode == TransportMode::Radiance)
            ft *= (etaI * etaI) / (etaT * etaT);
        if (sampledType)
            *sampledType = BxDFType(BSDF_SPECULAR | BSDF_TRANSMISSION);
        *pdf = 1 - F;
        return ft / AbsCosTheta(*wi);
    }
}
Beispiel #2
0
// SurfaceInteraction Method Definitions
SurfaceInteraction::SurfaceInteraction(
    const Point3f &p, const Vector3f &pError, const Point2f &uv,
    const Vector3f &wo, const Vector3f &dpdu, const Vector3f &dpdv,
    const Normal3f &dndu, const Normal3f &dndv, Float time, const Shape *shape)
    : Interaction(p, Normal3f(Normalize(Cross(dpdu, dpdv))), pError, wo, time,
                  nullptr),
      uv(uv),
      dpdu(dpdu),
      dpdv(dpdv),
      dndu(dndu),
      dndv(dndv),
      shape(shape) {
    // Initialize shading geometry from true geometry
    shading.n = n;
    shading.dpdu = dpdu;
    shading.dpdv = dpdv;
    shading.dndu = dndu;
    shading.dndv = dndv;

    // Adjust normal based on orientation and handedness
    if (shape &&
        (shape->reverseOrientation ^ shape->transformSwapsHandedness)) {
        n *= -1;
        shading.n *= -1;
    }
}
Beispiel #3
0
void ParamSetProxy::AddNormal3f(const std::string& name, std::vector<Float> values) {
  std::vector<Normal3f> v;
  for (size_t i = 0; i < values.size() - 2; i+=3) {
    v.push_back(Normal3f(values[i], values[i + 1], values[i + 2]));
  }
  ArrayView<Normal3f>* arrayView = new ArrayView<Normal3f>(v);
  paramSet->AddNormal3f(name, std::move(arrayView->v), arrayView->size);
  delete arrayView;
}
Beispiel #4
0
bool Sphere::Sample(const Point2f &sample, Interaction *it) const {
    Point3f pObj = Point3f(0, 0, 0) + radius * UniformSampleSphere(sample);
    it->n = Normalize((*ObjectToWorld)(Normal3f(pObj.x, pObj.y, pObj.z)));
    if (ReverseOrientation) it->n *= -1.f;
    Vector3f pObjError =
        16.f * MachineEpsilon * Vector3f(radius, radius, radius);
    it->p = (*ObjectToWorld)(pObj, pObjError, &it->pError);
    return true;
}
Beispiel #5
0
bool Disk::Sample(const Point2f &sample, Interaction *it) const {
    Point2f pd = ConcentricSampleDisk(sample);
    Point3f pObj(pd.x * radius, pd.y * radius, height);
    it->n = Normalize((*ObjectToWorld)(Normal3f(0, 0, 1)));
    if (ReverseOrientation) it->n *= -1.f;
    Vector3f pObjError(0.f, 0.f, MachineEpsilon * height);
    it->p = (*ObjectToWorld)(pObj, pObjError, &it->pError);
    return true;
}
Beispiel #6
0
Interaction Sphere::Sample(const Point2f &u) const {
    Interaction it;
    Point3f pObj = Point3f(0, 0, 0) + radius * UniformSampleSphere(u);
    it.n = Normalize((*ObjectToWorld)(Normal3f(pObj.x, pObj.y, pObj.z)));
    if (reverseOrientation) it.n *= -1.f;
    // Reproject _pObj_ to sphere surface and compute _pObjError_
    pObj *= radius / Distance(pObj, Point3f(0, 0, 0));
    Vector3f pObjError = gamma(5) * Abs((Vector3f)pObj);
    it.p = (*ObjectToWorld)(pObj, pObjError, &it.pError);
    return it;
}
Beispiel #7
0
Interaction Cylinder::Sample(const Point2f &u) const {
    Interaction it;
    Float z = Lerp(u[0], zMin, zMax);
    Float t = u[1] * phiMax;
    Point3f pObj = Point3f(radius * std::cos(t), radius * std::sin(t), z);
    it.n = Normalize((*ObjectToWorld)(Normal3f(pObj.x, pObj.y, 0)));
    if (reverseOrientation) it.n *= -1.f;
    // Reproject _pObj_ to cylinder surface and compute _pObjError_
    Float hitRad = std::sqrt(pObj.x * pObj.x + pObj.y * pObj.y);
    pObj.x *= radius / hitRad;
    pObj.y *= radius / hitRad;
    Vector3f pObjError = gamma(3) * Abs(Vector3f(pObj.x, pObj.y, 0));
    it.p = (*ObjectToWorld)(pObj, pObjError, &it.pError);
    return it;
}
Beispiel #8
0
Spectrum SpecularTransmission::Sample_f(const Vector3f &wo, Vector3f *wi,
                                        const Point2f &sample, Float *pdf,
                                        BxDFType *sampledType) const {
    // Figure out which $\eta$ is incident and which is transmitted
    bool entering = CosTheta(wo) > 0;
    Float etaI = entering ? etaA : etaB;
    Float etaT = entering ? etaB : etaA;

    // Compute ray direction for specular transmission
    if (!Refract(wo, Faceforward(Normal3f(0, 0, 1), wo), etaI / etaT, wi))
        return 0;
    *pdf = 1;
    Spectrum ft = T * (Spectrum(1.) - fresnel.Evaluate(CosTheta(*wi)));
    // Account for non-symmetry with transmission to different medium
    if (mode == TransportMode::Radiance) ft *= (etaI * etaI) / (etaT * etaT);
    return ft / AbsCosTheta(*wi);
}
Beispiel #9
0
Interaction Sphere::Sample(const Interaction &ref, const Point2f &u) const {
    // Compute coordinate system for sphere sampling
    Point3f pCenter = (*ObjectToWorld)(Point3f(0, 0, 0));
    Vector3f wc = Normalize(pCenter - ref.p);
    Vector3f wcX, wcY;
    CoordinateSystem(wc, &wcX, &wcY);

    // Sample uniformly on sphere if $\pt{}$ is inside it
    Point3f pOrigin =
        OffsetRayOrigin(ref.p, ref.pError, ref.n, pCenter - ref.p);
    if (DistanceSquared(pOrigin, pCenter) <= radius * radius) return Sample(u);

    // Sample sphere uniformly inside subtended cone

    // Compute $\theta$ and $\phi$ values for sample in cone
    Float sinThetaMax2 = radius * radius / DistanceSquared(ref.p, pCenter);
    Float cosThetaMax = std::sqrt(std::max((Float)0, 1 - sinThetaMax2));
    Float cosTheta = (1 - u[0]) + u[0] * cosThetaMax;
    Float sinTheta = std::sqrt(1 - cosTheta * cosTheta);
    Float phi = u[1] * 2 * Pi;

    // Compute angle $\alpha$ from center of sphere to sampled point on surface
    Float dc = Distance(ref.p, pCenter);
    Float ds = dc * cosTheta -
               std::sqrt(std::max(
                   (Float)0, radius * radius - dc * dc * sinTheta * sinTheta));
    Float cosAlpha = (dc * dc + radius * radius - ds * ds) / (2 * dc * radius);
    Float sinAlpha = std::sqrt(std::max((Float)0, 1 - cosAlpha * cosAlpha));

    // Compute surface normal and sampled point on sphere
    Vector3f nObj =
        SphericalDirection(sinAlpha, cosAlpha, phi, -wcX, -wcY, -wc);
    Point3f pObj = radius * Point3f(nObj.x, nObj.y, nObj.z);

    // Return _Interaction_ for sampled point on sphere
    Interaction it;

    // Reproject _pObj_ to sphere surface and compute _pObjError_
    pObj *= radius / Distance(pObj, Point3f(0, 0, 0));
    Vector3f pObjError = gamma(5) * Abs((Vector3f)pObj);
    it.p = (*ObjectToWorld)(pObj, pObjError, &it.pError);
    it.n = (*ObjectToWorld)(Normal3f(nObj));
    if (reverseOrientation) it.n *= -1.f;
    return it;
}
Beispiel #10
0
ArbitraryMeshVertex MD2Vertex_construct( const md2Header_t* pHeader, const md2Frame_t* pFrame, const md2XyzNormal_t* xyz, const md2St_t* st ){
	return ArbitraryMeshVertex(
			   Vertex3f(
				   xyz->v[0] * pFrame->scale[0] + pFrame->translate[0],
				   xyz->v[1] * pFrame->scale[1] + pFrame->translate[1],
				   xyz->v[2] * pFrame->scale[2] + pFrame->translate[2]
				   ),
			   Normal3f(
				   g_mdl_normals[xyz->lightnormalindex][0],
				   g_mdl_normals[xyz->lightnormalindex][1],
				   g_mdl_normals[xyz->lightnormalindex][2]
				   ),
			   TexCoord2f(
				   (float)st->s / pHeader->skinwidth,
				   (float)st->t / pHeader->skinheight
				   )
			   );
}
Beispiel #11
0
inline ArbitraryMeshVertex MDLVertex_construct( const mdlHeader_t& header, const mdlXyzNormal_t& xyz, const mdlSt_t& st, bool facesfront ){
	return ArbitraryMeshVertex(
			   Vertex3f(
				   xyz.v[0] * header.scale[0] + header.scale_origin[0],
				   xyz.v[1] * header.scale[1] + header.scale_origin[1],
				   xyz.v[2] * header.scale[2] + header.scale_origin[2]
				   ),
			   Normal3f(
				   g_mdl_normals[xyz.lightnormalindex][0],
				   g_mdl_normals[xyz.lightnormalindex][1],
				   g_mdl_normals[xyz.lightnormalindex][2]
				   ),
			   TexCoord2f(
				   ( (float)st.s / header.skinwidth ) + ( ( st.onseam == MDL_ONSEAM && !facesfront ) ? 0.5f : 0.0f ),
				   (float)st.t / header.skinheight
				   )
			   );
}
Beispiel #12
0
bool RealisticCamera::IntersectSphericalElement(Float radius, Float zCenter,
        const Ray &ray, Float *t,
        Normal3f *n) {
    // Compute _t0_ and _t1_ for ray--element intersection
    Point3f o = ray.o - Vector3f(0, 0, zCenter);
    Float A = ray.d.x * ray.d.x + ray.d.y * ray.d.y + ray.d.z * ray.d.z;
    Float B = 2 * (ray.d.x * o.x + ray.d.y * o.y + ray.d.z * o.z);
    Float C = o.x * o.x + o.y * o.y + o.z * o.z - radius * radius;
    Float t0, t1;
    if (!Quadratic(A, B, C, &t0, &t1)) return false;

    // Select intersection $t$ based on ray direction and element curvature
    bool useCloserT = (ray.d.z > 0) ^ (radius < 0);
    *t = useCloserT ? std::min(t0, t1) : std::max(t0, t1);
    if (*t < 0) return false;

    // Compute surface normal of element at ray intersection point
    *n = Normal3f(Vector3f(o + *t * ray.d));
    *n = Faceforward(Normalize(*n), -ray.d);
    return true;
}
Beispiel #13
0
void normalquantisation_draw()
{
  glPointSize(1);
  glBegin(GL_POINTS);
  for(std::size_t i = 0; i <= c_quantise_normal; ++i)
  {
    for(std::size_t j = 0; j <= c_quantise_normal; ++j)
    {
      Normal3f vertex(normal3f_normalised(Normal3f(
        static_cast<float>(c_quantise_normal - j - i),
        static_cast<float>(i),
        static_cast<float>(j)
        )));
      VectorScale(normal3f_to_array(vertex), 64.f, normal3f_to_array(vertex));
      glVertex3fv(normal3f_to_array(vertex));
      vertex.x = -vertex.x;
      glVertex3fv(normal3f_to_array(vertex));
    }
  }
  glEnd();
}
Beispiel #14
0
void MD5Surface::buildVertexNormals()
{
	for (Indices::iterator j = _indices.begin(); j != _indices.end(); j += 3)
	{
		ArbitraryMeshVertex& a = _vertices[*(j + 0)];
		ArbitraryMeshVertex& b = _vertices[*(j + 1)];
		ArbitraryMeshVertex& c = _vertices[*(j + 2)];

		Vector3 weightedNormal((c.vertex - a.vertex).crossProduct(b.vertex - a.vertex));

		a.normal += weightedNormal;
		b.normal += weightedNormal;
		c.normal += weightedNormal;
	}

	// Normalise all normal vectors
	for (Vertices::iterator j = _vertices.begin(); j != _vertices.end(); ++j)
	{
		j->normal = Normal3f(j->normal.getNormalised());
	}
}
Beispiel #15
0
void MD5Surface::updateToSkeleton(const MD5Skeleton& skeleton)
{
	// Ensure we have all vertices allocated
	if (_vertices.size() != _mesh->vertices.size())
	{
		_vertices.resize(_mesh->vertices.size());
	}

	// Deform vertices to fit the skeleton
	for (std::size_t j = 0; j < _mesh->vertices.size(); ++j)
	{
		MD5Vert& vert = _mesh->vertices[j];

		Vector3 skinned(0, 0, 0);

		for (std::size_t k = 0; k != vert.weight_count; ++k)
		{
			MD5Weight& weight = _mesh->weights[vert.weight_index + k];
			const IMD5Anim::Key& key = skeleton.getKey(weight.joint);
			//const Joint& joint = skeleton.getJoint(weight.joint);

			Vector3 rotatedPoint = key.orientation.transformPoint(weight.v);
			skinned += (rotatedPoint + key.origin) * weight.t;
		}

		_vertices[j].vertex = skinned;
		_vertices[j].texcoord = TexCoord2f(vert.u, vert.v);
		_vertices[j].normal = Normal3f(0,0,0);
	}
    
	// Ensure the index array is ok
	if (_indices.empty())
	{
		buildIndexArray();
	}

	buildVertexNormals();

	updateGeometry();
}
Beispiel #16
0
Interaction Triangle::Sample(const Point2f &u) const {
    Point2f b = UniformSampleTriangle(u);
    // 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]];
    Interaction it;
    it.p = b[0] * p0 + b[1] * p1 + (1 - b[0] - b[1]) * p2;
    // Compute surface normal for sampled point on triangle
    if (mesh->n)
        it.n = Normalize(b[0] * mesh->n[v[0]] + b[1] * mesh->n[v[1]] +
                         (1 - b[0] - b[1]) * mesh->n[v[2]]);
    else
        it.n = Normalize(Normal3f(Cross(p1 - p0, p2 - p0)));
    if (reverseOrientation) it.n *= -1;

    // Compute error bounds for sampled point on triangle
    Point3f pAbsSum =
        Abs(b[0] * p0) + Abs(b[1] * p1) + Abs((1 - b[0] - b[1]) * p2);
    it.pError = gamma(6) * Vector3f(pAbsSum.x, pAbsSum.y, pAbsSum.z);
    return it;
}
Beispiel #17
0
Spectrum PerspectiveCamera::Sample_Wi(const Interaction &ref, const Point2f &u,
                                      Vector3f *wi, Float *pdf,
                                      Point2f *pRaster,
                                      VisibilityTester *vis) const {
    // Uniformly sample a lens interaction _lensIntr_
    Point2f pLens = lensRadius * ConcentricSampleDisk(u);
    Point3f pLensWorld = CameraToWorld(ref.time, Point3f(pLens.x, pLens.y, 0));
    Interaction lensIntr(pLensWorld, ref.time, medium);
    lensIntr.n = Normal3f(CameraToWorld(ref.time, Vector3f(0, 0, 1)));

    // Populate arguments and compute the importance value
    *vis = VisibilityTester(ref, lensIntr);
    *wi = lensIntr.p - ref.p;
    Float dist = wi->Length();
    *wi /= dist;

    // Compute PDF for importance arriving at _ref_

    // Compute lens area of perspective camera
    Float lensArea = lensRadius != 0 ? (Pi * lensRadius * lensRadius) : 1;
    *pdf = (dist * dist) / (AbsDot(lensIntr.n, *wi) * lensArea);
    return We(lensIntr, -*wi, pRaster);
}
Beispiel #18
0
void MD5Surface::updateToDefaultPose(const MD5Joints& joints)
{
	if (_vertices.size() != _mesh->vertices.size())
	{
		_vertices.resize(_mesh->vertices.size());
	}

	for (std::size_t j = 0; j < _mesh->vertices.size(); ++j)
	{
		MD5Vert& vert = _mesh->vertices[j];

		Vector3 skinned(0, 0, 0);

		for (std::size_t k = 0; k != vert.weight_count; ++k)
		{
			MD5Weight& weight = _mesh->weights[vert.weight_index + k];
			const MD5Joint& joint = joints[weight.joint];

			Vector3 rotatedPoint = joint.rotation.transformPoint(weight.v);
			skinned += (rotatedPoint + joint.position) * weight.t;
		}

		_vertices[j].vertex = skinned;
		_vertices[j].texcoord = TexCoord2f(vert.u, vert.v);
		_vertices[j].normal = Normal3f(0,0,0);
	}

	// Ensure the index array is ok
	if (_indices.empty())
	{
		buildIndexArray();
	}

	buildVertexNormals();

	updateGeometry();
}
	// Constructor. Copy the provided picoSurface_t structure into this object
	RenderablePicoSurface::RenderablePicoSurface (picoSurface_t* surf) :
		_originalShaderName(""), _mappedShaderName("")
	{
		// Get the shader from the picomodel struct.
		picoShader_t* shader = PicoGetSurfaceShader(surf);
		if (shader != 0) {
			_originalShaderName = PicoGetShaderName(shader);
		}

		// Capture the shader
		_shader = GlobalShaderCache().capture(_originalShaderName);
		if (_shader)
			_mappedShaderName = _originalShaderName; // no skin at this time

		// Get the number of vertices and indices, and reserve capacity in our vectors in advance
		// by populating them with empty structs.
		const int nVerts = PicoGetSurfaceNumVertexes(surf);
		_nIndices = PicoGetSurfaceNumIndexes(surf);
		_vertices.resize(nVerts);
		_indices.resize(_nIndices);

		// Stream in the vertex data from the raw struct, expanding the local AABB to include
		// each vertex.
		for (int vNum = 0; vNum < nVerts; ++vNum) {
			Vertex3f vertex(PicoGetSurfaceXYZ(surf, vNum));
			_localAABB.includePoint(vertex);
			_vertices[vNum].vertex = vertex;
			_vertices[vNum].normal = Normal3f(PicoGetSurfaceNormal(surf, vNum));
			_vertices[vNum].texcoord = TexCoord2f(PicoGetSurfaceST(surf, 0, vNum));
		}

		// Stream in the index data
		picoIndex_t* ind = PicoGetSurfaceIndexes(surf, 0);
		for (unsigned int i = 0; i < _nIndices; i++)
			_indices[i] = ind[i];
	}
Beispiel #20
0
bool Cylinder::Intersect(const Ray &r, Float *tHit, SurfaceInteraction *isect,
                         bool testAlphaTexture) const {
    Float phi;
    Point3f pHit;
    // Transform _Ray_ to object space
    Vector3f oErr, dErr;
    Ray ray = (*WorldToObject)(r, &oErr, &dErr);

    // Compute quadratic cylinder 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;
    EFloat b = 2 * (dx * ox + dy * oy);
    EFloat c = ox * ox + oy * oy - 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 (tShapeHit.LowerBound() <= 0) {
        tShapeHit = t1;
        if (tShapeHit.UpperBound() > ray.tMax) return false;
    }

    // Compute cylinder hit point and $\phi$
    pHit = ray((Float)tShapeHit);

    // Refine cylinder intersection point
    Float hitRad = std::sqrt(pHit.x * pHit.x + pHit.y * pHit.y);
    pHit.x *= radius / hitRad;
    pHit.y *= radius / hitRad;
    phi = std::atan2(pHit.y, pHit.x);
    if (phi < 0) phi += 2 * Pi;

    // Test cylinder intersection against clipping parameters
    if (pHit.z < zMin || pHit.z > zMax || phi > phiMax) {
        if (tShapeHit == t1) return false;
        tShapeHit = t1;
        if (t1.UpperBound() > ray.tMax) return false;
        // Compute cylinder hit point and $\phi$
        pHit = ray((Float)tShapeHit);

        // Refine cylinder intersection point
        Float hitRad = std::sqrt(pHit.x * pHit.x + pHit.y * pHit.y);
        pHit.x *= radius / hitRad;
        pHit.y *= radius / hitRad;
        phi = std::atan2(pHit.y, pHit.x);
        if (phi < 0) phi += 2 * Pi;
        if (pHit.z < zMin || pHit.z > zMax || phi > phiMax) return false;
    }

    // Find parametric representation of cylinder hit
    Float u = phi / phiMax;
    Float v = (pHit.z - zMin) / (zMax - zMin);

    // Compute cylinder $\dpdu$ and $\dpdv$
    Vector3f dpdu(-phiMax * pHit.y, phiMax * pHit.x, 0);
    Vector3f dpdv(0, 0, zMax - zMin);

    // Compute cylinder $\dndu$ and $\dndv$
    Vector3f d2Pduu = -phiMax * phiMax * Vector3f(pHit.x, pHit.y, 0);
    Vector3f d2Pduv(0, 0, 0), d2Pdvv(0, 0, 0);

    // 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 cylinder intersection
    Vector3f pError = gamma(3) * Abs(Vector3f(pHit.x, pHit.y, 0));

    // 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;
}
// Constructor. Copy the provided picoSurface_t structure into this object
RenderablePicoSurface::RenderablePicoSurface(picoSurface_t* surf,
											 const std::string& fExt)
: _shaderName(""),
  _dlRegular(0),
  _dlProgramVcol(0),
  _dlProgramNoVCol(0)
{
	// Get the shader from the picomodel struct. If this is a LWO model, use
	// the material name to select the shader, while for an ASE model the
	// bitmap path should be used.
	picoShader_t* shader = PicoGetSurfaceShader(surf);
	std::string rawName = "";

	if (shader != 0)
	{
		if (fExt == "lwo")
		{
			_shaderName = PicoGetShaderName(shader);
		}
		else if (fExt == "ase")
		{
			rawName = PicoGetShaderName(shader);
			std::string rawMapName = PicoGetShaderMapName(shader);
			_shaderName = cleanupShaderName(rawMapName);
		}
	}

	// If shader not found, fallback to alternative if available
	// _shaderName is empty if the ase material has no BITMAP
	// materialIsValid is false if _shaderName is not an existing shader
	if ((_shaderName.empty() || !GlobalMaterialManager().materialExists(_shaderName)) &&
		!rawName.empty())
	{
		_shaderName = cleanupShaderName(rawName);
	}

	// Capturing the shader happens later on when we have a RenderSystem reference

    // Get the number of vertices and indices, and reserve capacity in our
    // vectors in advance by populating them with empty structs.
    int nVerts = PicoGetSurfaceNumVertexes(surf);
    _nIndices = PicoGetSurfaceNumIndexes(surf);
    _vertices.resize(nVerts);
    _indices.resize(_nIndices);

    // Stream in the vertex data from the raw struct, expanding the local AABB
    // to include each vertex.
    for (int vNum = 0; vNum < nVerts; ++vNum) {

    	// Get the vertex position and colour
		Vertex3f vertex(PicoGetSurfaceXYZ(surf, vNum));

		// Expand the AABB to include this new vertex
    	_localAABB.includePoint(vertex);

    	_vertices[vNum].vertex = vertex;
    	_vertices[vNum].normal = Normal3f(PicoGetSurfaceNormal(surf, vNum));
    	_vertices[vNum].texcoord = TexCoord2f(PicoGetSurfaceST(surf, 0, vNum));
    	_vertices[vNum].colour =
    		getColourVector(PicoGetSurfaceColor(surf, 0, vNum));
    }

    // Stream in the index data
    picoIndex_t* ind = PicoGetSurfaceIndexes(surf, 0);
    for (unsigned int i = 0; i < _nIndices; i++)
    	_indices[i] = ind[i];

	// Calculate the tangent and bitangent vectors
	calculateTangents();

	// Construct the DLs
	createDisplayLists();
}
Beispiel #22
0
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
        Vector2f segmentDirection = Point2f(cp[3]) - Point2f(cp[0]);

        // 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
        // TODO: update to match the starting test.
        Vector2f endTangent = Point2f(cp[2]) - Point2f(cp[3]);
        if (Dot(segmentDirection, endTangent) < 0) endTangent = -endTangent;
        if (Dot(endTangent, Vector2f(cp[3])) < 0) return false;

        // Compute line $w$ that gives minimum distance to sample point
        Float denom = Dot(segmentDirection, segmentDirection);
        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;
    }
}
Beispiel #23
0
bool Sphere::Intersect(const Ray &r, Float *tHit, SurfaceInteraction *isect,
                       bool testAlphaTexture) 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 (tShapeHit.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;
}
Beispiel #24
0
 static Normal3f normalise(float x, float y, float z)
 {
   return normal3f_normalised(Normal3f(x, y, z));
 }
Beispiel #25
0
bool Hyperboloid::Intersect(const Ray &r, Float *tHit,
                            SurfaceInteraction *isect) const {
    Float phi, v;
    Point3f pHit;
    // Transform _Ray_ to object space
    Vector3f oErr, dErr;
    Ray ray = (*WorldToObject)(r, &oErr, &dErr);

    // Compute quadratic hyperboloid 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 = ah * dx * dx + ah * dy * dy - ch * dz * dz;
    EFloat b = 2.f * (ah * dx * ox + ah * dy * oy - ch * dz * oz);
    EFloat c = ah * ox * ox + ah * oy * oy - ch * oz * oz - 1.f;

    // 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 hyperboloid inverse mapping
    pHit = ray((Float)tShapeHit);
    v = (pHit.z - p1.z) / (p2.z - p1.z);
    Point3f pr = (1 - v) * p1 + v * p2;
    phi = std::atan2(pr.x * pHit.y - pHit.x * pr.y,
                     pHit.x * pr.x + pHit.y * pr.y);
    if (phi < 0) phi += 2 * Pi;

    // Test hyperboloid intersection against clipping parameters
    if (pHit.z < zMin || pHit.z > zMax || phi > phiMax) {
        if (tShapeHit == t1) return false;
        tShapeHit = t1;
        if (t1.UpperBound() > ray.tMax) return false;
        // Compute hyperboloid inverse mapping
        pHit = ray((Float)tShapeHit);
        v = (pHit.z - p1.z) / (p2.z - p1.z);
        Point3f pr = (1 - v) * p1 + v * p2;
        phi = std::atan2(pr.x * pHit.y - pHit.x * pr.y,
                         pHit.x * pr.x + pHit.y * pr.y);
        if (phi < 0) phi += 2 * Pi;
        if (pHit.z < zMin || pHit.z > zMax || phi > phiMax) return false;
    }

    // Compute parametric representation of hyperboloid hit
    Float u = phi / phiMax;

    // Compute hyperboloid $\dpdu$ and $\dpdv$
    Float cosPhi = std::cos(phi), sinPhi = std::sin(phi);
    Vector3f dpdu(-phiMax * pHit.y, phiMax * pHit.x, 0.);
    Vector3f dpdv((p2.x - p1.x) * cosPhi - (p2.y - p1.y) * sinPhi,
                  (p2.x - p1.x) * sinPhi + (p2.y - p1.y) * cosPhi, p2.z - p1.z);

    // Compute hyperboloid $\dndu$ and $\dndv$
    Vector3f d2Pduu = -phiMax * phiMax * Vector3f(pHit.x, pHit.y, 0);
    Vector3f d2Pduv = phiMax * Vector3f(-dpdv.y, dpdv.x, 0.);
    Vector3f d2Pdvv(0, 0, 0);

    // 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 hyperboloid intersection

    // Compute error bounds for intersection computed with ray equation
    EFloat px = ox + tShapeHit * dx;
    EFloat py = oy + tShapeHit * dy;
    EFloat pz = oz + tShapeHit * dz;
    Vector3f pError = Vector3f(px.GetAbsoluteError(), py.GetAbsoluteError(),
                               pz.GetAbsoluteError());

    // Initialize _SurfaceInteraction_ from parametric information
    *isect = (*ObjectToWorld)(SurfaceInteraction(pHit, pError, Point2f(u, v),
                                                 -ray.d, dpdu, dpdv, dndu, dndv,
                                                 ray.time, this));
    *tHit = (Float)tShapeHit;
    return true;
}
Beispiel #26
0
bool Paraboloid::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 paraboloid 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 k = EFloat(zMax) / (EFloat(radius) * EFloat(radius));
    EFloat a = k * (dx * dx + dy * dy);
    EFloat b = 2.f * k * (dx * ox + dy * oy) - dz;
    EFloat c = k * (ox * ox + oy * oy) - oz;

    // 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 (tShapeHit.LowerBound() <= 0) {
        tShapeHit = t1;
        if (tShapeHit.UpperBound() > ray.tMax) return false;
    }

    // Compute paraboloid inverse mapping
    pHit = ray((Float)tShapeHit);
    phi = std::atan2(pHit.y, pHit.x);
    if (phi < 0.) phi += 2 * Pi;

    // Test paraboloid intersection against clipping parameters
    if (pHit.z < zMin || pHit.z > zMax || phi > phiMax) {
        if (tShapeHit == t1) return false;
        tShapeHit = t1;
        if (t1.UpperBound() > ray.tMax) return false;
        // Compute paraboloid inverse mapping
        pHit = ray((Float)tShapeHit);
        phi = std::atan2(pHit.y, pHit.x);
        if (phi < 0.) phi += 2 * Pi;
        if (pHit.z < zMin || pHit.z > zMax || phi > phiMax) return false;
    }

    // Find parametric representation of paraboloid hit
    Float u = phi / phiMax;
    Float v = (pHit.z - zMin) / (zMax - zMin);

    // Compute paraboloid $\dpdu$ and $\dpdv$
    Vector3f dpdu(-phiMax * pHit.y, phiMax * pHit.x, 0.);
    Vector3f dpdv = (zMax - zMin) *
                    Vector3f(pHit.x / (2 * pHit.z), pHit.y / (2 * pHit.z), 1.);

    // Compute paraboloid $\dndu$ and $\dndv$
    Vector3f d2Pduu = -phiMax * phiMax * Vector3f(pHit.x, pHit.y, 0);
    Vector3f d2Pduv =
        (zMax - zMin) * phiMax *
        Vector3f(-pHit.y / (2 * pHit.z), pHit.x / (2 * pHit.z), 0);
    Vector3f d2Pdvv = -(zMax - zMin) * (zMax - zMin) *
                      Vector3f(pHit.x / (4 * pHit.z * pHit.z),
                               pHit.y / (4 * pHit.z * pHit.z), 0.);

    // 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 paraboloid intersection

    // Compute error bounds for intersection computed with ray equation
    EFloat px = ox + tShapeHit * dx;
    EFloat py = oy + tShapeHit * dy;
    EFloat pz = oz + tShapeHit * dz;
    Vector3f pError = Vector3f(px.GetAbsoluteError(), py.GetAbsoluteError(),
                               pz.GetAbsoluteError());

    // Initialize _SurfaceInteraction_ from parametric information
    *isect = (*ObjectToWorld)(SurfaceInteraction(pHit, pError, Point2f(u, v),
                                                 -ray.d, dpdu, dpdv, dndu, dndv,
                                                 ray.time, this));
    *tHit = (Float)tShapeHit;
    return true;
}
Beispiel #27
0
    Color3f Li(const Scene *scene, Sampler *sampler, const Ray3f &ray) const {
        /* Find the surface that is visible in the requested direction */
        Intersection its;

        //check if the ray intersects the scene
        if (!scene->rayIntersect(ray, its)) {
            //check if a distant disk light is set
            const Emitter* distantsDisk = scene->getDistantEmitter();
            if(distantsDisk == nullptr ) return Color3f(0.0f);

            //sample the distant disk light
            Vector3f d = ray.d;
            return distantsDisk->sampleL(d);
        }

        //get the Number of lights from the scene
        const  std::vector<Emitter *> lights = scene->getEmitters();
        uint32_t nLights = lights.size();

        Color3f tp(1.0f, 1.0f, 1.0f);
        Color3f L(0.0f, 0.0f, 0.0f);
        Ray3f pathRay(ray.o, ray.d);

        bool deltaFlag = true;

        while(true) {

            if (its.mesh->isEmitter() && deltaFlag) {
                const Emitter* areaLightEM = its.mesh->getEmitter();
                const areaLight* aEM = static_cast<const areaLight *> (areaLightEM);
                L += tp * aEM->sampleL(-pathRay.d, its.shFrame.n, its);
            }

            //Light sampling
            //randomly select a lightsource
            uint32_t var = uint32_t(std::min(sampler->next1D()*nLights, float(nLights) - 1.0f));

            //init the light color
            Color3f Li(0.0f, 0.0f, 0.0f);
            Color3f Ld(1.0f, 1.0f, 1.0f);

            //create a sample for the light
            const BSDF* curBSDF = its.mesh->getBSDF();
            const Point2f lightSample = sampler->next2D();
            VisibilityTester vis;
            Vector3f wo;
            float lightpdf;
            float bsdfpdf;
            Normal3f n = its.shFrame.n;

            deltaFlag = curBSDF->isDeltaBSDF();

            //sample the light

            {
                Li = lights[var]->sampleL(its.p, Epsilon, lightSample , &wo, &lightpdf, &vis);
                lightpdf /= float(nLights);
                //check if the pdf of the sample is greater than 0 and if the color is not black
                if(lightpdf > 0 && Li.maxCoeff() != 0.0f) {
                    //calculate the cosine term wi in my case the vector to the light
                    float cosTerm = std::abs(n.dot(wo));
                    const BSDFQueryRecord queryEM = BSDFQueryRecord(its.toLocal(- pathRay.d), its.toLocal(wo), EMeasure::ESolidAngle, sampler);
                    Color3f f = curBSDF->eval(queryEM);

                    if(f.maxCoeff() > 0.0f && f.minCoeff() >= 0.0f && vis.Unoccluded(scene)) {
                        bsdfpdf = curBSDF->pdf(queryEM);
                        float weight = BalanceHeuristic(float(1), lightpdf, float(1), bsdfpdf);
                        if(curBSDF->isDeltaBSDF())  weight = 1.0f;
                        if(bsdfpdf > 0.0f) {
                            Ld = (weight * f * Li * cosTerm) / lightpdf;
                            L += tp * Ld;
                        } else {
                            //cout << "bsdfpdf = " << bsdfpdf  << endl;
                            //cout << "f = " << f  << endl;
                        }
                    }
                }
            }

            //Material part
            BSDFQueryRecord queryMats = BSDFQueryRecord(its.toLocal(-pathRay.d), Vector3f(0.0f), EMeasure::ESolidAngle, sampler);

            Color3f fi =  curBSDF->sample(queryMats, sampler->next2D());
            bsdfpdf = curBSDF->pdf(queryMats);
            lightpdf = 0.0f;
            if(fi.maxCoeff() > 0.0f && fi.minCoeff() >= 0.0f) {
                if(bsdfpdf > 0.0f) {
                    Ray3f shadowRay(its.p, its.toWorld(queryMats.wo));
                    Intersection lightIsect;

                     if (scene->rayIntersect(shadowRay, lightIsect)) {
                         if(lightIsect.mesh->isEmitter()){
                            const Emitter* areaLightEMcur = lightIsect.mesh->getEmitter();
                            const areaLight* aEMcur = static_cast<const areaLight *> (areaLightEMcur);

                            Li = aEMcur->sampleL(-shadowRay.d, lightIsect.shFrame.n, lightIsect);
                            lightpdf = aEMcur->pdf(its.p, (lightIsect.p - its.p).normalized(), lightIsect.p, Normal3f(lightIsect.shFrame.n));
                         }
                     } else {
                         const Emitter* distantsDisk = scene->getDistantEmitter();
                         if(distantsDisk != nullptr ) {
                             //check if THIS is right!
                             Li = distantsDisk->sampleL(lightIsect.toWorld(queryMats.wo));
                             lightpdf = distantsDisk->pdf(Point3f(0.0f), wo, Point3f(0.0f), Normal3f(0.0f));
                         }
                     }
                     lightpdf /= float(nLights);
                     //calculate the weights
                     float weight = BalanceHeuristic(float(1), bsdfpdf, float(1), lightpdf);


                     //check if the lightcolor is not black
                     if(Li.maxCoeff() > 0.0f  && lightpdf > 0.0f ) {
                         //wo in my case the vector to the light
                         Ld = weight * Li * fi;
                         L += tp * Ld;
                     }
                }



                 tp *= fi;
            } else {
                break;
            }

            wo = its.toWorld(queryMats.wo);
            pathRay = Ray3f(its.p, wo);

            if (!scene->rayIntersect(pathRay, its)) {
                const Emitter* distantsDisk = scene->getDistantEmitter();
                if(distantsDisk != nullptr ) {
                    //sample the distant disk light
                    Vector3f d = pathRay.d;
                    L += tp * distantsDisk->sampleL(d);
                }


                break;
            }

            float maxCoeff = tp.maxCoeff();
            float q = std::min(0.99f, maxCoeff);
            if(q < sampler->next1D()){
                break;
            }
            tp /= q;
        }

        return L;

    }
Beispiel #28
0
std::vector<std::shared_ptr<Shape>> CreateNURBS(const Transform *o2w,
                                                const Transform *w2o,
                                                bool reverseOrientation,
                                                const ParamSet &params) {
    int nu = params.FindOneInt("nu", -1);
    if (nu == -1) {
        Error("Must provide number of control points \"nu\" with NURBS shape.");
        return std::vector<std::shared_ptr<Shape>>();
    }

    int uorder = params.FindOneInt("uorder", -1);
    if (uorder == -1) {
        Error("Must provide u order \"uorder\" with NURBS shape.");
        return std::vector<std::shared_ptr<Shape>>();
    }
    int nuknots, nvknots;
    const Float *uknots = params.FindFloat("uknots", &nuknots);
    if (uknots == nullptr) {
        Error("Must provide u knot vector \"uknots\" with NURBS shape.");
        return std::vector<std::shared_ptr<Shape>>();
    }

    if (nuknots != nu + uorder) {
        Error(
            "Number of knots in u knot vector %d doesn't match sum of "
            "number of u control points %d and u order %d.",
            nuknots, nu, uorder);
        return std::vector<std::shared_ptr<Shape>>();
    }

    Float u0 = params.FindOneFloat("u0", uknots[uorder - 1]);
    Float u1 = params.FindOneFloat("u1", uknots[nu]);

    int nv = params.FindOneInt("nv", -1);
    if (nv == -1) {
        Error("Must provide number of control points \"nv\" with NURBS shape.");
        return std::vector<std::shared_ptr<Shape>>();
    }

    int vorder = params.FindOneInt("vorder", -1);
    if (vorder == -1) {
        Error("Must provide v order \"vorder\" with NURBS shape.");
        return std::vector<std::shared_ptr<Shape>>();
    }

    const Float *vknots = params.FindFloat("vknots", &nvknots);
    if (vknots == nullptr) {
        Error("Must provide v knot vector \"vknots\" with NURBS shape.");
        return std::vector<std::shared_ptr<Shape>>();
    }

    if (nvknots != nv + vorder) {
        Error(
            "Number of knots in v knot vector %d doesn't match sum of "
            "number of v control points %d and v order %d.",
            nvknots, nv, vorder);
        return std::vector<std::shared_ptr<Shape>>();
    }

    Float v0 = params.FindOneFloat("v0", vknots[vorder - 1]);
    Float v1 = params.FindOneFloat("v1", vknots[nv]);

    bool isHomogeneous = false;
    int npts;
    const Float *P = (const Float *)params.FindPoint3f("P", &npts);
    if (!P) {
        P = params.FindFloat("Pw", &npts);
        if (!P) {
            Error(
                "Must provide control points via \"P\" or \"Pw\" parameter to "
                "NURBS shape.");
            return std::vector<std::shared_ptr<Shape>>();
        }
        if ((npts % 4) != 0) {
            Error(
                "Number of \"Pw\" control points provided to NURBS shape must "
                "be "
                "multiple of four");
            return std::vector<std::shared_ptr<Shape>>();
        }
        npts /= 4;
        isHomogeneous = true;
    }
    if (npts != nu * nv) {
        Error("NURBS shape was expecting %dx%d=%d control points, was given %d",
              nu, nv, nu * nv, npts);
        return std::vector<std::shared_ptr<Shape>>();
    }

    // Compute NURBS dicing rates
    int diceu = 30, dicev = 30;
    std::unique_ptr<Float[]> ueval(new Float[diceu]);
    std::unique_ptr<Float[]> veval(new Float[dicev]);
    std::unique_ptr<Point3f[]> evalPs(new Point3f[diceu * dicev]);
    std::unique_ptr<Normal3f[]> evalNs(new Normal3f[diceu * dicev]);
    int i;
    for (i = 0; i < diceu; ++i)
        ueval[i] = Lerp((float)i / (float)(diceu - 1), u0, u1);
    for (i = 0; i < dicev; ++i)
        veval[i] = Lerp((float)i / (float)(dicev - 1), v0, v1);

    // Evaluate NURBS over grid of points
    memset(evalPs.get(), 0, diceu * dicev * sizeof(Point3f));
    memset(evalNs.get(), 0, diceu * dicev * sizeof(Point3f));
    std::unique_ptr<Point2f[]> uvs(new Point2f[diceu * dicev]);

    // Turn NURBS into triangles
    std::unique_ptr<Homogeneous3[]> Pw(new Homogeneous3[nu * nv]);
    if (isHomogeneous) {
        for (int i = 0; i < nu * nv; ++i) {
            Pw[i].x = P[4 * i];
            Pw[i].y = P[4 * i + 1];
            Pw[i].z = P[4 * i + 2];
            Pw[i].w = P[4 * i + 3];
        }
    } else {
        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[(v * diceu + u)].x = ueval[u];
            uvs[(v * diceu + u)].y = veval[v];

            Vector3f dpdu, dpdv;
            Point3f pt = NURBSEvaluateSurface(uorder, uknots, nu, ueval[u],
                                              vorder, vknots, nv, veval[v],
                                              Pw.get(), &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] = Normal3f(Normalize(Cross(dpdu, dpdv)));
        }
    }

    // Generate points-polygons mesh
    int nTris = 2 * (diceu - 1) * (dicev - 1);
    std::unique_ptr<int[]> vertices(new int[3 * nTris]);
    int *vertp = vertices.get();
    // 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;

    return CreateTriangleMesh(o2w, w2o, reverseOrientation, nTris,
                              vertices.get(), nVerts, evalPs.get(), nullptr,
                              evalNs.get(), uvs.get(), nullptr);
}
Beispiel #29
0
const Distribution1D *SpatialLightDistribution::Lookup(const Point3f &p) const {
    ProfilePhase _(Prof::LightDistribLookup);
    ++nLookups;

    // Compute integer voxel coordinates for the given point |p| with
    // respect to the overall voxel grid.
    Vector3f offset = scene.WorldBound().Offset(p);  // offset in [0,1].
    Point3i pi;
    for (int i = 0; i < 3; ++i) pi[i] = int(offset[i] * nVoxels[i]);

    // Create the per-thread cache of sampling distributions if needed.
    LocalBucketHash *localVoxelDistribution =
        localVoxelDistributions[ThreadIndex].get();
    if (!localVoxelDistribution) {
        LOG(INFO) << "Created per-thread SpatialLightDistribution for thread" <<
            ThreadIndex;
        localVoxelDistribution = new LocalBucketHash;
        localVoxelDistributions[ThreadIndex].reset(localVoxelDistribution);
    }
    else {
        // Otherwise see if we have a sampling distribution for the voxel
        // that |p| is in already available in the local cache.
        auto iter = localVoxelDistribution->find(pi);
        if (iter != localVoxelDistribution->end())
            return iter->second;
    }

    // Now we need to either get the distribution from the shared hash
    // table (if another thread has already created it), or create it
    // ourselves and add it to the shared table.
    ProfilePhase __(Prof::LightDistribLookupL2);

    // First, compute a hash into the first-level hash table.
    size_t hash = std::hash<int>{}(pi[0] + nVoxels[0] * pi[1] +
                                   nVoxels[0] * nVoxels[1] * pi[2]);
    hash &= (nBuckets - 1);

    // Acquire the lock for the corresponding second-level hash table.
    std::lock_guard<std::mutex> lock(mutexes[hash]);
    // See if we can find it.
    auto iter = voxelDistribution[hash].find(pi);
    if (iter != voxelDistribution[hash].end()) {
        // Success. Add the pointer to the thread-specific hash table so
        // that we can look up this distribution more efficiently in the
        // future.
        (*localVoxelDistribution)[pi] = iter->second.get();
        return iter->second.get();
    }

    // We need to compute a new sampling distriibution for this voxel. Note
    // that we're holding the lock for the first-level hash table bucket
    // throughout the following; in general, we'd like to do the following
    // quickly so that other threads don't get held up waiting for that
    // lock (for this or other voxels that share it).
    ProfilePhase ___(Prof::LightDistribCreation);
    ++nCreated;
    ++nDistributions;

    // Compute the world-space bounding box of the voxel.
    Point3f p0(Float(pi[0]) / Float(nVoxels[0]),
               Float(pi[1]) / Float(nVoxels[1]),
               Float(pi[2]) / Float(nVoxels[2]));
    Point3f p1(Float(pi[0] + 1) / Float(nVoxels[0]),
               Float(pi[1] + 1) / Float(nVoxels[1]),
               Float(pi[2] + 1) / Float(nVoxels[2]));
    Bounds3f voxelBounds(scene.WorldBound().Lerp(p0),
                         scene.WorldBound().Lerp(p1));

    // Compute the sampling distribution. Sample a number of points inside
    // voxelBounds using a 3D Halton sequence; at each one, sample each
    // light source and compute a weight based on Li/pdf for the light's
    // sample (ignoring visibility between the point in the voxel and the
    // point on the light source) as an approximation to how much the light
    // is likely to contribute to illumination in the voxel.
    int nSamples = 128;
    std::vector<Float> lightContrib(scene.lights.size(), Float(0));
    for (int i = 0; i < nSamples; ++i) {
        Point3f po = voxelBounds.Lerp(Point3f(
            RadicalInverse(0, i), RadicalInverse(1, i), RadicalInverse(2, i)));
        Interaction intr(po, Normal3f(), Vector3f(), Vector3f(1, 0, 0),
                         0 /* time */, MediumInterface());

        // Use the next two Halton dimensions to sample a point on the
        // light source.
        Point2f u(RadicalInverse(3, i), RadicalInverse(4, i));
        for (size_t j = 0; j < scene.lights.size(); ++j) {
            Float pdf;
            Vector3f wi;
            VisibilityTester vis;
            Spectrum Li = scene.lights[j]->Sample_Li(intr, u, &wi, &pdf, &vis);
            if (pdf > 0) {
                // TODO: look at tracing shadow rays / computing beam
                // transmittance.  Probably shouldn't give those full weight
                // but instead e.g. have an occluded shadow ray scale down
                // the contribution by 10 or something.
                lightContrib[j] += Li.y() / pdf;
            }
        }
    }

    // We don't want to leave any lights with a zero probability; it's
    // possible that a light contributes to points in the voxel even though
    // we didn't find such a point when sampling above.  Therefore, compute
    // a minimum (small) weight and ensure that all lights are given at
    // least the corresponding probability.
    Float sumContrib =
        std::accumulate(lightContrib.begin(), lightContrib.end(), Float(0));
    Float avgContrib = sumContrib / (nSamples * lightContrib.size());
    Float minContrib = (avgContrib > 0) ? .001 * avgContrib : 1;
    for (size_t i = 0; i < lightContrib.size(); ++i) {
        VLOG(2) << "Voxel pi = " << pi << ", light " << i << " contrib = "
                << lightContrib[i];
        lightContrib[i] = std::max(lightContrib[i], minContrib);
    }
    LOG(INFO) << "Initialized light distribution in voxel pi= " <<  pi <<
        ", avgContrib = " << avgContrib;

    // Compute a sampling distribution from the accumulated
    // contributions.
    std::unique_ptr<Distribution1D> distrib(
        new Distribution1D(&lightContrib[0], lightContrib.size()));

    // Store a pointer to it in the per-thread cache for the future.
    (*localVoxelDistribution)[pi] = distrib.get();

    // Store the canonical unique_ptr for it in the global hash table so
    // other threads can use it.
    voxelDistribution[hash][pi] = std::move(distrib);

    return (*localVoxelDistribution)[pi];
}
Beispiel #30
0
Distribution1D *
SpatialLightDistribution::ComputeDistribution(Point3i pi) const {
    ProfilePhase _(Prof::LightDistribCreation);
    ++nCreated;
    ++nDistributions;

    // Compute the world-space bounding box of the voxel corresponding to
    // |pi|.
    Point3f p0(Float(pi[0]) / Float(nVoxels[0]),
               Float(pi[1]) / Float(nVoxels[1]),
               Float(pi[2]) / Float(nVoxels[2]));
    Point3f p1(Float(pi[0] + 1) / Float(nVoxels[0]),
               Float(pi[1] + 1) / Float(nVoxels[1]),
               Float(pi[2] + 1) / Float(nVoxels[2]));
    Bounds3f voxelBounds(scene.WorldBound().Lerp(p0),
                         scene.WorldBound().Lerp(p1));

    // Compute the sampling distribution. Sample a number of points inside
    // voxelBounds using a 3D Halton sequence; at each one, sample each
    // light source and compute a weight based on Li/pdf for the light's
    // sample (ignoring visibility between the point in the voxel and the
    // point on the light source) as an approximation to how much the light
    // is likely to contribute to illumination in the voxel.
    int nSamples = 128;
    std::vector<Float> lightContrib(scene.lights.size(), Float(0));
    for (int i = 0; i < nSamples; ++i) {
        Point3f po = voxelBounds.Lerp(Point3f(
            RadicalInverse(0, i), RadicalInverse(1, i), RadicalInverse(2, i)));
        Interaction intr(po, Normal3f(), Vector3f(), Vector3f(1, 0, 0),
                         0 /* time */, MediumInterface());

        // Use the next two Halton dimensions to sample a point on the
        // light source.
        Point2f u(RadicalInverse(3, i), RadicalInverse(4, i));
        for (size_t j = 0; j < scene.lights.size(); ++j) {
            Float pdf;
            Vector3f wi;
            VisibilityTester vis;
            Spectrum Li = scene.lights[j]->Sample_Li(intr, u, &wi, &pdf, &vis);
            if (pdf > 0) {
                // TODO: look at tracing shadow rays / computing beam
                // transmittance.  Probably shouldn't give those full weight
                // but instead e.g. have an occluded shadow ray scale down
                // the contribution by 10 or something.
                lightContrib[j] += Li.y() / pdf;
            }
        }
    }

    // We don't want to leave any lights with a zero probability; it's
    // possible that a light contributes to points in the voxel even though
    // we didn't find such a point when sampling above.  Therefore, compute
    // a minimum (small) weight and ensure that all lights are given at
    // least the corresponding probability.
    Float sumContrib =
        std::accumulate(lightContrib.begin(), lightContrib.end(), Float(0));
    Float avgContrib = sumContrib / (nSamples * lightContrib.size());
    Float minContrib = (avgContrib > 0) ? .001 * avgContrib : 1;
    for (size_t i = 0; i < lightContrib.size(); ++i) {
        VLOG(2) << "Voxel pi = " << pi << ", light " << i << " contrib = "
                << lightContrib[i];
        lightContrib[i] = std::max(lightContrib[i], minContrib);
    }
    LOG(INFO) << "Initialized light distribution in voxel pi= " <<  pi <<
        ", avgContrib = " << avgContrib;

    // Compute a sampling distribution from the accumulated contributions.
    return new Distribution1D(&lightContrib[0], lightContrib.size());
}