HDR/Bloom

Eldritch

30-03-2007 16:04:45

I noticed there is a file called Bloom.material in materials/scripts. I am curious to get some tips regarding how to use this. Should I draw a simple quad on the screen that uses this material, or is it more advanced than that?

Eldritch

30-03-2007 18:07:49

I did this (taken from Compositor sample in the SDK):


using System;
using Mogre;

namespace GFW.Graphics
{
public class CBloomFX
{
public void Setup()
{
CompositorPtr bloomComp = CompositorManager.Singleton.Create
(
"BloomFX",
ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME
);

CompositionTechnique tech = bloomComp.CreateTechnique();
{
CompositionTechnique.TextureDefinition_NativePtr def = tech.CreateTextureDefinition("rt0");
def.width = 128;
def.height = 128;
def.format = PixelFormat.PF_A8R8G8B8;
}
{
CompositionTechnique.TextureDefinition_NativePtr def = tech.CreateTextureDefinition("rt1");
def.width = 128;
def.height = 128;
def.format = PixelFormat.PF_A8R8G8B8;
}
{
CompositionTargetPass tp = tech.CreateTargetPass();
tp.SetInputMode(CompositionTargetPass.InputMode.IM_PREVIOUS);
tp.OutputName = "rt1";
}
{
CompositionTargetPass tp = tech.CreateTargetPass();
tp.SetInputMode(CompositionTargetPass.InputMode.IM_NONE);
tp.OutputName = "rt0";
CompositionPass pass = tp.CreatePass();
pass.Type = CompositionPass.PassType.PT_RENDERQUAD;
pass.SetMaterialName("Ogre/Compositor/Blur0");
pass.SetInput(0, "rt1");
}
{
CompositionTargetPass tp = tech.CreateTargetPass();
tp.SetInputMode(CompositionTargetPass.InputMode.IM_NONE);
tp.OutputName = "rt1";
CompositionPass pass = tp.CreatePass();
pass.Type = CompositionPass.PassType.PT_RENDERQUAD;
pass.SetMaterialName("Ogre/Compositor/Blur1");
pass.SetInput(0, "rt0");
}
{
CompositionTargetPass tp = tech.OutputTargetPass;
tp.SetInputMode(CompositionTargetPass.InputMode.IM_PREVIOUS);
{
CompositionPass pass = tp.CreatePass();
pass.Type = CompositionPass.PassType.PT_RENDERQUAD;
pass.SetMaterialName("Ogre/Compositor/BloomBlend");
pass.SetInput(0, "rt1");
}
}
}
}
}


But I think I need to do more to actually use this, right? The Compositor sample shows nothing, which makes me think that either I am blind or they have forgot something...

Eldritch

30-03-2007 20:23:04

Nevermind.. solved Bloom :D


Viewport vp = CCanvas_s.Instance.GetRenderWindow().GetViewport(0);
CompositorInstance c = CompositorManager.Singleton.AddCompositor(vp, "Bloom");
c.Enabled = true;


Though, "HDR" does not seem to be correct. Am I guessing right if I guess that I have to do lots more than just the above to get HDR to work?

Kerion

01-04-2007 03:14:01

Have you tried asking this in the OGRE help forums? This is more of a question on how the OGRE compositor works than MOGRE. You will likely get your answer in C++, but converting that over to MOGRE/C# is not hard.

Eldritch

01-04-2007 10:28:31

True, thanks for the tip.

Eldritch

03-04-2007 06:48:03

Seems like no one wants to give me some tips on this over at the other forum :(

Bekas

04-04-2007 00:50:06

I've ported the Ogre HDR compositor code, here it is (press '1' for HDR and '2' for Glass):
using System;
using System.Collections.Generic;
using Mogre;

namespace Mogre.Demo.Compositor
{
class HDRListener
{
protected int mVpWidth, mVpHeight;
protected int mBloomSize;
// Array params - have to pack in groups of 4 since this is how Cg generates them
// also prevents dependent texture read problems if ops don't require swizzle
protected float[,] mBloomTexWeights = new float[15, 4];
protected float[,] mBloomTexOffsetsHorz = new float[15, 4];
protected float[,] mBloomTexOffsetsVert = new float[15, 4];

public void NotifyViewportSize(int width, int height)
{
mVpWidth = width;
mVpHeight = height;
}

public void NotifyCompositor(CompositorInstance instance)
{
instance.NotifyMaterialSetup += new CompositorInstance.Listener.NotifyMaterialSetupHandler(NotifyMaterialSetup);

// Get some RTT dimensions for later calculations
CompositionTechnique.TextureDefinitionIterator defIter =
instance.Technique.GetTextureDefinitionIterator();

foreach (CompositionTechnique.TextureDefinition_NativePtr def in defIter)
{
if (def.name == "rt_bloom0")
{
mBloomSize = (int)def.width; // should be square
// Calculate gaussian texture offsets & weights
float deviation = 3.0f;
float texelSize = 1.0f / (float)mBloomSize;

// central sample, no offset
mBloomTexOffsetsHorz[0, 0] = 0.0f;
mBloomTexOffsetsHorz[0, 1] = 0.0f;
mBloomTexOffsetsVert[0, 0] = 0.0f;
mBloomTexOffsetsVert[0, 1] = 0.0f;
mBloomTexWeights[0, 0] = mBloomTexWeights[0, 1] =
mBloomTexWeights[0, 2] = GaussianDistribution(0, 0, deviation);
mBloomTexWeights[0, 3] = 1.0f;

// 'pre' samples
for (int i = 1; i < 8; ++i)
{
mBloomTexWeights[i, 0] = mBloomTexWeights[i, 1] =
mBloomTexWeights[i, 2] = 1.25f * GaussianDistribution(i, 0, deviation);
mBloomTexWeights[i, 3] = 1.0f;
mBloomTexOffsetsHorz[i, 0] = i * texelSize;
mBloomTexOffsetsHorz[i, 1] = 0.0f;
mBloomTexOffsetsVert[i, 0] = 0.0f;
mBloomTexOffsetsVert[i, 1] = i * texelSize;
}
// 'post' samples
for (int i = 8; i < 15; ++i)
{
mBloomTexWeights[i, 0] = mBloomTexWeights[i, 1] =
mBloomTexWeights[i, 2] = mBloomTexWeights[i - 7, 0];
mBloomTexWeights[i, 3] = 1.0f;

mBloomTexOffsetsHorz[i, 0] = -mBloomTexOffsetsHorz[i - 7, 0];
mBloomTexOffsetsHorz[i, 1] = 0.0f;
mBloomTexOffsetsVert[i, 0] = 0.0f;
mBloomTexOffsetsVert[i, 1] = -mBloomTexOffsetsVert[i - 7, 1];
}

}
}
}

float GaussianDistribution(float x, float offset, float scale)
{
float nom = (float)System.Math.Exp(
-Math.Sqr(x - offset) / (2 * Math.Sqr(scale)));
float denom = scale * Math.Sqrt(2 * Math.PI);

return nom / denom;
}

unsafe private void NotifyMaterialSetup(uint pass_id, MaterialPtr mat)
{
// Prepare the fragment params offsets
switch (pass_id)
{
//case 994: // rt_lum4
case 993: // rt_lum3
case 992: // rt_lum2
case 991: // rt_lum1
case 990: // rt_lum0
break;
case 800: // rt_brightpass
break;
case 701: // rt_bloom1
{
// horizontal bloom
mat.Load();
GpuProgramParametersSharedPtr fparams =
mat.GetBestTechnique().GetPass(0).GetFragmentProgramParameters();
String progName = mat.GetBestTechnique().GetPass(0).FragmentProgramName;
fixed (float* p_mBloomTexOffsetsHorz = &mBloomTexOffsetsHorz[0, 0])
{
fparams.SetNamedConstant("sampleOffsets", p_mBloomTexOffsetsHorz, 15);
}
fixed (float* p_mBloomTexWeights = &mBloomTexWeights[0, 0])
{
fparams.SetNamedConstant("sampleWeights", p_mBloomTexWeights, 15);
}

break;
}
case 700: // rt_bloom0
{
// vertical bloom
mat.Load();
GpuProgramParametersSharedPtr fparams =
mat.GetTechnique(0).GetPass(0).GetFragmentProgramParameters();
String progName = mat.GetBestTechnique().GetPass(0).FragmentProgramName;
fixed (float* p_mBloomTexOffsetsVert = &mBloomTexOffsetsVert[0, 0])
{
fparams.SetNamedConstant("sampleOffsets", p_mBloomTexOffsetsVert, 15);
}
fixed (float* p_mBloomTexWeights = &mBloomTexWeights[0, 0])
{
fparams.SetNamedConstant("sampleWeights", p_mBloomTexWeights, 15);
}

break;
}
}
}
}

class CompositorToggler
{
public string debugText = null;

public string compositorName;
public MOIS.KeyCode keyCode;
Viewport vp;

bool keyPressed = false;
bool compositorIsOn = false;

public CompositorToggler(string compositorName, MOIS.KeyCode keyCode, Viewport vp)
{
this.compositorName = compositorName;
this.keyCode = keyCode;
this.vp = vp;
}

public bool Update(MOIS.Keyboard input)
{
if (input.IsKeyDown(keyCode))
{
if (!keyPressed)
{
keyPressed = true;
ToggleCompositor();
debugText = compositorName + " " + (compositorIsOn ? "Enabled" : "Disabled");
return true;
}
}
else
keyPressed = false;

return false;
}

private void ToggleCompositor()
{
compositorIsOn = !compositorIsOn;
CompositorManager.Singleton.SetCompositorEnabled(vp, compositorName, compositorIsOn);
}
}

class CompositorDemo : Demo.ExampleApplication.Example
{
CompositorToggler[] togglers;
SceneNode mSpinny;

public override void CreateFrameListener()
{
base.CreateFrameListener();
root.FrameStarted += new FrameListener.FrameStartedHandler(Compositor_FrameStarted);
}

bool Compositor_FrameStarted(FrameEvent evt)
{
if (mSpinny != null)
mSpinny.Yaw(new Degree(10 * evt.timeSinceLastFrame));

foreach (CompositorToggler toggler in togglers)
{
if (toggler.Update(inputKeyboard))
mDebugText = toggler.debugText;
}

return true;
}

public override void CreateScene()
{
sceneMgr.ShadowTechnique = ShadowTechnique.SHADOWTYPE_TEXTURE_MODULATIVE;
sceneMgr.ShadowFarDistance = 1000;

MovableObject.DefaultVisibilityFlags = 0x00000001;

// Set ambient light
sceneMgr.AmbientLight = new ColourValue(0.3f, 0.3f, 0.2f);

Light l = sceneMgr.CreateLight("Light2");
Vector3 dir = new Vector3(-1, -1, 0);
dir.Normalise();
l.Type = Light.LightTypes.LT_DIRECTIONAL;
l.Direction = dir;
l.SetDiffuseColour(1, 1, 0.8f);
l.SetSpecularColour(1, 1, 1);


Entity pEnt;

// House
pEnt = sceneMgr.CreateEntity("1", "tudorhouse.mesh");
SceneNode n1 = sceneMgr.RootSceneNode.CreateChildSceneNode(new Vector3(350, 450, -200));
n1.AttachObject(pEnt);

pEnt = sceneMgr.CreateEntity("2", "tudorhouse.mesh");
SceneNode n2 = sceneMgr.RootSceneNode.CreateChildSceneNode(new Vector3(-350, 450, -200));
n2.AttachObject(pEnt);

pEnt = sceneMgr.CreateEntity("3", "knot.mesh");
mSpinny = sceneMgr.RootSceneNode.CreateChildSceneNode(new Vector3(0, 0, 300));
mSpinny.AttachObject(pEnt);
pEnt.SetMaterialName("Examples/MorningCubeMap");

sceneMgr.SetSkyBox(true, "Examples/MorningSkyBox");


Plane plane;
plane.normal = Vector3.UNIT_Y;
plane.d = 100;
MeshManager.Singleton.CreatePlane("Myplane",
ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME, plane,
1500, 1500, 10, 10, true, 1, 5, 5, Vector3.UNIT_Z);
Entity pPlaneEnt = sceneMgr.CreateEntity("plane", "Myplane");
pPlaneEnt.SetMaterialName("Examples/Rockwall");
pPlaneEnt.CastShadows = false;
sceneMgr.RootSceneNode.CreateChildSceneNode().AttachObject(pPlaneEnt);

camera.SetPosition(-400, 50, 900);
camera.LookAt(0, 80, 0);

AddCompositors();
}

void AddCompositors()
{
// HDR
CompositorInstance instance = CompositorManager.Singleton.AddCompositor(viewport, "HDR", 0);
CompositorManager.Singleton.SetCompositorEnabled(viewport, "HDR", false);
HDRListener hdrListener = new HDRListener();
hdrListener.NotifyViewportSize(viewport.ActualWidth, viewport.ActualHeight);
hdrListener.NotifyCompositor(instance);

// Glass
instance = CompositorManager.Singleton.AddCompositor(viewport, "Glass");
CompositorManager.Singleton.SetCompositorEnabled(viewport, "Glass", false);

togglers = new CompositorToggler[]
{
new CompositorToggler("HDR", MOIS.KeyCode.KC_1, viewport),
new CompositorToggler("Glass", MOIS.KeyCode.KC_2, viewport)
};

System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (CompositorToggler toggler in togglers)
{
sb.Append(toggler.keyCode.ToString().Substring(3));
sb.Append('-');
sb.Append(toggler.compositorName);
sb.Append(", ");
}
sb.Length -= 2;

mDebugText = sb.ToString();
}
}
}

Eldritch

04-04-2007 07:49:46

Awesome!! Thank you very much!! Add to Wiki?

Ack.. just tried it.. When I enable it, it crashes the whole application at no specific point in the code. Ogre.Log says nothing except:

"09:31:34: WARNING: Texture instance 'CompositorInstanceTexture0' was defined as manually loaded, but no manual loader was provided. This Resource will be lost if it has to be reloaded.
09:31:34: WARNING: Texture instance 'CompositorInstanceTexture5' was defined as manually loaded, but no manual loader was provided. This Resource will be lost if it has to be reloaded.
09:31:34: WARNING: Texture instance 'CompositorInstanceTexture4' was defined as manually loaded, but no manual loader was provided. This Resource will be lost if it has to be reloaded.
09:31:34: WARNING: Texture instance 'CompositorInstanceTexture3' was defined as manually loaded, but no manual loader was provided. This Resource will be lost if it has to be reloaded.
09:31:34: WARNING: Texture instance 'CompositorInstanceTexture2' was defined as manually loaded, but no manual loader was provided. This Resource will be lost if it has to be reloaded.
09:31:34: WARNING: Texture instance 'CompositorInstanceTexture1' was defined as manually loaded, but no manual loader was provided. This Resource will be lost if it has to be reloaded.
09:31:34: WARNING: Texture instance 'CompositorInstanceTexture6' was defined as manually loaded, but no manual loader was provided. This Resource will be lost if it has to be reloaded."

Bekas

04-04-2007 09:57:26

Add to Wiki?
I added it to SVN; it will be part of the samples.

I get the warnings too but it is working fine here. Try it on a clean SDK install. Also run it with unmanaged debugging on and check out where the crash is happening.

Eldritch

04-04-2007 16:25:56

No need to make a clean SDK install, I don't use anything from there except having linked to DLLs.

The problem occurs when I set Enabled to true on the compositor instance for HDR.

Bekas

04-04-2007 18:58:12

Are you running the executable from inside "c:\OgreSDK\bin\debug" (or release) ?
Maybe your graphics card doesn't support the shaders used for HDR ? Download the Ogre demos and try HDR out.

Eldritch

04-04-2007 21:58:41

I am running the executable from my own folder. Everything else works perfectly (except of course Newton, but that is another thing). And yes, my card does support HDR... even the Ogre HDR shaders.

Bekas

05-04-2007 11:04:28

Give it a try to run it from the OgreSDK folder too.

Eldritch

05-04-2007 12:51:22

Won't make a difference in this case.

Edit: The reason being, that I don't use anything from the OgreSDK that I don't already have in my own folder.

Eldritch

09-04-2007 19:20:32

Here's the code I am using:

Setting up HDR. Done when game starts.

public void SetupHDR()
{
m_refHDR = CompositorManager.Singleton.AddCompositor(m_refViewport, "HDR", 0);
CHDRListener HDR = new CHDRListener();
HDR.SetupHDRCompositor(m_refHDR);
m_refHDR.Enabled = true
CLogTool_s.Instance.Write("Setting up HDR FX", true);
}


The CHDRListener class.

using System;
using Mogre;
using GFW.Canvas;

namespace GFW.Graphics
{
public class CHDRListener
{
protected int m_iBloomSize;
protected float[,] m_fBloomTexWeights_a = new float[15, 4];
protected float[,] m_fBloomOffsetH_a = new float[15, 4];
protected float[,] m_fBloomOffsetV_a = new float[15, 4];

public void SetupHDRCompositor(CompositorInstance refInstance)
{
refInstance.NotifyMaterialSetup +=
new CompositorInstance.Listener.NotifyMaterialSetupHandler(NotifyMaterialSetup);

CompositionTechnique.TextureDefinitionIterator it = refInstance.Technique.GetTextureDefinitionIterator();

foreach (CompositionTechnique.TextureDefinition_NativePtr def in it)
{
if (def.name == "rt_bloom0")
{
m_iBloomSize = (int)def.width;
float deviation = 3.0f;
float texelSize = 1.0f / (float)m_iBloomSize;

m_fBloomOffsetH_a[0, 0] = 0.0f;
m_fBloomOffsetH_a[0, 1] = 0.0f;
m_fBloomOffsetV_a[0, 0] = 0.0f;
m_fBloomOffsetV_a[0, 0] = 0.0f;
m_fBloomTexWeights_a[0, 0] = m_fBloomTexWeights_a[0, 1] = m_fBloomTexWeights_a[0, 2] =
GaussianDistribution(0, 0, deviation);
m_fBloomTexWeights_a[0, 3] = 1.0f;

for (int i = 1; i < 8; ++i)
{
m_fBloomTexWeights_a[i, 0] = m_fBloomTexWeights_a[i, 1] = m_fBloomTexWeights_a[i, 2] =
1.25f * GaussianDistribution(0, 0, deviation);
m_fBloomTexWeights_a[i, 3] = 1.0f;

m_fBloomOffsetH_a[i, 0] = i * texelSize;
m_fBloomOffsetH_a[i, 1] = 0.0f;
m_fBloomOffsetV_a[i, 0] = 0.0f;
m_fBloomOffsetV_a[i, 1] = i * texelSize;
}

for (int i = 8; i < 15; ++i)
{
m_fBloomTexWeights_a[i, 0] = m_fBloomTexWeights_a[i, 1] = m_fBloomTexWeights_a[i, 2] =
m_fBloomTexWeights_a[i - 7, 0];
m_fBloomTexWeights_a[i, 3] = 1.0f;

m_fBloomOffsetH_a[i, 0] = -m_fBloomOffsetH_a[i - 7, 0];
m_fBloomOffsetH_a[i, 1] = 0.0f;
m_fBloomOffsetV_a[i, 0] = 0.0f;
m_fBloomOffsetV_a[i, 1] = -m_fBloomOffsetV_a[i - 7, 1];
}
}
}
}

protected float GaussianDistribution(float fX, float fOffset, float fScale)
{
float nom = (float)System.Math.Exp(-Mogre.Math.Sqr(fX - fOffset) / (2 * Mogre.Math.Sqr(fScale)));
float denom = fScale * Mogre.Math.Sqrt(2 * Mogre.Math.PI);
return nom / denom;
}

unsafe private void NotifyMaterialSetup(uint pass_id, MaterialPtr mat)
{
switch (pass_id)
{
case 993: // rt_lum3
case 992: // rt_lum2
case 991: // rt_lum1
case 990: // rt_lum0
break;
case 800: // rt_brightpass
break;
case 701: // rt_bloom1
{
mat.Load();
GpuProgramParametersSharedPtr fParams =
mat.GetBestTechnique().GetPass(0).GetFragmentProgramParameters();
String progName = mat.GetBestTechnique().GetPass(0).FragmentProgramName;
fixed (float* ptrBloomOffsetH = &m_fBloomOffsetH_a[0, 0])
{
fParams.SetNamedConstant("sampleOffsets", ptrBloomOffsetH, 15);
}
fixed (float* ptrBloomWeights = &m_fBloomTexWeights_a[0, 0])
{
fParams.SetNamedConstant("sampleWeights", ptrBloomWeights, 15);
}
}
break;
case 700: // rt_bloom0
{
mat.Load();
GpuProgramParametersSharedPtr fParams =
mat.GetBestTechnique().GetPass(0).GetFragmentProgramParameters();
String progName = mat.GetBestTechnique().GetPass(0).FragmentProgramName;
fixed (float* ptrBloomOffsetV = &m_fBloomOffsetV_a[0, 0])
{
fParams.SetNamedConstant("sampleOffsets", ptrBloomOffsetV, 15);
}
fixed (float* ptrBloomWeights = &m_fBloomTexWeights_a[0, 0])
{
fParams.SetNamedConstant("sampleWeights", ptrBloomWeights, 15);
}
}
break;
}
}
}
}



Also, this error occurs:

-----------------------------------
Details:
-----------------------------------
Error #: 7
Function: GpuProgramParameters::getParamIndex
Description: Cannot find a parameter named sampleOffsets.
File: ..\src\OgreGpuProgram.cpp
Line: 837