
.. DO NOT EDIT.
.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY.
.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE:
.. "../../docs/source/_gallery/example_photometric_rendering_on_cylinder.py"
.. LINE NUMBERS ARE GIVEN BELOW.

.. only:: html

    .. note::
        :class: sphx-glr-download-link-note

        :ref:`Go to the end <sphx_glr_download_.._.._docs_source__gallery_example_photometric_rendering_on_cylinder.py>`
        to download the full example code.

.. rst-class:: sphx-glr-example-title

.. _sphx_glr_.._.._docs_source__gallery_example_photometric_rendering_on_cylinder.py:


.. _example_photometric_rendering_on_cylinder:

Rendering Photometric Properties on a Cylinder
=====================================================================================

.. contents:: Table of Contents
   :local:
   :depth: 1
   :backlinks: top

This example demonstrates how to use the Bouguer law and Ward's BRDF model
from the ``pysdic`` library to render photometric properties on a cylindrical mesh.

.. seealso::

    - :func:`pysdic.compute_bouguer_law` - Official documentation for the Bouguer law function.
    - :func:`pysdic.compute_brdf_ward` - Official documentation for Ward's BRDF function.

.. note::

    Other implemented BRDF models can be use in a similar way, such as Beckmann's model
    using the :func:`pysdic.compute_brdf_beckmann` function.
    

.. GENERATED FROM PYTHON SOURCE LINES 28-33

Define some points on a cylinder surface
--------------------------------------------------------------------------------

Construct some points on a cylinder surface using cylindrical coordinates.
The cylinder is defined by its radius and height range.

.. GENERATED FROM PYTHON SOURCE LINES 33-60

.. code-block:: Python


    import numpy

    theta_min = -numpy.pi
    theta_max = numpy.pi
    height_min = -1.0
    height_max = 1.0
    radius = 1.0
    nt = 1000  # Number of points along the circumference
    nh = 100  # Number of points along the height

    theta = numpy.linspace(theta_min, theta_max, nt)
    height = numpy.linspace(height_min, height_max, nh)
    theta_grid, height_grid = numpy.meshgrid(theta, height)

    # points
    x = radius * numpy.cos(theta_grid)
    y = radius * numpy.sin(theta_grid)
    z = height_grid
    points_coordinates = numpy.stack([x.flatten(), y.flatten(), z.flatten()], axis=1)  # (N_points, 3)

    # normals
    normals_x = numpy.cos(theta_grid)
    normals_y = numpy.sin(theta_grid)
    normals_z = numpy.zeros_like(normals_x)
    points_normals = numpy.stack([normals_x.flatten(), normals_y.flatten(), normals_z.flatten()], axis=1)  # (N_points, 3)








.. GENERATED FROM PYTHON SOURCE LINES 61-69

Define light source and view directions
--------------------------------------------------------------------------------

Define the light source direction and observer position for the photometric rendering.

For this example, we will use two light sources positioned at different locations.
We also define the observer position and the objective is the render the appearance of the cylinder
as seen from this position.

.. GENERATED FROM PYTHON SOURCE LINES 69-77

.. code-block:: Python


    light_positions = numpy.array([
        [1.0, 1.0, 0.0],
        [1.0, -1.0, 0.0]
    ])  # (N_light_sources, 3)

    observer_positions = numpy.array([5.0, 0.0, 0.0])  # (3,)








.. GENERATED FROM PYTHON SOURCE LINES 78-88

Compute photometric properties using Bouguer law and Ward's BRDF model
--------------------------------------------------------------------------------

Use the ``compute_bouguer_law`` and ``compute_brdf_ward`` functions to compute
the photometric properties at the defined points on the cylinder surface.

The first one is the ratio between irradiance :math:`E` at source intensity :math:`I`, the second one is the BRDF ratio between outgoing radiance :math:`L_o` and incoming irradiance :math:`E`,
using 3 parameters: diffuse reflectance :math:`\rho_d`, specular reflectance :math:`\rho_s`, and surface roughness :math:`\sigma` (See the official documentation for more details).

Assuming a given intensity for the light sources :math:`I = 1.0`, the image brightness is proportional to the incoming radiance :math:`L_o` on the camera sensor.

.. GENERATED FROM PYTHON SOURCE LINES 88-117

.. code-block:: Python


    from pysdic import compute_bouguer_law, compute_brdf_ward

    bouger_law_ratio = compute_bouguer_law(
        surface_points=points_coordinates,
        surface_normals=points_normals,
        light_positions=light_positions,
    ) # (N_points, N_light_sources)
    print(f"Bouguer law ratio shape: {bouger_law_ratio.shape}, min: {bouger_law_ratio.min()}, max: {bouger_law_ratio.max()}")

    brdf_ward_values = compute_brdf_ward(
        surface_points=points_coordinates,
        surface_normals=points_normals,
        light_positions=light_positions,
        observer_positions=observer_positions,
        parameters = [0.1, 0.1, 0.5]  # rho_d, rho_s, sigma
    ) # (N_points, N_light_sources, N_observers, N_models)

    # Here N_observers = 1 and N_models = 1, so we can squeeze these dimensions
    brdf_ward_values = brdf_ward_values[:, :, 0, 0]  # (N_points, N_light_sources)
    print(f"BRDF Ward values shape: {brdf_ward_values.shape}, min: {brdf_ward_values.min()}, max: {brdf_ward_values.max()}")

    # Compute the radiance
    radiance = bouger_law_ratio * brdf_ward_values  # (N_points, N_light_sources)

    # Sum the contributions from all light sources
    total_radiance = numpy.sum(radiance, axis=1)  # (N_points,)
    print(f"Total radiance shape: {total_radiance.shape}, min: {total_radiance.min()}, max: {total_radiance.max()}")





.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    Bouguer law ratio shape: (100000, 2), min: 0.0, max: 5.822776397789505
    /home/fdahe241/Programs/pysdic/docs/source/../../pysdic/core/photometric_operations.py:396: RuntimeWarning: divide by zero encountered in divide
      brdf = (rho_d / numpy.pi) + (rho_s / (4 * numpy.pi * sigma**2 * numpy.sqrt(cos_theta_i * cos_theta_0))) * \
    /home/fdahe241/Programs/pysdic/docs/source/../../pysdic/core/photometric_operations.py:396: RuntimeWarning: invalid value encountered in multiply
      brdf = (rho_d / numpy.pi) + (rho_s / (4 * numpy.pi * sigma**2 * numpy.sqrt(cos_theta_i * cos_theta_0))) * \
    BRDF Ward values shape: (100000, 2), min: 0.0, max: 0.07336558608523565
    Total radiance shape: (100000,), min: 0.0, max: 0.318519420048296




.. GENERATED FROM PYTHON SOURCE LINES 118-123

Visualize the rendered photometric properties on the cylinder surface
--------------------------------------------------------------------------------

Lets build a Point Cloud object to visualize the rendered photometric properties
on the cylinder surface using pyvista.

.. GENERATED FROM PYTHON SOURCE LINES 123-138

.. code-block:: Python


    from pysdic import PointCloud

    pc = PointCloud(points_coordinates)
    pc['radiance'] = total_radiance
    pc.visualize(
        property='radiance', 
        property_cmap='plasma', 
        point_size=5,
        camera_position=[10.0, 0.0, 0.0],
        camera_view_up=[0, 0, 1],
        camera_focal_point=[0, 0, 0],
        title="Photometric Rendering on Cylinder Surface"
    )




.. image-sg:: /_gallery/images/sphx_glr_example_photometric_rendering_on_cylinder_001.png
   :alt: example photometric rendering on cylinder
   :srcset: /_gallery/images/sphx_glr_example_photometric_rendering_on_cylinder_001.png
   :class: sphx-glr-single-img






.. rst-class:: sphx-glr-timing

   **Total running time of the script:** (0 minutes 0.361 seconds)


.. _sphx_glr_download_.._.._docs_source__gallery_example_photometric_rendering_on_cylinder.py:

.. only:: html

  .. container:: sphx-glr-footer sphx-glr-footer-example

    .. container:: sphx-glr-download sphx-glr-download-jupyter

      :download:`Download Jupyter notebook: example_photometric_rendering_on_cylinder.ipynb <example_photometric_rendering_on_cylinder.ipynb>`

    .. container:: sphx-glr-download sphx-glr-download-python

      :download:`Download Python source code: example_photometric_rendering_on_cylinder.py <example_photometric_rendering_on_cylinder.py>`

    .. container:: sphx-glr-download sphx-glr-download-zip

      :download:`Download zipped: example_photometric_rendering_on_cylinder.zip <example_photometric_rendering_on_cylinder.zip>`


.. only:: html

 .. rst-class:: sphx-glr-signature

    `Gallery generated by Sphinx-Gallery <https://sphinx-gallery.github.io>`_
