Perlin-noise based renderer fully functional. perlin.py adjusted to produce fully dynamic Perlin noises, per resource. Scenery generated to produce proper ZL16 tiles. Correction for incorrectly rendered water bodies in photogen.py . Removed waterway:stream from rendering as it is no actual geographical feature.
This commit is contained in:
parent
9eddb97425
commit
88905ac509
@ -71,7 +71,7 @@ mstr_xp_genscenery = True
|
|||||||
|
|
||||||
# Generate normal maps for X-Plane scenery?
|
# Generate normal maps for X-Plane scenery?
|
||||||
# Strong recommendation: yes
|
# Strong recommendation: yes
|
||||||
mstr_xp_scn_normalmaps = True
|
mstr_xp_scn_normalmaps = False
|
||||||
|
|
||||||
# Paths to required X-Plane scenery tools
|
# Paths to required X-Plane scenery tools
|
||||||
#mstr_xp_meshtool = "/home/marcus/Developer/Projects/orthographic/bin/MeshTool"
|
#mstr_xp_meshtool = "/home/marcus/Developer/Projects/orthographic/bin/MeshTool"
|
||||||
@ -195,11 +195,11 @@ mstr_ortho_layers = [
|
|||||||
("building", "commercial", "building", "commercial"),
|
("building", "commercial", "building", "commercial"),
|
||||||
("building", "warehouse", "building", "warehouse"),
|
("building", "warehouse", "building", "warehouse"),
|
||||||
("building", "yes", "building", "common"),
|
("building", "yes", "building", "common"),
|
||||||
|
#("waterway", "river", 3),
|
||||||
("water", "lake", "natural", "water"),
|
("water", "lake", "natural", "water"),
|
||||||
("water", "pond", "natural", "water"),
|
("water", "pond", "natural", "water"),
|
||||||
("water", "river", "natural", "water"),
|
("water", "river", "natural", "water"),
|
||||||
("natural", "water", "natural", "water"),
|
("natural", "water", "natural", "water"),
|
||||||
("waterway", "river", 3),
|
|
||||||
("place", "sea", "natural", "sea"),
|
("place", "sea", "natural", "sea"),
|
||||||
("place", "ocean", "natural", "sea")
|
("place", "ocean", "natural", "sea")
|
||||||
]
|
]
|
||||||
@ -244,11 +244,12 @@ mstr_mask_blur = [
|
|||||||
("natural", "water", 1),
|
("natural", "water", 1),
|
||||||
("natural", "bay", 7),
|
("natural", "bay", 7),
|
||||||
("natural", "beach", 7),
|
("natural", "beach", 7),
|
||||||
|
("natural", "sand", 3),
|
||||||
("water", "lake", 3),
|
("water", "lake", 3),
|
||||||
("water", "pond", 3),
|
("water", "pond", 3),
|
||||||
("water", "river", 3),
|
("water", "river", 3),
|
||||||
("leisure", "swimming_pool", 3),
|
("leisure", "swimming_pool", 3),
|
||||||
("waterway", "river", 3),
|
#("waterway", "river", 3),
|
||||||
("waterway", "stream", 2),
|
("waterway", "stream", 2),
|
||||||
("amenity", "parking", 1),
|
("amenity", "parking", 1),
|
||||||
("amenity", "school", 1),
|
("amenity", "school", 1),
|
||||||
|
@ -361,8 +361,8 @@ class mstr_layergen:
|
|||||||
for x in range(0, layer.width):
|
for x in range(0, layer.width):
|
||||||
xp = prln_x + int(x/prln_pix_step)
|
xp = prln_x + int(x/prln_pix_step)
|
||||||
yp = prln_y + int(y/prln_pix_step)
|
yp = prln_y + int(y/prln_pix_step)
|
||||||
if xp == perlin_map.width: xp = perlin_map.width - 1
|
if xp >= perlin_map.width: xp = perlin_map.width - 1
|
||||||
if yp == perlin_map.height: yp = perlin_map.height - 1
|
if yp >= perlin_map.height: yp = perlin_map.height - 1
|
||||||
pc = perlin_pix[xp,yp]
|
pc = perlin_pix[xp,yp]
|
||||||
df = randrange(0, 6)
|
df = randrange(0, 6)
|
||||||
lc = (pc[0]+df, pc[1]+df, pc[2]+df, 255)
|
lc = (pc[0]+df, pc[1]+df, pc[2]+df, 255)
|
||||||
@ -666,7 +666,6 @@ class mstr_layergen:
|
|||||||
#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" )
|
||||||
mstr_msg("layergen", "Layer image finalized and saved.")
|
mstr_msg("layergen", "Layer image finalized and saved.")
|
||||||
|
|
||||||
|
|
||||||
# Return image
|
# Return image
|
||||||
return layer_comp
|
return layer_comp
|
||||||
|
|
||||||
@ -801,8 +800,6 @@ class mstr_layergen:
|
|||||||
if mp[3] == 255 and tp[3] == 255:
|
if mp[3] == 255 and tp[3] == 255:
|
||||||
tree_pix[x,y] = (0,0,0,0)
|
tree_pix[x,y] = (0,0,0,0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if mstr_shadow_enabled == True:
|
if mstr_shadow_enabled == True:
|
||||||
tree_pix = trees.load()
|
tree_pix = trees.load()
|
||||||
shadow_pix = tree_shadow.load()
|
shadow_pix = tree_shadow.load()
|
||||||
@ -842,7 +839,6 @@ class mstr_layergen:
|
|||||||
return bld_comp
|
return bld_comp
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Find the next "by-ten" numbers for the current latitude and longitude
|
# Find the next "by-ten" numbers for the current latitude and longitude
|
||||||
def find_earthnavdata_number(self):
|
def find_earthnavdata_number(self):
|
||||||
earthnavdata = []
|
earthnavdata = []
|
||||||
|
46
og.py
46
og.py
@ -19,25 +19,26 @@ from defines import *
|
|||||||
|
|
||||||
|
|
||||||
# Print a welcome message
|
# Print a welcome message
|
||||||
print(r' ')
|
def _welcome():
|
||||||
print(r' ____ __ __ __ _ ')
|
print(r' ')
|
||||||
print(r' / __ \_____/ /_/ /_ ____ ____ __________ _____ / /_ (_)____')
|
print(r' ____ __ __ __ _ ')
|
||||||
print(r' / / / / ___/ __/ __ \/ __ \/ __ `/ ___/ __ `/ __ \/ __ \/ / ___/')
|
print(r' / __ \_____/ /_/ /_ ____ ____ __________ _____ / /_ (_)____')
|
||||||
print(r'/ /_/ / / / /_/ / / / /_/ / /_/ / / / /_/ / /_/ / / / / / /__ ')
|
print(r' / / / / ___/ __/ __ \/ __ \/ __ `/ ___/ __ `/ __ \/ __ \/ / ___/')
|
||||||
print(r'\____/_/ \__/_/ /_/\____/\__, /_/ \__,_/ .___/_/ /_/_/\___/ ')
|
print(r'/ /_/ / / / /_/ / / / /_/ / /_/ / / / /_/ / /_/ / / / / / /__ ')
|
||||||
print(r' /____/ /_/ ')
|
print(r'\____/_/ \__/_/ /_/\____/\__, /_/ \__,_/ .___/_/ /_/_/\___/ ')
|
||||||
print(r' ----------------------------------------------------------------')
|
print(r' /____/ /_/ ')
|
||||||
print(r' A ground texture generator, using photo realistic resources,')
|
print(r' ----------------------------------------------------------------')
|
||||||
print(r' for flight simulators.')
|
print(r' A ground texture generator, using photo realistic resources,')
|
||||||
print(r' ----------------------------------------------------------------')
|
print(r' for flight simulators.')
|
||||||
print(r' Developed by and (c) Marcus Str.')
|
print(r' ----------------------------------------------------------------')
|
||||||
print(r' Website: https://marstr.online/orthographic')
|
print(r' Developed by and (c) Marcus Str.')
|
||||||
print(r' Code repo: https://marstr.online/code/gitweb.cgi?p=orthographic')
|
print(r' Website: https://marstr.online/orthographic')
|
||||||
print(r' ----------------------------------------------------------------')
|
print(r' Code repo: http://marstr.online:3000/marstr/orthographic')
|
||||||
print(r' If you paid for this software, you have been scammed. The source')
|
print(r' ----------------------------------------------------------------')
|
||||||
print(r' code and always available free of charge.')
|
print(r' If you paid for this software, you have been scammed. The source')
|
||||||
print(r' ----------------------------------------------------------------')
|
print(r' code and always available free of charge.')
|
||||||
print(r' ')
|
print(r' ----------------------------------------------------------------')
|
||||||
|
print(r' ')
|
||||||
|
|
||||||
|
|
||||||
# Evaluate CLI arguments and process tile.
|
# Evaluate CLI arguments and process tile.
|
||||||
@ -61,20 +62,17 @@ if __name__ == '__main__':
|
|||||||
# Create the class and init values
|
# Create the class and init values
|
||||||
og = mstr_orthographic(lat, lng, mstr_datafolder, os.getcwd(), prep)
|
og = mstr_orthographic(lat, lng, mstr_datafolder, os.getcwd(), prep)
|
||||||
|
|
||||||
# Prepare a tile
|
|
||||||
if sys.argv[3] == "prepare":
|
|
||||||
og._prepareTile()
|
|
||||||
|
|
||||||
# Generate orthos
|
# Generate orthos
|
||||||
if sys.argv[3] != "prepare" and sys.argv[3] != "xpscenery":
|
if sys.argv[3] != "prepare" and sys.argv[3] != "xpscenery":
|
||||||
|
_welcome()
|
||||||
og._generateOrthos_mt(int(sys.argv[3]))
|
og._generateOrthos_mt(int(sys.argv[3]))
|
||||||
|
|
||||||
# Build the terrain mesh and assign ground textures
|
# Build the terrain mesh and assign ground textures
|
||||||
if sys.argv[3] == "xpscenery":
|
if sys.argv[3] == "xpscenery":
|
||||||
|
_welcome()
|
||||||
og.generate_xp_scenery()
|
og.generate_xp_scenery()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if cli == False and pbf == False:
|
if cli == False and pbf == False:
|
||||||
mstr_msg("_main", "Please provide Latitude and Longitude. Exiting.")
|
mstr_msg("_main", "Please provide Latitude and Longitude. Exiting.")
|
||||||
print ("")
|
print ("")
|
||||||
|
@ -241,15 +241,16 @@ class mstr_orthographic:
|
|||||||
# Step 2
|
# Step 2
|
||||||
# Create folders and generate all perlin noise maps
|
# Create folders and generate all perlin noise maps
|
||||||
self._createFolders()
|
self._createFolders()
|
||||||
"""
|
#"""
|
||||||
for l in mstr_ortho_layers:
|
for l in mstr_ortho_layers:
|
||||||
if l[0] != "highway" and l[0] != "building":
|
if l[0] != "highway" and l[0] != "building":
|
||||||
|
fn = mstr_datafolder + "z_orthographic/data/" + self._latlngfld + "/perlin/" + l[0] + "_" + l[1] + ".png"
|
||||||
|
if os.path.isfile(fn) == False:
|
||||||
mstr_important_msg("orthographic", "Generating Perlin map for " + l[0] + ":" + l[1])
|
mstr_important_msg("orthographic", "Generating Perlin map for " + l[0] + ":" + l[1])
|
||||||
prln = mstr_perlin(l[0], l[1], mlat, mlng, 16)
|
prln = mstr_perlin(l[0], l[1], mlat, mlng, 16)
|
||||||
pmap = prln._generatePerlinMap()
|
pmap = prln._generatePerlinMap()
|
||||||
fn = mstr_datafolder + "z_orthographic/data/" + self._latlngfld + "/perlin/" + l[0] + "_" + l[1] + ".png"
|
|
||||||
pmap.save(fn)
|
pmap.save(fn)
|
||||||
"""
|
#"""
|
||||||
|
|
||||||
# For completion layers
|
# For completion layers
|
||||||
numbers = list(range(1, 16))
|
numbers = list(range(1, 16))
|
||||||
@ -285,9 +286,15 @@ class mstr_orthographic:
|
|||||||
mlng = 1
|
mlng = 1
|
||||||
while bb_lat < self._lat + 1:
|
while bb_lat < self._lat + 1:
|
||||||
bb_lat = bb_lat + self._vstep
|
bb_lat = bb_lat + self._vstep
|
||||||
|
if bb_lat >= self._lat + 1:
|
||||||
|
bb_lat = bb_lat - self._zoomlevel
|
||||||
|
break
|
||||||
mlat = mlat+1
|
mlat = mlat+1
|
||||||
while bb_lng < self._long + 1:
|
while bb_lng < self._long + 1:
|
||||||
bb_lng = bb_lng + self._zoomlevel
|
bb_lng = bb_lng + self._zoomlevel
|
||||||
|
if bb_lng >= self._long + 1:
|
||||||
|
bb_lng = bb_lng - self._zoomlevel
|
||||||
|
break
|
||||||
mlng = mlng+1
|
mlng = mlng+1
|
||||||
mstr_msg("orthographic", "Max lat tile: " + str(mlat) + " - max lng tile: " + str(mlng))
|
mstr_msg("orthographic", "Max lat tile: " + str(mlat) + " - max lng tile: " + str(mlng))
|
||||||
maxlatlng = [ mlat, mlng ]
|
maxlatlng = [ mlat, mlng ]
|
||||||
@ -631,7 +638,7 @@ class mstr_orthographic:
|
|||||||
# - the finished orthos
|
# - the finished orthos
|
||||||
# - a current LIDAR scan of the terrain
|
# - a current LIDAR scan of the terrain
|
||||||
def generate_xp_scenery(self):
|
def generate_xp_scenery(self):
|
||||||
mstr_msg("orthographic", "[X-Plane] Generation of scenery started")
|
mstr_important_msg("orthographic", "[X-Plane] Generation of scenery started")
|
||||||
|
|
||||||
# This call appears quite often... surely this can be done better
|
# This call appears quite often... surely this can be done better
|
||||||
mlat = 1
|
mlat = 1
|
||||||
@ -654,8 +661,8 @@ class mstr_orthographic:
|
|||||||
mstr_msg("orthographic", "[X-Plane] Scenery object instantiated")
|
mstr_msg("orthographic", "[X-Plane] Scenery object instantiated")
|
||||||
|
|
||||||
# Download LIDAR scan from our endpoint
|
# Download LIDAR scan from our endpoint
|
||||||
xpscn.acquire_elevation_data()
|
#xpscn.acquire_elevation_data()
|
||||||
mstr_msg("orthographic", "[X-Plane] Elevation data acquired")
|
#mstr_msg("orthographic", "[X-Plane] Elevation data acquired")
|
||||||
|
|
||||||
# Generate the .ter files
|
# Generate the .ter files
|
||||||
xpscn.build_ter_files()
|
xpscn.build_ter_files()
|
||||||
|
107
perlin.py
107
perlin.py
@ -15,6 +15,8 @@ from PIL import Image # Depends on the Pillow lib
|
|||||||
from random import randrange
|
from random import randrange
|
||||||
import random
|
import random
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
import glob
|
||||||
|
from defines import *
|
||||||
from perlin_numpy import (
|
from perlin_numpy import (
|
||||||
generate_perlin_noise_2d, generate_fractal_noise_2d
|
generate_perlin_noise_2d, generate_fractal_noise_2d
|
||||||
)
|
)
|
||||||
@ -32,85 +34,42 @@ class mstr_perlin:
|
|||||||
if zl == 16: self._mapscale = 80
|
if zl == 16: self._mapscale = 80
|
||||||
if zl == 18: self._mapscale = 20
|
if zl == 18: self._mapscale = 20
|
||||||
|
|
||||||
# Define some base colors
|
|
||||||
# tag, value, base color, perlin noise color palette
|
|
||||||
self._bc = [
|
|
||||||
# Amenity
|
|
||||||
["amenity", "parking", (31,32,34,255), [ (31,32,34), (74,74,73), (56,55,55), (34,40,44) ]],
|
|
||||||
["amenity", "school", (26,26,26,255), [ (26,26,26), (78,78,78), (28,29,25), (86,74,64) ]],
|
|
||||||
# Barrier
|
|
||||||
["barrier", "hedge", (27,37,25,255), [ (27,37,25), (8,14,13), (15,20,23), (40,40,38) ]],
|
|
||||||
# Boundary
|
|
||||||
["boundary", "administrative", (50,49,46,255), [ (50,49,46), (32,38,34), (9,14,18), (82,80,76) ]],
|
|
||||||
# Landuse
|
|
||||||
["landuse", "cemetery", (22,22,20,255), [ (22,22,20), (44,43,40), (31,33,29), (39,37,34) ]],
|
|
||||||
["landuse", "construction", (65,51,32,255), [ (65,51,32), (77,73,67), (45,49,43), (74,63,48) ]],
|
|
||||||
["landuse", "farmland", (66,60,49,255), [ (66,60,49), (23,32,27), (14,18,20), (45,43,39) ]],
|
|
||||||
["landuse", "farmyard", (66,60,49,255), [ (66,60,49), (23,32,27), (14,18,20), (45,43,39) ]],
|
|
||||||
["landuse", "forest", (0,30,10,255), [ (0,30,10), (18,23,16), (15,23,24), (24,29,27) ]],
|
|
||||||
["landuse", "grass", (23,24,22,255), [ (23,24,22), (40,27,35), (32,34,30), (54,53,51) ]],
|
|
||||||
["landuse", "greenfield", (23,24,22,255), [ (23,24,22), (40,27,35), (32,34,30), (54,53,51) ]],
|
|
||||||
["landuse", "meadow", (28,29,27,255), [ (28,29,27), (36,42,40), (45,44,41), (21,22,20) ]],
|
|
||||||
["landuse", "military", (23,24,22,255), [ (23,24,22), (40,27,35), (32,34,30), (54,53,51) ]],
|
|
||||||
["landuse", "orchard", (27,38,27,255), [ (27,38,27), (19,22,16), (40,42,33), (40,50,45) ]],
|
|
||||||
["landuse", "recreation_ground", (27,38,27,255), [ (27,38,27), (19,22,16), (40,42,33), (40,50,45) ]],
|
|
||||||
["landuse", "residential", (50,49,46,255), [ (50,49,46), (32,38,34), (9,14,18), (82,80,76) ]],
|
|
||||||
["landuse", "residential-boundary", (50,49,46,255), [ (50,49,46), (32,38,34), (9,14,18), (82,80,76) ]],
|
|
||||||
["landuse", "vineyard", (66,60,49,255), [ (66,60,49), (23,32,27), (14,18,20), (45,43,39) ]],
|
|
||||||
# Leisure
|
|
||||||
["leisure", "dog_park", (66,60,49,255), [ (66,60,49), (23,32,27), (14,18,20), (45,43,39) ]],
|
|
||||||
["leisure", "garden", (39,39,32,255), [ (39,39,32), (38,47,43), (35,41,31), (21,25,18) ]],
|
|
||||||
["leisure", "golf_course", (29,39,28,255), [ (29,39,28), (86,81,76), (60,55,45), (13,18,14) ]],
|
|
||||||
["leisure", "green", (66,60,49,255), [ (66,60,49), (23,32,27), (14,18,20), (45,43,39) ]],
|
|
||||||
["leisure", "nature_reserve", (0,30,10,255), [ (0,30,10), (18,23,16), (15,23,24), (24,29,27) ]],
|
|
||||||
["leisure", "park", (23,24,22,255), [ (23,24,22), (40,27,35), (32,34,30), (54,53,51) ]],
|
|
||||||
["leisure", "pitch", (66,60,49,255), [ (66,60,49), (23,32,27), (14,18,20), (45,43,39) ]],
|
|
||||||
["leisure", "playground", (65,51,32,255), [ (65,51,32), (77,73,67), (45,49,43), (74,63,48) ]],
|
|
||||||
["leisure", "sports_centre", (66,60,49,255), [ (66,60,49), (23,32,27), (14,18,20), (45,43,39) ]],
|
|
||||||
["leisure", "swimming_pool", (9,13,18,255), [ (9,13,18), (9,15,21), (11,12,12), (22,28,31) ]],
|
|
||||||
# Natural
|
|
||||||
["natural", "bare_rock", (47,54,56,255), [ (47,54,56), (79,75,71), (84,51,43), (26,33,45) ]],
|
|
||||||
["natural", "beach", (79,76,69,255), [ (79,76,69), (82,83,80), (71,61,48), (69,68,66) ]],
|
|
||||||
["natural", "desert", (79,64,42,255), [ (79,64,42), (79,47,24), (37,41,27), (51,39,23) ]],
|
|
||||||
["natural", "grassland", (23,24,22,255), [ (23,24,22), (40,27,35), (32,34,30), (54,53,51) ]],
|
|
||||||
["natural", "heath", (26,28,23,255), [ (26,28,23), (45,44,42), (30,34,29), (45,45,42) ]],
|
|
||||||
["natural", "sand", (79,76,69,255), [ (79,76,69), (82,83,80), (71,61,48), (69,68,66) ]],
|
|
||||||
["natural", "scree", (38,36,33,255), [ (38,36,33), (81,80,76), (43,42,31), (37,34,27) ]],
|
|
||||||
["natural", "scrub", (41,39,35,255), [ (41,39,35), (44,38,34), (30,32,39), (20,27,22) ]],
|
|
||||||
["natural", "water", (9,13,18,255), [ (9,13,18), (9,15,21), (11,12,12), (22,28,31) ]],
|
|
||||||
["natural", "wetland", (32,34,33,255), [ (32,34,33), (5, 8, 8), (35,36,35), (17,19,17) ]],
|
|
||||||
["natural", "wood", (0,30,10,255), [ (0,30,10), (18,23,16), (15,23,24), (24,29,27) ]],
|
|
||||||
# Water
|
|
||||||
["water", "lake", (9,13,18,255), [ (9,13,18), (9,15,21), (11,12,12), (22,28,31) ]],
|
|
||||||
["water", "pond", (9,13,18,255), [ (9,13,18), (9,15,21), (11,12,12), (22,28,31) ]],
|
|
||||||
["water", "river", (9,13,18,255), [ (9,13,18), (9,15,21), (11,12,12), (22,28,31) ]]
|
|
||||||
]
|
|
||||||
|
|
||||||
|
def _generateColorIndex(self):
|
||||||
|
idx = []
|
||||||
|
|
||||||
|
colorsrc = glob.glob(mstr_datafolder + "textures/" + self._tag + "/" + self._value + "/*.png")
|
||||||
|
if len(colorsrc) >= 4:
|
||||||
|
picknum = list(range(0, len(colorsrc)))
|
||||||
|
picksel = random.sample(picknum, 4)
|
||||||
|
|
||||||
|
for p in range(0, 4):
|
||||||
|
ptc = Image.open(colorsrc[picksel[p]])
|
||||||
|
ptc = ptc.resize((1,1), resample=Image.Resampling.BILINEAR)
|
||||||
|
clr = ptc.getpixel((0,0))
|
||||||
|
res = (clr[0], clr[1], clr[2])
|
||||||
|
idx.append(res)
|
||||||
|
|
||||||
# Find base color depending on tag/value
|
|
||||||
def _findBaseColor(self):
|
|
||||||
idx = -1
|
|
||||||
for b in range(len(self._bc)):
|
|
||||||
if self._bc[b][0] == self._tag and self._bc[b][1] == self._value:
|
|
||||||
idx = b
|
|
||||||
break
|
|
||||||
return idx
|
return idx
|
||||||
|
|
||||||
|
|
||||||
# Generates a Perlin map depending on what we need
|
# Generates a Perlin map depending on what we need
|
||||||
def _generatePerlinMap(self):
|
def _generatePerlinMap(self):
|
||||||
idx = self._findBaseColor()
|
#idx = self._findBaseColor()
|
||||||
|
clr = self._generateColorIndex()
|
||||||
bw = self._mlng * self._mapscale
|
bw = self._mlng * self._mapscale
|
||||||
bh = self._mlat * self._mapscale
|
bh = self._mlat * self._mapscale
|
||||||
wh = 2048
|
base = Image.new("RGBA", (bw,bh))
|
||||||
base = Image.new("RGBA", (bw,bh), self._bc[idx][2])
|
|
||||||
|
|
||||||
for c in range(len(self._bc[idx][3])):
|
if len(clr) == 4:
|
||||||
|
wh = 2048
|
||||||
|
base = Image.new("RGBA", (bw,bh), clr[0])
|
||||||
|
|
||||||
|
for c in range(len(clr)):
|
||||||
np.random.seed(randrange(10000000, 100000000))
|
np.random.seed(randrange(10000000, 100000000))
|
||||||
noise1 = generate_fractal_noise_2d((wh,wh), (16,16), 5)
|
noise1 = generate_fractal_noise_2d((wh,wh), (64,64), 5)
|
||||||
np.random.seed(randrange(10000000, 100000000))
|
np.random.seed(randrange(10000000, 100000000))
|
||||||
noise2 = generate_fractal_noise_2d((wh,wh), (8,8), 4)
|
noise2 = generate_fractal_noise_2d((wh,wh), (32,32), 4)
|
||||||
|
|
||||||
im1 = Image.new("RGBA", (wh,wh))
|
im1 = Image.new("RGBA", (wh,wh))
|
||||||
im2 = Image.new("RGBA", (wh,wh))
|
im2 = Image.new("RGBA", (wh,wh))
|
||||||
@ -119,9 +78,9 @@ class mstr_perlin:
|
|||||||
for x in range(0, wh):
|
for x in range(0, wh):
|
||||||
n = (noise1[y][x] + 1) / 2
|
n = (noise1[y][x] + 1) / 2
|
||||||
v = (
|
v = (
|
||||||
self._bc[idx][3][c][0],
|
clr[c][0],
|
||||||
self._bc[idx][3][c][1],
|
clr[c][1],
|
||||||
self._bc[idx][3][c][2],
|
clr[c][2],
|
||||||
int(n*255)
|
int(n*255)
|
||||||
)
|
)
|
||||||
im1.putpixel((x,y), v)
|
im1.putpixel((x,y), v)
|
||||||
@ -130,14 +89,14 @@ class mstr_perlin:
|
|||||||
for x in range(0, wh):
|
for x in range(0, wh):
|
||||||
n = (noise2[y][x] + 1) / 2
|
n = (noise2[y][x] + 1) / 2
|
||||||
v = (
|
v = (
|
||||||
self._bc[idx][3][c][0],
|
clr[c][0],
|
||||||
self._bc[idx][3][c][1],
|
clr[c][1],
|
||||||
self._bc[idx][3][c][2],
|
clr[c][2],
|
||||||
int(n*255)
|
int(n*255)
|
||||||
)
|
)
|
||||||
im2.putpixel((x,y), v)
|
im2.putpixel((x,y), v)
|
||||||
|
|
||||||
im = Image.blend(im1,im2, alpha=0.5)
|
im = Image.blend(im1,im2, alpha=0.675)
|
||||||
base.alpha_composite(im)
|
base.alpha_composite(im)
|
||||||
|
|
||||||
# Provide the perlin map
|
# Provide the perlin map
|
||||||
|
85
photogen.py
85
photogen.py
@ -210,8 +210,6 @@ class mstr_photogen:
|
|||||||
#self._tile = ImageEnhance.Contrast(self._tile).enhance(0.1)
|
#self._tile = ImageEnhance.Contrast(self._tile).enhance(0.1)
|
||||||
|
|
||||||
# This we can save accordingly.
|
# This we can save accordingly.
|
||||||
self._tile.show()
|
|
||||||
exit()
|
|
||||||
self._tile.save(mstr_datafolder + "z_orthographic/orthos/" + self._latlngfld + "/" + str(self._ty) + "_" + str(self._tx) + ".png")
|
self._tile.save(mstr_datafolder + "z_orthographic/orthos/" + self._latlngfld + "/" + str(self._ty) + "_" + str(self._tx) + ".png")
|
||||||
|
|
||||||
# Now we convert this into a DDS
|
# Now we convert this into a DDS
|
||||||
@ -489,13 +487,13 @@ class mstr_photogen:
|
|||||||
# First the residential/forest dilemma
|
# First the residential/forest dilemma
|
||||||
residential = -1
|
residential = -1
|
||||||
forest = -1
|
forest = -1
|
||||||
|
reserve = -1
|
||||||
|
|
||||||
curlyr = 0
|
curlyr = 0
|
||||||
for lyr in self._lyrnames:
|
for lyr in self._lyrnames:
|
||||||
if lyr[0] == "landuse" and lyr[1] == "residential":
|
if lyr[0] == "landuse" and lyr[1] == "residential": residential=curlyr
|
||||||
residential=curlyr
|
if lyr[0] == "landuse" and lyr[1] == "forest": forest = curlyr
|
||||||
if lyr[0] == "landuse" and lyr[1] == "forest":
|
if lyr[0] == "leisure" and lyr[1] == "nature_reserve": reserve = curlyr
|
||||||
forest = curlyr
|
|
||||||
curlyr = curlyr+1
|
curlyr = curlyr+1
|
||||||
|
|
||||||
# Make sure we hit the correct layers with correct content!
|
# Make sure we hit the correct layers with correct content!
|
||||||
@ -515,11 +513,82 @@ class mstr_photogen:
|
|||||||
|
|
||||||
layers[forest].alpha_composite(rsd_adj)
|
layers[forest].alpha_composite(rsd_adj)
|
||||||
|
|
||||||
|
|
||||||
|
if residential != -1 and reserve != -1:
|
||||||
|
rsd_pix = layers[residential].load()
|
||||||
|
frs_pix = layers[reserve].load()
|
||||||
|
rsd_adj = Image.new("RGBA", (self._imgsize, self._imgsize))
|
||||||
|
adj_pix = rsd_adj.load()
|
||||||
|
|
||||||
|
for y in range(0, self._tile.height):
|
||||||
|
for x in range(0, self._tile.width):
|
||||||
|
fp = frs_pix[x,y]
|
||||||
|
rp = rsd_pix[x,y]
|
||||||
|
if rp[3] > 0 and fp[3] > 0:
|
||||||
|
adj_pix[x,y] = (rp[0], rp[1], rp[2], rp[3])
|
||||||
|
|
||||||
|
layers[reserve].alpha_composite(rsd_adj)
|
||||||
|
|
||||||
|
# At ZL16 there seems to be an issue with water bodies, especially rivers (natural:water).
|
||||||
|
# Let's see if we can correct that
|
||||||
|
|
||||||
|
# natural:water
|
||||||
|
ntrl_water = False
|
||||||
|
ntrl_idx = 0
|
||||||
|
for lyr in self._lyrnames:
|
||||||
|
if lyr[0] == "natural" and lyr[1] == "water":
|
||||||
|
ntrl_water = True
|
||||||
|
break
|
||||||
|
ntrl_idx = ntrl_idx + 1
|
||||||
|
|
||||||
|
if ntrl_water == True:
|
||||||
|
|
||||||
|
# We'll go through all layers and "shavve off" excess.
|
||||||
|
# This way we can hopefully correct incorrect line and polygon renders.
|
||||||
|
for l in range(0, len(layers)):
|
||||||
|
if l < ntrl_idx: # <- We don't want to load the target layer itself
|
||||||
|
lyrpix = layers[l].load()
|
||||||
|
wtr_pix = layers[ntrl_idx].load()
|
||||||
|
for y in range(0, self._tile.height):
|
||||||
|
for x in range(0, self._tile.width):
|
||||||
|
lp = lyrpix[x,y]
|
||||||
|
wp = wtr_pix[x,y]
|
||||||
|
if lp[3] > 0:
|
||||||
|
a = 255 - lp[3]
|
||||||
|
if a < wp[3]:
|
||||||
|
c = (wp[0], wp[1], wp[2], a)
|
||||||
|
wtr_pix[x,y] = c
|
||||||
|
|
||||||
|
# water:river
|
||||||
|
river_water = False
|
||||||
|
river_idx = 0
|
||||||
|
for lyr in self._lyrnames:
|
||||||
|
if lyr[0] == "water" and lyr[1] == "river":
|
||||||
|
river_water = True
|
||||||
|
break
|
||||||
|
river_idx = river_idx + 1
|
||||||
|
|
||||||
|
if river_water == True:
|
||||||
|
|
||||||
|
# We'll go through all layers and "shavve off" excess.
|
||||||
|
# This way we can hopefully correct incorrect line and polygon renders.
|
||||||
|
for l in range(0, len(layers)):
|
||||||
|
if l < river_idx and l != ntrl_idx: # <- We don't want to load the target layer itself
|
||||||
|
lyrpix = layers[l].load()
|
||||||
|
wtr_pix = layers[river_idx].load()
|
||||||
|
for y in range(0, self._tile.height):
|
||||||
|
for x in range(0, self._tile.width):
|
||||||
|
lp = lyrpix[x,y]
|
||||||
|
wp = wtr_pix[x,y]
|
||||||
|
if lp[3] > 0:
|
||||||
|
a = 255 - lp[3]
|
||||||
|
if a < wp[3]:
|
||||||
|
c = (wp[0], wp[1], wp[2], a)
|
||||||
|
wtr_pix[x,y] = c
|
||||||
|
|
||||||
return layers
|
return layers
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 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,
|
||||||
|
@ -92,8 +92,13 @@ class mstr_xp_scenery:
|
|||||||
end = self.find_earthnavdata_number()
|
end = self.find_earthnavdata_number()
|
||||||
llf = self.xplane_latlng_folder(end)
|
llf = self.xplane_latlng_folder(end)
|
||||||
meshtxt = mstr_datafolder + "_cache/mesh_"+self._latlngfld+".txt"
|
meshtxt = mstr_datafolder + "_cache/mesh_"+self._latlngfld+".txt"
|
||||||
cmd = mstr_xp_dsftool + " --text2dsf " + meshtxt + " '" + mstr_datafolder + "z_orthographic/Earth nav data/" + llf + "/" + self._latlngfld + ".dsf'"
|
meshtxt = meshtxt.replace("/", "\\")
|
||||||
|
cmdpath = mstr_datafolder + "_cache/" + self._latlngfld + ".dsf"
|
||||||
|
#cmdpath = mstr_datafolder + "z_orthographic/Earth nav data/" + llf + "/" + self._latlngfld + ".dsf"
|
||||||
|
cmdpath = cmdpath.replace("/", "\\")
|
||||||
|
cmd = mstr_xp_dsftool + " --text2dsf " + meshtxt + " " + cmdpath
|
||||||
os.system(cmd)
|
os.system(cmd)
|
||||||
|
os.replace(cmdpath, mstr_datafolder + "z_orthographic/Earth nav data/" + llf + "/" + self._latlngfld + ".dsf")
|
||||||
|
|
||||||
|
|
||||||
# Find exact with of longitude
|
# Find exact with of longitude
|
||||||
@ -165,14 +170,14 @@ class mstr_xp_scenery:
|
|||||||
cur_lat = self._lat
|
cur_lat = self._lat
|
||||||
cur_lng = self._lng
|
cur_lng = self._lng
|
||||||
xp_folder = self.xplane_latlng_folder([self._lat, self._lng])
|
xp_folder = self.xplane_latlng_folder([self._lat, self._lng])
|
||||||
for lat in range(1, self._mlat+1):
|
for lat in range(1, self._mlat):
|
||||||
for lng in range(1, self._mlng+1):
|
for lng in range(1, self._mlng):
|
||||||
|
|
||||||
wdt = self.find_width_of_longitude(cur_lat)
|
wdt = self.find_width_of_longitude(cur_lat)
|
||||||
dmt = wdt * mstr_zl_18
|
dmt = wdt * mstr_zl_16
|
||||||
|
|
||||||
cnt_x = cur_lat + (self._vstep/2)
|
cnt_x = cur_lat + (self._vstep/2)
|
||||||
cnt_y = cur_lng + (mstr_zl_18/2)
|
cnt_y = cur_lng + (mstr_zl_16/2)
|
||||||
|
|
||||||
terstr = ""
|
terstr = ""
|
||||||
terstr = terstr + "A\r\n"
|
terstr = terstr + "A\r\n"
|
||||||
@ -181,15 +186,15 @@ class mstr_xp_scenery:
|
|||||||
terstr = terstr + "\r\n"
|
terstr = terstr + "\r\n"
|
||||||
terstr = terstr + "LOAD_CENTER " + str(cnt_x) + " " + str(cnt_y) + " " + str(dmt) + " 2048\r\n"
|
terstr = terstr + "LOAD_CENTER " + str(cnt_x) + " " + str(cnt_y) + " " + str(dmt) + " 2048\r\n"
|
||||||
terstr = terstr + "BASE_TEX_NOWRAP ../../orthos/" + self._latlngfld + "/" + str(lat)+"_"+str(lng)+".dds\r\n"
|
terstr = terstr + "BASE_TEX_NOWRAP ../../orthos/" + self._latlngfld + "/" + str(lat)+"_"+str(lng)+".dds\r\n"
|
||||||
if mstr_xp_scn_normalmaps:
|
#if mstr_xp_scn_normalmaps:
|
||||||
terstr = terstr + "NORMAL_TEX 1.0 ../../normals/" + self._latlngfld + "/" + str(lat)+"_"+str(lng)+".png\r\n"
|
# terstr = terstr + "NORMAL_TEX 1.0 ../../normals/" + self._latlngfld + "/" + str(lat)+"_"+str(lng)+".png\r\n"
|
||||||
|
|
||||||
terfln = mstr_datafolder + "z_orthographic/terrain/" + self._latlngfld + "/" + str(lat)+"_"+str(lng)+".ter"
|
terfln = mstr_datafolder + "z_orthographic/terrain/" + self._latlngfld + "/" + str(lat)+"_"+str(lng)+".ter"
|
||||||
|
|
||||||
with open(terfln, 'w') as textfile:
|
with open(terfln, 'w') as textfile:
|
||||||
textfile.write(terstr)
|
textfile.write(terstr)
|
||||||
|
|
||||||
cur_lng = round(cur_lng + mstr_zl_18, 6)
|
cur_lng = round(cur_lng + mstr_zl_16, 6)
|
||||||
|
|
||||||
cur_lng = self._lng
|
cur_lng = self._lng
|
||||||
cur_lat = round(cur_lat + self._vstep, 6)
|
cur_lat = round(cur_lat + self._vstep, 6)
|
||||||
@ -200,7 +205,7 @@ class mstr_xp_scenery:
|
|||||||
# This generates the entire terrain mesh
|
# This generates the entire terrain mesh
|
||||||
def generate_terrain_mesh(self):
|
def generate_terrain_mesh(self):
|
||||||
# Get the DEM model file name, and acquire important info about the data
|
# Get the DEM model file name, and acquire important info about the data
|
||||||
meshfn = mstr_datafolder + "_cache/" + self.build_dem_filename()
|
meshfn = mstr_datafolder + "z_orthographic/data/" + self._latlngfld + "/" + self.build_dem_filename()
|
||||||
siz = os.path.getsize(meshfn)
|
siz = os.path.getsize(meshfn)
|
||||||
dim = int(math.sqrt(siz/2))
|
dim = int(math.sqrt(siz/2))
|
||||||
assert dim*dim*2 == siz, 'Invalid file size'
|
assert dim*dim*2 == siz, 'Invalid file size'
|
||||||
@ -245,8 +250,8 @@ class mstr_xp_scenery:
|
|||||||
dsf_str = ""
|
dsf_str = ""
|
||||||
|
|
||||||
# Orthos
|
# Orthos
|
||||||
for lat in range(1, self._mlat+1):
|
for lat in range(1, self._mlat):
|
||||||
for lng in range(1, self._mlng+1):
|
for lng in range(1, self._mlng):
|
||||||
# Write the line only if an ortho exists of course.
|
# Write the line only if an ortho exists of course.
|
||||||
ddsf = mstr_datafolder + "z_orthographic/orthos/" + self._latlngfld + "/" + str(lat) + "_" + str(lng) + ".dds"
|
ddsf = mstr_datafolder + "z_orthographic/orthos/" + self._latlngfld + "/" + str(lat) + "_" + str(lng) + ".dds"
|
||||||
if os.path.isfile(ddsf):
|
if os.path.isfile(ddsf):
|
||||||
@ -261,8 +266,8 @@ class mstr_xp_scenery:
|
|||||||
# Current patch
|
# Current patch
|
||||||
curpatch = 0
|
curpatch = 0
|
||||||
|
|
||||||
for lat in range(1, self._mlat+1):
|
for lat in range(1, self._mlat):
|
||||||
for lng in range(1, self._mlng+1):
|
for lng in range(1, self._mlng):
|
||||||
|
|
||||||
# Create the patch only if the matching ortho exists.
|
# Create the patch only if the matching ortho exists.
|
||||||
# This way we make sure that we hit the same order as the .ter files.
|
# This way we make sure that we hit the same order as the .ter files.
|
||||||
@ -273,7 +278,7 @@ class mstr_xp_scenery:
|
|||||||
|
|
||||||
# Base coords for this ortho
|
# Base coords for this ortho
|
||||||
base_lat = self._lat + ((lat-1) * self._vstep)
|
base_lat = self._lat + ((lat-1) * self._vstep)
|
||||||
base_lng = self._lng + ((lng-1) * mstr_zl_18)
|
base_lng = self._lng + ((lng-1) * mstr_zl_16)
|
||||||
|
|
||||||
# Begin a new patch
|
# Begin a new patch
|
||||||
mstr_msg("xp_scenery", "[X-Plane] Processing ortho patch " + str(curpatch))
|
mstr_msg("xp_scenery", "[X-Plane] Processing ortho patch " + str(curpatch))
|
||||||
@ -281,9 +286,10 @@ class mstr_xp_scenery:
|
|||||||
textfile.write("BEGIN_PATCH " + str(curpatch) + " 0.000000 -1.000000 1 7\r\n")
|
textfile.write("BEGIN_PATCH " + str(curpatch) + " 0.000000 -1.000000 1 7\r\n")
|
||||||
|
|
||||||
# Step for each ortho vertex
|
# Step for each ortho vertex
|
||||||
odiv = 4
|
#odiv = 4
|
||||||
|
odiv = 16
|
||||||
latstep = self._vstep/odiv
|
latstep = self._vstep/odiv
|
||||||
lngstep = mstr_zl_18 /odiv
|
lngstep = mstr_zl_16 /odiv
|
||||||
uv_step = 1 / odiv
|
uv_step = 1 / odiv
|
||||||
|
|
||||||
# Generate the ortho tile
|
# Generate the ortho tile
|
||||||
@ -300,10 +306,14 @@ class mstr_xp_scenery:
|
|||||||
lng_l = base_lng
|
lng_l = base_lng
|
||||||
if y == 0:
|
if y == 0:
|
||||||
lat_b = base_lat
|
lat_b = base_lat
|
||||||
if y == 3:
|
if y == 15:
|
||||||
|
#if y == 3:
|
||||||
lat_t = base_lat + self._vstep
|
lat_t = base_lat + self._vstep
|
||||||
if x == 3:
|
if x == 15:
|
||||||
lng_r = base_lng + mstr_zl_18
|
lng_r = base_lng + mstr_zl_16
|
||||||
|
#if x == 3:
|
||||||
|
#lng_r = base_lng + mstr_zl_18
|
||||||
|
|
||||||
|
|
||||||
# Corrections, just in case
|
# Corrections, just in case
|
||||||
if lat_b > self._lat + 1: lat_b = self._lat+1
|
if lat_b > self._lat + 1: lat_b = self._lat+1
|
||||||
|
Loading…
x
Reference in New Issue
Block a user