Open Shando opened 2 years ago
And this is the def for world3dA:
def world3dA(inHeightmap, inWidth, inDepth, inHeight, inTextureMap, inBumpMap, inSeaLevel):
DISPLAY = pi3d.Display.create(0, 0, 1280, 1024)
CAMERA = pi3d.Camera.instance()
base_tex = np.array(Image.open(inTextureMap))
# texture for land
base_gr = base_tex.copy()
ix = np.where(base_gr[:,:,2] > 20) # i.e. was blue
base_gr[ix[0], ix[1], 1] += 50 # increase green
base_gr[ix[0], ix[1], 2] = 0 # reduce blue
texg = pi3d.Texture(base_gr)
# texture for water
base_bl = base_tex.copy()
base_bl[:,:] = [0, 0, 60, 170] # uniform slightly transparent
texb = pi3d.Texture(base_bl)
grass_tex = pi3d.Texture('textures/grasstile_n.jpg')
w_norm = pi3d.Texture('textures/n_norm000.png')
shader = pi3d.Shader("uv_bump")
rshader = pi3d.Shader("uv_reflect")
mapwidth = inWidth
mapdepth = inDepth
mapheight = inHeight
mymap = pi3d.ElevationMap(inBumpMap, width=mapwidth, depth=mapdepth, height=mapheight, divx=199, divy=199,
ntiles=1, name="sub")
mymap.set_draw_details(shader, [texg, grass_tex], 200.0)
wmap = pi3d.ElevationMap(inBumpMap, width=mapwidth, depth=mapdepth, height=mapheight * 0.1, divx=199, divy=199,
ntiles=1, name="water", y=inSeaLevel)
wmap.set_draw_details(rshader, [texb, w_norm, texg], 50.0, 0.2)
rot = 0.0
tilt = 0.0
height = 20.0
viewHeight = 4
sky = 200
xm, ym, zm = 0.0, height, 0.0
onGround = False
mykeys = pi3d.Keyboard()
mymouse = pi3d.Mouse(restrict=False)
mymouse.start()
omx, omy = mymouse.position()
while DISPLAY.loop_running():
mx, my = mymouse.position()
rot -= (mx - omx) * 0.2
tilt -= (my - omy) * 0.2
omx = mx
omy = my
CAMERA.reset()
CAMERA.rotate(-tilt, rot, 0)
CAMERA.position((xm, ym, zm))
mymap.draw()
wmap.draw()
k = mykeys.read()
if k > -1:
if k == 48: # ESCAPE key - '0' Key
mykeys.close()
mymouse.stop()
DISPLAY.destroy()
break
elif k == 87 or k == 119: # FORWARDS key - 'W' Key
xm -= sin(radians(rot))
zm += cos(radians(rot))
elif k == 83 or k == 115: # BACKWARDS key - 'S' Key
xm += sin(radians(rot))
zm -= cos(radians(rot))
elif k == 82 or k == 114: # UPWARDS key - 'R' Key
ym += 2
onGround = False
elif k == 84 or k == 116: # DOWNWARDS key - 'T' Key
ym -= 2
ym -= 0.1
xm = limit(xm, -(mapwidth / 2), (mapwidth / 2))
zm = limit(zm, -(mapdepth / 2), (mapdepth / 2))
if ym >= sky:
ym = sky
ground = mymap.calcHeight(xm, zm) + viewHeight
if (onGround is True) or (ym <= ground):
ym = mymap.calcHeight(xm, zm) + viewHeight
onGround = True
Hi, I will try too have a look at this later today. What hardware are you running on?
Hi, I've had a quick look and there are a couple of things: 1. The argument naming (the diffuse texture is called '..elevation' and the elevation texture is called '..normal')! 2. I haven't really understood why you want to close and recreate the display window rather than just regenerate mymap
and wmap
, which would be much quicker and wouldn't cause any errors.
world3dA is effectively the main()
function and calling that from inside itself seem fraught with unnecessary problems. Maybe explain a bit more why you need to do that. If it turns out to be the only way they you probably should open and close each instance as a subprocess.
Paddy
Hey Paddy, thanks for the quick reply.
I probably didn't explain myself too well :(
1) I'm running on a Ryzen 7 with inbuilt Radeon graphics on Windows 10 (I do also have a GeForce GTX1650 in the same machine, but haven't tried with that yet) 2) The naming is due to me creating a Grayscale Heightmap, a Normal Map and an Elevation Map (a coloured view of the world). These maps are generated (except the Normal Map) to be displayed in my graphical WorldEngine GUI, which generates worlds using plate tectonics etc. 3) The 3D View is generated when the user clicks a button in the GUI and is meant to give them an idea what the world would look like in 3D. This is the reason I need to close and reopen the pi3d instance, as I can't leave the 3D view running when they are generating a different world.
The file I attached was just a test that I did to ensure that the blue screen always happened on the 2nd and subsequent attempts to create a new view. In my actual code, it's called from a main file where all my gui code is.
Hope that explains a bit more?
Thanks again
Shando
OK. It sounds to be an interesting idea. I think you will have problems trying to close and reopen pi3d.Display
. It might be possible to do but the OpenGL side is all C function calls and that means 'unsafety' is built in! Especially calling from python through ctypes, which tends to have a go at doing what it thinks you want... fine until it stops working.
I think my approach would be to have my main()
function creating and holding an instance of the pi3d scene stuff as a class which would have the key checking as a public method and the texture and environment map creation as a public method. I will hack the code into an approximation of what I mean, as an example. If you don't want the pi3d window showing you can have a method to move it out of the way so you can't see it.
Hi, this is a superficial re-structure of your zipped file. I've not done too much and not even tried running it so there are probably typos and other bugs/mistakes. However it gives you the idea of the approach I might take. You mention a button on the GUI so it will be critical what event loop you are using for that. Generally speaking I find it much better to hang pi3d off the GUI event loop rather than getting the two fighting. i.e. the while world.loop_running():
below would be a tk or pygame loop.
from math import sin, cos, radians
import pi3d
from PIL import Image
import numpy as np
WORLDS = (
('Maps/seed_32829_grayscale.png', 1024, 1024, 200, 'Maps/seed_32829_elevation.png', 'Maps/seed_32829_normal.png', 100),
('Maps/seed_11111_grayscale.png', 1024, 1024, 200, 'Maps/seed_11111_elevation.png', 'Maps/seed_11111_normal.png', 100),
('Maps/seed_42958_grayscale.png', 1024, 1024, 200, 'Maps/seed_42958_elevation.png', 'Maps/seed_42958_normal.png', 100),
('Maps/seed_2593_grayscale.png', 1024, 1024, 200, 'Maps/seed_2593_elevation.png', 'Maps/seed_2593_normal.png', 100),
('Maps/seed_32829_grayscale.png', 1024, 1024, 200, 'Maps/seed_32829_elevation.png', 'Maps/seed_32829_normal.png', 100)
)
def limit(value, inMin, inMax):
if value < inMin:
value = inMin
elif value > inMax:
value = inMax
return value
class World3dA:
def__init__(self, inHeightmap, inWidth, inDepth, inHeight, inTextureMap, inBumpMap, inSeaLevel):
self.DISPLAY = pi3d.Display.create(0, 0, 1280, 1024)
self.CAMERA = pi3d.Camera.instance()
self.grass_tex = pi3d.Texture('textures/grasstile_n.jpg')
self.w_norm = pi3d.Texture('textures/n_norm000.png')
self.shader = pi3d.Shader("uv_bump")
self.rshader = pi3d.Shader("uv_reflect")
self.viewHeight = 4
self.sky = 200
self.mykeys = pi3d.Keyboard()
self.mymouse = pi3d.Mouse(restrict=False)
self.mymouse.start()
self.create_world(inHeightmap, inWidth, inDepth, inHeight, inTextureMap, inBumpMap, inSeaLevel)
self.keep_looping = True
def create_world(self, inHeightmap, inWidth, inDepth, inHeight, inTextureMap, inBumpMap, inSeaLevel):
base_tex = np.array(Image.open(inTextureMap))
# texture for land
base_gr = base_tex.copy()
ix = np.where(base_gr[:,:,2] > 20) # i.e. was blue
base_gr[ix[0], ix[1], 1] += 50 # increase green
base_gr[ix[0], ix[1], 2] = 0 # reduce blue
texg = pi3d.Texture(base_gr)
# texture for water
base_bl = base_tex.copy()
base_bl[:,:] = [0, 0, 60, 170] # uniform slightly transparent
texb = pi3d.Texture(base_bl)
self.mapwidth = inWidth
self.mapdepth = inDepth
self.mapheight = inHeight
self.mymap = pi3d.ElevationMap(inBumpMap, width=self.mapwidth, depth=self.mapdepth, height=self.mapheight, divx=199, divy=199,
ntiles=1, name="sub")
self.mymap.set_draw_details(self.shader, [texg, grass_tex], 200.0)
self.wmap = pi3d.ElevationMap(inBumpMap, width=self.mapwidth, depth=self.mapdepth, height=self.mapheight * 0.1, divx=199, divy=199,
ntiles=1, name="water", y=inSeaLevel)
self.wmap.set_draw_details(self.rshader, [texb, w_norm, texg], 50.0, 0.2)
self.rot = 0.0
self.tilt = 0.0
self.height = 20.0
self.xm, self.ym, self.zm = 0.0, self.height, 0.0
self.onGround = False
self.omx, self.omy = self.mymouse.position()
def loop_running(self):
if self.keep_looping and self.DISPLAY.loop_running():
mx, my = mymouse.position()
self.rot -= (mx - self.omx) * 0.2
self.tilt -= (my - self.omy) * 0.2
self.omx = mx
self.omy = my
self.CAMERA.reset()
self.CAMERA.rotate(-self.tilt, self.rot, 0)
self.CAMERA.position((self.xm, self.ym, self.zm))
self.mymap.draw()
self.wmap.draw()
return True
else:
return False
def stop_looping(self):
self.keep_looping = False
self.mykeys.close()
self.mymouse.stop()
self.DISPLAY.destroy()
def read_key_and_move(self):
k = self.mykeys.read()
if k > -1:
if k == 48: # ESCAPE key - '0' Key
return k # return early and do scene change or stop
elif k == 87 or k == 119: # FORWARDS key - 'W' Key
self.xm -= sin(radians(rot))
self.zm += cos(radians(rot))
elif k == 83 or k == 115: # BACKWARDS key - 'S' Key
self.xm += sin(radians(rot))
self.zm -= cos(radians(rot))
elif k == 82 or k == 114: # UPWARDS key - 'R' Key
self.ym += 2
self.onGround = False
elif k == 84 or k == 116: # DOWNWARDS key - 'T' Key
self.ym -= 2
# only do this if a move key was pressed?
self.ym -= 0.1
self.xm = limit(self.xm, -(self.mapwidth / 2), (self.mapwidth / 2))
self.zm = limit(self.zm, -(self.mapdepth / 2), (self.mapdepth / 2))
if self.ym >= self.sky:
self.ym = self.sky
self.ground = mymap.calcHeight(self.xm, self.zm) + self.viewHeight
if self.onGround or (self.ym <= self.ground):
self.ym = mymap.calcHeight(self.xm, self.zm) + self.viewHeight
self.onGround = True
return None
def main():
my_var = 0
world = World3dA(*WORLDS[my_var])
my_var += 1
while world.loop_running():
if world.read_key_and_move() == 48:
if my_var >= len(WORLDS):
world.stop_looping()
else:
world.create_world(*WORLDS[my_var])
my_var += 1
if __name__ == '__main__':
main()
Hey Paddy,
Thanks for the help. It certainly pointed me in the right direction and, with some messing about with 'win32gui' and 'win32con' I now have the 3D window not only pausing and updating correctly every time the button is pressed, but also being moved in front of the main GUI window when running and back behind it when not :)
Thanks again for the help
Shando
Great, look forward to seeing the finished product.
Hey Paddy,
Not sure if you're a Windoze person, but my WorldEngine GUI is now complete (as far as I can tell!). You can access the GitHub repository here https://github.com/Shando/WorldEngine_UI. In the 'WorldEngine/worldengine/dist/wegui' folder there is the 'wegui.exe' file that should run the whole shebang without needing to set up any special environments.
There is one prebuilt "World" included (seed_11111.world), which you can load up to view the Maps / 3D. Unfortunately, due to its size, I've had to use the GitHub LFS, so not sure if I still have any bandwidth left? If it doesn't download, you can also download it from here https://1drv.ms/u/s!Au7DMGV6totzgsA7TIAjmXee_3HegA?e=CIm8Kt
Thanks for your help with this.
Shando
I have tried to launch pi3d multiple times from the same code and every time it works fine the 1st time around and then I get a blue pi3d screen on subsequent launches (i.e. when pressing the '0' key) and the mouse only allows movement in a very small area in the middle of the screen?
Each launch follows calls to: mykeys.close() mymouse.stop() DISPLAY.destroy() as I need to close the pi3d window before loading another map.
See code here: MyTest.zip
This is part of a larger codebase (my GUI for WorldEngine) and I am probably doing something wrong?
Any help would be greatly appreciated
Thanks in advance
Shando
PS: I'm using the following: python 3.6.8 pi3d 2.49 pygame 2.1.1 PyOpenGL 3.1.5