Improved building rendering by adding subtle details to make residential areas look more alive.
BIN
Textures/building/area/p1.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
Textures/building/area/p10.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
Textures/building/area/p2.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
Textures/building/area/p3.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
Textures/building/area/p4.png
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
Textures/building/area/p5.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
Textures/building/area/p6.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
Textures/building/area/p7.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
Textures/building/area/p8.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
Textures/building/area/p9.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
@ -139,6 +139,7 @@ mstr_ortho_layers = [
|
|||||||
# Z-Order 5
|
# Z-Order 5
|
||||||
("aeroway", "taxiway", 42),
|
("aeroway", "taxiway", 42),
|
||||||
("aeroway", "runway", 80),
|
("aeroway", "runway", 80),
|
||||||
|
("building", "detached", "building", "common"),
|
||||||
("building", "church", "building", "common"),
|
("building", "church", "building", "common"),
|
||||||
("building", "hotel", "building", "industrial"),
|
("building", "hotel", "building", "industrial"),
|
||||||
("building", "farm", "building", "industrial"),
|
("building", "farm", "building", "industrial"),
|
||||||
@ -151,6 +152,8 @@ mstr_ortho_layers = [
|
|||||||
("building", "industrial", "building", "industrial"),
|
("building", "industrial", "building", "industrial"),
|
||||||
("building", "house", "building", "house"),
|
("building", "house", "building", "house"),
|
||||||
("building", "terrace", "building", "industrial"),
|
("building", "terrace", "building", "industrial"),
|
||||||
|
("building", "hangar", "building", "industrial"),
|
||||||
|
("building", "school", "building", "common"),
|
||||||
("building", "yes", "building", "common")
|
("building", "yes", "building", "common")
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -213,6 +216,7 @@ mstr_mask_blur = [
|
|||||||
# Z-Order 5
|
# Z-Order 5
|
||||||
("aeroway", "taxiway", 12),
|
("aeroway", "taxiway", 12),
|
||||||
("aeroway", "runway", 12),
|
("aeroway", "runway", 12),
|
||||||
|
("building", "detached", 1),
|
||||||
("building", "church", 1),
|
("building", "church", 1),
|
||||||
("building", "hotel", 1),
|
("building", "hotel", 1),
|
||||||
("building", "farm", 1),
|
("building", "farm", 1),
|
||||||
@ -225,5 +229,7 @@ mstr_mask_blur = [
|
|||||||
("building", "industrial", 1),
|
("building", "industrial", 1),
|
||||||
("building", "house", 1),
|
("building", "house", 1),
|
||||||
("building", "terrace", 1),
|
("building", "terrace", 1),
|
||||||
|
("building", "hangar", 1),
|
||||||
|
("building", "school", 1),
|
||||||
("building", "yes", 1)
|
("building", "yes", 1)
|
||||||
]
|
]
|
||||||
|
134
layergen.py
@ -134,7 +134,7 @@ class mstr_layergen:
|
|||||||
# There are some things we need to use sources for, and some things, we do not.
|
# There are some things we need to use sources for, and some things, we do not.
|
||||||
# We need to differentiate that.
|
# We need to differentiate that.
|
||||||
|
|
||||||
if (self._isline == False) or (self._is_completion == True):
|
if (self._isline == False and self._tag != "building") or (self._is_completion == True):
|
||||||
# Determine where we get the our source material from
|
# Determine where we get the our source material from
|
||||||
root_folder = mstr_datafolder + "Textures\\"
|
root_folder = mstr_datafolder + "Textures\\"
|
||||||
for s in mstr_ortho_layers:
|
for s in mstr_ortho_layers:
|
||||||
@ -371,16 +371,10 @@ class mstr_layergen:
|
|||||||
ptc = randrange(1, 14)
|
ptc = randrange(1, 14)
|
||||||
img = Image.open(mstr_datafolder + "Textures\\tile\\completion\\p" + str(ptc)+".png")
|
img = Image.open(mstr_datafolder + "Textures\\tile\\completion\\p" + str(ptc)+".png")
|
||||||
lx = randrange( int(layer.width/20), layer.width - (int(layer.width/20)) - img.width )
|
lx = randrange( int(layer.width/20), layer.width - (int(layer.width/20)) - img.width )
|
||||||
ly = randrange( int(layer.width/20), layer.width - (int(layer.width/20)) - img.width )
|
ly = randrange( int(layer.width/20), layer.width - (int(layer.width/20)) - img.height )
|
||||||
layer.alpha_composite( img, (lx, ly) )
|
layer.alpha_composite( img, (lx, ly) )
|
||||||
|
|
||||||
|
|
||||||
# Let's do something nice with buildings
|
|
||||||
if self._tag == "building":
|
|
||||||
osm_edge = osm_edge.filter(ImageFilter.GaussianBlur(radius=3))
|
|
||||||
layer.alpha_composite(osm_edge)
|
|
||||||
|
|
||||||
|
|
||||||
# We now need to add the seamless border
|
# We now need to add the seamless border
|
||||||
layer.alpha_composite( brd_src )
|
layer.alpha_composite( brd_src )
|
||||||
mstr_msg("layergen", "Layer image completed")
|
mstr_msg("layergen", "Layer image completed")
|
||||||
@ -517,7 +511,7 @@ class mstr_layergen:
|
|||||||
|
|
||||||
# If we encounter one of these road-specific tags, we need to proceed differently.
|
# If we encounter one of these road-specific tags, we need to proceed differently.
|
||||||
|
|
||||||
if self._isline == True:
|
if self._isline == True or self._tag == "building":
|
||||||
|
|
||||||
# We will need the mask in question
|
# We will need the mask in question
|
||||||
osm_mask = Image.open( mstr_datafolder + "_cache\\" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + ".png" )
|
osm_mask = Image.open( mstr_datafolder + "_cache\\" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + ".png" )
|
||||||
@ -543,6 +537,35 @@ class mstr_layergen:
|
|||||||
mask_pix = osm_mask.load()
|
mask_pix = osm_mask.load()
|
||||||
edge_pix = osm_edge.load()
|
edge_pix = osm_edge.load()
|
||||||
layer_comp_pix = layer_comp.load()
|
layer_comp_pix = layer_comp.load()
|
||||||
|
|
||||||
|
# Let's define some base color ranges for different types of buildings
|
||||||
|
bld_clr = [
|
||||||
|
("detached", 190, 192, 195),
|
||||||
|
("church", 134, 134, 136),
|
||||||
|
("hotel", 153, 147, 138),
|
||||||
|
("farm", 145, 124, 121),
|
||||||
|
("semidetached_house", 167, 163, 152),
|
||||||
|
("apartments", 129, 134, 127),
|
||||||
|
("civic", 134, 134, 136),
|
||||||
|
("garage", 101, 109, 111),
|
||||||
|
("office", 139, 152, 156),
|
||||||
|
("retail", 121, 122, 108),
|
||||||
|
("industrial", 191, 192, 187),
|
||||||
|
("house", 145, 124, 121),
|
||||||
|
("terrace", 191, 192, 187),
|
||||||
|
("hangar", 137, 162, 195),
|
||||||
|
("school", 111, 117, 115),
|
||||||
|
("yes", 152, 144, 141)
|
||||||
|
]
|
||||||
|
|
||||||
|
# Find the color index to work with
|
||||||
|
cidx = 0
|
||||||
|
if self._tag == "building":
|
||||||
|
for c in bld_clr:
|
||||||
|
if c[0] == self._value:
|
||||||
|
break
|
||||||
|
cidx = cidx+1
|
||||||
|
|
||||||
for y in range(self._imgsize):
|
for y in range(self._imgsize):
|
||||||
for x in range(self._imgsize):
|
for x in range(self._imgsize):
|
||||||
if mask_pix[x, y][3] > 0:
|
if mask_pix[x, y][3] > 0:
|
||||||
@ -579,29 +602,16 @@ class mstr_layergen:
|
|||||||
t = a[3]-d
|
t = a[3]-d
|
||||||
if t < 0: t = 0
|
if t < 0: t = 0
|
||||||
layer_comp_pix[x, y] = ( mats[pick-1][0], mats[pick-1][1], mats[pick-1][2], t )
|
layer_comp_pix[x, y] = ( mats[pick-1][0], mats[pick-1][1], mats[pick-1][2], t )
|
||||||
|
|
||||||
|
# A bit special here
|
||||||
if self._tag == "building":
|
if self._tag == "building":
|
||||||
r = randrange(1, 20)
|
|
||||||
|
|
||||||
if self._value == "yes":
|
# Find a color range
|
||||||
d = (116-r, 117-r,135-r)
|
d = randrange(1,21)
|
||||||
layer_comp_pix[x, y] = ( d[0], d[1], d[2], a[3] )
|
# Adjust this pixel
|
||||||
if e[3] > 0:
|
c = (bld_clr[cidx][1]-d, bld_clr[cidx][2]-d, bld_clr[cidx][3]-d, 255)
|
||||||
b = (96-r, 97-r, 115-r)
|
# Set pixel
|
||||||
layer_comp_pix[x, y] = ( b[0],b[1],b[2],e[3] )
|
layer_comp_pix[x, y] = c
|
||||||
|
|
||||||
if self._value == "office" or self._value == "retail":
|
|
||||||
d = (100-r, 100-r, 100-r)
|
|
||||||
layer_comp_pix[x, y] = ( d[0], d[1], d[2], a[3] )
|
|
||||||
if e[3] > 0:
|
|
||||||
b = (80-r, 80-r, 80-r)
|
|
||||||
layer_comp_pix[x, y] = ( b[0],b[1],b[2],e[3] )
|
|
||||||
|
|
||||||
if self._value == "industrial":
|
|
||||||
d = (166-r, 170-r, 175-r)
|
|
||||||
layer_comp_pix[x, y] = ( d[0], d[1], d[2], a[3] )
|
|
||||||
if e[3] > 0:
|
|
||||||
b = (146-r, 150-r, 155-r)
|
|
||||||
layer_comp_pix[x, y] = ( b[0],b[1],b[2],e[3] )
|
|
||||||
|
|
||||||
if self._value == "track" or self._value == "path":
|
if self._value == "track" or self._value == "path":
|
||||||
d = randrange(1,20)
|
d = randrange(1,20)
|
||||||
@ -610,6 +620,64 @@ class mstr_layergen:
|
|||||||
b = 138 - d
|
b = 138 - d
|
||||||
layer_comp_pix[x, y] = ( r,g,b,a[3] )
|
layer_comp_pix[x, y] = ( r,g,b,a[3] )
|
||||||
|
|
||||||
|
# We will do some super magic here to let houses look more realistic
|
||||||
|
if self._tag == "building":
|
||||||
|
vls = [ "detached", "hotel", "farm", "semidetached_house", "apartments", "civic", "office", "retail", "industrial", "house", "school" ]
|
||||||
|
if self._value in vls:
|
||||||
|
# Generate a new image
|
||||||
|
details = Image.new("RGBA", (self._imgsize, self._imgsize))
|
||||||
|
details_pix = details.load()
|
||||||
|
layer_pix = layer_comp.load()
|
||||||
|
for y in range(self._imgsize-1):
|
||||||
|
for x in range(self._imgsize-1):
|
||||||
|
p = layer_pix[x,y]
|
||||||
|
if p[3] > 0:
|
||||||
|
shf_x = x+randrange(1, 21)
|
||||||
|
shf_y = y+randrange(1, 21)
|
||||||
|
shf_x2 = x-randrange(1, 21)
|
||||||
|
shf_y2 = y-randrange(1, 21)
|
||||||
|
if shf_x <= self._imgsize-1 and shf_x >= 0 and shf_y <= self._imgsize-1 and shf_y >= 0:
|
||||||
|
st = random.uniform(0.85, 1.0)
|
||||||
|
ca = 255 * st
|
||||||
|
aa = int(ca)
|
||||||
|
d = randrange(1,26)
|
||||||
|
d2 = randrange(1,26)
|
||||||
|
details_pix[shf_x, shf_y] = (187-d, 179-d, 176-d, aa)
|
||||||
|
details_pix[shf_x2, shf_y2] = (187-d2, 179-d2, 176-d2, aa)
|
||||||
|
# Merge the details BELOW the houses
|
||||||
|
details.alpha_composite(layer_comp)
|
||||||
|
layer_comp = details
|
||||||
|
# New edge
|
||||||
|
osm_edge = osm_mask.filter(ImageFilter.FIND_EDGES)
|
||||||
|
osm_edge = osm_edge.filter(ImageFilter.GaussianBlur(radius=1))
|
||||||
|
# Blur the image
|
||||||
|
layer_comp = layer_comp.filter(ImageFilter.GaussianBlur(radius=1))
|
||||||
|
osm_edge.alpha_composite(layer_comp)
|
||||||
|
layer_comp = osm_edge
|
||||||
|
|
||||||
|
|
||||||
|
# Add some random trees
|
||||||
|
div = int(self._imgsize/200)
|
||||||
|
for y in range(0, self._imgsize, div):
|
||||||
|
for x in range(0, self._imgsize, div):
|
||||||
|
if x > 0 and x < self._imgsize and y > 0 and y < self._imgsize:
|
||||||
|
p = mask_pix[x, y]
|
||||||
|
if p[3] != 0:
|
||||||
|
# We found something...
|
||||||
|
# Determine if we put something somewhere
|
||||||
|
placement = randrange(0, 5)
|
||||||
|
if placement == 1:
|
||||||
|
# Do some random shift away from this location
|
||||||
|
shf_x = randrange(x-11, x+11)
|
||||||
|
shf_y = randrange(y-11, y+11)
|
||||||
|
if shf_x > 0 and shf_x < self._imgsize and shf_y > 0 and shf_y < self._imgsize:
|
||||||
|
# Pick some file
|
||||||
|
pick = str(randrange(1, 11))
|
||||||
|
tree = Image.open(mstr_datafolder + "Textures\\building\\area\\p" + pick + ".png")
|
||||||
|
layer_comp.alpha_composite(tree, (shf_x, shf_y))
|
||||||
|
#layer_comp.paste(tree, (shf_x, shf_y))
|
||||||
|
|
||||||
|
|
||||||
mstr_msg("layergen", "Layer image generated")
|
mstr_msg("layergen", "Layer image generated")
|
||||||
|
|
||||||
# Building shadow
|
# Building shadow
|
||||||
@ -622,13 +690,15 @@ class mstr_layergen:
|
|||||||
for y in range(self._imgsize-1):
|
for y in range(self._imgsize-1):
|
||||||
for x in range(self._imgsize-1):
|
for x in range(self._imgsize-1):
|
||||||
m = mask_pix[x,y]
|
m = mask_pix[x,y]
|
||||||
shf_x = x + mstr_shadow_shift
|
shf_x = x + randrange(1, mstr_shadow_shift)
|
||||||
if shf_x <= self._imgsize-1:
|
shf_x2 = x + randrange(1, mstr_shadow_shift)
|
||||||
|
if shf_x <= self._imgsize-1 and shf_x >= 0 and shf_x2 <= self._imgsize-1 and shf_x2 >= 0:
|
||||||
a = mask_pix[x,y][3]
|
a = mask_pix[x,y][3]
|
||||||
st = random.uniform(0.45, mstr_shadow_strength)
|
st = random.uniform(0.45, mstr_shadow_strength)
|
||||||
ca = a * st
|
ca = a * st
|
||||||
aa = int(ca)
|
aa = int(ca)
|
||||||
shadow_pix[shf_x, y] = (0,0,0,aa)
|
shadow_pix[shf_x, y] = (0,0,0,aa)
|
||||||
|
shadow_pix[shf_x2, y] = (0,0,0,aa)
|
||||||
shadow.save(mstr_datafolder + "_cache\\" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_layer_shadow.png")
|
shadow.save(mstr_datafolder + "_cache\\" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_layer_shadow.png")
|
||||||
mstr_msg("layergen", "Shadow layer completed")
|
mstr_msg("layergen", "Shadow layer completed")
|
||||||
|
|
||||||
|
@ -183,3 +183,4 @@ class mstr_maskgen:
|
|||||||
# Inform
|
# Inform
|
||||||
mstr_msg("maskgen", "Mask built.")
|
mstr_msg("maskgen", "Mask built.")
|
||||||
|
|
||||||
|
|
||||||
|