Added distance attenuation and 1D depth buffer.
This commit is contained in:
43
py_caster.py
43
py_caster.py
@@ -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
|
||||||
|
Reference in New Issue
Block a user