Tuesday 25 September 2012

Interplanetary, quite extraordinary craft

It's been a bit of a disjointed week for my geekery, lots of little bits and pieces.

Screenshots - Having had no luck with existing apps, I asked on the Raspberry Pi forums and the only suggestion I got was to use glReadPixels. This requires screenshot dumping code to be written into the app generating the framebuffer, which is perfectly doable and the code should just be boilerplate. With libjpeg to compress the raw pixels, it works a treat. I'm wondering if it's worth writing a standalone capture app, assuming that would actually work, or if a portable function is adequate, perhaps even better.

Freezes - Since I started doing more and more complex stuff with OpenGL ES 2.0 I've been getting regular freezes. These were so bad that everything locked up, the network died, no debug was dumped anywhere that I could see, even the keyboard died so the Magic SysRq keys were of no use. I was just about to start the old comment-things-out-one-at-a-time trick, when a Raspbian update was released and sort of fixed it. It now seems to run indefinitely without freezing, but sometimes the USB hub spontaneously dies even though the graphics still keep going. I've plugged my keyboard directly into the RPi now, and it seems to be OK.

3D modelling - While manually-constructed vertices are fine for hello triangle, they're not really feasible for bigger things. So I've downloaded Blender and started learning how to use it. It's not hard, there's just a lot to learn. Thankfully there are some excellent tutorials to get started with. The biggest problems I'm having are my lack of artistic ability, and trying to avoid making my alien craft look like anything from any movie or game I've seen. At the moment it looks like it came right out of Elite. I'll get better, hopefully.

Flight physics - For my anti-Defender (working title: "Offender", better suggestions welcome) the centrepiece is going to be the alien craft. When I think of the archetypal UFO, I think flying saucer - something which doesn't look terribly aerodynamic and just hovers in the air, better suited to interstellar travel than air-to-air combat. The kind of craft I'm picturing is based on that, but has been adapted to fly at speed in the earth's atmosphere. I want something which flies like nothing on earth, but obeys the same laws of physics that earthly craft are bound to and depend upon. I'm going to have to work out the physics with little-to-no knowledge of aeronautics. Here goes then...

Whereas a fixed-wing aircraft uses its wings to generate lift, the craft I picture will have some kind of anti-grav thing propelling it upwards. How would that behave differently to wings? It'd make lift more or less constant, not dependent on velocity or angle of attack, and there'd be no ceiling. The thrust would have to be manually varied with the angle of climb or descent or there'd be a kind of lift-induced drag - in a vertical cimb it'd fall backwards. Hinged ailerons or a rudder wouldn't be practical so the anti-grav would need to vary to generate pitch and roll. If there were multiple upwards anti-grav thrusters, then increasing thrust on one side while decreasing on the other should accomplish this and maintain stability. Yaw would require horizontal thrust, and maintaining the ability to roll in a vertical climb would require downward thrust.

With a half-decent physics model I think I can get that to work, and also have human aeroplanes, helicopers and missiles behaving with a moderate degree of relism. The trick is going to be getting the level of complexity right so it's accurate enough but isn't computationally intractable, especially if I want this to run on a Raspberry Pi. I'm hoping that by modelling a few simple laws of physics, higher level effects will just drop out - for example, modelling angle of attack should correctly should result in stalls. After thinking through the basics it's clear that the most difficult and important bit is going to be aerodynamics and drag.

When an aircraft stalls and tailspins, why does it turn into a nosedive? It can't be its weight distribution as net weight acts through the centre of gravity and imparts no torque. It's got to be drag. When an aircraft rolls, why does the roll not accelerate? It's got to be some kind of angular drag. Also, if my craft is going to be capable of entering the atmosphere from space, drag would determine how much heat gets generated. As I understand it, for an accurate drag model you need to be able to assess the drag coefficient for every possible angle of attack. I basically need a virtual wind tunnel. That's going to be fun... there's got to be a way to simplify it.

I'm kind of looking forward to trying this out, I don't think it would take a huge amount of effort to get to the stage where I have a craft (even if the model is just a placeholder), some control and some basic physics to try out. I'd need to provide some terrain for context if nothing else. No proper collision detection for a while - that's a whole new can of worms - but I should be able to add something which causes a splat or bounce at zero altitude. So far I'm still plucking bits of boilerplate from the stuff I've done so far, making it as generic and reusable as possible, and building up some library functions. Might as well do it properly from the start, eh?

And finally some linkage, as I thought this was pretty cool: Kindleberry Pi

Sunday 16 September 2012

They have a fight, triangle wins

I'm just a dabbler in OpenGL really. Come to think of it, all I've really done is the most basic geometry and transforms, I've not even done texture mapping (though I've done that in DirectX). As I've had an interest in 3D graphics since college, it's something I want to get more practice at.

The Raspberry Pi supports OpenGL ES 2.0, which is also used in some of the newer mobile phones and tablets. The main difference between ES 2.0 and the OpenGL I'm used to is that it's built around a programmable pipeline, which in practise means that a lot of the core functionality I've taken for granted has been removed.

OpenGL uses little programs called shaders, which are used to configure the graphics hardware or software to apply various transforms or effects. They're written in the imaginatively named GL Shader Language (GLSL) - put the code into a string and pass it to OpenGL, it'll get compiled at runtime and applied to the appropriate data.

I've never done anything complicated enough with OpenGL to warrant writing a shader - simple stuff is taken care of by the core functions - but in ES 2.0 even the simplest of tasks requires a shader. For example, to project the 3D image onto a screen - something anyone doing 3D work is going to want to do - I'd normally set up the projection matrix. But that's gone in OpenGL ES 2.0, you have to put together the matrix yourself and manually apply it to each vertex with a vertex shader. Apparently this isn't unique to OpenGL ES - "desktop" OpenGL 3.1 has got rid of the projection matrix too - so this is something I'm going to have to get used to.

There are good reasons for this - it makes the API simpler and more flexible for advanced users - but it does make it harder for the beginner who has to do a lot of work to get the simplest thing up and running. It also means that the code isn't backwards compatible with OpenGL ES 1.1 and OpenGL 3.0, which is a pain as I like to move my code around onto different platforms.

I've not found a really good guide or tutorial for OpenGL ES 2.0 in C++ (perhaps I should write one?), but by taking snippets of code from various webpages I've managed to cobble together a "Hello Triangle!" It's quite epic at over 300 lines, but there's so much to set up I'd struggle to make it shorter. In the middle of  doing this my HDMI->DVI adaptor finally turned up, so I've been able to plug my Raspberry Pi into a monitor and get my red triangle in glorious 1280x1024, instead of the crappy interlaced PAL which as we all know is 720x576.

After that initial hump, getting something a little more complicated working was relatively easy. The tutorial code was all in C, so I made it a bit more C++-like with some juicy classes, call-by-reference, iostream instead of stdio, and getting rid of explicit mallocs where possible. "Hello Triangle!" was using the native display (i.e. no windows), so I added the option to use XWindows instead where it's available. Turns out there's a problem with the Raspberry Pi implementation of X which prevents this from working, so I've abandoned that for now. Then I learned how to do rotations with the vertex shader - which was fairly easy once you have the right matrix and can remember how to do matrix multiplication - and texture mapping with the fragment shader - which is far more complicated than I expected.

The end result was something which mapped a picture to a diamond shape and flipped it over and over, which I'm calling Phantom Zone. I've not worked out how to do screenshots without XWindows, so no pretty pictures this time. It's not much, but it's been useful for picking up the basics. Unfortunately there's a bug where it crashes the Raspberry Pi so badly that all remote connections are killed. I've no idea how I'd even begin to debug that one.

Now I've got the basics working, I'm coming up with ideas for something a bit bigger. When the Acorn Archimedes first came out it was bundled with a demo called Lander. Written by the legend David Braben, it later became the full game Zarch and was ported to other platforms as Virus. I think something along those lines would be fairly simple to do with the benefit of hardware accelerated graphics, at the very least I could get the terrain and craft working.

If that goes well I thought about turning it into a kind of reverse Defender, where you pilot a lone flying saucer and have to abduct people while avoiding increasingly aggrivated human defences. That's the kind of idea I can pick up and run with all day, indeed I've already lost a few hours of sleep thinking through the physics alone... but I'm not going to reveal any of the ideas here yet, I'll see how many of them I can put into practise.

Six entries in and I've written a lot about what I'm going to do, and time spent learning the basics, but I haven't actually achieved much. I'm kind of enjoying playing with software for the time being, though a part of me is itching to do the robot and knows that once I've drawn out some schematics I can start buying parts.