Skip to content

Refactor custom surface properties using facets #38

@danieljfarrell

Description

@danieljfarrell

Surface reflection is currently handled with a delegate object approach. A node owns a geometry, the geometry owns material, the material owns a surface object, the surface object owns the delegate.

lsc = Node(
    name="LSC",
    geometry=Box(
      (l, w, d),
      material=Material(
          refractive_index=1.5, components=[],
          surface=Surface(delegate=OptionalMirrorAndSolarCell(self))
      ),
  ),
  parent=world,
)

Here OptionalMirrorAndSolarCell is an object that handles all surface interactions for the full surface area of the object. As you can see from the naming of the delegate it seems to have too much responsibility! The code for the delegate is similarly complicated. The chief problem is that the level of abstraction is too high.

Instead of providing one object to handle custom surface interactions we could supply multiple Facet objects which opt-in an arbitrarily defined sub-surface of the object. For example, for a the box geometry this could be full top surface or a part of the top surface.

lsc = Node(
    name="LSC",
    geometry=Box(
        (l, w, d),
        material=Material(
            refractive_index=1.5, components=...,
        ),
        facets=[
            Facet(
                label="left",
                where=lambda point, geometry: np.isclose(point[0], -geometry.size[0]/2, atol=EPS_ZERO),
                kind=SolarCell()
            ),
        ]
    ),
    parent=world,
)

Define a node with Fresnel reflections based on the material's refractive,

lsc = Node(
    name="LSC",
    geometry=Box(
        (l, w, d),
        material=Material(
            refractive_index=1.5, components=...,
        ),
    ),
    parent=world,
)

Modify so that the left surface has a solar cell,

lsc = Node(
    name="LSC",
    geometry=Box(
        (l, w, d),
        material=Material(
            refractive_index=1.5, components=...,
        ),
        facets=[
            Facet(
                label="left",
                where=lambda point, geometry: np.isclose(point[0], -geometry.size[0]/2, atol=EPS_ZERO),
                kind=SolarCell()
            ),
        ]
    ),
    parent=world,
)

Modify so that the bottom surface has a mirror,

lsc = Node(
    name="LSC",
    geometry=Box(
        (l, w, d),
        material=Material(
            refractive_index=1.5, components=...,
        ),
        facets=[
            Facet(
                label="left",
                where=lambda point, geometry: np.isclose(point[0], -geometry.size[0]/2, atol=EPS_ZERO),
                kind=SolarCell()
            ),
            Facet(
                label="left",
                where=lambda point, geometry: np.isclose(point[0], -geometry.size[0]/2, atol=EPS_ZERO),
                kind=Mirror()
            ),
        ]
    ),
    parent=world,
)

Modify so that the top surface has a coating with spectral dependence,

lsc = Node(
    name="LSC",
    geometry=Box(
        (l, w, d),
        material=Material(
            refractive_index=1.5, components=...,
        ),
        facets=[
            Facet(
                label="left",
                where=lambda point, geometry: np.isclose(point[0], -geometry.size[0]/2, atol=EPS_ZERO),
                kind=SolarCell()
            ),
            Facet(
                label="bottom",
                where=lambda point, geometry: np.isclose(point[2], -geometry.size[2]/2, atol=EPS_ZERO),
                kind=Mirror()
            ),
            Facet(
                label="top",
                where=lambda point, geometry: np.isclose(point[2],  geometry.size[2]/2, atol=EPS_ZERO),
                kind=Coating()
            ),
        ]
    ),
    parent=world,
)

The Facet object has a user defined label. The where parameter is a function which the facet will call to determine if a point is on the facet and therefore should be handled or not. The kind parameter is an object which contains custom reflection, transmission, scattering, diffraction or absorption information.

Here the "kind" object (need a better name) must be provided with simply an angle (with respect to the surface normal at the hit point) and a wavelength. This way it can be very simple -- almost just a look-up function of angular and spectral reflectivity. The facet object is responsible for handling any coordinate system transformations and providing the data to the "kind".

Metadata

Metadata

Labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions