Jump to content

  • Log In with Google      Sign In   
  • Create Account

Chronic Procrastination

Everything burns eventually

Posted by , 24 March 2010 - - - - - - · 636 views

I've made some progress since my last blag post. Here is a recent screen shot:



I've done a few thigns;

1) I've put vehicles back in. I took them out while I was refactoring my scene, but its good to be able to speed around and imagine what the finished product will be like.

2) I've added point lights to my render pipeline. These use the traditional deferred render method of drawing spheres for each light with depth testing disabled and back face culling enabled.

3) I've added a crude particle system; I plan to make this component based, with a list of emitters and a list of forces. The current one shown here is just a crude single vector for the force.

4) I've added a scene node which comprises both a light and a particle system, for making things like fire, explosions, and sparks which have both a light (to approximate the colour of the particle system) and the system itself. The image shown above is created using this system; it makes the light flicker from reddish orange to whitish orange, and it has to be seen to be appreciated. I should get fraps or something.




Lights from a render list

Posted by , 02 January 2010 - - - - - - · 451 views

Made some structural changes today to prepare my newly created lighting system for use with the scene.

I've got my system gathering spotlights from a render list and drawing as many as possible in a single pass; it performs quite well with around 50 lights per pass. This render list is gathered by the scene (ill detail my scene system in a later post) but atm the lighting is only debug data.






My light manager is capable of taking lights from a render list, batching them up into uniforms, and rendering as many as possible with a single pass. This will cut down on the number of fullscreen quads to be rendered. Fillrate is my primary bottleneck right now. I've seen methods which render the AABB of a light system as some kind of volume on screen, which conveniently means projecting it and reducing the number of fragments to render by orders of magnitude, this will likely be a good option.

void LightManager::startList(RenderList3D& source){
current_position = source.light_begin(), last_position = source.light_end();
}

LightManager::Step LightManager::stepList(int shader_program)
{
static SpotLight dummy_light;
dummy_light.setOn(true);

static std::vector<float> pos(3 * available_spotlights);
static std::vector<float> dir(3 * available_spotlights);
static std::vector<float> colour(3 * available_spotlights);
static std::vector<float> radius(available_spotlights);
static std::vector<float> cosAngle(available_spotlights);

for(int i = 0; i < available_spotlights; i++)
{
SpotLight * l;

if(current_position != last_position)
{ // apply each light in turn
l = ( current_position->light );
current_position++;
}
else
{ // fill the remainder of the list with dummy lights
l = &dummy_light;
}

pos[3 * i + 0] = l->pos[0];
pos[3 * i + 1] = l->pos[1];
pos[3 * i + 2] = l->pos[2];

dir[3 * i + 0] = l->dir[0];
dir[3 * i + 1] = l->dir[1];
dir[3 * i + 2] = l->dir[2];

colour[3 * i + 0] = l->rgb[0];
colour[3 * i + 1] = l->rgb[1];
colour[3 * i + 2] = l->rgb[2];

cosAngle[i] = cos(l->angle * 0.0174532925f);

radius[i] = l->on ? l->radius : 1e-1f;
}

GLint location = glGetUniformLocation(shader_program, "uLightPos");
if(location != -1)
glUniform3fv(location, available_spotlights, &pos[0]);

location = glGetUniformLocation(shader_program, "uLightDir");
if(location != -1)
glUniform3fv(location, available_spotlights, &dir[0]);

location = glGetUniformLocation(shader_program, "uLightColour");
if(location != -1)
glUniform3fv(location, available_spotlights, &colour[0]);

location = glGetUniformLocation(shader_program, "uLightRadius");
if(location != -1)
glUniform1fv(location, available_spotlights, &radius[0]);

location = glGetUniformLocation(shader_program, "uLightCosAngle");
if(location != -1)
glUniform1fv(location, available_spotlights, &cosAngle[0]);

if(current_position != last_position)
{ // we are still iterating our spotlights
return SPOTLIGHTS;
}
else
{ // we have reached the end of the list
return FINISHED;
}
}



My next step is to work the way lights are gathered into the scene itself, I've created various code paths for lights in the scene but not integrated this with my 3d editor.
that: add point lights to the system.


Multiple passes, deferred lighting

Posted by , 01 January 2010 - - - - - - · 404 views

I've now set up my multiple pass system, using g-buffers for lighting, this means I can render the first pass as a single quad, then use the g-buffers rendered at the same time to perform multiple, far cheaper lighting passes.

Here is a screen shot of the result:




I still dont have properly sorted translucent geometry, but at least its rendered as part of the whole process; i only wanted translucent geometry for things like shop windows and street lamp glass, so hopefully not too many bits of translucent geometry will be visible. I'll fiddle around with the depth g-buffer and the depth of each translucent fragment to see if I cant figure out some way to do additive blending on translucent geometry without depth testing, while still only rendering it when its in front of the previous pass. Most translucent geometry in reality will be clear (not coloured) glass with a dirt texture so the colouration wont be an issue.


g-buffers and ambient pass

Posted by , 01 January 2010 - - - - - - · 423 views

I wasnt going to go with full blown deferred rendering, so only my lighting pass will be defferred. That is, the first pass (ambient light, sun light / shadow and light / shadow from one or more lightening flashes) will be rendered the old fashioned way; but at the same time as doing this pass, I will generate g-buffers for the second pass to make use of. Here is a screen shot of what I have:

The top left image is the first pass; no shadows as yet, only a directional light. You will notice that I have rendered translucent geometry on this pass. In this pass, different materials have a different shader attached, and geometry is sorted in order of shader to avoid too frequent binding of new shaders and uniforms, which can be a bottleneck.




The second image is my albedo map; this is only the textures and material properties. You will notice that the translucent geometry doesnt write to this buffer, this allows me to use various tricks to get the translucent geometry into some g-buffers but not others. For example, I write to a specular buffer if need be, but miss out the albedo. I may need to seperate material properties and texture at some point but for now they are together.

The bottom two are world space normals, and world space position; by doing things in world space i've been able to simplify the way lights are gathered, I simply need to render all lights which intersect the view frustum.

Hopefully by the end of today I'll be able to render many lights using only the g-buffers, and use additive blending to apply them over the first pass.


Spot lights and stuff

Posted by , 20 December 2009 - - - - - - · 358 views

Today I expanded my shaders / architecture to support more than 1 light per render pass. Its my plan to implement a multipass, forward renderer with some use of seperate buffers. This is my plan for rendering things:

1) Render the geometry albedo with a single directional light w/ shadow map to represent illuminating objects in the sky. The ambient lighting will be handled in this pass, whereby I can approximate the ambient light in terms of what is coming from the sky (sun, moon / stars, etc). The shadow map here will be very high resolution, and only recalculated occasionally.

2) I render a normal buffer, which will aid in the lighting passes, since each fragment will already have the appropriate normal after this step. I think this should be a nice optimisation, but I might skip it at first.

3) in several passes, I render up to 6 spotlights at once, adding up the results each time. By fiddling with its input params this shader can also render a single point light but with 6 shadow maps all to itself. I do this until there are less than 6 spotlights (or one point light) left over. Then, I use similar shaders optimised for 4, 2 or 1 light until all lights have been processed.

4) I combine the results of 1 and 3 and then apply post process effects.

Here is a screen shot of just the scene drawn with some spot lights, without shadow maps or ambient colours; this would be the result of one of the passes in step. Due do my decision to calculate ambient lighting in step 1, you will notive there is no ambient light here; the buffer only tells me how much each fragment is lit by various lights in the scene.
Ambient light will depend on the intensity of the main light source (the sun or moon etc) and will be rendered on the first pass.



Tomorrow:
Get a single directional light, coming from an arbitrary point in the sky, to work.
Figure out how to render a depth texture, which would be the first step to getting shadow maps working.
If possible: combine the two, so I have a sun / moon shadow effect.


Starting again

Posted by , 19 December 2009 - - - - - - · 358 views

Its been a while since I last made a journal post (over a year I think) mainly because development slowed considerably; also, ive been working on physics rather than graphics, until now, so there wasnt much to show.

Here, have some per pixel lighting:
per pixel lighting with point light

However, people keep wanting to see screen shots, so ive decided to work on the renderer for a while. I've set up a nice system for loading / linking shaders, and I've vastly simplified my resource loading system. The previous system relied on loading a single resource, asking it what its dependencies were, and then loading those. This was fun when I was an academic, but now I realise it was overengineered and innefficient.

I have a new system, which took me approx. 1 day to write; whereas the previous one took two weeks. My engine is designed to load from two kinds of data; it can load from intermediate files, in which case it must calculate dependencies (I've hacked this up and its slow, but its not critical for loading intermediate files) and then each resource is stored in a table with a string key. Next, I assign each loaded resource an integer ID, and create a vector of references to each resource; this means I can perform an O(1) resource lookup, and I mean proper O(1), not an ammortised one; and its considerably faster than any kind of hash table. I then give each resource links, through these integer ID's, to all their dependencies.

This is a slow process, but it does have several advantages; once its done, I can index resources without having to give each object a pointer or reference to its dependencies. I can bind dependencies instantly by directly accessing the pointer.

When I serialise my resources into blocks of data, I send the integer ID's along with them; this creates a header file for each block of binary data. I can serialise the entire resource manager, or individual tables. From here on, its the same as my old resource loading system, except without the need for linking resources to each other. Rather than gathering a shopping list, I lazy load every resource, and demand that every resource table provide a suitible fallback resource if a resource that was requested is not currently available.

When the game loads from packed blocks, it first loads the headers of each resource table, which is simply the integer ID, the string name (which is still useful) the block they are within, and the start / end point within that block. When a resource is needed, it will load its data and cache it in GPU memory. There is no need to link resources because they also know the integer ID of their dependencies.

This should make things simpler, and faster when loading from blocks of data.


Change of plans

Posted by , 06 February 2009 - - - - - - · 396 views

Change in plans


Well, after 3 weeks of working on work for uni, and making one of those rediculously long job applications, I've not done anything related to spawning characters.

Instead, I spent the last week making a GUI lib. This was a big change in plans, but the mood struck me, and I need a GUI of some kind eventually. Currently implemented are buttons and surfaces to put buttons on. I'm in the middle of creating text box widgets, although for them to be of a production standard I'll need to redo my font rendering system, which currenly draws nicely kerned and antialiased text, but by brute force, with no caching of glyphs.





Building this screen took only the following code to do:

gui_manager = new GUI::Manager(0, 0, 500, 400);
GUI::Button * exit = new GUI::Button("butnExit", "Exit", 100.f, 40.f);
exit->setListener(this);

cmd_history = new GUI::TextBox("txtdHistory","",20,8);
cmd_line = new GUI::TextBox("txtCmd","",20,1);
cmd_line->setListener(this);

gui_manager->addWidget(0,0,cmd_history);
gui_manager->addWidget(0,8*25,cmd_line);
gui_manager->addWidget(500 - 110,400 - 50,exit);


I'm quite happy with this for a weeks worth of work (less than 10 hours of actual work all told) and am actually surprised at how quick it was to do this. Having done it twice before may have helped.

All the widgets are drawn using vector art, generated from within OpenGL. I can customise the colours, but apart from that its pretty fixed. However, there is no reason I can't make other appearences than a coloured border, thanks to my skin system. The round corners are a mesh, and the lines between them are a single quad. I've had a lengthy discussion about alternatives to this method and ive decided that im right and everybody else is wrong... at least for now. I'm hard coding the details of each skin, with some of the properties loaded from a file such as this:


SKIN
DEFAULT
BACKGROUND Colour 0.1 0.1 0.1 0.7
NORMAL Colour 0.0 0.33 0.71 1.0
ACTIVE Colour 0.0 0.63 0.91 1.0
CLICK Colour 0.3 0.4 0.9 1.0
/DEFAULT

BUTTON
BACKGROUND Colour 0.3 0.3 0.3 1.0
MOUSEOVER Colour 1.0 0.0 0.0 1.0
CLICK Colour 1.0 1.0 1.0 1.0
/BUTTON
/SKIN


Once again ive decided against XML and am rolling my own.

I've also refactored my game once again, removing all traces of the old event system. I'm now using a combination of two event systems; for the GUI communicating back to its owners, I'm using an EventListener system, where the object recieving the events must inherit the interface ButtonListener, TextBoxListener, etc.

To recieve the input from that button, I need to override ButtonListener::listenButtonClick, like so:


void ZFrenzy::listenButtonClick(GUI::Button * sender, int x, int y, int button)
{
exit(0);
}

And there it is, a button that exits the program. Basically this is a cut down version of the observer pattern, since only one observer can be attached to each widget. There is no reason I couldnt make this more than one, but this is just a prototype GUI system, build from previous experience building GUI systems.

In the next 3 days I hope to have the font rendering sorted out enough that I can have a decent text input box, and will then create a console; this console will allow me to make interfaces for various parts of the game which are currently hard coded, and form the basics of an in-game editor.



Factory pattern and such

Posted by , 18 January 2009 - - - - - - · 371 views

So, did a few things of interest today:
wrote a system for loading keymappings from file. The number of config files my game will use is rapidly growing. the file looks like this:


KEYBOARD
w FORWARD
s BACK
a LEFT
d RIGHT
r RELOAD
e ACTION1
f ACTION2
1 WEAPON_1
2 WEAPON_2
3 WEAPON_3
4 ITEM_1
5 ITEM_2
6 ITEM_3
7 ITEM_4
8 ITEM_5
SHIFT SPRINT
C CREEP
/KEYBOARD


This lets me have more than one keymapping, and lets users customise their keymappings with little effort from myself. I could provide an in-game interface later if I wish.

refactored the system so the world is spawning objects and the scene is only aware of what to draw. Thusly, each entity has different and unrelated data structures within each system, and systems communicate between each other via event queues. This loose coupling makes refactoring easy

Created a factory system for spawning a "Thing" from a prototype, just by its name. This loads from a text file like this:

PROTOTYPES
PROTOTYPE NAME "TV" WEIGHT 35.0 MODEL "TV" SCRIPT "TV" /PROTOTYPE
PROTOTYPE NAME "broom" WEIGHT 2.0 MODEL "broom" SCRIPT "broom" /PROTOTYPE
PROTOTYPE NAME "safety_stick" WEIGHT 4.0 MODEL "safety_stick" SCRIPT "safety_stick" /PROTOTYPE
PROTOTYPE NAME "bench" WEIGHT 150.0 MODEL "bench" SCRIPT "chair3" /PROTOTYPE
PROTOTYPE NAME "street lamp" WEIGHT 300.0 MODEL "street lamp" SCRIPT "street lamp" /PROTOTYPE
PROTOTYPE NAME "cine_camera" WEIGHT 45.0 MODEL "cine_camera" SCRIPT "cine camera" /PROTOTYPE
PROTOTYPE NAME "street lamp 2" INHERIT "street lamp" MODEL "street lamp 2" /PROTOTYPE
/PROTOTYPES


The advantage here is that some objects will be able to inherit the properties of another object, and then simply override the ones that are different. Note that "street lamp 2" inherits street lamp but has a different model. The rule here is that an object can inherit the properties of an object that appeared above it in the file. Very simple but creates lots of opportunities.

I can spawn an object from this system at any time by just having the world send an "this object spawned" event, and the other systems will instantiate the appropriate object within their own ranks to match it.

My interpretation of the factory pattern is quite literal; I have an actual object being the factory, and this object creates the prototypes based on the data in a file, such as the one above. Each prototype knows how to instantiate an object with those properties.

The factory knows how to spawn only one class of object, so for each type of entity I have a different factory object.

Next weeks objective: Have characters spawning from a factory, and moving around the world, represented by a piece of debug geometry.






December 2016 »

S M T W T F S
    123
4567 8 910
11121314151617
18192021222324
25262728293031

Recent Entries

Recent Comments

Recent Entries

Recent Comments