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", "wetland", "natural", "wetland"),
|
||||||
("natural", "scrub", "natural", "scrub"),
|
("natural", "scrub", "natural", "scrub"),
|
||||||
("natural", "heath", "natural", "heath"),
|
("natural", "heath", "natural", "heath"),
|
||||||
|
("natural", "sand", "natural", "sand"),
|
||||||
|
("natural", "desert", "natural", "desert"),
|
||||||
# Z-Order 3
|
# Z-Order 3
|
||||||
("natural", "water", "natural", "water"),
|
("natural", "water", "natural", "water"),
|
||||||
("natural", "bay", "natural", "beach"),
|
("natural", "bay", "natural", "beach"),
|
||||||
@ -180,7 +182,9 @@ mstr_ortho_layers = [
|
|||||||
("building", "terrace", "building", "industrial"),
|
("building", "terrace", "building", "industrial"),
|
||||||
("building", "hangar", "building", "industrial"),
|
("building", "hangar", "building", "industrial"),
|
||||||
("building", "school", "building", "common"),
|
("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", "terrace", 1),
|
||||||
("building", "hangar", 1),
|
("building", "hangar", 1),
|
||||||
("building", "school", 1),
|
("building", "school", 1),
|
||||||
("building", "yes", 1)
|
("building", "yes", 1),
|
||||||
|
("place", "sea", 1),
|
||||||
|
("place", "ocean", 1)
|
||||||
]
|
]
|
||||||
|
43
layergen.py
43
layergen.py
@ -38,8 +38,6 @@ class mstr_layergen:
|
|||||||
self._longitude = lng
|
self._longitude = lng
|
||||||
self._lng_number = lngnum
|
self._lng_number = lngnum
|
||||||
self._layerborder = -1
|
self._layerborder = -1
|
||||||
self._tiledb = mstr_tiledb(lat, lng)
|
|
||||||
self._tiledb.create_tables()
|
|
||||||
self._is_completion = is_completion
|
self._is_completion = is_completion
|
||||||
# Define layer size depending on what is wanted
|
# Define layer size depending on what is wanted
|
||||||
self._imgsize = 0
|
self._imgsize = 0
|
||||||
@ -58,6 +56,11 @@ class mstr_layergen:
|
|||||||
def set_latlng_folder(self, latlngfld):
|
def set_latlng_folder(self, latlngfld):
|
||||||
self._latlngfld = 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
|
# 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,
|
# before the actual crop of farm field itself. This generates this "border" layer,
|
||||||
# and returns it.
|
# and returns it.
|
||||||
@ -355,8 +358,9 @@ class mstr_layergen:
|
|||||||
# on what they are.
|
# on what they are.
|
||||||
for i in mstr_mask_blur:
|
for i in mstr_mask_blur:
|
||||||
if i[0] == self._tag and i[1] == self._value:
|
if i[0] == self._tag and i[1] == self._value:
|
||||||
osm_mask = osm_mask.filter(ImageFilter.BoxBlur(radius=i[2]))
|
if self._tag != "place" and (self._value != "sea" or self._value != "ocean"):
|
||||||
break
|
osm_mask = osm_mask.filter(ImageFilter.BoxBlur(radius=i[2]))
|
||||||
|
break
|
||||||
|
|
||||||
# Begin producing a largely random image
|
# Begin producing a largely random image
|
||||||
samples = 250 # <- We need this in a moment
|
samples = 250 # <- We need this in a moment
|
||||||
@ -414,13 +418,6 @@ class mstr_layergen:
|
|||||||
layer_border = self.genborder(osm_edge, "landuse", "meadow")
|
layer_border = self.genborder(osm_edge, "landuse", "meadow")
|
||||||
layer_comp.alpha_composite(layer_border)
|
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
|
# Store layer
|
||||||
if self._is_completion == False:
|
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" )
|
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.")
|
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
|
# Let's try our hand at pseudo shadows
|
||||||
if mstr_shadow_enabled == True:
|
if mstr_shadow_enabled == True:
|
||||||
if mstr_shadow_shift >= 2:
|
if mstr_shadow_shift >= 2:
|
||||||
@ -759,6 +770,12 @@ class mstr_layergen:
|
|||||||
# need to make them at this exact point
|
# need to make them at this exact point
|
||||||
if mstr_xp_genscenery == True:
|
if mstr_xp_genscenery == True:
|
||||||
if mstr_xp_generate_normal_maps == True:
|
if mstr_xp_generate_normal_maps == True:
|
||||||
nrm = mstr_xp_normalmap(self._latitude, self._longitude, self._tag, self._value, self._lat_number, self._lng_number, self._latlngfld)
|
nm = False
|
||||||
nrm.build_normalmap()
|
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 photogen import *
|
||||||
from osmxml import *
|
from osmxml import *
|
||||||
from tilegen import *
|
from tilegen import *
|
||||||
|
from xp_dsfgen import *
|
||||||
|
|
||||||
|
|
||||||
# The main class which handles the rest
|
# The main class which handles the rest
|
||||||
@ -110,18 +111,18 @@ class mstr_orthographic:
|
|||||||
mstr_msg("orthographic", "Created Tiles sub folder: " + self._latlngfld)
|
mstr_msg("orthographic", "Created Tiles sub folder: " + self._latlngfld)
|
||||||
|
|
||||||
# Generate the orthos folder
|
# Generate the orthos folder
|
||||||
if not os.path.exists(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_orthograpic_" + self._latlngfld +"/orthos")
|
os.makedirs(self._output + "/Tiles/z_orthographic_" + self._latlngfld +"/orthos")
|
||||||
mstr_msg("orthographic", "Created tile orthos folder")
|
mstr_msg("orthographic", "Created tile orthos folder")
|
||||||
|
|
||||||
if mstr_xp_genscenery == True:
|
if mstr_xp_genscenery == True:
|
||||||
if not os.path.exists(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_orthograpic_" + self._latlngfld + "/terrain")
|
os.makedirs(self._output + "/Tiles/z_orthographic_" + self._latlngfld + "/terrain")
|
||||||
mstr_msg("orthographic", "Created X-Plane tile terrain folder")
|
mstr_msg("orthographic", "Created X-Plane tile terrain folder")
|
||||||
|
|
||||||
if mstr_xp_generate_normal_maps == True:
|
if mstr_xp_generate_normal_maps == True:
|
||||||
if not os.path.exists(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_orthograpic_" + self._latlngfld + "/normals")
|
os.makedirs(self._output + "/Tiles/z_orthographic_" + self._latlngfld + "/normals")
|
||||||
mstr_msg("orthographic", "Created X-Plane tile normals folder")
|
mstr_msg("orthographic", "Created X-Plane tile normals folder")
|
||||||
|
|
||||||
# The tile is constructed of many smaller parts. We walk through the
|
# 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")
|
mstr_msg("orthographic", "Adjusted bounding box for XML object")
|
||||||
|
|
||||||
# Determine what to do... maybe work was interrupted
|
# 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
|
# Let the user know
|
||||||
mstr_msg("orthographic", "Generating missing orthophoto " + str(cur_tile_y) + "-" + str(cur_tile_x))
|
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 = 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_max_latlng_tile(maxlatlng)
|
||||||
lg.set_latlng_folder(self._latlngfld)
|
lg.set_latlng_folder(self._latlngfld)
|
||||||
|
lg.open_db()
|
||||||
lg.genlayer()
|
lg.genlayer()
|
||||||
curlyr = curlyr+1
|
curlyr = curlyr+1
|
||||||
mstr_msg("orthographic", "All layers created")
|
mstr_msg("orthographic", "All layers created")
|
||||||
@ -210,11 +212,9 @@ class mstr_orthographic:
|
|||||||
# We should have all layers now.
|
# We should have all layers now.
|
||||||
# Snap a photo with our satellite :)
|
# Snap a photo with our satellite :)
|
||||||
mstr_msg("orthographic", "Generating ortho photo")
|
mstr_msg("orthographic", "Generating ortho photo")
|
||||||
pg = mstr_photogen(self._lat, self._long, cur_tile_y, cur_tile_x, maxlatlng[0], maxlatlng[1])
|
pg = mstr_photogen(self._lat, self._long, cur_tile_y, cur_tile_x, maxlatlng[0], maxlatlng[1])
|
||||||
pg.genphoto()
|
pg.genphoto()
|
||||||
mstr_msg("orthographic", " -- Ortho photo generated -- ")
|
mstr_msg("orthographic", " -- Ortho photo generated -- ")
|
||||||
if mstr_xp_genscenery == True:
|
|
||||||
xp_datagroup = xp_datagroup + 1
|
|
||||||
print("")
|
print("")
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
@ -254,6 +254,21 @@ class mstr_orthographic:
|
|||||||
|
|
||||||
mstr_msg("orthographic", "Generation of all tiles completed!")
|
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")
|
mstr_msg("orthographic", "Generating ZL16 tiles and keeping airport tiles")
|
||||||
tg = mstr_tilegen(self._lat, self._lng, self._vstep, top_lat, top_lng)
|
tg = mstr_tilegen(self._lat, self._lng, self._vstep, top_lat, top_lng)
|
||||||
tg.genTiles()
|
tg.genTiles()
|
||||||
@ -264,6 +279,7 @@ class mstr_orthographic:
|
|||||||
print("")
|
print("")
|
||||||
mstr_msg("orthographic", "Thanks for using Orthographic! -- Best, Marcus")
|
mstr_msg("orthographic", "Thanks for using Orthographic! -- Best, Marcus")
|
||||||
print("")
|
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
|
# 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 = 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_max_latlng_tile(self._maxlatlng)
|
||||||
|
lg.set_latlng_folder(self._latlngfld)
|
||||||
|
lg.open_db()
|
||||||
lg.genlayer()
|
lg.genlayer()
|
||||||
|
|
||||||
# Load the image
|
# Load the image
|
||||||
@ -100,6 +102,16 @@ class mstr_photogen:
|
|||||||
self._tile = completion
|
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.
|
# We are now in posession of the final image.
|
||||||
|
|
||||||
# Scale to correct size.
|
# Scale to correct size.
|
||||||
@ -107,15 +119,18 @@ class mstr_photogen:
|
|||||||
|
|
||||||
# This we can save accordingly.
|
# 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")
|
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
|
# 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:
|
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.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
|
# 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")
|
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
|
# This checks the final image for empty patches. Should one be
|
||||||
# found, we will generate something to fill the gap. If this is
|
# 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,
|
# the case, we will also note this in the database for the tile,
|
||||||
|
@ -18,13 +18,14 @@ from functions import *
|
|||||||
from log import *
|
from log import *
|
||||||
|
|
||||||
class mstr_tiledb:
|
class mstr_tiledb:
|
||||||
def __init__(self, lat, lng):
|
def __init__(self, lat, lng, latlngfld):
|
||||||
# Note coords
|
# Note coords
|
||||||
self._latitude = lat
|
self._latitude = lat
|
||||||
self._longitude = lng
|
self._longitude = lng
|
||||||
|
self._latlngfld = latlngfld
|
||||||
|
|
||||||
# The db file will be created, should it not exist
|
# 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()
|
self._crs = self._conn.cursor()
|
||||||
#mstr_msg("tiledb", "Database object initiated")
|
#mstr_msg("tiledb", "Database object initiated")
|
||||||
|
|
||||||
|
@ -209,8 +209,3 @@ class mstr_xp_dsfgen:
|
|||||||
self.convert_dsf_text()
|
self.convert_dsf_text()
|
||||||
|
|
||||||
mstr_msg("xp_dsfgen", "[X-Plane] DSF for tile completed")
|
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
|
# then provide it
|
||||||
def load_layer(self):
|
def load_layer(self):
|
||||||
qtr = int(mstr_photores / 4)
|
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)
|
image = image.resize((qtr,qtr), Image.Resampling.LANCZOS)
|
||||||
mstr_msg("xp_normalmap", "[X-Plane] Layer image loaded")
|
mstr_msg("xp_normalmap", "[X-Plane] Layer image loaded")
|
||||||
return image
|
return image
|
||||||
@ -50,13 +50,16 @@ class mstr_xp_normalmap:
|
|||||||
|
|
||||||
# A few mathematical calls we need
|
# A few mathematical calls we need
|
||||||
# --------------------------------------------------------
|
# --------------------------------------------------------
|
||||||
def intensity(pixel):
|
def intensity(self, pixel):
|
||||||
avg = (pixel[0] + pixel[1] + pixel[2]) / 3
|
avg = (pixel[0] + pixel[1] + pixel[2]) / 3
|
||||||
pavg = 255.0 / avg
|
if avg > 0:
|
||||||
|
pavg = 255.0 / avg
|
||||||
|
else:
|
||||||
|
pavg = 0
|
||||||
return pavg
|
return pavg
|
||||||
|
|
||||||
|
|
||||||
def clamp(px, mpx):
|
def clamp(self, px, mpx):
|
||||||
if px > mpx-1:
|
if px > mpx-1:
|
||||||
return mpx-1
|
return mpx-1
|
||||||
else:
|
else:
|
||||||
@ -66,11 +69,11 @@ class mstr_xp_normalmap:
|
|||||||
return px
|
return px
|
||||||
|
|
||||||
|
|
||||||
def map_component(px):
|
def map_component(self, px):
|
||||||
return (px + 1.0) * (255.0 / 2.0)
|
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]])
|
vc = np.array([v[0], v[1], v[2]])
|
||||||
norm = np.linalg.norm(vc)
|
norm = np.linalg.norm(vc)
|
||||||
nv = vc / norm
|
nv = vc / norm
|
||||||
@ -81,7 +84,8 @@ class mstr_xp_normalmap:
|
|||||||
# The Big Mac. Generate the normal map
|
# The Big Mac. Generate the normal map
|
||||||
def generate_normal_map_for_layer(self, image):
|
def generate_normal_map_for_layer(self, image):
|
||||||
mstr_msg("xp_normalmap", "[X-Plane] Beginning normal map generation")
|
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()
|
org = image.load()
|
||||||
nmp_pix = nmp.load()
|
nmp_pix = nmp.load()
|
||||||
|
|
||||||
@ -93,44 +97,49 @@ class mstr_xp_normalmap:
|
|||||||
a = v * 255.0
|
a = v * 255.0
|
||||||
alpha = int(a)
|
alpha = int(a)
|
||||||
|
|
||||||
|
|
||||||
# Let's try some shenanigans
|
# Let's try some shenanigans
|
||||||
for y in range(image.width):
|
w = image.width
|
||||||
for x in range(image.height):
|
h = image.height
|
||||||
# Neighboring pixels
|
for y in range(h):
|
||||||
px_t = org[ self.clamp(x, image.width), self.clamp(y+1, image.height) ]
|
for x in range(w):
|
||||||
px_tr = org[ self.clamp(x+1, image.width), self.clamp(y+1, image.height) ]
|
p = org[x,y]
|
||||||
px_r = org[ self.clamp(x+1, image.width), self.clamp(y, image.height) ]
|
if p[3] > 0: # Only do something if there is something to do in layer
|
||||||
px_br = org[ self.clamp(x+1, image.width), self.clamp(y+1, image.height) ]
|
# Neighboring pixels
|
||||||
px_b = org[ self.clamp(x, image.width), self.clamp(y-1, image.height) ]
|
px_t = org[ self.clamp(x, w), self.clamp(y+1, h) ]
|
||||||
px_bl = org[ self.clamp(x-1, image.width), self.clamp(y-1, image.height) ]
|
px_tr = org[ self.clamp(x+1, w), self.clamp(y+1, h) ]
|
||||||
px_l = org[ self.clamp(x-1, image.width), self.clamp(y, image.height) ]
|
px_r = org[ self.clamp(x+1, w), self.clamp(y, h) ]
|
||||||
px_tl = org[ self.clamp(x-1, image.width), self.clamp(y+1, image.height) ]
|
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
|
# Intensities of pixels
|
||||||
it_t = self.intensity(px_t)
|
it_t = self.intensity(px_t)
|
||||||
it_tr = self.intensity(px_tr)
|
it_tr = self.intensity(px_tr)
|
||||||
it_r = self.intensity(px_r)
|
it_r = self.intensity(px_r)
|
||||||
it_br = self.intensity(px_br)
|
it_br = self.intensity(px_br)
|
||||||
it_b = self.intensity(px_b)
|
it_b = self.intensity(px_b)
|
||||||
it_bl = self.intensity(px_bl)
|
it_bl = self.intensity(px_bl)
|
||||||
it_l = self.intensity(px_l)
|
it_l = self.intensity(px_l)
|
||||||
it_tl = self.intensity(px_tl)
|
it_tl = self.intensity(px_tl)
|
||||||
|
|
||||||
# Sobel filter
|
# Sobel filter
|
||||||
dx = (it_tr + 2.0 * it_r + it_br) - (it_tl + 2.0 * it_l + it_bl)
|
dx = (it_tr + 2.0 * it_r + it_br) - (it_tl + 2.0 * it_l + it_bl)
|
||||||
dy = (it_bl + 2.0 * it_b + it_br) - (it_tl + 2.0 * it_t + it_tr)
|
dy = (it_bl + 2.0 * it_b + it_br) - (it_tl + 2.0 * it_t + it_tr)
|
||||||
dz = 10 # This is usually a good value for strength
|
dz = 10 # This is usually a good value for strength
|
||||||
v = (dx, dy, dz)
|
v = (dx, dy, dz)
|
||||||
nrm = self.normalize_vector(v)
|
nrm = self.normalize_vector(v)
|
||||||
|
|
||||||
# Invert height for our Orthos
|
# Invert height for our Orthos
|
||||||
if nrm[1] > 0:
|
if nrm[1] > 0:
|
||||||
nrm[1] = 0 - (abs(nrm[1]))
|
nrm[1] = 0 - (abs(nrm[1]))
|
||||||
else:
|
else:
|
||||||
nrm[1] = abs(nrm[1])
|
nrm[1] = abs(nrm[1])
|
||||||
|
|
||||||
# Set pixel
|
# Set pixel
|
||||||
nmp_pix[x,y] = (int(self.map_component(nrm[0])), int(self.map_component(nrm[1])), int(self.map_component(nrm[2])), alpha)
|
nmp_pix[x,y] = (int(self.map_component(nrm[0])), int(self.map_component(nrm[1])), int(self.map_component(nrm[2])), alpha)
|
||||||
|
|
||||||
mstr_msg("xp_normalmap", "[X-Plane] Normal map generated")
|
mstr_msg("xp_normalmap", "[X-Plane] Normal map generated")
|
||||||
return nmp
|
return nmp
|
||||||
|
Loading…
x
Reference in New Issue
Block a user