pysdic.compute_brdf_ward#
- compute_brdf_ward(surface_points, surface_normals, light_positions, observer_positions, parameters, *, default=0.0)[source]#
Compute the Bidirectional Reflectance Distribution Function (BRDF) using Ward’s model for given parameters \((\rho_d, \rho_s, \sigma)\) (ie. diffuse, specular, and roughness).
The BRDF describes how light is reflected at an opaque surface. Ward’s model accounts for both diffuse and specular reflection components. The equation for the BRDF in Ward’s model is given by:
\[\text{BRDF}(\theta_i, \theta_o) = \frac{\rho_d}{\pi} + \frac{\rho_s}{4 \pi \sigma^2 \sqrt{\cos(\theta_i) \cos(\theta_o)}} \exp\left(-\frac{\tan^2(\delta)}{\sigma^2}\right)\]where:
\(\theta_i = \arccos(\mathbf{I} \cdot \mathbf{N})\) is the angle between the input light direction and the surface normal.
\(\theta_o = \arccos(\mathbf{O} \cdot \mathbf{N})\) is the angle between the observer direction and the surface normal.
\(\delta = \arccos(\mathbf{H} \cdot \mathbf{N})\) is the angle between the surface normal and the half-vector (the bisector between the input and observer directions).
\(\rho_d\) is the diffuse reflection coefficient.
\(\rho_s\) is the specular reflection coefficient.
\(\sigma\) is the surface roughness parameter.
\[\delta = \arccos(\mathbf{H} \cdot \mathbf{N}) \quad \text{where} \quad \mathbf{H} = \frac{\mathbf{I} + \mathbf{O}}{||\mathbf{I} + \mathbf{O}||}\]Note that \((A \cdot B)\) denotes the positive dot product between vectors \(A\) and \(B\) given by \(\max(0, A^T B)\). If the input light direction \(\mathbf{I}\) or the observer direction \(\mathbf{O}\) is below the surface (i.e., \(\theta_i > \frac{\pi}{2}\) or \(\theta_o > \frac{\pi}{2}\)), the BRDF is defined to be zero.
Note
The inputs arrays will be converted to
numpy.float64for computation. The output array will be also of typenumpy.float64.- Parameters:
surface_points (ArrayLike) – Array of shape \((N_p, 3)\) or \((3,)\) representing the coordinates of \(N_p\) surface points in 3-dimensional space. If a 1D array is provided, it is treated as a single surface point \((1, 3)\).
surface_normals (ArrayLike) – Array of shape \((N_p, 3)\) or \((3,)\) representing the normal vectors at each surface point. Must have the same shape as
surface_points.light_positions (ArrayLike) – Array of shape \((N_l, 3)\) or \((3,)\) representing the position(s) of the light source(s). If a 1D array is provided, it is treated as a single light source \((1, 3)\).
observer_positions (ArrayLike) – Array of shape \((N_o, 3)\) or \((3,)\) representing the position(s) of the observer(s). If a 1D array is provided, it is treated as a single observer \((1, 3)\).
parameters (ArrayLike) – Array of shape \((N_{\text{models}}, 3)\) or \((3,)\) representing the BRDF parameters \((\rho_d, \rho_s, \sigma)\) for each model. Diffuse coefficient \(\rho_d\) must be non-negative. Specular coefficient \(\rho_s\) must be non-negative. Roughness \(\sigma\) must be positive. If a 1D array is provided, it is treated as a single set of parameters \((1, 3)\).
default (Real, optional) – Default value to use for invalid BRDF computations (e.g., when input or observer directions are below the surface). By default,
0.0is used.
- Returns:
brdf – Array of shape \((N_p, N_l, N_o, N_{\text{models}})\) representing the BRDF values at each \((N_p)\) surface point for each \((N_l)\) light source and each \((N_o)\) observer position for each \((N_{\text{models}})\) set of parameters.
- Return type:
- Raises:
TypeError – If the inputs cannot be converted to floating-point numpy arrays.
ValueError – If input arrays do not have the correct dimensions or if coefficients are not valid numbers.
Examples
Basic usage with single point, light source, and observer:
1import numpy 2form pysdic import compute_brdf_ward 3 4surface_points = numpy.array([ 5 [0.0, 0.0, 0.0] 6 [1.0, 0.0, 0.0] 7]) 8 9surface_normals = numpy.array([ 10 [0.0, 0.0, 1.0] 11 [0.0, 0.0, 1.0] 12]) 13 14light_positions = numpy.array([10.0, 0.0, 10.0]) 15 16observer_positions = numpy.array([0.0, 0.0, 10.0]) 17 18brdf_values = compute_brdf_ward( 19 surface_points, 20 surface_normals, 21 light_positions, 22 observer_positions, 23 parameters=numpy.array([0.5, 0.5, 0.2]) 24) 25 26print(f"BRDF values (Shape: {brdf_values.shape}):") 27print(brdf_values)
BRDF values (Shape: (2, 1, 1, 1)): [[[0.06366198]] [[0.06366198]]]