|
14 | 14 | from ..cameras import OpenGLPerspectiveCameras
|
15 | 15 | from ..lighting import PointLights
|
16 | 16 | from ..materials import Materials
|
17 |
| -from .shading import gourad_shading, phong_shading |
| 17 | +from .shading import flat_shading, gourad_shading, phong_shading |
18 | 18 | from .texturing import interpolate_texture_map, interpolate_vertex_colors
|
19 | 19 |
|
20 | 20 | # A Shader should take as input fragments from the output of rasterization
|
|
26 | 26 | # - blend colors across top K faces per pixel.
|
27 | 27 |
|
28 | 28 |
|
29 |
| -class PhongShader(nn.Module): |
| 29 | +class HardPhongShader(nn.Module): |
30 | 30 | """
|
31 |
| - Per pixel lighting. Apply the lighting model using the interpolated coords |
32 |
| - and normals for each pixel. |
| 31 | + Per pixel lighting - the lighting model is applied using the interpolated |
| 32 | + coordinates and normals for each pixel. The blending function hard assigns |
| 33 | + the color of the closest face for each pixel. |
33 | 34 |
|
34 | 35 | To use the default values, simply initialize the shader with the desired
|
35 | 36 | device e.g.
|
36 | 37 |
|
37 | 38 | .. code-block::
|
38 | 39 |
|
39 |
| - shader = PhongShader(device=torch.device("cuda:0")) |
| 40 | + shader = HardPhongShader(device=torch.device("cuda:0")) |
40 | 41 | """
|
41 | 42 |
|
42 | 43 | def __init__(self, device="cpu", cameras=None, lights=None, materials=None):
|
@@ -70,17 +71,74 @@ def forward(self, fragments, meshes, **kwargs) -> torch.Tensor:
|
70 | 71 | return images
|
71 | 72 |
|
72 | 73 |
|
73 |
| -class GouradShader(nn.Module): |
| 74 | +class SoftPhongShader(nn.Module): |
74 | 75 | """
|
75 |
| - Per vertex lighting. Apply the lighting model to the vertex colors and then |
76 |
| - interpolate using the barycentric coordinates to get colors for each pixel. |
| 76 | + Per pixel lighting - the lighting model is applied using the interpolated |
| 77 | + coordinates and normals for each pixel. The blending function returns the |
| 78 | + soft aggregated color using all the faces per pixel. |
77 | 79 |
|
78 | 80 | To use the default values, simply initialize the shader with the desired
|
79 | 81 | device e.g.
|
80 | 82 |
|
81 | 83 | .. code-block::
|
82 | 84 |
|
83 |
| - shader = GouradShader(device=torch.device("cuda:0")) |
| 85 | + shader = SoftPhongShader(device=torch.device("cuda:0")) |
| 86 | + """ |
| 87 | + |
| 88 | + def __init__( |
| 89 | + self, |
| 90 | + device="cpu", |
| 91 | + cameras=None, |
| 92 | + lights=None, |
| 93 | + materials=None, |
| 94 | + blend_params=None, |
| 95 | + ): |
| 96 | + super().__init__() |
| 97 | + self.lights = ( |
| 98 | + lights if lights is not None else PointLights(device=device) |
| 99 | + ) |
| 100 | + self.materials = ( |
| 101 | + materials if materials is not None else Materials(device=device) |
| 102 | + ) |
| 103 | + self.cameras = ( |
| 104 | + cameras |
| 105 | + if cameras is not None |
| 106 | + else OpenGLPerspectiveCameras(device=device) |
| 107 | + ) |
| 108 | + self.blend_params = ( |
| 109 | + blend_params if blend_params is not None else BlendParams() |
| 110 | + ) |
| 111 | + |
| 112 | + def forward(self, fragments, meshes, **kwargs) -> torch.Tensor: |
| 113 | + texels = interpolate_vertex_colors(fragments, meshes) |
| 114 | + cameras = kwargs.get("cameras", self.cameras) |
| 115 | + lights = kwargs.get("lights", self.lights) |
| 116 | + materials = kwargs.get("materials", self.materials) |
| 117 | + colors = phong_shading( |
| 118 | + meshes=meshes, |
| 119 | + fragments=fragments, |
| 120 | + texels=texels, |
| 121 | + lights=lights, |
| 122 | + cameras=cameras, |
| 123 | + materials=materials, |
| 124 | + ) |
| 125 | + images = softmax_rgb_blend(colors, fragments, self.blend_params) |
| 126 | + return images |
| 127 | + |
| 128 | + |
| 129 | +class HardGouradShader(nn.Module): |
| 130 | + """ |
| 131 | + Per vertex lighting - the lighting model is applied to the vertex colors and |
| 132 | + the colors are then interpolated using the barycentric coordinates to |
| 133 | + obtain the colors for each pixel. The blending function hard assigns |
| 134 | + the color of the closest face for each pixel. |
| 135 | +
|
| 136 | + To use the default values, simply initialize the shader with the desired |
| 137 | + device e.g. |
| 138 | +
|
| 139 | + .. code-block:: |
| 140 | +
|
| 141 | + shader = HardGouradShader(device=torch.device("cuda:0")) |
84 | 142 | """
|
85 | 143 |
|
86 | 144 | def __init__(self, device="cpu", cameras=None, lights=None, materials=None):
|
@@ -112,12 +170,69 @@ def forward(self, fragments, meshes, **kwargs) -> torch.Tensor:
|
112 | 170 | return images
|
113 | 171 |
|
114 | 172 |
|
115 |
| -class TexturedPhongShader(nn.Module): |
| 173 | +class SoftGouradShader(nn.Module): |
| 174 | + """ |
| 175 | + Per vertex lighting - the lighting model is applied to the vertex colors and |
| 176 | + the colors are then interpolated using the barycentric coordinates to |
| 177 | + obtain the colors for each pixel. The blending function returns the |
| 178 | + soft aggregated color using all the faces per pixel. |
| 179 | +
|
| 180 | + To use the default values, simply initialize the shader with the desired |
| 181 | + device e.g. |
| 182 | +
|
| 183 | + .. code-block:: |
| 184 | +
|
| 185 | + shader = SoftGouradShader(device=torch.device("cuda:0")) |
| 186 | + """ |
| 187 | + |
| 188 | + def __init__( |
| 189 | + self, |
| 190 | + device="cpu", |
| 191 | + cameras=None, |
| 192 | + lights=None, |
| 193 | + materials=None, |
| 194 | + blend_params=None, |
| 195 | + ): |
| 196 | + super().__init__() |
| 197 | + self.lights = ( |
| 198 | + lights if lights is not None else PointLights(device=device) |
| 199 | + ) |
| 200 | + self.materials = ( |
| 201 | + materials if materials is not None else Materials(device=device) |
| 202 | + ) |
| 203 | + self.cameras = ( |
| 204 | + cameras |
| 205 | + if cameras is not None |
| 206 | + else OpenGLPerspectiveCameras(device=device) |
| 207 | + ) |
| 208 | + self.blend_params = ( |
| 209 | + blend_params if blend_params is not None else BlendParams() |
| 210 | + ) |
| 211 | + |
| 212 | + def forward(self, fragments, meshes, **kwargs) -> torch.Tensor: |
| 213 | + cameras = kwargs.get("cameras", self.cameras) |
| 214 | + lights = kwargs.get("lights", self.lights) |
| 215 | + materials = kwargs.get("materials", self.materials) |
| 216 | + pixel_colors = gourad_shading( |
| 217 | + meshes=meshes, |
| 218 | + fragments=fragments, |
| 219 | + lights=lights, |
| 220 | + cameras=cameras, |
| 221 | + materials=materials, |
| 222 | + ) |
| 223 | + images = softmax_rgb_blend(pixel_colors, fragments, self.blend_params) |
| 224 | + return images |
| 225 | + |
| 226 | + |
| 227 | +class TexturedSoftPhongShader(nn.Module): |
116 | 228 | """
|
117 | 229 | Per pixel lighting applied to a texture map. First interpolate the vertex
|
118 | 230 | uv coordinates and sample from a texture map. Then apply the lighting model
|
119 | 231 | using the interpolated coords and normals for each pixel.
|
120 | 232 |
|
| 233 | + The blending function returns the soft aggregated color using all |
| 234 | + the faces per pixel. |
| 235 | +
|
121 | 236 | To use the default values, simply initialize the shader with the desired
|
122 | 237 | device e.g.
|
123 | 238 |
|
@@ -167,7 +282,52 @@ def forward(self, fragments, meshes, **kwargs) -> torch.Tensor:
|
167 | 282 | return images
|
168 | 283 |
|
169 | 284 |
|
170 |
| -class SilhouetteShader(nn.Module): |
| 285 | +class HardFlatShader(nn.Module): |
| 286 | + """ |
| 287 | + Per face lighting - the lighting model is applied using the average face |
| 288 | + position and the face normal. The blending function hard assigns |
| 289 | + the color of the closest face for each pixel. |
| 290 | +
|
| 291 | + To use the default values, simply initialize the shader with the desired |
| 292 | + device e.g. |
| 293 | +
|
| 294 | + .. code-block:: |
| 295 | +
|
| 296 | + shader = HardFlatShader(device=torch.device("cuda:0")) |
| 297 | + """ |
| 298 | + |
| 299 | + def __init__(self, device="cpu", cameras=None, lights=None, materials=None): |
| 300 | + super().__init__() |
| 301 | + self.lights = ( |
| 302 | + lights if lights is not None else PointLights(device=device) |
| 303 | + ) |
| 304 | + self.materials = ( |
| 305 | + materials if materials is not None else Materials(device=device) |
| 306 | + ) |
| 307 | + self.cameras = ( |
| 308 | + cameras |
| 309 | + if cameras is not None |
| 310 | + else OpenGLPerspectiveCameras(device=device) |
| 311 | + ) |
| 312 | + |
| 313 | + def forward(self, fragments, meshes, **kwargs) -> torch.Tensor: |
| 314 | + texels = interpolate_vertex_colors(fragments, meshes) |
| 315 | + cameras = kwargs.get("cameras", self.cameras) |
| 316 | + lights = kwargs.get("lights", self.lights) |
| 317 | + materials = kwargs.get("materials", self.materials) |
| 318 | + colors = flat_shading( |
| 319 | + meshes=meshes, |
| 320 | + fragments=fragments, |
| 321 | + texels=texels, |
| 322 | + lights=lights, |
| 323 | + cameras=cameras, |
| 324 | + materials=materials, |
| 325 | + ) |
| 326 | + images = hard_rgb_blend(colors, fragments) |
| 327 | + return images |
| 328 | + |
| 329 | + |
| 330 | +class SoftSilhouetteShader(nn.Module): |
171 | 331 | """
|
172 | 332 | Calculate the silhouette by blending the top K faces for each pixel based
|
173 | 333 | on the 2d euclidean distance of the centre of the pixel to the mesh face.
|
|
0 commit comments