]> marstr Code Repo - orthographic/commitdiff
Normal map maker for X-Plane now working correctly, and properly implemented in layer...
authormarstr <marcus@marstr.online>
Tue, 10 Sep 2024 17:38:48 +0000 (19:38 +0200)
committermarstr <marcus@marstr.online>
Tue, 10 Sep 2024 17:38:48 +0000 (19:38 +0200)
defines.py
layergen.py
orthographic.py
photogen.py
tiledb.py
xp_dsfgen.py
xp_normalmap.py

index a746dacb2ccb6056a986c42c666576ceb8ef1310..11c56e08463d6f648a39ffddfc19681f8a29a281 100644 (file)
@@ -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)
 ]
index fd334af52cb4bbc9d9c97de40a78a949be73ddfe..2dde29cb727b9374ff5850815c94c4e636862bc2 100644 (file)
@@ -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,8 +358,9 @@ class mstr_layergen:
             # on what they are.
             for i in mstr_mask_blur:
                 if i[0] == self._tag and i[1] == self._value:
-                    osm_mask = osm_mask.filter(ImageFilter.BoxBlur(radius=i[2]))
-                    break
+                    if self._tag != "place" and (self._value != "sea" or self._value != "ocean"): 
+                        osm_mask = osm_mask.filter(ImageFilter.BoxBlur(radius=i[2]))
+                        break
             
             # Begin producing a largely random image
             samples = 250   # <- We need this in a moment
@@ -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:
-                    nrm = mstr_xp_normalmap(self._latitude, self._longitude, self._tag, self._value, self._lat_number, self._lng_number, self._latlngfld)
-                    nrm.build_normalmap()
+                    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()
 
index 09024dbbeea3e235318a4da78c40b085e3be7a85..c692a167b6d62b718370fb1a40034cb49aab87f3 100644 (file)
@@ -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")
@@ -210,11 +212,9 @@ class mstr_orthographic:
                     # We should have all layers now.
                     # Snap a photo with our satellite :)
                     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()
                     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("")
+        """
 
 
 
index 99b8bb0eafc7741bc3ecff3e74f171115df75b26..51c97784d9464b973624bd8ee459de5570915ef7 100644 (file)
@@ -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.
@@ -107,15 +119,18 @@ 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,
index 021f59e5da13fadb874910f8e48df0c44613d681..b05c1ae943ae72e2ba2d73735fdbe28082596106 100644 (file)
--- a/tiledb.py
+++ b/tiledb.py
@@ -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")
 
index 4ee910ace742837b16c1345cab4a61ba4aba0524..d764230977ca9f4f60051c8bf78ee335632b343a 100644 (file)
@@ -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()
\ No newline at end of file
index 3f1850b55c6f70c21d8c4fa08a6342df1d024d6b..56996c38eae6d21a9a6d7aac53c85d681e258958 100644 (file)
@@ -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
-        pavg = 255.0 / avg
+        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,44 +97,49 @@ 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):
-                # 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) ]
-
-                # Intensities of pixels
-                it_t  = self.intensity(px_t)
-                it_tr = self.intensity(px_tr)
-                it_r  = self.intensity(px_r)
-                it_br = self.intensity(px_br)
-                it_b  = self.intensity(px_b)
-                it_bl = self.intensity(px_bl)
-                it_l  = self.intensity(px_l)
-                it_tl = self.intensity(px_tl)
-
-                # Sobel filter
-                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)
-                dz = 10 # This is usually a good value for strength
-                v = (dx, dy, dz)
-                nrm = self.normalize_vector(v)
-                
-                # Invert height for our Orthos
-                if nrm[1] > 0:
-                    nrm[1] = 0 - (abs(nrm[1]))
-                else:
-                    nrm[1] = abs(nrm[1])
-
-                # 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)
+        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, 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)
+                    it_tr = self.intensity(px_tr)
+                    it_r  = self.intensity(px_r)
+                    it_br = self.intensity(px_br)
+                    it_b  = self.intensity(px_b)
+                    it_bl = self.intensity(px_bl)
+                    it_l  = self.intensity(px_l)
+                    it_tl = self.intensity(px_tl)
+
+                    # Sobel filter
+                    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)
+                    dz = 10 # This is usually a good value for strength
+                    v = (dx, dy, dz)
+                    nrm = self.normalize_vector(v)
+                    
+                    # Invert height for our Orthos
+                    if nrm[1] > 0:
+                        nrm[1] = 0 - (abs(nrm[1]))
+                    else:
+                        nrm[1] = abs(nrm[1])
+
+                    # 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)
 
         mstr_msg("xp_normalmap", "[X-Plane] Normal map generated")
         return nmp