I'm slowly writing a space game and am ready for introducing some actual graphics.
I need to wrap a planet texture around a sphere, and have this sphere tilted, rotating and have a variable colour light source + shadow applied to it. Ideally I'd also love to have an atmosphere sphere over it.
My knowlege of DX, API, etc, etc is next to nothing, I'm picture box and PSET level.
I've looked at various examples on PlanetSourceCode but none are really what I'm after.
The best I've found uses a rmcontrol.ocx control but I've been unable to find any documentation about it. I've been able to make a new project that uses this control and display a rotating sphere and even change the lighting colour but I've been unable to work out if it can do transparencies for the atmosphere layer or how to specify a tilt.
I'd also like to be able to take a static version of the generated image to put into a picturebox for display in other areas. It's possible I could use the RMControl instead of the picturebox but without knowing what I can do with it I can't yet make an education decision.
Other examples use just the VB Picturebox but one doesn't turn the image into a true sphere, another crashes after a few seconds display and another produces a static sphere. My knowledge isn't sufficent to adjust the code in any of those demos to get the correct result.
Does anyone know of this rmcontrol.ocx or can point me to any online tutorials that will allow me to write up the code without the tutorial going too indepth? Or could someone write me a module that I could then easily insert my own variables?
Seems to me a simple thing if you know how. I was originally planning on having a big library of static images which were assigned to each planet I've created, but I'm now experimenting with generating a heightmap for each planet which is textured based on it's stats, so as the game progresses, any changes to the planet are visually shown.
I may go back to the static image approach as that's within my knowledge, but it would be a shame.
Are you planning on making a Direct3D game or just want a mathematical simulation of a 3d planet for a 2D Game? You can imitate a planet using a repeating texture some chord mathematics and the paintpicture command.
Chord lengths are calculated something like this:
Code:
xw = 2 * (Sqr(r^2 - I ^ 2))
X = r - xw / 2
where:
r=radius
i= distance from center
xw=eqauls width to stretch image line to.
x=offset from center of image line
The only thing missing would be a shadow - you would have to alphablend one on if it's critical.
Give me a little bit, I'll see if I can do up a quick example.
Last edited by technorobbo; Feb 18th, 2009 at 05:27 PM.
Here it is - fake 3D planets:
make 1 form with 1 timer
I've attached a repeating image of planet earth and a planet texture I did in photoshop- put it in the same directory where you save the project
I decided to go with API calls for speed. that way you can do multiple planets.
I use a stdpicture (OLE Automation reference required) but you could put the image in a picture box.
Code:
Option Explicit
Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function StretchBlt Lib "gdi32" (ByVal hdc As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal nSrcWidth As Long, ByVal nSrcHeight As Long, ByVal dwRop As Long) As Long
Dim revolve As Integer, Earth As StdPicture, Ehdc As Long
Private Sub Form_Load()
Me.Show
DoEvents
Me.AutoRedraw = True
Me.ScaleMode = vbPixels
Me.BackColor = &H400000
Me.WindowState = 2
Set Earth = New StdPicture
Set Earth = LoadPicture(App.Path & "\earth.jpg")
Ehdc = CreateCompatibleDC(0)
SelectObject Ehdc, Earth.Handle
Timer1.Interval = 10
End Sub
Private Sub drawplanet(X As Single, Y As Single, ByVal radius As Single, ByVal rotate As Single, ByVal DPhdc As Long, ByVal BMhdc)
Dim XOffset As Single, xWidth As Single, i As Single
Dim radSqr As Single, radX2 As Single
radSqr = radius ^ 2
radX2 = radius * 2
For i = 0 To radius - 1
xWidth = 2 * (Sqr(radSqr - i ^ 2))
XOffset = radius - xWidth / 2
StretchBlt DPhdc, X + XOffset, Y + radius - i, xWidth, 2, BMhdc, rotate, radius - i, radX2, 2, vbSrcCopy
Next
For i = 0 To radius - 1
xWidth = 2 * (Sqr(radSqr - i ^ 2))
XOffset = radius - xWidth / 2
StretchBlt DPhdc, X + XOffset, Y + radius + i, xWidth, 2, BMhdc, rotate, radius + i, radX2, 2, vbSrcCopy
Next
End Sub
Private Sub Form_Resize()
Me.Cls
End Sub
Private Sub Form_Unload(Cancel As Integer)
DeleteDC Ehdc
End Sub
Private Sub Timer1_Timer()
drawplanet Me.ScaleWidth / 2 - 128, Me.ScaleHeight / 2 - 128, 128, revolve, Me.hdc, Ehdc
revolve = (revolve + 1) Mod 512
Me.Refresh
End Sub
Last edited by technorobbo; Feb 18th, 2009 at 10:21 PM.
Brilliant, I'll try this out and what's even better is that it's the shortest and nicest layed out code I've seen and can be easily integrated.
It's just a 2D game with above view solar sytem and I'm investigating having the game generate the image for the planet based on it's stats, so having it showing rotating in an info pane and when the display is large enough would be great.
These pics show a simple representation of the data being produced, all orbits are to scale, planets/moons naturally are to scale with orbit distance, but are to scale to each other (depending on zoom factor). It also generates asteriod belts and trojan asteriods all using rules after a study of our solar system layout and the limited information we know about other solar systems.
No Binary/Trinary star systems, I didn't take them into account and it would be too much effort now to rewrite my code to cope with them
Planets are colour coded by type, Reds are Gas Giants, Greens are Earth Sized.
Yellow unfilled circles are major asteriods, and filled yellow circles are trojans, and the grey dots represent an asteriod belt zone.
I'd like to have a shadow and I believe I know how I can work that out.
I can now progress further with getting the initial GUI designed allowing the user to view any object at any zoom.
Thanks, no doubt I'll have more questions at a later date!
Does the texture have to be repeated twice?
I've tried changing the Mod 512 to be half the texture width (using a 512x256 image, so Mod 256) but when it reaches the end of the texture, it jumps back to the start view again.
If it does then I can double the image up in a picture box and get the display box to use this picture instead.
Can I introduce a tilt to the image? I believe the Blt can do that so it can draw the image then rotate it. I think I have a demo program that rotates an image but I'm not sure how it achieves it.
Looking at the results, I'll definately need to add a shadow.
Last edited by piratelord; Feb 19th, 2009 at 06:52 AM.
I've introduced various rotation routines to the project but for some reason it always causes it to freeze up so I'm stuck since I don't know Blt.
Can you help with that and also putting a shadow on top? I'm sure you can somehow use the same function to merge a shadow BMP with the generated planet.
Big thanks in advance, when I do eventually finish this project I'll be sure to mention you (and any links if you want) in a credits screen.
I now understand the reason for the double image which saves some code extracting the right bit of the texture to make into the sphere.
I've used picture boxes to replicate the double image from the single image which works just as well. (first question greyed out)
Last edited by piratelord; Feb 19th, 2009 at 06:53 AM.
Thanks! Don't forget the tilt too (if poss).
I assume the alpha will use a BMP for it's information. If you just make a crude BMP, I'll worry about getting the amount of shading right to my tastes.
As they say "You da man!"
This is much appreciated and a lot clearer then everything I've found to date.
GDI can only take us so far. Tilting will invlove full blown directx and a mesh globe. Here's a zip of the Full 2D illusion with Shadow - very cool.
If you want to venture into real 3D we can go for it but it's a shallow learning curve.
Post Edit - for testing I changed the form background to white - sorry, but it does go to show that the graphics are independent of the container. In other words "no picture boxes were harmed in the making of theses graphics. Also this program is VB5/6 compatible is you have net you may have other commands available that can tilt - I don't know net. In that case you would stretchblt and alpha blend to an off screen picturebox then rotate it on another surface.
Those net-heads out there please chime in with any advice.
BTW - The shade.bmp was designed for planetx.jpg - you will find that a changing shade.bmp to an all black image will look better with earth.jpg. There is a built in highlight that works great with planet-x but due to their relative brightness makes the highlight area look darker on earth.jpg. The black image will act as a shade only effect with no highlight.
Last edited by technorobbo; Feb 19th, 2009 at 11:00 AM.
I'm going to convert this to a .BAS module but I just need to understand what's in Form_Load.
If I want to change the texture at any point, do I have to have all the new code run or is part of that code storing the shadow for later use so once it's initialised it's always in memory?
It looks like the shadow data is being stored in Shdc/lBF and used whenever drawplanet is called.
I've been able to change the texture at a click of a button with just
Code:
Set Earth = LoadPicture(App.Path & "\grid.jpg")
SelectObject Ehdc, Earth
but is that safe to do?
I won't worry about the Tilt, not really vital
I managed a quick simple way of cleaning up the edge of the image (due to the alpha being a higher res then the planet edge) by a simple transparent circle with a black border drawn around the image.
With some manipulation with the shade and alpha mask, I can (crudely) give the planet a different colour atmosphere which is great news, plus a bright spot for the sun.
Yep, I can usually grasp what the code is doing, even if I don't understand everything it's doing. I'm not afraid to experiment with code.
Now I just have to finish calculating the heightmap and texture it accordingly.
Thanks for the help, I was going to give up with the 2D 3D sphere effect. Posting here was my last resort, now I wish I posted sooner
This is actually a very good bit of demo code. Should it be stored somewhere for other people to make use off?
Should it be stored somewhere for other people to make use off?
Don't know - it has such a specific purpose. Maybe when you finish your game you could post it in the demo forum (or a mini version of it). And people will understand it's use and execution.
Hope it's okay by forum standards to continue posting here since it's related and I hope technorobbo can assist again.
First I thought I'd show you my result at the moment. Planet Pic
This uses a texture generated by VB itself by first calculating heightmap, and then texturing the landscape taking into account temperature, atmospheric pressure and altitude. Only takes a second or two uncompiled to produce.
I made a new alpha map for the shadow, and in this example, it has a green hue to it to represent a slightly different atmosphere color.
What I would like to do now is overlay a cloud layer image over the top of the generated texture, before it's used for the 2D sphere. Can I use the existing transparency code to do this, or is there some existing picture box method that would do this? I'm aware of the various different draw methods when using commands like circle, line and pset, but not with manipulating bitmaps.
I also seem to get missing pixels drawn when the source texture pixel is a green shade (as you can see in the image). This isn't a major issue it just seems strange it only affects part of the image by pixel colour.
You can use the same transparency code along with the wrapping algorithm. Yes, Alphablend does stretching! I would sandwich the cloud layer in between the planet and the shading, using alphablend for the clouds instead of stretchblt for a realistic look. You would put the new alphablend command immidiately after the strechblt command(s) in the for next loop using the same parameters withthe clouds dc handle for the source. You'll need a cloud image and a cloud alpha mask.
Alternately, you could put the clouds in their own loop rotating at a different speed.
As for the missing pixels that's a Stretchblt artifact that can show up when adjacent colors. Any fix I know (like averaging pixels) would sacrifice speed.
Wow, your modeling planets. How cool.
Last edited by technorobbo; Mar 6th, 2009 at 07:14 AM.
Correct - you need to layer the effects
Bottom layer - planet
Middle Layer - clouds
Top Layer- shading (static)
I can do an example if you want , when i get home from work. The code difference would be small if you use arrays.
Make sure you read again I did post edit several times.
One interesting thing you can do - the SourceConstantAlpha setting in the blend function can be used to do and overall ghost effect on the clouds.
Setting it below 255 starts fading away the layer so you can dynamically control cloud cover!
The simplest cloud render would be tou suse the same image for the clouds and the alpha but that wouldnt let you do cumulus billows too well.
Last edited by technorobbo; Mar 6th, 2009 at 08:00 AM.
Could you show me an example that will put the cloud layer over the top of the image that is loaded into the form/picturebox. I don't actually need anything fancy like different rotation speeds.
I know the cloud layer will have the Stretchblt artifact on it, but I think I can write a fairly fast routine to correct just those pixels. I don't need the planet to rotate really fast, so the extra time to fix those pixels shouldn't be noticable.
I started making planet images in photoshop, but since my game isn't really graphic based, having these nice looking planets would look out of place against the rest of the project, and make the project filesize massive.
Now I only have minimal number of support images which then produce virtually an infinate number of different looking planets that use the planets stats to generate the image. While they look less realistic it gives a better visual representation to players. Since they will be able to eventually terraform worlds, the image will change. Lowering the temperature of a earth type planet will cause the polar caps to grow, sea level to drop, and deserts to spread.
The only effect I don't think I'll be able to integrate is cratering, but I think I can store various crater heightmaps in arrays and then apply this to random locations of the planet heightmap array. Just a case of getting the loops correct. If it works then I can add in other large features like canyons.
Many thanks for all your help.
Edit:
Here's a picture of an earth type world (middle image), with the two above showing it getting colder, and the bottom two getting hotter. I still need to try and get a good balance on the colours, but overall I think it's a pretty impressive result. Actually took longer to compile the 5 images in photoshop then to generate them!
Last edited by piratelord; Mar 6th, 2009 at 09:30 AM.
Here's a different version where I warped the second axis. the first one was an x-axis warp only. In this one I warped x and y, basically the same math but slower because the warps have to be buffered. but if your CPU is faster than mine ( like 99% of those out there) you may notice a difference. Note that the upload in the post directly above was streamlined to make this one possible.
On my display I had an interlaced effect on the image, but I found when I changed the 5th variable in the alphablend command under Warp X to a 2 instead of a 1 it fixed this.
thank you for this, it's a great effect.
Now to turn it all into a module I can plug into my existing code.