Get distance to camera with shaders and buffers

If anyone is ever trying to replicate this, the working shaders and code can be found below.

Vertex Shader

#version 150

// Uniform inputs
uniform mat4 p3d_ProjectionMatrix;
uniform mat4 p3d_ModelViewMatrix;

// Vertex inputs
in vec4 p3d_Vertex;

// Vertex outputs
out float distanceToCamera;

void main() {
  vec4 cs_position = p3d_ModelViewMatrix * p3d_Vertex;
  distanceToCamera = length(cs_position.xyz);
  gl_Position = p3d_ProjectionMatrix * cs_position;
}

Fragment Shader

#version 150

in float distanceToCamera;
out vec4 fragColor;

void main() {
  fragColor = vec4(distanceToCamera, 0, 0, 1);
}

Code

import os
import numpy as np
from direct.showbase.ShowBase import ShowBase
from panda3d.core import FrameBufferProperties, WindowProperties
from panda3d.core import GraphicsOutput, GraphicsPipe
from panda3d.core import Texture, PerspectiveLens, Shader
from panda3d.core import ConfigVariableString, ConfigVariableBool, Filename, ConfigVariableManager
import matplotlib.pyplot as plt


class SceneSimulator(ShowBase):

  def __init__(self):
    ShowBase.__init__(self)

    # set up texture and graphics buffer
    window_props = WindowProperties.size(1920, 1080)
    frame_buffer_props = FrameBufferProperties()
    frame_buffer_props.set_float_color(True)
    frame_buffer_props.set_rgba_bits(32, 0, 0, 0)
    buffer = self.graphicsEngine.make_output(self.pipe,
      f'Buffer',
      -2,
      frame_buffer_props,
      window_props,
      GraphicsPipe.BFRefuseWindow,    # don't open a window
      self.win.getGsg(),
      self.win
    )
    texture = Texture()
    buffer.add_render_texture(texture, GraphicsOutput.RTMCopyRam)
    buffer.set_clear_color_active(True)
    buffer.set_clear_color((10, 0, 0, 0))
    self.buffer = buffer

    # place a box in the scene
    x, y, side_length = 0, 0, 1
    box = self.loader.loadModel("models/box")
    box.reparentTo(self.render)
    box.setScale(side_length)
    box.setPos(x - side_length / 2, y - side_length / 2, 0)

    # set up camera
    lens = PerspectiveLens()
    lens.set_film_size(1920, 1080)
    lens.set_fov(45, 30)
    pos = (0, 6, 4)
    camera = self.make_camera(buffer, lens=lens, camName=f'Camera')
    camera.reparent_to(self.render)
    camera.set_pos(*pos)
    camera.look_at(box)
    self.camera = camera

    # load shaders
    vert_path = '/Users/michael/mit/sli/scene/scene/glsl_simple.vert'
    frag_path = '/Users/michael/mit/sli/scene/scene/glsl_simple.frag'
    custom_shader = Shader.load(Shader.SL_GLSL, vertex=vert_path, fragment=frag_path)

    self.render.set_shader(custom_shader)

  def render_image(self) -> np.ndarray:
    self.graphics_engine.render_frame()
    texture = self.buffer.get_texture()
    data = texture.get_ram_image()
    frame = np.frombuffer(data, np.float32)
    frame.shape = (texture.getYSize(), texture.getXSize())
    frame = np.flipud(frame)
    return frame


if __name__ == '__main__':
  simulator = SceneSimulator()
  image = simulator.render_image()
  plt.imshow(image)
  plt.colorbar()
  plt.show()
2 Likes