Thursday, 15 August 2013

Using sketchup for level models (First game video inside)

Right now I'm trialling Sketchup as part of my asset creation pipeline, mainly as a way of quickly making rooms for further refinement (texturing, optimising etc) in blender. This week I decided to trial sketchup and see just how easily I could get it to make something usable as a game asset, first I started off by creating a floor plan.

Then with a collection of free plugins (which will be listed at the end of the article) I set about bringing my dream into reality. This was a fairly quick process, I'd say it only took me 1-2 hours (including making the floor plan. Which I didn't invest a lot of time on.)



So with this done what I spend my next 1-2 hours doing is hiding walls and removing coplanar faces. When I draw a wall that comes out of another one, the end of my second wall meets part of the face on my first wall. These two faces occupy the same space and are hidden geometries so with the goal of improving the quality of the model I set about deleting these faces.

With that done I exported as a .Obj, loaded into blender, and found the stairs about ten times bigger hovering quite far away from the room. To solve this I made the whole scene into one component essentially binding the separate parts of the model. Imported into blender and found everything was in order.

So I imported the .blend file to JMonkey to see the initial results. And my god was I surprised! The surfaces were all flickering and all the doorways seem to flicker in and out of existence. This wasn't what I'd seen in blender and it was definitely a surprise. I'd seen some flicker on the floor in some patches in blender but nothing to this extent. (unfortunately I didn't screenshot this monster).

The flicker was I found down to duplicate faces, it seemed that sketchup had overlaying faces. Now I'm no expert on the 3D assets front but any software that doubles the number of faces required seems to be a no go for me. But I expected some tweaking in blender so I selected all the vertices in edit mode and then pressed: w -> delete duplicates. Over 500 vertices were removed, so in other words things were looking pretty bad.

Imported into JMonkey. Less flicker but still flicker, and more disturbingly the doorways were still obscured. Something which I did manage to screenshot:

That rectangle on the right... That shouldn't be there.
In fact none of the black bits should

Okay. Time to google.

From my googling I found two programs: Meshlab and Netfabb basic, I used Meshlab to convert my .Obj to a .STL so I could load it into Netfabb. Netfabb seems to have quite a few uses (at least the paid for version does). But one thing it can do is take a format suited to a 3D printer (STL), and find flaws in the mesh. Things like hidden vertices, coplanar faces, inverted faces, lack of a closed volume.

And sure enough Netfabb showed the flaws that blender wouldn't:


The red parts are flaws in the mesh, and you can clearly see the doorways are filled in as well as part of the floor is red. The red floor is down to the face being upside down making the normals wrong. So I went into Sketchup and flipped the upside down faces to the right way round. But the doors. The doors were still a problem.

So I decided to take a walk around the level with the flipped faces fixed, the room did look better (slightly) but as I walked I saw something with the flickering faces. The majority of them seemed to be triangles, and then it occurred to me. I hadn't triangulated the mesh!

So I went into Sketchup and checked the triangulate mesh options on the exporter and voila:

Perfecto
So with some quick texturing in blender (Sketchup is definitely not for my texturing needs no UV unwrapping). I have my first piece of "game footage". You'll see the lighting isn't presentable yet (something I'm still to look into) and the texture seems a bit pixelated, also in the model I appear to have made rooms, corridors and doorways too narrow/small so things feel a bit claustrophobic. But that's something I'll address.

However it's exciting to have a room to walk around in instead of just a flat plane. One step closer to realising my dream!



Sketchup plugins used:

FredoScale
Cleanup
Joint Push Pull
1001bit tools
Buildedge

You can find all these from the sketchup plugin warehouse or sketchucation. 



Wednesday, 7 August 2013

Sound the alarm! A post on AI and spatial access methods

Preamble

Firstly to avoid confusion, I know I often refer to entities in the game as Spatials (as that is the object I use) but with this post the spatial in the title is referring to an objects location in 3D space.

So recently I've paused work on asset creation and have taken to working on something far more interesting, my game AI. I've programmed up some basic decision making to allow the AI to work out if it's scared, confident or concerned and to what level but that's not what this post is about. This post is about what happens when an enemy NPC discovers the player and raises an alarm.

So raising an alarm could be done in numerous ways and could have varying consequences:

  • A physical alarm is rung and either through the alarms location, loudspeaker, or general flashing lights the players rough location is broadcast to all enemies in a large area.
  • The enemy that spotted the player shouts over radio and alerts all other enemies the players precise location, unless they lose sight of the player in which case where the player was last seen.
  • The enemy shouts out hoping that someone hears and comes to assist.
I've been toying with all three ideas and I'm thinking of doing a combination of 1 and 3, with the NPC having the choice of shouting and engaging in combat or running scared to an alarm and hoping for backup. Then environmental properties such as distance to the nearest alarm would factor in the decision making and make the combat less predictable, something which is always good.

So now that's decided and it comes to implementation an important question presents itself.

How do I find all the enemies within a given radius?

This is important for the third method as the NPCs need to hear the shout, so what were my initial thoughts:
  • Using a spatial access method such as a binary space partition or a k-d tree.
  • Creating a bounding box centred on the location of the sound and extending out to its range and checking for the NPCs that fall within the box
Now the first method can require a fair bit of programming and also every time an NPC moves the bsp or k-d tree would need to be regenerated. However it allows to quickly determine which NPCs are within range.

The second method on the other hand is very simplistic to program and maintain but comes with a performance drop. It would iterate through every NPC checking for intersection whereas the previous method would only look at a subset.

Now at this point hash maps had popped into my mind but I'd cringed and thought about iterating through them checking for every continuous point in 3D space within the range. Which is just icky.

So still undecided I did some googling and suddenly team hash map presented a winning pitch. They keys I'd use would be discrete points and I'd split the map into cubes of a set size [source: http://goo.gl/dtXSfw ]

Now for my hash map the key will be an array of integers and the object a list of spatials (the entity sort). And as non-primitives in java are passed by reference not value to update the hash map I decided to:
  • Iterate through the values in the hash map (so loop through all the array lists)
  • Get each spatials key based on current position
  • Check if the array list stored at that key is equal to the one I'm at in the iterator.
  • If not add the spatial to the array list at that key and remove it from the array list it was in.
Now worst case that should perform at O(n) where n is the number of entities. And getting all the entities within the range of a sound should be O(log(n)) as we are only dealing with a subset of the entities rather than brute forcing through every entity.

All in all I think this was the best way to do it, but we'll see when I start testing it out and nearer the end when I start stress testing my game to see what it can handle in terms of how many NPCs active at once etc.

A word on sound intensity

So I've probably (hopefully) mentioned it before (at least in passing) but I'm aiming on using a form of utility in my AI where scores are assigned to attributes and actions and used to determine the best result. So from this some new inputs to the AIs decision making process is born, sound intensity and context.

So initially my thoughts on sound intensity would be that it would most likely be an exponential decay, like most things that drop off in nature. But in the name of science I decided to have a proper look into it. 

This lead me to this formula [Source: http://goo.gl/FQ9sEL ]:


Where L2 is the sound intensity we want to work out and r2 the distance it is from the sound
L1 is a reference intensity and r1 how far that is from the sound.

I suppose the reference is there to try and take account for the varying acoustic properties of rooms but it's not really that relevant (after all I posted an excellent link for those that want to learn more!) What is relevant is that from the graphs on the page and the sum we can see that I wasn't far off, I can model this with an exponential decay.

This decay will represent the intensity of the sound where the AI is based on the distance from the sounds origin and how intense it is at the origin:



The perceived intensity will be normalised between 1 and 0 where 1 is definitely hearing something of note and 0 is hearing nothing of note. Whether or not the NPC responds to the sound at values between 0 and 1 depends on its own attributes such as alertness etc.

I should also take into account any instances of background noise that could dilute the intensity of the sound but that's a stretch goal for now.

Once I've done with this fleshing out of AI I should go back to graphics and design and maybe even be able to provide my first game play video... Not sure if that's a goal for the distant or not too distant future though.