Class: Doom::Render::ZBufferRenderer

Inherits:
Renderer
  • Object
show all
Defined in:
lib/doom/render/zbuffer_renderer.rb

Overview

Experimental renderer path. It deliberately reuses the proven BSP visibility and texture sampling code while replacing the visibility target with a full, per-pixel depth buffer. This makes it possible to add mesh rasterisation and ray traced passes without changing game logic.

Defined Under Namespace

Classes: Light

Constant Summary collapse

MAX_DYNAMIC_LIGHTS =
8
LIGHT_LEVELS =
16

Constants inherited from Renderer

Renderer::SKY_TEXTUREMID, Renderer::SKY_XSCALE, Renderer::SKY_YSCALE

Instance Attribute Summary collapse

Attributes inherited from Renderer

#animations, #colormap, #combat, #cos_angle, #flats, #framebuffer, #hidden_things, #leveltime, #map, #monster_ai, #palette, #player_angle, #player_x, #player_y, #player_z, #players, #sin_angle, #skip_background_fill, #sprites, #textures, #view_player, #wad

Instance Method Summary collapse

Methods inherited from Renderer

#apply_view, #build_native_renderer, #check_plane, #draw_all_visplanes, #draw_floor_ceiling_background, #draw_sky_plane, #draw_span, #fill_uncovered_with_sector, #find_or_create_visplane, #native_wall_pass, #precompute_column_data, #render_visplane_spans, #set_player, #sprite_diagnostics

Constructor Details

#initializeZBufferRenderer

Returns a new instance of ZBufferRenderer.



16
17
18
19
20
# File 'lib/doom/render/zbuffer_renderer.rb', line 16

def initialize(...)
  super
  @depth_buffer = Array.new(SCREEN_WIDTH * SCREEN_HEIGHT, Float::INFINITY)
  @light_lut = build_light_lut
end

Instance Attribute Details

#depth_bufferObject (readonly)

Returns the value of attribute depth_buffer.



10
11
12
# File 'lib/doom/render/zbuffer_renderer.rb', line 10

def depth_buffer
  @depth_buffer
end

Instance Method Details

#draw_wall_column_ex(x, y1, y2, texture_name, dist, light_level, tex_col, tex_y_start, scale, world_top) ⇒ Object

Opaque walls are the first geometry producer for the new depth target. BSP clipping remains the visibility algorithm for this initial stage; later raster passes can consume the per-pixel depth values written here.



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/doom/render/zbuffer_renderer.rb', line 31

def draw_wall_column_ex(x, y1, y2, texture_name, dist, light_level,
                        tex_col, tex_y_start, scale, world_top)
  clip_top = @ceiling_clip[x] + 1
  clip_bottom = @floor_clip[x] - 1
  first = [[y1, clip_top, 0].max, SCREEN_HEIGHT].min
  last = [[y2, clip_bottom, SCREEN_HEIGHT - 1].min, -1].max

  super

  return if first > last || texture_name.nil? || texture_name.empty? || texture_name == '-'
  return unless @textures[anim_texture(texture_name)]

  # Reconstruct the world-space wall hit. Each dynamic source casts a
  # visibility ray to it; one-sided linedefs produce hard shadows.
  ray_distance = dist * @column_distscale[x]
  hit_x = @player_x + (ray_distance * @column_cos[x])
  hit_y = @player_y - (ray_distance * @column_sin[x])
  visible_lights = @dynamic_lights.select do |light|
    dx = light.x - hit_x
    dy = light.y - hit_y
    (dx * dx) + (dy * dy) < light.radius * light.radius && light_visible?(hit_x, hit_y, light)
  end

  y = first
  while y <= last
    offset = (y * SCREEN_WIDTH) + x
    @depth_buffer[offset] = dist if dist < @depth_buffer[offset]
    unless visible_lights.empty?
      world_z = world_top - ((y - (HALF_HEIGHT - ((world_top - @player_z) * scale))) / scale)
      intensity = visible_lights.sum do |light|
        distance = Math.sqrt(((light.x - hit_x)**2) + ((light.y - hit_y)**2) + ((light.z - world_z)**2))
        distance < light.radius ? light.energy * ((1.0 - (distance / light.radius))**2) : 0.0
      end
      level = (intensity * (LIGHT_LEVELS - 1)).to_i.clamp(0, LIGHT_LEVELS - 1)
      @framebuffer[offset] = @light_lut[level][@framebuffer[offset]] if level.positive?
    end
    y += 1
  end
end

#render_frameObject



22
23
24
25
26
# File 'lib/doom/render/zbuffer_renderer.rb', line 22

def render_frame
  @depth_buffer.fill(Float::INFINITY)
  @dynamic_lights = collect_dynamic_lights
  super
end