Tag Archives: Ogre3D

Optimising Shaders

I am using HLSL shader model 3, but this article should apply to other languages and shader models.

It is Good to MAD

One of the most basic optimisation is to use mad operation, which is to multiply 2 values and add a third value to the result.
This is two instructions for the price of one, luckily the compiler is usually smart enough to snap this bargain when they sense it.
It is still useful to look at the compiled asm to combine any exceptions

The Power of 4

The beauty of GPU is most instructions are process in 4 components data block. This will caused any instruction that uses 1 data to cost as much as the same instruction using 4 data.

Eg pow(NdotH, shininess) cost the same as pow(float4(light1NdotH, light2NdotH, light3NdotH, light4NdotH), shininess)

Step operation and comparision operator also work in 4
float4 sampleDepths;
float depthToCompare;

float4 results = step(sampleDepths, depthToCompare);
float4 results = (sampleDepths > depthToCompare);

When 4 become 1

After comparision, it is often desirable to combine the results together to get total number of samples compared correctly.
This is where dotproduct shine.
Remember dot product of 2 float4 is

vec1.x * vec2.x + vec1.y * vec2.y + vec1.z * vec2.z + vec1.w * vec2.w

which is 4 mad instruction for 1 dp4 instruction

float numberOfResultsTrue = dot(results, 1);

Cheap Matrix Inverse

Remember orthonormal matrices Inverse is equal to their Transpose. Tangent, Binormal(Bitangent), Normal are usually in unit length and are perpendicular to each other. Use their transpose to convert any tangent space vector back to object space.

Eg
float3x3 matTan = float3x3(T, B, N);
float3x3 matTanInverse = transpose(matTan);
float3 normalFromNormalMap;
float3 worldNormal = mul(matTanInverse, normalFromNormalMap);

Playing with NormalMap

Combining tangent space normal map is different from combining normal images. Here are some ways to combine two normal map together. The general idea is the identity normal, float3(0, 0, 1), will use the vertex default normal.

Adding

Adding two normals and preserving both details can be done this way.
finalNormal = float3(normal1.xy + normal2.xy, normal1.z * normal2.z);
finalNormal = normalize(finalNormal);

Blending

Using lerp. we can easily blend two normal
lerp(normal1, normal2, factor)

Strengthen

To make the normal map look stronger we could do

normal.xy *= strength;
normalize(normal);

This will cause any slope to bent away from the surface normal making it look steeper.

Decompress

To compress normal, it is common to copy the X value to the A channel of the image, and calculate the Z value from X and Y
In short it is to take advantage of the uncompressed A channel in DXT5 and to save an additional channel data by calculating Z during runtime.

float3 normal;
normal.xy = tex2D(normalMap, uv).ag;

normal.z = sqrt(1 – normal.x * normal.x – normal.y * normal.y);
which can be optimise to
normal.z = sqrt(1 – dot(normal.xy, normal.xy));

Create a simple mini-map using Ogre3D and CEGUI

Objective: Creating a mini-map display using Ogre 3D and CEGUI.

Difficulty: Beginner
Code Length: Short
 
This tutorial explains how to render the whole scene from a top down view and render it to a CEGUI StaticImage.
 
//calculate the height of camera to view the whole scene
 
Ogre::Radian fieldOfView = _camera->getFOVy();
float height = _sceneLength/2 / Ogre::Math::Sin(fieldOfView / 2);
 
Vector3 cameraPosition = Vector3(_sceneLength/2,_sceneWidth/2, height);
Vector3 lookAt = Vector3(_sceneLength/2,_sceneWidth/2, 0);
 
//create a texture for the mini-map to render on
 
TexturePtr texture = TextureManager::getSingleton().createManual(“mmTex”,
   ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D,
   512, 512, 0, PF_R8G8B8, TU_RENDERTARGET );
 
RenderTarget rt = texture->getBuffer()->getRenderTarget();
{
   //create a minimap camera, use the same settings as main camera
   _mmCamera = _sceneManager->createCamera(“minimapCamera”);
   _mmCamera->setNearClipDistance(_camera->getNearClipDistance());
   _mmCamera->setFarClipDistance(_camera->getFarClipDistance());
 
   //AspectRatio(1) is for a square minimap
   _mmCamera->setAspectRatio(1);
   _mmCamera->setPosition(cameraPosition);
   _mmCamera->lookAt(lookAt);
   Viewport *vp = _rt->addViewport(_mmCamera);
   vp->setClearEveryFrame(true);
   vp->setOverlaysEnabled(false);
   vp->setBackgroundColour(ColourValue::Black);
}
 
//Create a CEGUI texture from mmTex
CEGUI::Texture* cetex = GUIManager::instance()->_guiRenderer->createTexture((CEGUI::utf8*) “mmTex”);
 
//CEGUI require an imageset to store the texture
CEGUI::Imageset* imageset = CEGUI::ImagesetManager::getSingleton().createImageset((CEGUI::utf8*)”minimapTexImageset”, cetex);
 
imageset->defineImage((CEGUI::utf8*)”minimapImage”,
CEGUI::Point(0.0f, 0.0f),
CEGUI::Size(cetex->getWidth(), cetex->getHeight()),
CEGUI::Point(0.0f,0.0f));
 
//retrieve the CEGUI StaticImage(window) used to render the minimap
CEGUI::Window* si = CEGUI::WindowManager::getSingleton().getWindow((CEGUI::utf8*)”MiniMap”);
si->setProperty(“Image”, CEGUI::PropertyHelper::imageToString(
   &imageset->getImage((CEGUI::utf8*)|CEGUI::utf8*)”minimapImage”)));