Indirect illumination and dynamic objects

May 4, 2011 by

Today I fixed the last parts to get the indirect illumination rendering going properly, and I even made a video of it! The times when it goes dark is when the light map is reset and rebuilt (I do this for demonstrational purposes) from scratch. As you may notice, the color bleeding looks a bit strange from the yellow, red and orange cubes to the left. This is because the cube sides are not solid and become invisible when rendered from the lights perspective, which makes these cubes cast indirect illumination onto the wall. The frame rate of this application is around 1500 on my ATI 5770, so it’s pretty fast (still debug mode). The only other light source is from the sky, using the sky occlusion map described in the last post; direct lighting not included in this scene. The ugly stuff in the top of the screen is because I don’t clear the back buffer properly each frame. Oh, and this lighting is not physically based, and in the video the indirect illumination is probably far too strong.

Dynamic objects
I haven’t yet mentioned anything about how I plan on handling dynamic objects. Dynamic objects are slightly problematic as they tend to move and ruin any nice acceleration structure that was built. Dynamic objects should be able to illuminate nearby objects with indirect illumination and thus be able to “emit” color bleeding. I don’t think that this will be very problematic, indirect illumination from dynamic objects can use a dedicated light maps that is updated more often than the main light map. To ray trace the light in this low resolution light map will also be quicker as the rays will be a lot fewer compared to the static scene due to (most likely) fewer and smaller objects.
Then there is being affected by indirect illumination from other objects. This one will be a little bit trickier. I’m currently leaning towards using light probes placed all over the scene, and dynamic objects then use values that are interpolated between the closest light probes. These light probes will get their values from when I ray trace indirect illumination for the static geometry.
Finally, there is (large-scale) ambient occlusion. Receiving occlusion from static objects will be handled by the light probes. However, occluding static geometry is harder and I haven’t decided how I’ll solve this yet. At the moment I’m leaning between two alternatives. The first alternative is that I’ll solve the problem by having sky visibility maps for static geometry, but for every pixel I just project the bounding spheres/boxes of the significant occluders onto the pixels hemisphere and approximate the occlusion that way. The second alternative is that I don’t solve it at all and instead implement some variant of SSAO, as dynamic objects mostly are quite small and don’t provide much occlusion anyway.

I’m not sure what I’ll work on next, a proper scene to test the performance (as in visual quality and speed) of this technique would be nice. However, since I have some additional requirements about geometry and UV-mapping this will be slightly problematic. I could implement some nice shadowing algorithm and see the result with direct illumination as well, and tweak some parameters to fix the strength of the indirect light.

Just an additional note, I’m fully aware that measuring performance in terms of FPS is rather useless. However, my graphics card has suddenly forgotten that is has performance timers, so I can’t do any profiling with it. Not that the performance numbers are realistic anyway, since the scene I’m not using isn’t exactly the most commonly used one in games.

Sky occlusion

May 3, 2011 by

One of the things that I’m currently busy with on my global illumination system is the calculation of sky visibility. The sky itself is an important source of the indirect illumination in an outdoor scene, and thus I’ll have to simulate it somehow. Since the sky is a pretty uniform light source I figured that I might as well just pre-compute it and store it in a 8 bits per pixel light map, using the same resolution as all my other light maps (i.e. very low). This way, I still have the freedom to change the sky color and similar. A couple of days ago I began my work on doing these pre-computations using my existing DirectCompute ray tracing kernel, and it works by simply tracing 128 rays across the hemisphere from each light map texel and then counting how many of them are occluded. If I run the computations in every frame instead of once, I still get pretty decent frame rates (37 FPS with doing the computations, compared to 350+ FPS without), this is also in debug mode as my graphics card drivers crash if I turn on shader optimization. The following screenshot demonstrates how the sky occlusion map looks:
Sky occlusion

As can be seen in the screenshot above, there are some artifacts at the edges of objects. This is because of my terrible light map unwrap, combined with the fact that D3D doesn’t use conservative rasterization; some texels are partly used by the mesh, but the mesh doesn’t cover the center of that texel. Maybe I can reduce it doing some clever trick with MSAA samples or some simple blur, I haven’t investigated it very closely yet. Also, it seems like it might have too much weight for occluders straight up, I was pretty sure that this was due to pole clustering due to a poor distribution scheme but changing it haven’t seemed to reduce the problem. Hopefully the problem is that my distribution scheme still sucks :].

Another ISPM update

April 25, 2011 by

Since the last update, I’ve updated the ray tracing kernel to use kd-trees instead of brute-forcing all of the triangles. Kd-trees are quite heavy on branching as is not exactly the best usage scenario for GPUs, but it’s a lot faster than the brute force variant on scenes containing a lot of triangles.

However, this is far from the only thing that has occupied my attention. I have been thinking about avoiding the quite expensive rendering of photon volumes each frame, and instead do some kind of caching of the result. There is simply no point in spending a lot of resources on updating indirect illumination each frame when it is such a low-frequency phenomena. Being inspired by Geomerics and DICE I decided to use light maps, rendered on the GPU. So I guess that I’m not implementing ISPM any more. Here are a couple of the problems that I can currently see with the approach:
*Noise – I’m guessing that to reduce noise, a large amount of rays and/or a low resolution light map is required
*Rendering of the light maps – My current approach uses DirectCompute to render the light map (which is a RWTexture2D), and it works fairly well. The problem is that data is not completely synchronized in the memory so one thread might overwrite data that was recently written by another thread, that is obviously bad. This leads to spots in the light map being slightly darker than they should be (and that, if updated each frame, the light map flickers).

The funny thing is that by solving the first of these two problems by adding more rays or lowering the resolution of the light map, I make the second problem worse. The solutions I currently have for the second problem does not completely remove the artifacts, just reduces them a lot. The first option is to render the light map at a much higher resolution, to reduce the risk of conflicting pixels, and then down sample it. However, this requires a lot of memory and down sampling could be quite costly. The other option is to trace a small subset of all rays and store the result in a separate texture, then this texture is additively blended onto the main light map. Depending on how many rays that is required in a scene and how much collisions that generally occur, I’m wildly guessing that somewhere around 10-100 iterations are necessary. These iterations can also be trivially amortized over several frames, and it’s really only necessary to perform such an update when the lighting condition changes.

I have quite a few more ideas that I would like to write about, but that will have to wait for another time.

Also, I have rewritten large chunks of my resource manager and written a simple thread pool to go with it. Now, resources are loaded asynchronously with a nicer API and the possibility to reload resources that are out of date. I must say that the last part is pretty convenient when experimenting with the shaders, no more restarts and instant result really rocks! My only regret is that I didn’t implement it sooner. I would love to post some source code, but since I’m quite new at multithreaded programming and there could be some very nasty and hard to track down bugs I think I’ll skip it this time.

~Daniel

ISPM progress

February 2, 2011 by

The last two weeks I have been working on getting a general “framework” or “pipeline” of my ISPM renderer up and going. It’s been really interesting and I must say that DirectCompute does enable one to do some pretty cool stuff. Below is a screenshot of my implementation running. There are a few flaws of my implementation so far: some visual artifacts, I haven’t used a proper splatting kernel yet and the ray tracing is limited to scenes consisting of 24 triangles. However, the frame rate is pretty good, normally over 100 fps in 512×512 resolution. The most frame rate eating part of the algorithm is to render the photon volumes, everything else takes less than a millisecond to perform and the rest is due to the huge fill rate required by the photon volumes pass. This is also the reason for the low resolution, the implementation is not using any up-sampling of the indirect illumination buffer so I’m using a low resolution back buffer until I get that part up and running – in order to avoid a slide show. The ray tracer is just a place holder, but it can trace the scene pretty fast; up to 15k rays in approx 0.1 ms is pretty decent. In the end, I’m hoping to be able to do the ray tracing of a normal scene in less than a millisecond, time will tell how that turns out. :]

As mentioned, frame rate is around 100 fps, there are quite a few visual artifacts and the indirect illumination is very much too bright. Otherwise it looks pretty cool, you can even see some signs of ambient occlusion in there.

~Daniel

Font rendering in Direct3D 11

January 14, 2011 by

As you maybe noticed in my previous screenshots, there is some font rendering going on. I must admit that I have not performed any experimenting or testing various techniques for rendering font, but the way I’m doing it now seems to be fairly decent. At least I’m not getting any notable reduction in framerate when rendering my 20 letters :]. Let’s move on to more important matters, how is this done? I was quite disappointed when I noticed that DirectX had dropped font rendering in D3D11 and that I basically was forced to write my own or rely on GDI. I thought GDI sounded a bit scary and since I knew about the excellent FreeType font library I gave custom font rendering a shot. As it turns out, it was pretty easy with the help of FreeType. It uses pixel positioning and sizing but I’m not 100% convinced that this works as it should, the text seems to change size when I change the resolution. The purpose of me posting this code is mostly so other can see the general idea on how to get started with custom font rendering, and I would probably not recommend just copying and pasting it. However, you can copy and paste it if you like, since it’s licensed under the BSD license. Hopefully, someone will find the code useful.

Below is practically all code I use for C++-side font rendering. I will try to write comments for most of the parts but I’m usually quite greedy with comments so if you read this and have questions – don’t hesitate to ask! The code below is not very thoroughly tested, e.g. while I was reading it as I commented it I spotted no less than two memory leak (hopefully fixed now), so take care while using it. The most important high-level function is placed in the end. Also, I really recommend reading the freetype tutorial. Once again, I’m sorry about the formatting, wordpress ruined it for me when it was almost done.

////////LICENSE STUFF
Copyright (c) 2011, Daniel Lindén
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer 
       in the documentation and/or other materials provided with the distribution.
    * Neither the name of the project nor the names of its contributors may be used to endorse or promote products derived from 
      this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


//////// HEADER FILE

//Data used for information about all glyphs
//A glyph is a bitmap with one character in it
struct GlyphData
{
	Vector2 start;
	Vector2 end;
	Vector2 size;

	unsigned int advance;

	int xOffset;
	int yOffset;
};

//A static string whose content can't be modified
class StaticString
{
	friend class FaceMap;
public:
	void Render(int xpos, int ypos);

protected:
	std::tr1::shared_ptr m_pVerts;

	FaceMap* m_pFace;
	Device* m_pDevice;
};

//To be implemented
class DynamicString : public StaticString
{
	friend class FaceMap;
public:

private:

};

//A FaceMap is a class which contains a texture with all of the glyphs, it is also the class used for creating renderable strings of text
class FaceMap
{
	friend class FontManager;
public:
	StaticString BuildStaticString(const std::string& text, const Vec3& color, unsigned int maxWidth = 0);
	DynamicString BuildDynamicString(unsigned int maxStringLength, unsigned int maxWidth = 0, bool lineBreak = false);

	unsigned int GetStringWidth(std::string text);

	unsigned int GetAdvance(char c1, char c2);

	TexResource GetTexture() { return m_TexResource; }

private:
	FaceMap() {}

	FT_Face m_Face;

	Device* m_pDevice;

	unsigned int m_Size;

	TexResource m_TexResource;
	std::map m_Coords;
};

//A font manager can be used for creating FaceMaps
class FontManager
{
public:
	FontManager() : m_LastError(0) {}

	bool Initialize(Device* pDevice);

	bool LoadFont(std::string fontName);

	std::vector GetAvailableFonts() const;

	FaceMap* CreateFace(std::string familyName, std::string styleName, unsigned int size);

private:
	FT_Library m_Library;
	std::multimap m_Faces;
	std::map, FaceMap*> m_FaceMaps;
	Device* m_pDevice;

	const char* m_LastError;
};

/////////// CPP FILE
//The vertex type used for rendering fonts
struct FontVertex
{
	Vector2 position;
	Vector2 size;
	Vector2 startUV;
	Vector2 endUV;

	static const D3D11_INPUT_ELEMENT_DESC* GetLayoutDesc(int& count)
	{
		count = 4;

		static const D3D11_INPUT_ELEMENT_DESC pDesc[] =  {
			{"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
			{"POSITION", 1, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
			{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
			{"TEXCOORD", 1, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0}
		};

		return pDesc;
	}
};

//Just rendering the vertex buffer in the usual fashion
void StaticString::Render(int xpos, int ypos)
{
	Matrix4 world = Matrix4::CreateTranslation(xpos, ypos, 0.f);
	Material mat;
	mat.m_Decal = m_pFace->GetTexture();

	m_pDevice->GetDeviceContext()->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);

	m_pDevice->SetObjectProperties(world, mat);
	m_pDevice->SetVertexBuffer(m_pVerts);
	m_pDevice->SetLayout();
	m_pDevice->Draw();

	m_pDevice->GetDeviceContext()->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
}

//A helper function that converts a string into a vector that contains all the lines, where each line is a vector of all words
//Sidenote: is there really not a split function for strings in C++?!
std::vector> SplitToLinesOfWords(std::string text)
{
	//Inner vector contains all words of a line, outer contains all lines.
	std::vector> words;
	words.push_back(std::vector());

	std::string lastWord = "";

	for (int i = 0; i second.advance;

	int penX = 0;
	int penY = 0;

	std::vector vertices;

	//Nothing special going on here, I guess
	for (auto i = words.begin(); i != words.end(); ++i)
	{
		for (auto j = i->begin(); j != i->end(); ++j)
		{
			//Check if a new linebreak should be performed due to line overflow
			if (maxWidth && GetStringWidth(*j) + penX > maxWidth)
			{
				penX = 0;
				penY += m_Face->height;
			}

			for (int c = 0; c length(); ++c)
			{
				char c1 = j->at(c);
				auto dataIt = m_Coords.find(c1);

				if (dataIt != m_Coords.end())
				{
					GlyphData data = dataIt->second;
					FontVertex v;
					v.position = Vector2(penX + data.xOffset, penY + data.yOffset);
					v.size = data.size;
					v.startUV = data.start;
					v.endUV = data.end;

					vertices.push_back(v);

					char c2 = (j->length() - 1) - c > 0 ? j->at(c + 1) : ' ';

					penX += GetAdvance(c1, c2);

				}
			}

			penX += spaceWidth;
		}

		penX = 0;
		penY += m_Face->height;
	}

	StaticString str;
	str.m_pVerts = VertexBuffer::CreateStatic(m_pDevice, &vertices[0], sizeof(FontVertex), vertices.size());
	str.m_pFace = this;
	str.m_pDevice = m_pDevice;

	return str;
}

//Calculates the total width of a given string, assuming no line breaks
unsigned int FaceMap::GetStringWidth(std::string text)
{
	unsigned int width = 0;
	for (int i = 0; i second.size.x + 0.5f);
			}
		}
	}

	return width;
}

//Returns the advance between two characters
unsigned int FaceMap::GetAdvance(char c1, char c2)
{
	auto it = m_Coords.find(c1);
	if (it != m_Coords.end())
	{
		return it->second.advance;
	}

	return 0;
}

bool FontManager::Initialize(Device* pDevice)
{
	m_pDevice = pDevice;

	int error = FT_Init_FreeType(&m_Library);

	if (error)
	{
		return false;
	}

	return true;

}

struct GlyphBitmap
{
	int glyphIndex;
	char* pGlyphBitmap;

	unsigned int width;
	unsigned int height;

	int xOffset;
	int yOffset;

	int advance;
};

//Create a list of all glyps, with FreeType bitmaps, that is ready to be packed
std::vector RenderGlyphs(FT_Face f, std::string chars)
{
	int error;

	std::vector res;
	res.reserve(chars.length());

	FT_GlyphSlot slot = f->glyph;

	for (int i = 0; i bitmap_left;

		bmp.yOffset = -slot->bitmap_top;
		bmp.width = slot->bitmap.width;
		bmp.height = slot->bitmap.rows;

		bmp.pGlyphBitmap = new char[bmp.width * bmp.height];

		for (int y = 0; y < bmp.height; ++y)
		{
			for (int x = 0; x bitmap.buffer[x + y * slot->bitmap.pitch];
			}
		}

		bmp.advance = slot->advance.x >> 6;

		res.push_back(bmp);
	}

	return res;
}

//Do some clean up
void FreeGlyphBitmaps(std::vector& bmps)
{
	for(auto i = bmps.begin(); i != bmps.end(); ++i)
	{
		delete [] i->pGlyphBitmap;
	}
}

struct GlyphPos
{
	unsigned int x;
	unsigned int y;
};

struct PackedGlyphs
{
	std::vector positioning;

	unsigned int textureWidth;
	unsigned int textureHeight;
};

//Pack the glyphs into a texture, only actual positioning will be calculated here
PackedGlyphs PackGlyphs(std::vector& glyphs, int maxTextureWidth = 64)
{
	//Not using a sophisticated packing algorithm... yet. Hopefully this one turns out to be
	//sufficiently good, glyphs are after all quite easy to pack.

	PackedGlyphs pg;
	pg.positioning.reserve(glyphs.size());

	int currentX = 0;
	int currentY = 0;
	unsigned int lineMaxSize = 0;

	for (auto i = glyphs.begin(); i != glyphs.end(); ++i)
	{
		if (currentX + i->width + 1 >= maxTextureWidth)
		{
			currentX = 0;
			currentY += lineMaxSize + 1;
			lineMaxSize = i->height;
		}

		GlyphPos data;
		data.x = currentX;
		data.y = currentY;

		currentX += i->width + 1;
		lineMaxSize = Max(i->height, lineMaxSize);

		pg.positioning.push_back(data);
	}

	pg.textureWidth = maxTextureWidth;
	pg.textureHeight = currentY + lineMaxSize + 1;

	return pg;
}

//Just a helper function for copying a glyph into a full texture
void CopyGlyphBitmap(char* dest, unsigned int destPitch, GlyphBitmap src, GlyphPos dstPos)
{
	for (int y = 0; y < src.height; ++y)
	{
		for (int x = 0; x < src.width; ++x)
		{
			dest[dstPos.x + x + (dstPos.y + y) * destPitch] = src.pGlyphBitmap[x + y * src.width];
		}
	}
}

//Creates the actual font texture
std::tr1::shared_ptr CreateFontTexture(Device* pDevice, PackedGlyphs& pg, std::vector& bmps)
{
	char* textureData = new char[pg.textureHeight * pg.textureWidth];
	ZeroMemory(textureData, pg.textureHeight * pg.textureWidth);

	for (int i = 0; i < bmps.size(); ++i)
	{
		CopyGlyphBitmap(textureData, pg.textureWidth, bmps[i], pg.positioning[i]);
	}

	auto res = Texture::CreateFromData(pDevice, pg.textureWidth, pg.textureHeight, TEXTURE_FORMAT_8BIT_UNORM, textureData);

	delete [] textureData;

	return res;
}

//A function for converting our packed glyphs and bitmaps into the data that we actually need.
std::vector BuildGlyphData(PackedGlyphs& pg, std::vector& bmps)
{
	std::vector gd;
	gd.reserve(bmps.size());

	for (int i = 0; i GetFile(fileName, RF_NORMAL);

	if (!pRes)
	{
		m_LastError = "Invalid resource pointer";
		return false;
	}

	FT_Face face;
	int error = FT_New_Memory_Face(m_Library, (FT_Byte*)pRes->GetData(), pRes->GetSize(), 0, &face);

	if (error)
	{
		m_LastError = "Unable to load font from file";
		return false;
	}

	std::string familyName = face->family_name;

	m_Faces.insert(make_pair(familyName, face));

	int numFaces = face->num_faces;
	for (int i = 1; i GetData(), pRes->GetSize(), i, &face);

		if (error)
		{
			continue;
		}

		std::string familyName = face->family_name;

		m_Faces.insert(make_pair(familyName, face));
	}

	return true;
}

FaceMap* FontManager::CreateFace(std::string familyName, std::string styleName, unsigned int size)
{
	m_LastError = 0;

	auto r = m_Faces.equal_range(familyName);

	FT_Face f = nullptr;

	for (auto i = r.first; i != r.second; ++i)
	{
		if (i->second->style_name == styleName)
		{
			f = i->second;
			break;
		}
	}

	if (!f)
	{
		//It could be a good idea to just take a random face or something here instead
		m_LastError = "Unable to find specified font face";
		return nullptr;
	}

	int error = 0;
	error = FT_Set_Pixel_Sizes(f, 0, size);

	if (error)
	{
		m_LastError = "Specified font size not supported by font";
		return nullptr;
	}

	FaceMap* pFace = new FaceMap();
	pFace->m_pDevice = m_pDevice;
	pFace->m_Size = size;
	pFace->m_Face = f;

	std::string str = "ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖabcdefghijklmnopqrstuvwxyzåäö0123456789 ,.-!?$\"'";
	auto bmps = RenderGlyphs(f, str);
	auto packInfo = PackGlyphs(bmps);
	auto glyphData = BuildGlyphData(packInfo, bmps);
	auto pTexture = CreateFontTexture(m_pDevice, packInfo, bmps);
	FreeGlyphBitmaps(bmps);

	pFace->m_TexResource = m_pDevice->GetResources()->LoadTexture(pTexture);

	for (int i = 0; i m_Coords.insert(std::make_pair(str.at(i), glyphData[i]));

	}

	return pFace;
}

There are lots of code uncommented, but most parts of it should be fairly easy to follow. I have been trying to stick with classic C functions for most of the parts, as I have started to like plain C functions more and more lately. Maybe it is because of that course in functional programming (haskell, to be precise – a really cool language by the way) I took last semester, I can really recommend looking into some functional language if you haven’t done it before. It certainly looks really strange in the beginning, but once you get used to it you really miss stuff like map, for example.

Here is the shader code, with some constants undefined (I have them in my common header file, just replace them):

////// VERTEX SHADER
struct VS_INPUT
{
	float2 pos : POSITION0;
	float2 size : POSITION1;
	float2 uvStart : TEXCOORD0;
	float2 uvEnd : TEXCOORD1;
};

VS_INPUT main(VS_INPUT input)
{
	VS_INPUT output;
	output.pos = mul(float4(input.pos, 0.f, 1.f), World).xy * InvResolution * 2.f - float2(1.f, 1.f);
	output.pos.y = -output.pos.y;
	output.size = input.size * InvResolution * 2.f;
	output.size.y = -output.size.y;
	output.uvStart = input.uvStart;
	output.uvEnd = input.uvEnd;

	return output;
}

////// GEOMETRY SHADER
struct GS_INPUT
{
	float2 pos : POSITION0;
	float2 size : POSITION1;
	float2 uvStart : TEXCOORD0;
	float2 uvEnd : TEXCOORD1;
};

struct GS_OUTPUT
{
	float2 uv : TEXCOORD0;
	float4 pos : SV_Position;
};

[maxvertexcount(4)]
void main(point GS_INPUT input[1], inout TriangleStream stream)
{
	float2 pos = input[0].pos;
	float2 size = input[0].size;
	float2 uvBegin = input[0].uvStart;
	float2 uvEnd = input[0].uvEnd;

	GS_OUTPUT output0, output1, output2, output3;
	output0.pos = float4(pos, 1.0f, 1.0f);
	output0.uv = uvBegin;

	output1.pos = float4(pos.x + size.x, pos.y, 1.0f, 1.0f);
	output1.uv = float2(uvEnd.x, uvBegin.y);

	output2.pos = float4(pos.x, pos.y + size.y, 1.0f, 1.0f);
	output2.uv = float2(uvBegin.x, uvEnd.y);

	output3.pos = float4(pos + size, 1.0f, 1.0f);
	output3.uv = uvEnd;

	stream.Append(output0);
	stream.Append(output1);
	stream.Append(output2);
	stream.Append(output3);
	stream.RestartStrip();
}

///////// PIXEL SHADER
float4 main(float2 uv : TEXCOORD0) : SV_Target0
{
	return float4(Decal.Sample(Bilinear, uv).rrr, 1.f);
}

Oh, and a suggested to-do-list for the font renderer (depending on requirements, of course):

  • Colored text
  • Dynamic strings
  • Using some sort of markup for creating partly colored strings, etc.

~Daniel

Project update

January 14, 2011 by

I have been secretly working on the project for a some time now. However, I haven’t written anything about it since I don’t really considered it terribly interesting, I would certainly recommend reading other blogs written by more experienced people. The latest news is that the graphics engine is getting in shape and the editor is getting a decent start with editable terrain and stuff. I have also (finally) updated the math library from using simple scalar math to using SSE intrinsics. I can’t really comment on the speed improvement, since I don’t really measure that at the moment – I mostly write such stuff to learn new techniques.

More interestingly, the engine is now capable of indirect lighting by using the light propagation volumes technique developed by CryTek. It looks quite nice, there is no support for indirect occlusion yet but that is something I will look into in the next couple of days. There are a couple of pitfalls, and direct errors in the paper, one has to be aware of when implementing this algorithm, which BlackHC has written a really nice document about. My implementation is currently running the CryTek sponza scene at 100 fps on my Radeon 5770 in 1920×1080 resolution with some SSAO, screenshots are available below. I have implemented regular shadow mapping, but the resolution is so bad that I don’t use it. I made a half-hearted attempt at ESM and it does look slightly better. However, I need to configure my shadow frustum better because geometry which is too far away from the camera doesn’t cast shadows, and it looks awful.

Indirect illumination

Full illumination

My upcoming project is to implement image space photon mapping, but implement the ray tracing on the GPU instead using ComputeShader. This is going to be a very interesting project, I have done some research on GPU ray tracing and there are quite a few techniques that I’m going to try. There are a lot of recent, excellent papers on the subject of GPU ray tracing. My first step was to write a simple ray tracer for my test scene. This ray tracer just uses brute force to determine the close triangle intersecting in my tiny 72 triangle scene. If this goes well, I will extend to full scene ray tracing and it seems like a two level hierarchy with a BVH and then a kdTree seems to be the best choice but I’ll need to do some testing on that. My tiny ray tracer is practically finished (100% untested), and I’ll start looking at how the initial bounce is going to be implemented. It feels like a pixel shader that writes out to an AppendStructuredBuffer is the way to go.

~Daniel

Rewriting the graphics engine!

April 6, 2010 by

I’ve for some time been busy working at my bachelor degree project (which happens to be a 3D racing game written in XNA with awesome pre-pass lighting (aka deferred lighting)) and now I’ve just started programming at this project again. I decided that my old graphics engine was too slow and also that it was using a boring lighting model with huge overhead (needed to render the scene 1 + N + S, where N is the number of lights and S is the number of lights with shadow, times) which was pretty slow. I’m also moving on to DirectX 11 but 10 is going to be supported as well, and so far it’s looking very nice.

The general design of the graphics engine is taking shape, it will mostly be a lightweight wrapper around D3D11 with practically no virtual functions (the old graphics engine was basically made up of virtual calls) and I’m going to rely more on std::tr1::shared_ptr this time in order to avoid keeping track of resources as much. Right now I’m messing around a bit with D3D11 and implementing bits of my wrapper classes as I discover more details about the API. My, quite unrealistic I’m afraid, goal at the moment is to have a deferred lighting engine with light propagation volumes in one and a half week. I’m currently rendering the normals and depth of a cube as the first step of the deferred lighting algorithm, so I’m about to start with the lighting system which hopefully will be finished today and I need to implement a couple of differend scene nodes for my new scene graph so that I can start to use this system for real.

~Daniel

The editor and wxWidgets

November 17, 2009 by

The latest progress on the game is probably the font rendering which is based around D3DXFont. Apparently I was way wrong when I thought that it wouldn’t be easy to adapt as I wanted to, when I read the documentation I realized that it was really awesome. Out of the box it has access to all the fonts installed in the system, and by calling AddFontResourceEx you can even add custom fonts to this pool. Another feature is that it’s possible to get automatic word wrapping, clipping and also change the alignment of the text.

Lately I’ve started thinking about an editor for the game, which means that I will need a rather sophisticated GUI system. At first I started implementing a GUI with my own in game components and it sure has the potential to work really good. But I figured that the editor will be a ton easier to use with a native interface, so I started looking towards wxWidgets.

wxWidgets appeared to be almost totally worthless at the first glance, the only documentation on how to initialize the application told me to use some macro IMPLEMENT_APP which would create a main() function and initialize the application to use some wxWidgets main loop. That would not fit into my structure at all. I started reading the wxWidgets code to find out how to use it without having it hijack my main loop and my message pump. Initializing it without the macro appeared to be quite easy (after reading code for a couple of hours) (sorry about the formatting):

class CrazEdApplication : public Craze::Win32Application, public wxApp
{
....
};

bool CrazEdApplication::VInitialize()
{
wxApp::SetInstance(this);

int argc = 0;
wxEntryStart(argc, (char**)0);

if (!Craze::IApplication::VInitialize())
return false;

OnInit();

VShowCursor(true);

return true;
}

bool CrazEdApplication::VCreateWindow(int width, int height, bool windowed)
{
m_pMainFrame = new wxFrame(NULL, -1, _T("CrazEd - Craze Engine Level Editor"), wxDefaultPosition, wxSize(1024, 768));
m_pMainFrame->Show(true);
SetTopWindow(m_pMainFrame);

wxEventLoop::SetActive(new wxEventLoop());

wxPanel* pPanel = new wxPanel(m_pMainFrame, 0, 0, width, height, wxSUNKEN_BORDER);

m_hWnd = (HWND)pPanel->GetHWND();

m_WindowWidth = width;
m_WindowHeight = height;

CreateUI();

return true;
}
void CrazEdApplication::VMessagePump()
{
//Steal our own messages before wxWidgets does so :]
Craze::Win32Application::VMessagePump();

while (Pending())
{
if (!Dispatch())
{
Shutdown();
}
}

while (ProcessIdle());

}

There are a few important things which are noteworthy here:

  • The call to wxApp::SetInstance registers the this pointer to be the wxApp which is used. I don’t remember what the call to wxEntryStart does, but be sure to not use wxEntry since it starts its own main loop.
  • wxEventLoop::SetActive is the line that enables wxWidgets to dispatch messages.
  • The HWND from the panel created is stored and later sent into the graphics engine for creation of the Direct3D device.
  • The message pump starts with taking the window messages sent to its own HWND first and then lets wxWidgets take care of the rest. It’s possible that I should call my own message pump between each call to wxWidgets’ Dispatch().
  • Well, that’s basically it. Now I’ve just got to design an awesome looking interface in wxWidgets and think of all the functionality that I want to have in the editor.

     

    ~Daniel

    Stereoscopic rendering

    October 29, 2009 by

    I was reading a topic on a forum about 3D-rendering using red/blue glasses and other techniques when I remembered about stereoscopic images using the cross eye technique ( http://en.wikipedia.org/wiki/Stereoscopy ). I thought that this would be pretty cool and rather easy to implement in my game so I went ahead and gave it a shot (in a new branch 😉 ) and this is the result:

    1

    It works pretty good for me and it’s rendered in real time, I just had to tweak the camera offset distance a bit to get it at least decent. I have been a bit lazy so user interface is not rendered at both sides (which is because I use the interface to render the sides) which produces a pretty irritating effect but it’s still something which you can disregard from.

    ~Daniel

    Possible slight change in style

    September 22, 2009 by

    I’m currently studying a course in computer graphics and we can either choose to do some tutorials (boring ;]) or create a bigger project. Not surprisingly I chose the latter and decided to keep on working on this game and add my graphics effects that I had in a separate branch and also create a few new graphics “effects”. Lately I’ve been working on the water and trying to make it look cool. I’m pretty happy with how it looks, the only problem is some really ugly minification artifacts which occurs because I’m using a sine function to generate the normals. I might want to throw a normal map at it instead, or I’ll just have to make sure that distant water isn’t covering large areas, or I’ll have to increase the wave size just a bit. The latest thing I’ve added to the water is an effect that makes it fade towards a water color (almost black, just a little blue) when the distance to the surface below increases, I’ve also added Fresnel reflectance so it looks pretty sweet.

    The very latest addition I’ve been working on for two or three days is support for animated skinned meshes (hardware skinning) with a little… “help” from D3DX. To be honest, I definitely think it would have been easier to roll my own system but then I would have to write code to export meshes from some modeling software and I would also have to create some file type and models to test the animation system on. Thus, it would really take a long time so I decided to go with D3DX. I’m not going to describe the loading process in detail, there are documentation and also some samples available in the DirectX SDK, but it was quite the pain and a really complicated beast of code to work with. It didn’t really help the case that I made a small typo in my code that made the bone matrices not multiply correctly and I had to spend a lot of time debugging the whole thing (that wasn’t the only problem though). Now all those problems are fixed and it’s working pretty good, I’ll just have to create a way to render the skinned mesh for my shadow map as well, but that will be really quick. Of course I also had the classic skinning problems making my model look really funny :].

    Since we are studying computer graphics, Jakob and I have started to get interesting in using 3D models instead of 2D sprites. It actually feels like it might be simpler to do so since everything is adapted for 3D now anyway. We have decided to stick with the top down camera and also not allow the user to move it, I really love static cameras so I don’t have to mess around with the camera myself and also allowing the game to be made for a static camera.

    Screenshot (slightly mspainted)!
    Slightly MsPainted Screenshot

    ~Daniel