コード例 #1
0
ファイル: bsdf.py プロジェクト: neodyme60/raypy
    def Sample_f(self, woW: Vector3d, bsdfSample: BSDFSample, BxDFTypeFlags: int)->(Vector3d, float, int, Spectrum):

        pdf = 0.0
        wiW = Vector3d()

        BxDFSampledTypeFlags = BxDFType.BSDF_NONE

        # Choose which _BxDF_ to sample
        matchingComps = self.NumComponents(BxDFTypeFlags)
        if matchingComps == 0:
            BxDFSampledTypeFlags = BxDFType.BSDF_NONE
            return wiW, pdf, BxDFSampledTypeFlags, Spectrum(0.0)

#        which = min(Floor2Int(bsdfSample.uComponent * matchingComps), matchingComps-1)
        which = min(int(bsdfSample.uComponent * matchingComps), matchingComps-1)

        bxdf = None

        count = which
        for b in self.bxdfs:
            if b.MatchesFlags(BxDFTypeFlags) and count == 0:
                bxdf = b
                break
            count -= 1

        # Sample chosen _BxDF_
        wo = self.WorldToLocal(woW)
#        if isinstance(bxdf, Microfacet):
#            print("dd")
        wi, pdf, f = bxdf.Sample_f(wo, bsdfSample.uDir)
        if pdf == 0.0:
            BxDFSampledTypeFlags = BxDFType.BSDF_NONE
            return wiW, pdf, BxDFSampledTypeFlags, Spectrum(0.0)

        if BxDFSampledTypeFlags != BxDFType.BSDF_NONE:
            BxDFSampledTypeFlags = bxdf.bxdf_types
        wiW.Set(self.LocalToWorld(wi))

        # Compute overall PDF with all matching _BxDF_s
        if not (bxdf.bxdf_types & BxDFType.BSDF_SPECULAR) and matchingComps > 1:
            for b in self.bxdfs:
                if b != bxdf and b.MatchesFlags(BxDFTypeFlags):
                    pdf += b.get_Pdf(wo, wi)
        if matchingComps > 1:
            pdf /= matchingComps

        # Compute value of BSDF for sampled direction
        if not bxdf.bxdf_types & BxDFType.BSDF_SPECULAR:
            f = Spectrum(0.0)
            if Vector3d.dot(wiW, self.ng) * Vector3d.dot(woW, self.ng) > 0: # ignore BTDFs
                flags = BxDFTypeFlags & ~BxDFType.BSDF_TRANSMISSION
            else: # ignore BRDFs
                flags = BxDFTypeFlags & ~BxDFType.BSDF_REFLECTION
            for i in range(len(self.bxdfs)):
                if self.bxdfs[i].MatchesFlags(flags):
                    f += self.bxdfs[i].get_f(wo, wi)
        return wiW, pdf, BxDFSampledTypeFlags, f
コード例 #2
0
    def Pdf(self, wo: Vector3d, wi: Vector3d) -> float:
        from core.bxdf import AbsCosTheta

        wh = (wo + wi).get_normalized()
        costheta = AbsCosTheta(wh)
        # Compute PDF for $\wi$ from Blinn distribution
        blinn_pdf = ((self.exponent + 1.0) * math.pow(costheta, self.exponent)) / (
            2.0 * CONST_PI * 4.0 * Vector3d.dot(wo, wh))
        if Vector3d.dot(wo, wh) <= 0.0:
            blinn_pdf = 0.0
        return blinn_pdf
コード例 #3
0
ファイル: bsdf.py プロジェクト: neodyme60/raypy
 def f(self, woW: Vector3d, wiW: Vector3d, BxDFTypeFlags: int)->Spectrum:
     wi = self.WorldToLocal(wiW)
     wo = self.WorldToLocal(woW)
     if Vector3d.dot(wiW, self.ng) * Vector3d.dot(woW, self.ng) > 0: # ignore BTDFs
         flags = BxDFTypeFlags & ~BxDFType.BSDF_TRANSMISSION
     else:  # ignore BRDFs
         flags = BxDFTypeFlags & ~BxDFType.BSDF_REFLECTION
     f = Spectrum(0.0)
     for i in range(len(self.bxdfs)):
         if self.bxdfs[i].MatchesFlags(flags):
             f += self.bxdfs[i].get_f(wo, wi)
     return f
コード例 #4
0
ファイル: plane.py プロジェクト: neodyme60/raypy
    def get_is_intersected(self, ray) -> bool:
        # ray from word_space_to_object_space
        ray_o = ray * self.worldToObject

        denominator = Vector3d.dot(self.normal, ray_o.direction)
        if math.fabs(denominator) < CONST_EPSILON:
            return False

        o = Vector3d.create_from_point3d(ray_o.origin)

        t = -(Vector3d.dot(self.normal, o) + self.distance) / denominator
        if ray_o.min_t <= t < ray_o.max_t:
            return True

        return False
コード例 #5
0
ファイル: sphere.py プロジェクト: neodyme60/raypy
    def Sample2(self, p: Point3d, u: (float, float), Ns: Normal) -> Point3d:
        # Compute coordinate system for sphere sampling
        Pcenter = Point3d(0, 0, 0) * self.objectToWorld
        wc = (Pcenter - p).get_normalized()
        wcX, wcY = Transform.create_coordinateSystem(wc)

        # Sample uniformly on sphere if $\pt{}$ is inside it
        if (p - Pcenter).get_length_squared() - self.radius * self.radius < 1e-40:
            return self.Sample1(u, Ns)

        # Sample sphere uniformly inside subtended cone
        sinThetaMax2 = self.radius * self.radius / (p - Pcenter).get_length_squared()
        cosThetaMax = math.sqrt(max(0.0, 1.0 - sinThetaMax2))
        dgSphere = DifferentialGeometry()

        thit = 1.0

        r = Ray(p, UniformSampleCone2(u, cosThetaMax, wcX, wcY, wc), 1e-3)
        b, t = self.get_intersection(r, dgSphere)
#        if not b:
        #bug
        thit = Vector3d.dot(Pcenter - p, r.direction.get_normalized())
        ps = r.get_at(thit)

        nn = (ps - Pcenter).get_normalized()
        Ns.Set(nn)
        # if (ReverseOrientation) *ns *= -1.f;
        return ps
コード例 #6
0
ファイル: ray.py プロジェクト: neodyme60/raypy
 def __init__(self, origin: Point3d=Point3d(0.0, 0.0, 0.0), direction:Vector3d=Vector3d.get_forward(),
              min_t: float=0.0, max_t: float=infinity_max_f, time: float=0.0, depth: int=0):
     self.origin = origin
     self.direction = direction
     self.depth = depth
     self.max_t = max_t
     self.min_t = min_t
     self.time = time
コード例 #7
0
ファイル: plane.py プロジェクト: neodyme60/raypy
    def get_intersection(self, ray: Ray, dg: DifferentialGeometry) -> (bool, float):

        # ray from word_space_to_object_space
        ray_o = ray * self.worldToObject

        denominator = Vector3d.dot(self.normal, ray_o.direction)
        if math.fabs(denominator) < CONST_EPSILON:
            return False, 0.0

        o = Vector3d.create_from_point3d(ray_o.origin)

        t = -(Vector3d.dot(self.normal, o) + self.distance) / denominator
        if ray_o.min_t <= t < ray_o.max_t:
            dg.point = ray_o.get_at(t) * self.objectToWorld
            dg.normal = self.normal  * self.objectToWorld
            dg.shape = self
            return True, t
        return False, 0.0
コード例 #8
0
ファイル: integrator.py プロジェクト: neodyme60/raypy
def EstimateDirect(scene: Scene, renderer: Renderer, light: Light, p: Point3d, n: Normal, wo: Vector3d,
                   time: float, bsdf: BSDF, lightSample: LightSample, bsdfSample: BSDFSample,
                   BxDFTypeFlag: int) -> Spectrum:
    Ld = Spectrum(0.0)

    visibility = VisibilityTester()
    wi, Li, lightPdf = light.Sample_L1(p, lightSample, time, visibility)

    if lightPdf > 0.0 and not Li.get_is_black():
            f = bsdf.f(wo, wi, BxDFTypeFlag)
            if not f.get_is_black() and visibility.Unoccluded(scene):
    # Add light's contribution to reflected radiance
     #Li *= visibility.Transmittance(scene, renderer, None)
                inv_lightPdf = 1.0 / lightPdf
                if light.get_is_delta_light():
                    Ld += f * Li * math.fabs(Vector3d.dot(wi, n)) * inv_lightPdf
                else:
                    bsdfPdf = bsdf.get_Pdf(wo, wi, BxDFTypeFlag)
                    weight = PowerHeuristic(1, lightPdf, 1, bsdfPdf)
                    Ld += f * Li * math.fabs(Vector3d.dot(wi, n)) * weight * inv_lightPdf

    # Sample BSDF with multiple importance sampling
    if not light.get_is_delta_light():
        wi, bsdfPdf, sampledType, f = bsdf.Sample_f(wo, bsdfSample, BxDFTypeFlag)
        if not f.get_is_black() and bsdfPdf > 0.0:
            weight = 1.0
            if not (BxDFTypeFlag & BxDFType.BSDF_SPECULAR):
                lightPdf = light.get_pdf(p, wi)
                if lightPdf == 0.0:
                    return Ld
                weight = PowerHeuristic(1, bsdfPdf, 1, lightPdf)
            # Add light contribution from BSDF sampling
            lightIsect = Intersection()
            Li = Spectrum(0.0)
            ray = Ray(p, wi, 1e-3, infinity_max_f, time)
            if scene.get_intersection(ray, lightIsect):
                if lightIsect.primitive.GetAreaLight() == light:
                    Li = lightIsect.Le(-wi)
            else:
                Li = light.Le(ray)
            if not Li.get_is_black():
                Li *= 1.0  #todo renderer.Transmittance(scene, ray, None)
                Ld += f * Li * math.fabs(Vector3d.dot(wi, n)) * weight / bsdfPdf
    return Ld
コード例 #9
0
ファイル: triangle.py プロジェクト: neodyme60/raypy
    def Area(self):
        # Get triangle vertices in _p1_, _p2_, and _p3_
        p1_index = self.mesh.index[self.triangle_index*3 + 0]
        p2_index = self.mesh.index[self.triangle_index*3 + 2]
        p3_index = self.mesh.index[self.triangle_index*3 + 1]

        p1 = self.mesh.points[p1_index]
        p2 = self.mesh.points[p2_index]
        p3 = self.mesh.points[p3_index]

        return 0.5 * Vector3d.cross(p2-p1, p3-p1).get_length()
コード例 #10
0
    def Sample_f(self, wo: Vector3d, u: (float, float)) -> (Vector3d, float):
        from core.bxdf import SameHemisphere
        # Compute sampled half-angle vector $\wh$ for Blinn distribution
        costheta = math.pow(u[0], 1.0 / (self.exponent + 1))
        sintheta = math.sqrt(max(0.0, 1.0 - costheta * costheta))
        phi = u[1] * 2.0 * CONST_PI
        wh = SphericalDirection1(sintheta, costheta, phi)
        if not SameHemisphere(wo, wh):
            wh = -wh

        # Compute incident direction by reflecting about $\wh$
        uu = wh * Vector3d.dot(wo, wh)
        wi = -wo + (uu * 2.0)

        # Compute PDF for $\wi$ from Blinn distribution
        blinn_pdf = ((self.exponent + 1.0) * math.pow(costheta, self.exponent)) / (
            2.0 * CONST_PI * 4.0 * Vector3d.dot(wo, wh))
        if Vector3d.dot(wo, wh) <= 0.0:
            blinn_pdf = 0.0
        return wi, blinn_pdf
コード例 #11
0
ファイル: diffuse_area_light.py プロジェクト: neodyme60/raypy
    def Sample_L2(self, scene: Scene, ls: LightSample, u: (float, float), n: Normal, ray: Ray, time: float) -> (
            Spectrum, float):
        origin = self.shapeSet.Sample2(ls, n)
        direction = UniformSampleSphere(u)
        if Vector3d.dot(direction, n) < 0.0:
            direction *= -1.0

        ray.Set(Ray(origin, direction, 1e-3, infinity_max_f, time))

        Ls = self.L(origin, n, direction)
        pdf = self.shapeSet.Pdf1(origin) * CONST_INV_TWOPI
        return ray, Ls, pdf
コード例 #12
0
ファイル: bxdf.py プロジェクト: neodyme60/raypy
 def get_f(self, wo: Vector3d, wi: Vector3d)->Spectrum:
     cosThetaO = AbsCosTheta(wo)
     cosThetaI = AbsCosTheta(wi)
     if cosThetaI == 0.0 or cosThetaO == 0.0:
         return Spectrum(0.0)
     wh = wi + wo
     if wh.x == 0.0 and wh.y == 0.0 and wh.z == 0.0:
         return Spectrum(0.0)
     wh = wh.get_normalized()
     cosThetaH = Vector3d.dot(wi, wh)
     F = self.fresnel.Evaluate(cosThetaH)
     return self.r * self.distribution.D(wh) * self.G(wo, wi, wh) * F / (4.0 * cosThetaI * cosThetaO)
コード例 #13
0
ファイル: test_transform.py プロジェクト: neodyme60/raypy
    def test__look_at(self):
        from core.transform import Transform
        from maths.point3d import Point3d
        from maths.vector3d import Vector3d

        pos = Point3d(1.0, 0.0, 0.0)
        at = Point3d(1.0, 0.0, 1.0)
        up = Vector3d.get_up()

        t = Transform.create_look_at(pos, at, up)

        foo = Vector3d(1.0, 0.0, 0.0)

        self.assertEqual(foo * t, Vector3d(0.0, 0.0, 0.0))
コード例 #14
0
ファイル: shape.py プロジェクト: neodyme60/raypy
    def Pdf2(self, p: Point3d, wi: Vector3d)->float:
        # Intersect sample ray with area light geometry
        dgLight = DifferentialGeometry()
        ray = Ray(p, wi, 1e-3)
        ray.depth = -1 # temporary hack to ignore alpha mask
        b, thit =self.get_intersection(ray, dgLight)
        if not b:
            return 0.0

        # Convert light sample weight to solid angle measure
        pdf = (p - ray.get_at(thit)).get_length_squared() / (math.fabs(Vector3d.dot(dgLight.normal, -wi) * self.Area()))
        if math.isinf(pdf):
            pdf = 0.0
        return pdf
コード例 #15
0
ファイル: sphere.py プロジェクト: neodyme60/raypy
    def internal_solve(self, ray_l: Ray, ray_w: Ray) -> (float, float):

        o = Vector3d.create_from_point3d(ray_l.origin)

        a = Vector3d.dot(ray_l.direction, ray_l.direction)
        b = 2.0 * Vector3d.dot(ray_l.direction, o)
        c = Vector3d.dot(o, o) - self.radius_squared

        # Solve quadratic equation for _t_ values
        t0, t1 = maths.tools.get_solve_quadratic(a, b, c)
        if t0 is None and t1 is None:
            return None, None

        # Compute intersection distance along ray
        if t0 > ray_w.max_t or t1 < ray_w.min_t:
            return None, None

        thit = t0
        if t0 < ray_w.min_t:
            thit = t1
        if thit > ray_w.max_t:
            return None, None
        return t0, t1
コード例 #16
0
ファイル: triangle.py プロジェクト: neodyme60/raypy
    def Sample1(self, u: (float, float), n: Normal) -> Point3d:
        b1, b2 = UniformSampleTriangle(u)
        # Get triangle vertices in _p1_, _p2_, and _p3_
        p1_index = self.mesh.index[self.triangle_index*3 + 0]
        p2_index = self.mesh.index[self.triangle_index*3 + 2]
        p3_index = self.mesh.index[self.triangle_index*3 + 1]

        p1 = self.mesh.points[p1_index]
        p2 = self.mesh.points[p2_index]
        p3 = self.mesh.points[p3_index]

        p = p1 * b1 + p2 * b2 + p3 * (1.0 - b1 - b2)
        n.Set(Normal.create_from_vector3d(Vector3d.cross(p2-p1, p3-p1)).get_normalized())
#todo        if (ReverseOrientation) *Ns *= -1.f;
        return p
コード例 #17
0
ファイル: texture_mapping.py プロジェクト: neodyme60/raypy
    def get_map(self, dg: DifferentialGeometry):
        vec = dg.point - Point3d(0,0,0)
        s = self.ds + Vector3d.dot(vec, self.vs)
        t = self.dt + Vector3d.dot(vec, self.vt)
        dsdx = Vector3d.dot(dg.dpdx, self.vs)
        dtdx = Vector3d.dot(dg.dpdx, self.vt)
        dsdy = Vector3d.dot(dg.dpdy, self.vs)
        dtdy = Vector3d.dot(dg.dpdy, self.vt)

        return s,t ,dsdx, dtdx, dsdy, dtdy
コード例 #18
0
    def Li(self, scene: Scene, renderer: Renderer, ray: Ray, intersection: Intersection, sample: Sample)->Spectrum:

        occlusion = 0
        intersection.ray_epsilon = infinity_max_f

        bsdf = intersection.get_bsdf(ray)
        p = bsdf.dgShading.point

        n = maths.tools.get_face_forward(intersection.differentialGeometry.normal, -ray.direction)

        for i in range(self.samples_count):
            w = maths.tools.get_uniform_sample_sphere(random(), random())

            if Vector3d.dot(w, n) < 0.0:
                w = -w

            r = Ray(p, w, 0.01, self.max_distance)
            if scene.get_is_intersected(r):
                occlusion += 1

        return Spectrum(1.0-(float(occlusion) / float(self.samples_count)))
コード例 #19
0
ファイル: triangle.py プロジェクト: neodyme60/raypy
    def get_intersection(self, ray: Ray, dg: DifferentialGeometry) -> (bool, float):
        p1_index = self.mesh.index[self.triangle_index*3 + 0]
        p2_index = self.mesh.index[self.triangle_index*3 + 2]
        p3_index = self.mesh.index[self.triangle_index*3 + 1]

        p1 = self.mesh.points[p1_index]
        p2 = self.mesh.points[p2_index]
        p3 = self.mesh.points[p3_index]

        e1 = p2 - p1
        e2 = p3 - p1
        s1 = Vector3d.cross(ray.direction, e2)
        divisor = Vector3d.dot(s1, e1)

        if divisor == 0.0:
            return False, 0.0
        invDivisor = 1.0 / divisor

        # Compute first barycentric coordinate
        d = ray.origin - p1
        b1 = Vector3d.dot(d, s1) * invDivisor
        if b1 < 0.0 or b1 > 1.0:
            return False, 0.0

        #Compute second barycentric coordinate
        s2 = Vector3d.cross(d, e1)
        b2 = Vector3d.dot(ray.direction, s2) * invDivisor
        if b2 < 0.0 or (b1 + b2) > 1.0:
            return False, 0.0

        # Compute _t_ to intersection point
        t = Vector3d.dot(e2, s2) * invDivisor
        if t < ray.min_t or t > ray.max_t:
            return False, 0.0

        dg.shape = self
        dg.point = ray.get_at(t)
        dg.normal = Normal.create_from_vector3d( Vector3d.cross(e1, e2).get_normalized())

        return True, t
コード例 #20
0
ファイル: triangle.py プロジェクト: neodyme60/raypy
    def get_is_intersected(self, ray) -> bool:
        p1_index = self.mesh.index[self.triangle_index*3 + 0]
        p2_index = self.mesh.index[self.triangle_index*3 + 2]
        p3_index = self.mesh.index[self.triangle_index*3 + 1]

        p1 = self.mesh.points[p1_index]
        p2 = self.mesh.points[p2_index]
        p3 = self.mesh.points[p3_index]

        e1 = p2 - p1
        e2 = p3 - p1
        s1 = Vector3d.cross(ray.direction, e2)
        divisor = Vector3d.dot(s1, e1)

        if divisor == 0.0:
            return False
        invDivisor = 1.0 / divisor

        # Compute first barycentric coordinate
        d = ray.origin - p1
        b1 = Vector3d.dot(d, s1) * invDivisor
        if b1 < 0.0 or b1 > 1.0:
            return False

        #Compute second barycentric coordinate
        s2 = Vector3d.cross(d, e1)
        b2 = Vector3d.dot(ray.direction, s2) * invDivisor
        if b2 < 0.0 or (b1 + b2) > 1.0:
            return False

        # Compute _t_ to intersection point
        t = Vector3d.dot(e2, s2) * invDivisor
        if t < ray.min_t or t > ray.max_t:
            return False

        return True
コード例 #21
0
ファイル: path.py プロジェクト: neodyme60/raypy
    def Li(self, scene, renderer: Renderer, r: Ray, intersection: Intersection, sample: Sample) -> Spectrum:
        # Declare common path integration variables
        pathThroughput = Spectrum(1.0)
        L = Spectrum(0.0)
        ray = deepcopy(r)
        specularBounce = False
        localIsect = Intersection()
        isectp = intersection
        bounces = 0
        while True:
            # Possibly add emitted light at path vertex
            if bounces == 0 or specularBounce:
                L += pathThroughput * isectp.Le(-ray.direction)

            # Sample illumination from lights to find path contribution
            bsdf = isectp.get_bsdf(ray)
            p = bsdf.dgShading.point
            n = bsdf.dgShading.normal
            wo = -ray.direction
            if bounces < self.maxDepth:
                L += pathThroughput * UniformSampleOneLight(scene, renderer, p, n, wo, ray.time, bsdf, sample,
                                                            self.lightSampleOffsets[bounces],
                                                            self.bsdfSampleOffsets[bounces],
                                                            self.lightNumOffset[bounces])
            else:
                L += pathThroughput * UniformSampleOneLight(scene, renderer, p, n, wo, ray.time, bsdf, sample)

            # Sample BSDF to get new path direction

            # Get _outgoingBSDFSample_ for sampling new path direction
            if bounces < self.maxDepth:
                outgoingBSDFSample = BSDFSample.create_from_sample(sample, self.pathSampleOffsets[bounces], 0)
            else:
                outgoingBSDFSample = BSDFSample.create_from_random()

            wi, pdf, flags, f = bsdf.Sample_f(wo, outgoingBSDFSample, BxDFType.BSDF_ALL)
            if f.get_is_black() or pdf == 0.0:
                break

            specularBounce = (flags & BxDFType.BSDF_SPECULAR) != 0
            pathThroughput *= f * math.fabs(Vector3d.dot(wi, n)) / pdf
            ray = Ray(p, wi, 0.01, ray.max_t)

            # Possibly terminate the path
            if bounces > 3:
                continueProbability = min(0.5, pathThroughput.y())
                if random() > continueProbability:
                    break
                pathThroughput /= continueProbability

            if bounces == self.maxDepth:
                break

            # Find next vertex of path
            if not scene.get_intersection(ray, localIsect):
                if specularBounce:
                    for i in range(scene.lights.size()):
                        L += pathThroughput * scene.lights[i].get_Le(ray)
                break
            # pathThroughput *= renderer->Transmittance(scene, ray, NULL, rng, arena);
            isectp = localIsect

            bounces += 1

        return L
コード例 #22
0
ファイル: bsdf.py プロジェクト: neodyme60/raypy
 def WorldToLocal(self, v: Vector3d)->Vector3d:
     return Vector3d(Vector3d.dot(v, self.sn), Vector3d.dot(v, self.tn), Vector3d.dot(v, self.nn))
コード例 #23
0
ファイル: bxdf.py プロジェクト: neodyme60/raypy
 def G(self, wo: Vector3d, wi: Vector3d, wh: Vector3d):
     NdotWh = AbsCosTheta(wh)
     NdotWo = AbsCosTheta(wo)
     NdotWi = AbsCosTheta(wi)
     WOdotWh = abs(Vector3d.dot(wo, wh))
     return min(1.0, min((2.0 * NdotWh * NdotWo / WOdotWh), 2.0 * NdotWh * NdotWi / WOdotWh))
コード例 #24
0
ファイル: plane.py プロジェクト: neodyme60/raypy
    def __init__(self, o2w, w2o):
        super().__init__(o2w, w2o)

        self.normal = Vector3d.get_up()
        self.distance = 0.0
コード例 #25
0
ファイル: test_vector3d.py プロジェクト: neodyme60/raypy
 def test_dot(self):
     foo1 = Vector3d(1.0, 2.0, 3.0)
     foo2 = Vector3d(10.0, 20.0, 30.0)
     foo3 = Vector3d.dot(foo1,foo2)
     self.assertEqual(foo3, foo1.x * foo2.x + foo1.y * foo2.y + foo1.z * foo2.z)
コード例 #26
0
ファイル: diffuse_area_light.py プロジェクト: neodyme60/raypy
 def L(self, p: Point3d, n: Normal, w: Vector3d) -> Spectrum:
     if Vector3d.dot(n, w) > 0.0:
         return self.Lemit
     return Spectrum(0.0)