Showing posts with label opengl. Show all posts
Showing posts with label opengl. Show all posts

Tuesday, 4 February 2014

Rendering With Haskell

I've been on a bit of a Haskell kick lately.

The reason? I mostly blame Light Table - I've been testing the alpha version with various Clojure toy projects and enjoying myself mightily, when I somewhat randomly opened a .hs file and discovered not only syntax highlighting but also relatively clean, not-overly-smart indentation. Haskell indentation is (IMO) much nicer than that of Python in that the layout is more permissive and you can always fall back on braces and semicolons in a pinch, but its nice when the editor doesn't try to be too clever (and shoots you in the foot with its cleverness). I hate feeling like I'm fighting a text editing tool, and have nearly come to blows with Visual Assist in the course of the day job.

So, I spent a bunch of time wrapping up the basics of the OpenGLRaw package - HOpenGL sadly lacks support for matrix uniforms where shaders are concerned, and exposes/uses the Compatibility profile. I'm trying to restrict myself to the relatively small surface area of OpenGL 3.1 - 3.2 Core. GLFW-b provides window/input management; JuicyPixels seems reasonable for loading various shapes of image file and doesn't involve linking against DevIL. Some really, really ugly Parsec code for dealing with .obj files exported by Blender completes the foundations for a cube-with-moveable-camera prototype.

Now the fiddly bits. Resource management, tying the game's logic to the rendering thread, input handler stacks, GUI, all that fun stuff. Trying to keep as much of it as possible in idiomatic, functional code and outside the IO monad. Much of it would be simplified by sticking to a single thread, but there's no point having all these lovely fast cores lying around if we don't use them.

Resource management is the first priority, because having a bunch of explicit paths lying about your main source file along with various attendant bits of code to load and render textures/meshes/shaders is... horrible. At this point the topic starts to veer into the venerable Wavefront .obj format and it's auxilliary material definitions, which thankfully form a very simple chain of dependencies for what files to grab and turn into OpenGL resources before you can render something. I'll go into that next time I remember to blog, I think.

Wednesday, 14 March 2012

Clojure-flavoured Rendering Framework: State

My rendering framework, such as it is, sits on clojars.org and does... not very much. That should change. I can't guess how useful it'd be to anyone else, but it could certainly be a lot more friendly.

With that in mind, I started taking a critical look at a few emergent antipatterns in the very core of the framework: the OpenGL wrapper.

This example, I am happy with. Mostly.

Last time, I mentioned how the rendering functions have state very explicitly threaded through them in the form of an argument. A bunch of my wrapper functions do very simple things to mutate GL state. Some of them reset it afterwards, or wrap those that don't in a friendly way. For example, matrix stuff is done something like this:

(ogl/with-matrix
  (ogl/translate 1 0 0)
  (ogl/scale 5.0)
  (ogl/triangles
    (ogl/vertex 0 0 0)
    (ogl/vertex 1 0 0)
    (ogl/vertex 1 1 0)))


Hopefully that's fairly obvious to someone familiar with OpenGL. The with-matrix wraps a glPush/PopMatrix pair of calls around all the expresions within it. Likewise triangles calls glBegin/glEnd with the appropriate primitive type. I debated not including this ancient method of drawing stuff, but it's so handy for debugging and quick tests... anyway, the point is that even though translate and scale mutate some OpenGL state, they're intended to be used within this kind of protected block. Maybe they should all have exclaimation marks, I'm a little bit hazy of when it's polite to start exclaiming when you're not mutating your arguments.

Obviously the triangles call and all the stuff therein is side effecting like crazy, but I'm not sure how much value attaches to trying to make those calls look different. If anyone has an opinion on the aesthetics of such things, please yell.

A lot of the rendering stuff behaves similarly to with-matrix. I have equivalent calls to wrap GL attribute fiddling, wireframe rendering (mostly debug friendliness), capturing the results of rendering expressions to render targets, assigning vertex buffers, and binding shaders. Some of these are could do with a refactor to make them more consistent, but they generally behave.


But then there's this...

So that's all well and good. Then I came across the with-matrix-mode macro.

Ick.

This one looks so similar to the with-matrix example, but instead of pushing and popping from the current matrix stack to allow safe manipulation of a transformation, it changes which matrix stack is currently active. OpenGL has a few of these, but the only ones that are really relevant are your "world" transform (GL_MODELVIEW) and your view/projection transform (GL_PROJECTION). The former moves vertices around, the latter manipulates your notional camera, as it were.

The reason this makes me twitch is that this doesn't in any way revert the changes you make within it. For example, here's a little function that sets up an orthographic view in place of the conventional camera-like perspective view:

(defn orthographic
  "Loads an orthographic projection matrix to the top
of the projection matrix stack."
  ([left right bottom top near far]
     (with-matrix-mode :projection
       (GL11/glLoadIdentity)
       (GL11/glOrtho left right bottom top near far)))
  ([left right bottom top]
     (orthographic left right bottom top -1.0 1.0)))


Sure, at the end of the function the matrix mode has been restored to whatever it was at the start, but there's no attempt made to preserve the state of the projection matrix. That's rather the point, in fact - it gets murdered and replaced. Everything after this will be rendered using the orthographic projection.

I suppose this function is named in a misleading fashion. Anyone assuming the state of the GL will be unchanged after executing it will be disappointed, whereas elsewhere I'm trying to leave things as I found them. On the other hand, changing matrix mode is rather rare compared to rendering stuff, you generally do it once to set up your camera and then leave it. This kind of mutate-and-forget approach makes it relatively easy to split up the rest of your rendering into small chunks, as long as you keep things in the correct order.

Elsewhere similar compromises might sensibly be made with the excuse of efficiency; there's no sense constantly setting and then resetting a bit of state if the next expression simply sets it again, or worse, if it sets it back to the same value. All told, I probably just want to find a consistent way to signal that some functions do not behave with respect to render state, whilst the default remains that all functions clean up their toys after playing with them.

Friday, 5 September 2008

Deferred Tentacles

Further work on the deferred rendering side. I finally found an example online using FBOs with a stencil buffer, and thereby discovered that despite using a combined depth-stencil renderbuffer it needs to be attached to the frame buffer object twice, once as a depth attachment and once as a stencil attachment. Sigh.

That done, efficient rendering of small lights via z-and-stencil-tested spheres works nicely!

Behold the scene, containing no less than fifty ickle lights, plus the large shadow-casting light from the player's avatar.


The majority of the screen is taken up by the final composite image. On the right, small sections show a sample of the buffers involved (yes, I don't even turn off my debugging chuffle before posting, I'm that lazy). Top is the SSAO term (very low intensity in the final image, as it looks pants). Below that are the lighting accumulation buffer, world-space normal, and finally unlit diffuse buffers.

Lastly, the image displays some filthy aliasing as the source render targets are only 512x512, violently scaled up to match the screen resolution. I should fix that.

Edit: here's a version using 1024x768 buffers throughout. Ouch, bye-bye framerate. Need to fix my absurd pixel shader usage methinks.

Thursday, 14 August 2008

GLState Snippet

Nothing particularly big and clever, just something that seems to work quite well for slightly wrapping up OpenGL state in Scala (complete with manual and probably incomplete syntax highlighting):

trait Bound {
  def unbind: Unit
}
trait Bind {
  protected def bind: Bound
  def boundWith( p: =>Unit ) = {
    val b = bind
    p
    b.unbind
  }
  def &&&(other: Bind) = new Bind {
     class CompositeBound( a:Bound, b:Bound ) extends Bound {
       def unbind = {
        a.unbind
        b.unbind
      }
    }
    protected def bind = {
      new CompositeBound( Bind.this.bind, other.bind )
    }
  }
}

And an implementation for those wonderful glEnable/glDisable chains:

object GLUnchanged extends Bound{ def unbind = () }
object GLStateUtil {
  def glSet( s:Int, v:Boolean ) = if(v) GL11.glEnable(s) else GL11.glDisable(s)
}
case class GLEnabledBound( state:Int, value:Boolean ) extends Bound {
  def unbind = GLStateUtil.glSet(state,value)
}
case class GLSetEnabled( state:Int, value:Boolean ) extends Bind {
  protected def bind = if( GL11.glIsEnabled(state) == value ) {
    GLUnchanged
  } else {
    GLStateUtil.glSet( state, value )
    GLEnabledBound( state, !value )
  }
}


And finally a stupid example of usage (I'm refactoring a lot of the rendering code, so I don't have a real example to hand right now):

val playerState = GLSetEnabled( GL13.GL_TEXTURE_CUBE_MAP, false ) &&&
    GLSetEnabled( GL11.GL_TEXTURE_2D, false ) &&&
    GLSetEnabled( GL11.GL_LIGHTING, false )

playerState boundWith {
  playerModel.render
}

I suspect there's a better way to handle the Bound class returned such that it's not sat in the open, and the terminology may change quite a bit (bind/unbind came from various C++ implementations of similar stuff, none this nice to use). I quite like the way state changes can be composed, although it doesn't even attempt to perform any optimisation on the combined set.

I think it could also be made less verbose to good effect, and possibly a way to skip the redundant state checks would also be nice in case the state of the GL changes due to things outside the scope of these classes - especially for debugging.

At some point I think I'll combine all the resources into implementations of this class.

Anyway, back to playing with code...

Sunday, 10 February 2008

Natural terrain

More OpenGL wrestling occurred, but eventually I bent it to my will and managed to get VBOs working.

The dungeon now has a floor and ceiling that varies in height, and a very rough first stab at a continuous mesh:


Now, there are many things wrong with the implementation so far, not least of which is the lack of textures and shaders. Those will require me to gird my loins and head back into the terrifying world of the GL. No, perhaps more fundamental is the way solid areas (natural rock in this case) are represented. Right now I did a quick hack and pulled the terrain up to mimic the effect, but this causes nasty artefacts thanks to the stretching of polys and is far too restrictive. A different approach would be needed for crafted walls.

I'm thinking a better approach will be to create a separate wall mesh by extruding the lines defining a change from solid to traversable terrain. There are some big potential problems with this, and another method is still required for constructed rather than natural areas, but I think on the whole it's a win. It also reduces the amount of geometry to be recalculated when creatures dig or destroy walls.

So the basic dungeon components are looking like:
Floor/ceiling - heightfield, possibly with discrete mesh tiles (flagstones)
Rock and ruined walls - extruded continuous mesh with procedural variation
Worked walls in good order, unique features - discrete meshes, possibly welded together.

A new map format will be needed soon. The .txt map generator is beginning to look a bit under-featured, especially for representing material differences. It may still be the first step in map creation though, as I like how easy it is to check the output.

The heightfield meshes still need to represent material variation (rock, sand, vegetation, pebbles) and there may be additional mesh layers (water, lava, ground cover). So much to do, and as ever so little time...

As an aside, my rough thoughts on combat with height variation:
Melee - if the attacker is half a tile-width or greater above the defender, attacker is at +1*. If half a tile lower, attacker is at -1. Height differences equal or greater than 1 tile prevent both standard movement and melee attacks.
Movement - movement uphill takes more energy than moving on a flat, and movement down less. I think this'll cap at around double/half cost for the max gradient. Maximum gradient for movement without a 'climb' action is 45 degrees. Non-climb movement down a slope >45 degrees counts as falling, and will cause damage roughly proportional to the height difference squared. There will be rules for falling/climbing on inclines that are greater than one tile wide.
Ranged - projectiles deal increased damage and have increased range when fired from an elevated position
LoS - high tiles may block LoS, depending on height relative to player and 'interesting objects' (monsters) in potentially hidden tiles.

* Where +1 is a small attack and damage bonus. Possibly +1d4 to both - it depends on the exact mechanics for combat and stuff, which are currently not defined...