class_docstr: Per pixel lighting - the lighting model is applied using the interpolated
  coordinates and normals for each pixel. The blending function returns the
  color aggregated using splats from surrounding pixels (see [0]).
  
  To use the default values, simply initialize the shader with the desired
  device e.g.
  
  .. code-block::
  
      shader = SplatterPhongShader(device=torch.device("cuda:0"))
  
  [0] Cole, F. et al., "Differentiable Surface Rendering via Non-differentiable
      Sampling".
class_docstr_tok: ["Per","pixel","lighting","-","the","lighting","model","is","applied","using","the","interpolated","coordinates","and","normals","for","each","pixel",".","The","blending","function","returns","the","color","aggregated","using","splats","from","surrounding","pixels","(","see","[","0","]",")",".","To","use","the","default","values",",","simply","initialize","the","shader","with","the","desired","device","e.g",".","..","code-block",":",":","shader","=","SplatterPhongShader","(","device=torch.device","(","``","cuda:0","''",")",")","[","0","]","Cole",",","F.","et","al.",",","``","Differentiable","Surface","Rendering","via","Non-differentiable","Sampling","''","."]
code: def forward(
      self, fragments: Fragments, meshes: Meshes, **kwargs
  ) -> torch.Tensor:
      cameras = super()._get_cameras(**kwargs)
      texels = meshes.sample_textures(fragments)
      lights = kwargs.get("lights", self.lights)
      materials = kwargs.get("materials", self.materials)
  
      colors, pixel_coords_cameras = _phong_shading_with_pixels(
          meshes=meshes,
          fragments=fragments.detach(),
          texels=texels,
          lights=lights,
          cameras=cameras,
          materials=materials,
      )
  
      if not self.splatter_blender:
          # Init only once, to avoid re-computing constants.
          N, H, W, K, _ = colors.shape
          self.splatter_blender = SplatterBlender(
              (N, H, W, K), colors.device
          )
  
      blend_params = kwargs.get("blend_params", self.blend_params)
      self.check_blend_params(blend_params)
  
      images = self.splatter_blender(
          colors,
          pixel_coords_cameras,
          cameras,
          fragments.pix_to_face < 0,
          kwargs.get("blend_params", self.blend_params),
      )
  
      return images
  
imports: import warnings
  from typing import Optional
  import torch
  import torch.nn
  from ...common.datatypes import Device
  from ...structures.meshes import Meshes
  from ..blending import BlendParams, hard_rgb_blend, sigmoid_alpha_blend, softmax_rgb_blend
  from ..lighting import PointLights
  from ..materials import Materials
  from ..splatter_blend import SplatterBlender
  from ..utils import TensorProperties
  from .rasterizer import Fragments
  from .shading import _phong_shading_with_pixels, flat_shading, gouraud_shading, phong_shading
label_desc: Use image node_id 3 for calling the SplatterPhongShader obj's underlying member method code with example usage: obj.forward(fragments, meshes) and returns: images