Normal map maker for X-Plane now working correctly, and properly implemented in layer generation process. Tile folder now has a proper "z_orthographic_" naming convention, data is stored in this folder. Orthos are now stored in DDS format, as opposed to jpg, which was twice as large in file size. Tile generation process completes by generating proper DSF data files for X-Plane.
This commit is contained in:
parent
a5e850feec
commit
7326984762
10
defines.py
10
defines.py
@ -150,6 +150,8 @@ mstr_ortho_layers = [
|
||||
("natural", "wetland", "natural", "wetland"),
|
||||
("natural", "scrub", "natural", "scrub"),
|
||||
("natural", "heath", "natural", "heath"),
|
||||
("natural", "sand", "natural", "sand"),
|
||||
("natural", "desert", "natural", "desert"),
|
||||
# Z-Order 3
|
||||
("natural", "water", "natural", "water"),
|
||||
("natural", "bay", "natural", "beach"),
|
||||
@ -180,7 +182,9 @@ mstr_ortho_layers = [
|
||||
("building", "terrace", "building", "industrial"),
|
||||
("building", "hangar", "building", "industrial"),
|
||||
("building", "school", "building", "common"),
|
||||
("building", "yes", "building", "common")
|
||||
("building", "yes", "building", "common"),
|
||||
("place", "sea", "natural", "sea"),
|
||||
("place", "ocean", "natural", "sea")
|
||||
]
|
||||
|
||||
|
||||
@ -257,5 +261,7 @@ mstr_mask_blur = [
|
||||
("building", "terrace", 1),
|
||||
("building", "hangar", 1),
|
||||
("building", "school", 1),
|
||||
("building", "yes", 1)
|
||||
("building", "yes", 1),
|
||||
("place", "sea", 1),
|
||||
("place", "ocean", 1)
|
||||
]
|
||||
|
35
layergen.py
35
layergen.py
@ -38,8 +38,6 @@ class mstr_layergen:
|
||||
self._longitude = lng
|
||||
self._lng_number = lngnum
|
||||
self._layerborder = -1
|
||||
self._tiledb = mstr_tiledb(lat, lng)
|
||||
self._tiledb.create_tables()
|
||||
self._is_completion = is_completion
|
||||
# Define layer size depending on what is wanted
|
||||
self._imgsize = 0
|
||||
@ -58,6 +56,11 @@ class mstr_layergen:
|
||||
def set_latlng_folder(self, latlngfld):
|
||||
self._latlngfld = latlngfld
|
||||
|
||||
# Open DB
|
||||
def open_db(self):
|
||||
self._tiledb = mstr_tiledb(self._latitude, self._longitude, self._latlngfld)
|
||||
self._tiledb.create_tables()
|
||||
|
||||
# This generates a "border" image, for example farmland usually has a small space of grass
|
||||
# before the actual crop of farm field itself. This generates this "border" layer,
|
||||
# and returns it.
|
||||
@ -355,6 +358,7 @@ class mstr_layergen:
|
||||
# on what they are.
|
||||
for i in mstr_mask_blur:
|
||||
if i[0] == self._tag and i[1] == self._value:
|
||||
if self._tag != "place" and (self._value != "sea" or self._value != "ocean"):
|
||||
osm_mask = osm_mask.filter(ImageFilter.BoxBlur(radius=i[2]))
|
||||
break
|
||||
|
||||
@ -414,13 +418,6 @@ class mstr_layergen:
|
||||
layer_border = self.genborder(osm_edge, "landuse", "meadow")
|
||||
layer_comp.alpha_composite(layer_border)
|
||||
|
||||
# Edges for waters
|
||||
if self._tag == "natural" and self._value == "water":
|
||||
osm_edge = osm_mask.filter(ImageFilter.FIND_EDGES)
|
||||
osm_edge = osm_edge.filter(ImageFilter.MaxFilter)
|
||||
osm_edge = osm_edge.filter(ImageFilter.GaussianBlur(radius=2))
|
||||
layer_comp.alpha_composite(osm_edge)
|
||||
|
||||
# Store layer
|
||||
if self._is_completion == False:
|
||||
layer_comp.save( mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_layer.png" )
|
||||
@ -430,6 +427,20 @@ class mstr_layergen:
|
||||
mstr_msg("layergen", "Layer image finalized and saved.")
|
||||
|
||||
|
||||
# Depending on if scenery for XP should be made, AND if normal maps should be made, we would
|
||||
# need to make them at this exact point
|
||||
if mstr_xp_genscenery == True:
|
||||
if mstr_xp_generate_normal_maps == True:
|
||||
nm = False
|
||||
for n in mstr_xp_normal_maps:
|
||||
if n[0] == self._tag and n[1] == self._value:
|
||||
nm = True
|
||||
break
|
||||
if nm == True:
|
||||
nrm = mstr_xp_normalmap(self._latitude, self._longitude, self._tag, self._value, self._lat_number, self._lng_number, self._latlngfld)
|
||||
nrm.build_normalmap()
|
||||
|
||||
|
||||
# Let's try our hand at pseudo shadows
|
||||
if mstr_shadow_enabled == True:
|
||||
if mstr_shadow_shift >= 2:
|
||||
@ -759,6 +770,12 @@ class mstr_layergen:
|
||||
# need to make them at this exact point
|
||||
if mstr_xp_genscenery == True:
|
||||
if mstr_xp_generate_normal_maps == True:
|
||||
nm = False
|
||||
for n in mstr_xp_normal_maps:
|
||||
if n[0] == self._tag and n[1] == self._value:
|
||||
nm = True
|
||||
break
|
||||
if nm == True:
|
||||
nrm = mstr_xp_normalmap(self._latitude, self._longitude, self._tag, self._value, self._lat_number, self._lng_number, self._latlngfld)
|
||||
nrm.build_normalmap()
|
||||
|
||||
|
@ -20,6 +20,7 @@ from layergen import *
|
||||
from photogen import *
|
||||
from osmxml import *
|
||||
from tilegen import *
|
||||
from xp_dsfgen import *
|
||||
|
||||
|
||||
# The main class which handles the rest
|
||||
@ -110,18 +111,18 @@ class mstr_orthographic:
|
||||
mstr_msg("orthographic", "Created Tiles sub folder: " + self._latlngfld)
|
||||
|
||||
# Generate the orthos folder
|
||||
if not os.path.exists(self._output + "/Tiles/z_orthograpic_" + self._latlngfld + "/orthos"):
|
||||
os.makedirs(self._output + "/Tiles/z_orthograpic_" + self._latlngfld +"/orthos")
|
||||
if not os.path.exists(self._output + "/Tiles/z_orthographic_" + self._latlngfld + "/orthos"):
|
||||
os.makedirs(self._output + "/Tiles/z_orthographic_" + self._latlngfld +"/orthos")
|
||||
mstr_msg("orthographic", "Created tile orthos folder")
|
||||
|
||||
if mstr_xp_genscenery == True:
|
||||
if not os.path.exists(self._output + "/Tiles/z_orthograpic_" + self._latlngfld + "/terrain"):
|
||||
os.makedirs(self._output + "/Tiles/z_orthograpic_" + self._latlngfld + "/terrain")
|
||||
if not os.path.exists(self._output + "/Tiles/z_orthographic_" + self._latlngfld + "/terrain"):
|
||||
os.makedirs(self._output + "/Tiles/z_orthographic_" + self._latlngfld + "/terrain")
|
||||
mstr_msg("orthographic", "Created X-Plane tile terrain folder")
|
||||
|
||||
if mstr_xp_generate_normal_maps == True:
|
||||
if not os.path.exists(self._output + "/Tiles/z_orthograpic_" + self._latlngfld + "/normals"):
|
||||
os.makedirs(self._output + "/Tiles/z_orthograpic_" + self._latlngfld + "/normals")
|
||||
if not os.path.exists(self._output + "/Tiles/z_orthographic_" + self._latlngfld + "/normals"):
|
||||
os.makedirs(self._output + "/Tiles/z_orthographic_" + self._latlngfld + "/normals")
|
||||
mstr_msg("orthographic", "Created X-Plane tile normals folder")
|
||||
|
||||
# The tile is constructed of many smaller parts. We walk through the
|
||||
@ -170,7 +171,7 @@ class mstr_orthographic:
|
||||
mstr_msg("orthographic", "Adjusted bounding box for XML object")
|
||||
|
||||
# Determine what to do... maybe work was interrupted
|
||||
if os.path.isfile(mstr_datafolder + "Tiles/" + self._latlngfld + "/orthos/" + str(cur_tile_y) + "_" + str(cur_tile_x) + ".jpg") == False:
|
||||
if os.path.isfile(mstr_datafolder + "Tiles/" + self._latlngfld + "/orthos/" + str(cur_tile_y) + "_" + str(cur_tile_x) + ".dds") == False:
|
||||
|
||||
# Let the user know
|
||||
mstr_msg("orthographic", "Generating missing orthophoto " + str(cur_tile_y) + "-" + str(cur_tile_x))
|
||||
@ -203,6 +204,7 @@ class mstr_orthographic:
|
||||
lg = mstr_layergen(layer[0], layer[1], self._lat, cur_tile_y, self._long, cur_tile_x, layer[2])
|
||||
lg.set_max_latlng_tile(maxlatlng)
|
||||
lg.set_latlng_folder(self._latlngfld)
|
||||
lg.open_db()
|
||||
lg.genlayer()
|
||||
curlyr = curlyr+1
|
||||
mstr_msg("orthographic", "All layers created")
|
||||
@ -213,8 +215,6 @@ class mstr_orthographic:
|
||||
pg = mstr_photogen(self._lat, self._long, cur_tile_y, cur_tile_x, maxlatlng[0], maxlatlng[1])
|
||||
pg.genphoto()
|
||||
mstr_msg("orthographic", " -- Ortho photo generated -- ")
|
||||
if mstr_xp_genscenery == True:
|
||||
xp_datagroup = xp_datagroup + 1
|
||||
print("")
|
||||
print("")
|
||||
|
||||
@ -254,6 +254,21 @@ class mstr_orthographic:
|
||||
|
||||
mstr_msg("orthographic", "Generation of all tiles completed!")
|
||||
|
||||
|
||||
# Complete scenery
|
||||
if mstr_xp_genscenery == True:
|
||||
dsf = mstr_xp_dsfgen(self._lat, self._long, mlat, mlng, self._vstep)
|
||||
dsf.build_dsf_for_tile()
|
||||
mstr_msg("orthographic", "X-Plane scenery completed")
|
||||
|
||||
mstr_msg("orthographic", "Final step completed.")
|
||||
mstr_msg("orthographic", "Tile data in: " + self._output + "/Tiles/z_orthographic_" + self._latlngfld)
|
||||
print("")
|
||||
mstr_msg("orthographic", "Thanks for using Orthographic! -- Best, Marcus")
|
||||
print("")
|
||||
|
||||
# Let's leave this out for the moment
|
||||
"""
|
||||
mstr_msg("orthographic", "Generating ZL16 tiles and keeping airport tiles")
|
||||
tg = mstr_tilegen(self._lat, self._lng, self._vstep, top_lat, top_lng)
|
||||
tg.genTiles()
|
||||
@ -264,6 +279,7 @@ class mstr_orthographic:
|
||||
print("")
|
||||
mstr_msg("orthographic", "Thanks for using Orthographic! -- Best, Marcus")
|
||||
print("")
|
||||
"""
|
||||
|
||||
|
||||
|
||||
|
17
photogen.py
17
photogen.py
@ -88,6 +88,8 @@ class mstr_photogen:
|
||||
# Generate the layer as if it were part of the OSM data
|
||||
lg = mstr_layergen(tag, value, self._lat, self._ty, self._lng, self._tx, False, is_completion=True)
|
||||
lg.set_max_latlng_tile(self._maxlatlng)
|
||||
lg.set_latlng_folder(self._latlngfld)
|
||||
lg.open_db()
|
||||
lg.genlayer()
|
||||
|
||||
# Load the image
|
||||
@ -100,6 +102,16 @@ class mstr_photogen:
|
||||
self._tile = completion
|
||||
|
||||
|
||||
# There may be some tiles that have a larger sea or even an ocean in them - these need to be
|
||||
# removed from the final tile
|
||||
ocean_pix = self._tile.load()
|
||||
for y in range(self._tile.width):
|
||||
for x in range(self._tile.height):
|
||||
p = ocean_pix[x,y]
|
||||
if p[0] == 255 and p[1] == 0 and p[2] == 255:
|
||||
t = (0,0,0,0)
|
||||
ocean_pix[x,y] = t
|
||||
|
||||
# We are now in posession of the final image.
|
||||
|
||||
# Scale to correct size.
|
||||
@ -108,14 +120,17 @@ class mstr_photogen:
|
||||
# This we can save accordingly.
|
||||
self._tile.convert('RGB').save(mstr_datafolder + "Tiles/z_orthographic_" + self._latlngfld + "/orthos/" + str(self._ty) + "_" + str(self._tx) + ".png")
|
||||
|
||||
|
||||
# Now we convert this into a DDS
|
||||
with image.Image(filename=mstr_datafolder + "Tiles/z_orthographic_" + self._latlngfld + "/orthos/" + str(self._ty) + "_" + str(self._tx) + ".png") as img:
|
||||
img.compression = "dxt1"
|
||||
img.save(mstr_datafolder + "Tiles/z_orthographic_" + self._latlngfld + "/orthos/" + str(self._ty) + "_" + str(self._tx) + ".dds")
|
||||
img.save(filename=mstr_datafolder + "Tiles/z_orthographic_" + self._latlngfld + "/orthos/" + str(self._ty) + "_" + str(self._tx) + ".dds")
|
||||
# TODO: CUT OUT OCEANS AND SEAS IN DDS
|
||||
os.remove(mstr_datafolder + "Tiles/z_orthographic_" + self._latlngfld + "/orthos/" + str(self._ty) + "_" + str(self._tx) + ".png")
|
||||
|
||||
|
||||
|
||||
|
||||
# This checks the final image for empty patches. Should one be
|
||||
# found, we will generate something to fill the gap. If this is
|
||||
# the case, we will also note this in the database for the tile,
|
||||
|
@ -18,13 +18,14 @@ from functions import *
|
||||
from log import *
|
||||
|
||||
class mstr_tiledb:
|
||||
def __init__(self, lat, lng):
|
||||
def __init__(self, lat, lng, latlngfld):
|
||||
# Note coords
|
||||
self._latitude = lat
|
||||
self._longitude = lng
|
||||
self._latlngfld = latlngfld
|
||||
|
||||
# The db file will be created, should it not exist
|
||||
self._conn = sqlite3.connect(mstr_datafolder + "Tiles/" + str(self._latitude) + "_" + str(self._longitude) + "/data.db")
|
||||
self._conn = sqlite3.connect(mstr_datafolder + "Tiles/z_orthographic_" + latlngfld + "/data.db")
|
||||
self._crs = self._conn.cursor()
|
||||
#mstr_msg("tiledb", "Database object initiated")
|
||||
|
||||
|
@ -209,8 +209,3 @@ class mstr_xp_dsfgen:
|
||||
self.convert_dsf_text()
|
||||
|
||||
mstr_msg("xp_dsfgen", "[X-Plane] DSF for tile completed")
|
||||
|
||||
|
||||
# Testing
|
||||
dsf = mstr_xp_dsfgen(51, 7, 101, 63, 0.01010)
|
||||
dsf.build_dsf_for_tile()
|
@ -42,7 +42,7 @@ class mstr_xp_normalmap:
|
||||
# then provide it
|
||||
def load_layer(self):
|
||||
qtr = int(mstr_photores / 4)
|
||||
image = Image.open(mstr_datafolder + "_cache/" + str(self._lat) + "-" + str(self._lng) + "_" + self._tag + "_" + self._value + "_layer.png")
|
||||
image = Image.open(mstr_datafolder + "_cache/" + str(self._lat) + "-" + str(self._tv) + "_" + str(self._lng) + "-" + str(self._th) + "_" + self._tag + "-" + self._value + "_layer.png")
|
||||
image = image.resize((qtr,qtr), Image.Resampling.LANCZOS)
|
||||
mstr_msg("xp_normalmap", "[X-Plane] Layer image loaded")
|
||||
return image
|
||||
@ -50,13 +50,16 @@ class mstr_xp_normalmap:
|
||||
|
||||
# A few mathematical calls we need
|
||||
# --------------------------------------------------------
|
||||
def intensity(pixel):
|
||||
def intensity(self, pixel):
|
||||
avg = (pixel[0] + pixel[1] + pixel[2]) / 3
|
||||
if avg > 0:
|
||||
pavg = 255.0 / avg
|
||||
else:
|
||||
pavg = 0
|
||||
return pavg
|
||||
|
||||
|
||||
def clamp(px, mpx):
|
||||
def clamp(self, px, mpx):
|
||||
if px > mpx-1:
|
||||
return mpx-1
|
||||
else:
|
||||
@ -66,11 +69,11 @@ class mstr_xp_normalmap:
|
||||
return px
|
||||
|
||||
|
||||
def map_component(px):
|
||||
def map_component(self, px):
|
||||
return (px + 1.0) * (255.0 / 2.0)
|
||||
|
||||
|
||||
def normalize_vector(v):
|
||||
def normalize_vector(self, v):
|
||||
vc = np.array([v[0], v[1], v[2]])
|
||||
norm = np.linalg.norm(vc)
|
||||
nv = vc / norm
|
||||
@ -81,7 +84,8 @@ class mstr_xp_normalmap:
|
||||
# The Big Mac. Generate the normal map
|
||||
def generate_normal_map_for_layer(self, image):
|
||||
mstr_msg("xp_normalmap", "[X-Plane] Beginning normal map generation")
|
||||
nmp = Image.new("RGBA", (image.width, image.height), (128,128,255,255))
|
||||
#nmp = Image.new("RGBA", (image.width, image.height), (128,128,255,255))
|
||||
nmp = Image.new("RGBA", (image.width, image.height), (0,0,0,0))
|
||||
org = image.load()
|
||||
nmp_pix = nmp.load()
|
||||
|
||||
@ -93,18 +97,23 @@ class mstr_xp_normalmap:
|
||||
a = v * 255.0
|
||||
alpha = int(a)
|
||||
|
||||
|
||||
# Let's try some shenanigans
|
||||
for y in range(image.width):
|
||||
for x in range(image.height):
|
||||
w = image.width
|
||||
h = image.height
|
||||
for y in range(h):
|
||||
for x in range(w):
|
||||
p = org[x,y]
|
||||
if p[3] > 0: # Only do something if there is something to do in layer
|
||||
# Neighboring pixels
|
||||
px_t = org[ self.clamp(x, image.width), self.clamp(y+1, image.height) ]
|
||||
px_tr = org[ self.clamp(x+1, image.width), self.clamp(y+1, image.height) ]
|
||||
px_r = org[ self.clamp(x+1, image.width), self.clamp(y, image.height) ]
|
||||
px_br = org[ self.clamp(x+1, image.width), self.clamp(y+1, image.height) ]
|
||||
px_b = org[ self.clamp(x, image.width), self.clamp(y-1, image.height) ]
|
||||
px_bl = org[ self.clamp(x-1, image.width), self.clamp(y-1, image.height) ]
|
||||
px_l = org[ self.clamp(x-1, image.width), self.clamp(y, image.height) ]
|
||||
px_tl = org[ self.clamp(x-1, image.width), self.clamp(y+1, image.height) ]
|
||||
px_t = org[ self.clamp(x, w), self.clamp(y+1, h) ]
|
||||
px_tr = org[ self.clamp(x+1, w), self.clamp(y+1, h) ]
|
||||
px_r = org[ self.clamp(x+1, w), self.clamp(y, h) ]
|
||||
px_br = org[ self.clamp(x+1, w), self.clamp(y+1, h) ]
|
||||
px_b = org[ self.clamp(x, w), self.clamp(y-1, h) ]
|
||||
px_bl = org[ self.clamp(x-1, w), self.clamp(y-1, h) ]
|
||||
px_l = org[ self.clamp(x-1, w), self.clamp(y, h) ]
|
||||
px_tl = org[ self.clamp(x-1, w), self.clamp(y+1, h) ]
|
||||
|
||||
# Intensities of pixels
|
||||
it_t = self.intensity(px_t)
|
||||
|
Loading…
x
Reference in New Issue
Block a user