class_docstr: A framebuffer holding rasterized values required for deferred shading.
  
  Tensors are expected to have shape [batch, height, width, channels].
  
  For now, the fields are specialized for triangle rendering. Other primitives
  may be supported in the future.
  
  Immutable once created. Uses cached_property to avoid creating redundant
  tf ops when properties are accessed multiple times.
class_docstr_tok: ["A","framebuffer","holding","rasterized","values","required","for","deferred","shading",".","Tensors","are","expected","to","have","shape","[","batch",",","height",",","width",",","channels","]",".","For","now",",","the","fields","are","specialized","for","triangle","rendering",".","Other","primitives","may","be","supported","in","the","future",".","Immutable","once","created",".","Uses","cached_property","to","avoid","creating","redundant","tf","ops","when","properties","are","accessed","multiple","times","."]
code: def __post_init__(self):
      # Checks that all buffers have rank and same shape up to the
      # number of channels.
      values = [
          self.barycentrics.value,
          self.triangle_id,
          self.vertex_ids,
          self.foreground_mask,
      ]
      values += [v.value for k, v in self.attributes.items()]
  
      ranks = [len(v.shape) for v in values]
      shapes = [tf.shape(v) for v in values]
      if not all(rank == ranks[0] for rank in ranks):
          raise ValueError(
              f"Expected all inputs to have the same rank, but found {shapes}"
          )
  
      same_as_first = [
          tf.reduce_all(tf.equal(shapes[0][:-1], s[:-1]))
          for s in shapes[1:]
      ]
      all_same_as_first = tf.reduce_all(same_as_first)
      tf.debugging.assert_equal(
          all_same_as_first,
          True,
          message="Expected all input shapes to be the same "
          "(up to channels), but found: "
          + ", ".join([str(s) for s in shapes]),
      )
  
file_path: graphics/tensorflow_graphics/rendering/framebuffer.py
imports: import dataclasses
  from typing import Dict, Optional
  import tensorflow
label_desc: Use image node_id 1 for calling the Framebuffer obj's underlying member method code with example usage: obj.__post_init__() without return types