Monday 19 April 2010

Wibble!

Mmm, lunchtime blogging.

First off, have a screenshot:


I've been playing with exponential shadow maps, and they're kinda fun. Not sure whether I'll use them over variance shadow maps, but it's tempting. I've also been messing with lit particles, although this has not been superbly successful. The image shows some alpha-tested jobbies that interact nicely with the deferred lighting, cast shadows and generally behave themselves, but the ultimate aim is to have nicely lit smoke effects and they do little to advance that goal.

I've been playing with rendering a lot of small fake-sphere particles to a render target and blurring it as a post process, but it's a bit too crude to work and smacks of megaparticles. I may go for a simple volume rendering approach.

I have moral objections to CPU-driven particles, which precludes the standard sort-and-render which makes such things easy. I'm also avoiding texture fetch in general (I got burned by ATI's render-to-vertex-buffer non-implementation in the past), so simulating particles in a position texture and doing the sorting GPU-side is not tempting either, although I may yet go back to that. In the meantime, the hunt for order-independent transparency continues!


do => for

I can't write much about this because I'm still feeling my way, but using a for expression to perform computation inside a monad is... weird, but quite nice. I'm not sure I prefer it to Haskell's do notation.

It's odd enough that I want to dump my exploratory fiddlings anyway, so here's a stub for the conflict-resolution step for two entities colliding after a movement phase. Note the awesome game logic for deciding the winner:
   private def collidePair( a: Ent, b: Ent ) : (Ent,Ent) = {
      val ab2 = for{
        aPos <- a.get[Int3]("position") if( a("solid",true) )
        bPos <- b.get[Int3]("position") if(aPos == bPos && b("solid",true) )
        aPosHis <- listToOption(a.history[Int3]("position").drop(1))
        bPosHis <- listToOption(b.history[Int3]("position").drop(1))
      } yield {
          val aWins = Math.random < 0.5
          if( aWins )
            (a,b.extend("position",bPosHis))
          else
            (a.extend("position",aPosHis),b)
        }
      ab2.getOrElse(a,b)
    }


Slightly odd exploratory code. Anyway, it crudely rips the current position from both entities, as well as their previous position, and yields an Option containing a tuple of new entities. If any of the extraction steps or predicates in the for chunk fails, it simply returns the original pair of entities.

Errors abound, of course. An entity doesn't always have a 'last' position, and if it does this in no way implies it's a reasonable place to go if it fails the conflict step. The listToOption thing is ugly as well. Bleh. But my original point stands: for is a weird and flexible beast in Scala, which I didn't appreciate before.

No comments: