0

correct (though chunk-local only) per-face lighting

This commit is contained in:
Aaron Griffith
2010-09-27 19:04:35 -04:00
parent a15390cc47
commit db62ad94ee
2 changed files with 68 additions and 9 deletions

View File

@@ -14,7 +14,7 @@
# with the Overviewer. If not, see <http://www.gnu.org/licenses/>. # with the Overviewer. If not, see <http://www.gnu.org/licenses/>.
import numpy import numpy
from PIL import Image, ImageDraw from PIL import Image, ImageDraw, ImageEnhance
from itertools import izip, count from itertools import izip, count
import os.path import os.path
import hashlib import hashlib
@@ -37,6 +37,13 @@ image
# use that as the mask. Then take the image and use im.convert("RGB") to strip # use that as the mask. Then take the image and use im.convert("RGB") to strip
# the image from its alpha channel, and use that as the source to paste() # the image from its alpha channel, and use that as the source to paste()
def get_lighting_coefficient(skylight, blocklight):
"""Takes a raw blocklight and skylight, and returns a value
between 0.0 (fully lit) and 1.0 (fully black) that can be used as
an alpha value for a blend with a black source image. It mimics
Minecraft lighting calculations."""
return 1.0 - pow(0.8, 15 - max(blocklight, skylight))
def get_lvldata(filename): def get_lvldata(filename):
"""Takes a filename and returns the Level struct, which contains all the """Takes a filename and returns the Level struct, which contains all the
level info""" level info"""
@@ -317,11 +324,38 @@ class ChunkRenderer(object):
# Draw the actual block on the image. For cave images, # Draw the actual block on the image. For cave images,
# tint the block with a color proportional to its depth # tint the block with a color proportional to its depth
if cave: if cave:
# no lighting for cave -- depth is probably more useful
img.paste(Image.blend(t[0],depth_colors[z],0.3), (imgx, imgy), t[1]) img.paste(Image.blend(t[0],depth_colors[z],0.3), (imgx, imgy), t[1])
else: else:
light_coeff = pow(0.95, 15 - max(blocklight[x,y,z], skylight[x,y,z])) if blockid in transparent_blocks:
img.paste(Image.blend(t[0], black_color, 1.0 - light_coeff), (imgx, imgy), t[1]) # transparent means draw the whole
#img.paste(t[0], (imgx, imgy), t[1]) # block shaded with the current
# block's light
black_coeff = get_lighting_coefficient(skylight[x,y,z], blocklight[x,y,z])
img.paste(Image.blend(t[0], black_color, black_coeff), (imgx, imgy), t[1])
else:
# draw each face lit appropriately,
# but first just draw the block
img.paste(t[0], (imgx, imgy), t[1])
# top face
if z != 127 and (blocks[x,y,z+1] in transparent_blocks):
black_coeff = get_lighting_coefficient(skylight[x,y,z+1], blocklight[x,y,z+1])
img.paste((0,0,0), (imgx, imgy), ImageEnhance.Brightness(facemasks[0]).enhance(black_coeff))
# left face
black_coeff = 0.0
if x != 0:
black_coeff = get_lighting_coefficient(skylight[x-1,y,z], blocklight[x-1,y,z])
if x == 0 or (blocks[x-1,y,z] in transparent_blocks):
img.paste((0,0,0), (imgx, imgy), ImageEnhance.Brightness(facemasks[1]).enhance(black_coeff))
# right face
black_coeff = 0.0
if y != 15:
black_coeff = get_lighting_coefficient(skylight[x,y+1,z], blocklight[x,y+1,z])
if y == 15 or (blocks[x,y+1,z] in transparent_blocks):
img.paste((0,0,0), (imgx, imgy), ImageEnhance.Brightness(facemasks[2]).enhance(black_coeff))
# Draw edge lines # Draw edge lines
if blockid not in transparent_blocks: if blockid not in transparent_blocks:
@@ -338,6 +372,32 @@ class ChunkRenderer(object):
return img return img
# Render 3 blending masks for lighting
# first is top (+Z), second is left (-X), third is right (+Y)
def generate_facemasks():
white = Image.new("L", (24,24), 255)
top = Image.new("L", (24,24), 0)
left = Image.new("L", (24,24), 0)
whole = Image.new("L", (24,24), 0)
toppart = textures.transform_image(white)
leftpart = textures.transform_image_side(white)
top.paste(toppart, (0,0))
left.paste(leftpart, (0,6))
right = left.transpose(Image.FLIP_LEFT_RIGHT)
# Manually touch up 6 pixels that leave a gap, like in
# textures._build_block()
for x,y in [(13,23), (17,21), (21,19)]:
right.putpixel((x,y), 255)
for x,y in [(3,4), (7,2), (11,0)]:
top.putpixel((x,y), 255)
return (top, left, right)
facemasks = generate_facemasks()
black_color = Image.new("RGB", (24,24), (0,0,0))
# Render 128 different color images for color coded depth blending in cave mode # Render 128 different color images for color coded depth blending in cave mode
def generate_depthcolors(): def generate_depthcolors():
@@ -358,5 +418,4 @@ def generate_depthcolors():
g -= 7 g -= 7
return depth_colors return depth_colors
black_color = Image.new("RGB", (24,24), (0,0,0))
depth_colors = generate_depthcolors() depth_colors = generate_depthcolors()

View File

@@ -106,7 +106,7 @@ def _split_terrain(terrain):
# This maps terainids to 16x16 images # This maps terainids to 16x16 images
terrain_images = _split_terrain(_get_terrain_image()) terrain_images = _split_terrain(_get_terrain_image())
def _transform_image(img): def transform_image(img):
"""Takes a PIL image and rotates it left 45 degrees and shrinks the y axis """Takes a PIL image and rotates it left 45 degrees and shrinks the y axis
by a factor of 2. Returns the resulting image, which will be 24x12 pixels by a factor of 2. Returns the resulting image, which will be 24x12 pixels
@@ -134,7 +134,7 @@ def _transform_image(img):
newimg = img.transform((24,12), Image.AFFINE, transform) newimg = img.transform((24,12), Image.AFFINE, transform)
return newimg return newimg
def _transform_image_side(img): def transform_image_side(img):
"""Takes an image and shears it for the left side of the cube (reflect for """Takes an image and shears it for the left side of the cube (reflect for
the right side)""" the right side)"""
@@ -158,13 +158,13 @@ def _build_block(top, side, texID=None):
""" """
img = Image.new("RGBA", (24,24), (38,92,255,0)) img = Image.new("RGBA", (24,24), (38,92,255,0))
top = _transform_image(top) top = transform_image(top)
if not side: if not side:
img.paste(top, (0,0), top) img.paste(top, (0,0), top)
return img return img
side = _transform_image_side(side) side = transform_image_side(side)
otherside = side.transpose(Image.FLIP_LEFT_RIGHT) otherside = side.transpose(Image.FLIP_LEFT_RIGHT)