Added distance attenuation and 1D depth buffer.

This commit is contained in:
2017-11-03 22:11:34 -04:00
parent c489c5e0d0
commit 682881ec83

View File

@@ -10,9 +10,7 @@ TITLE = "Py Caster"
FPS = 30 FPS = 30
SCREEN_SIZE = (800, 600) SCREEN_SIZE = (800, 600)
FILL_COLOR = (0, 0, 0) FILL_COLOR = (0, 0, 0)
FOG_COLOR = (128, 128, 128) FAR = 5.0
FOG_NEAR = 1.0
FOG_FAR = 5.0
TOLERANCE = 0.000001 TOLERANCE = 0.000001
FLOOR_TEXTURE = "Textures/goldlites.jpg" FLOOR_TEXTURE = "Textures/goldlites.jpg"
CEIL_TEXTURE = "Textures/brownstone.jpg" CEIL_TEXTURE = "Textures/brownstone.jpg"
@@ -219,14 +217,17 @@ class Plane3d(object):
def main(): def main():
global FOV, ANGLE_INCREMENT global FOV, ANGLE_INCREMENT
# Local variables. # Local variables.
done = False done = False
player_pos = vec2(0.0, 0.0) player_pos = vec2(0.0, 0.0)
player_dir = vec2(-1.0, 0.0) player_dir = vec2(-1.0, 0.0)
plane = vec2(0.0, 0.66) plane = vec2(0.0, 0.66)
arrow_keys = {pygame.K_UP: False, pygame.K_DOWN: False, pygame.K_LEFT: False, pygame.K_RIGHT: False}
# Update global variables
FOV = 2.0 * math.atan((plane.length() / player_dir.length())) * RAD2DEG FOV = 2.0 * math.atan((plane.length() / player_dir.length())) * RAD2DEG
ANGLE_INCREMENT = FOV / float(FB_SIZE[0]) ANGLE_INCREMENT = FOV / float(FB_SIZE[0])
arrow_keys = {pygame.K_UP: False, pygame.K_DOWN: False, pygame.K_LEFT: False, pygame.K_RIGHT: False}
# Initialize Pygame. # Initialize Pygame.
pygame.init() pygame.init()
@@ -296,6 +297,7 @@ def main():
# Render walls. # Render walls.
angle = -FOV / 2.0 angle = -FOV / 2.0
depth_buffer = [0 for x in xrange(FB_SIZE[0])]
for i in xrange(FB_SIZE[0]): for i in xrange(FB_SIZE[0]):
# Generate camera ray # Generate camera ray
camera_x = 2.0 * (float(i) / float(FB_SIZE[0])) - 1; camera_x = 2.0 * (float(i) / float(FB_SIZE[0])) - 1;
@@ -305,7 +307,6 @@ def main():
c = None c = None
p = None p = None
h = 0 h = 0
darken = None
# Check each wall for an intersection # Check each wall for an intersection
for l in walls: for l in walls:
intersection = l.intersect(r) intersection = l.intersect(r)
@@ -315,15 +316,7 @@ def main():
d = intersection.d d = intersection.d
c = l.get_tex_column(intersection.tc) c = l.get_tex_column(intersection.tc)
p = intersection.p p = intersection.p
df = (vec2(1.0, 0.0).dot(l.n) + 1.0) / 2.0 depth_buffer[i] = d
if df < 0.25:
darken = 32
elif df >= 0.25 and df < 0.5:
darken = 64
elif df >= 0.5 and df < 0.75:
darken = 128
else:
darken = 255
if c is not None: if c is not None:
# If an intersection was found then compute the projected height of the wall in pixels # If an intersection was found then compute the projected height of the wall in pixels
@@ -333,7 +326,16 @@ def main():
# Then scale the corresponding texture slice and blit it # Then scale the corresponding texture slice and blit it
scaled = pygame.transform.scale(c, (c.get_width(), h)) scaled = pygame.transform.scale(c, (c.get_width(), h))
frame_buffer.blit(scaled, (i, -(h / 2) + (FB_SIZE[1] / 2))) frame_buffer.blit(scaled, (i, -(h / 2) + (FB_SIZE[1] / 2)))
frame_buffer.fill((darken, darken, darken), pygame.Rect(i, -(h / 2) + (FB_SIZE[1] / 2) if -(h / 2) + (FB_SIZE[1] / 2) >= 0 else 0, 1, scaled.get_height()), pygame.BLEND_MULT)
# Darken wall according to distance
_d = (d if d < FAR else FAR) / FAR
depth = 255 - int(_d * 255)
frame_buffer.fill((depth, depth, depth),
pygame.Rect(i,
-(h / 2) + (FB_SIZE[1] / 2) if -(h / 2) + (FB_SIZE[1] / 2) >= 0 else 0,
1,
scaled.get_height() if scaled.get_height() < FB_SIZE[1] else FB_SIZE[1] - 1),
pygame.BLEND_MULT)
# Floor casting and ceiling casting # Floor casting and ceiling casting
if p is not None and h > 0 and h < FB_SIZE[1]: if p is not None and h > 0 and h < FB_SIZE[1]:
@@ -343,12 +345,21 @@ def main():
cd = FB_SIZE[1] / det cd = FB_SIZE[1] / det
weight = cd / (d * math.cos(angle * DEG2RAD)) weight = cd / (d * math.cos(angle * DEG2RAD))
st = vec2((weight * p.x) + ((1.0 - weight) * player_pos.x), (weight * p.y) + ((1.0 - weight) * player_pos.y)) st = vec2((weight * p.x) + ((1.0 - weight) * player_pos.x), (weight * p.y) + ((1.0 - weight) * player_pos.y))
# Sample floor and ceiling texture
ftex = floor.sample_texture(st) ftex = floor.sample_texture(st)
ctex = ceiln.sample_texture(st) ctex = ceiln.sample_texture(st)
# Draw floor and ceiling
frame_buffer.blit(ftex, (i, j)) frame_buffer.blit(ftex, (i, j))
frame_buffer.fill((192, 192, 192), pygame.Rect(i, j, 1, 1), pygame.BLEND_MULT)
frame_buffer.blit(ctex, (i, FB_SIZE[1] - j)) frame_buffer.blit(ctex, (i, FB_SIZE[1] - j))
# Darken floor and ceiling according to distance
_d = (cd if cd < FAR else FAR) / FAR
depth = 255 - int(_d * 255)
frame_buffer.fill((depth, depth, depth), pygame.Rect(i, j, 1, 1), pygame.BLEND_MULT)
frame_buffer.fill((depth, depth, depth), pygame.Rect(i, FB_SIZE[1] - j, 1, 1), pygame.BLEND_MULT)
angle += ANGLE_INCREMENT angle += ANGLE_INCREMENT
# Render framebuffer to the screen # Render framebuffer to the screen