Netskate
23-10-2008 12:31:17
This little how to should help you to solve these problems in the right way and should give you some "tricks" to avoid them.
This thread will deal only about the ProjectedGrid module (also if some problems are related to both hydrax module).
First of all you had to disable Caelum fog and be sure that setfarclipdistance of your camera is something like 9999*6 (if this setting is 0 you can't see the water).
You had to be sure that hydrax is updated AFTER any camera movement, else the projectedgrid infinite plane stay always a frame back from the camera and it
can't follow the camera correctly.
After you are sure you haven't problem with this you can go forward.
One of the most common problem is a black row in the horizon where hydrax infinite plane meet caelum, something like this:
You have two choice:
1. Waiting for the new hydrax v0.5 version that must have a method like: Hydrax::RttManager::addDisabledClipRenderQueue(...);
2. For now, edit hydrax source. The problem is that Caelum objects are rendered in different rendere queues, as you can see in the
CaelumPrerequisites.h:
// Render group for caelum stuff
// It's best to have them all together
enum CaelumRenderQueueGroupId
{
CAELUM_RENDER_QUEUE_STARFIELD = Ogre::RENDER_QUEUE_SKIES_EARLY + 0,
CAELUM_RENDER_QUEUE_MOON_BACKGROUND = Ogre::RENDER_QUEUE_SKIES_EARLY + 1,
CAELUM_RENDER_QUEUE_SKYDOME = Ogre::RENDER_QUEUE_SKIES_EARLY + 2,
CAELUM_RENDER_QUEUE_MOON = Ogre::RENDER_QUEUE_SKIES_EARLY + 3,
CAELUM_RENDER_QUEUE_SUN = Ogre::RENDER_QUEUE_SKIES_EARLY + 4,
CAELUM_RENDER_QUEUE_CLOUDS = Ogre::RENDER_QUEUE_SKIES_EARLY + 5,
CAELUM_RENDER_QUEUE_GROUND_FOG = Ogre::RENDER_QUEUE_SKIES_EARLY + 6,
};
This mean that Caelum objects avoid the disableCustomNearClipPlane that Hydrax disable in order to prevent these kind of artefacts.
So, you need to edit hydrax source to add the Caelum render queues which must be disabled.
Go to this file RttManager.cpp (row 497):
and substitute this:
void RttManager::CReflectionListener::CReflectionQueueListener::renderQueueStarted(Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool
&skipThisInvocation)
{
if ((queueGroupId == Ogre::RENDER_QUEUE_SKIES_EARLY || queueGroupId == Ogre::RENDER_QUEUE_SKIES_LATE)
&& mActive)
{
mRttManager->mHydrax->getCamera()->disableCustomNearClipPlane();
Ogre::Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mRttManager->mHydrax->getCamera()->getProjectionMatrixRS());
}
}
void RttManager::CReflectionListener::CReflectionQueueListener::renderQueueEnded(Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool
&skipThisInvocation)
{
if ((queueGroupId == Ogre::RENDER_QUEUE_SKIES_EARLY || queueGroupId == Ogre::RENDER_QUEUE_SKIES_LATE)
&& mActive)
{
mRttManager->mHydrax->getCamera()->enableCustomNearClipPlane(mRttManager->mPlanes[RTT_REFLECTION]);
Ogre::Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mRttManager->mHydrax->getCamera()->getProjectionMatrixRS());
}
}
with this:
void RttManager::CReflectionListener::CReflectionQueueListener::renderQueueStarted(Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool
&skipThisInvocation)
{
if ((queueGroupId == Ogre::RENDER_QUEUE_SKIES_EARLY || queueGroupId == Ogre::RENDER_QUEUE_SKIES_LATE || queueGroupId ==
(Ogre::RENDER_QUEUE_SKIES_EARLY + 2))
&& mActive)
{
mRttManager->mHydrax->getCamera()->disableCustomNearClipPlane();
Ogre::Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mRttManager->mHydrax->getCamera()->getProjectionMatrixRS());
}
}
void RttManager::CReflectionListener::CReflectionQueueListener::renderQueueEnded(Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool
&skipThisInvocation)
{
if ((queueGroupId == Ogre::RENDER_QUEUE_SKIES_EARLY || queueGroupId == Ogre::RENDER_QUEUE_SKIES_LATE || queueGroupId ==
(Ogre::RENDER_QUEUE_SKIES_EARLY + 2))
&& mActive)
{
mRttManager->mHydrax->getCamera()->enableCustomNearClipPlane(mRttManager->mPlanes[RTT_REFLECTION]);
Ogre::Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mRttManager->mHydrax->getCamera()->getProjectionMatrixRS());
}
}
now the black row in the horizon should be disappear
Another problem you can encounter is that sun, moon and/or other Caelum objects cause artifacts when fall into water. So, because they aren't ogre entities
to avoid this you need to add a specified hydrax depth technique to ALL caelum material objects.
This is the problem:
Add this HydraxDepthTechnique to ALL caelum objects materials, to avoid it:
technique HydraxDepth
{
scheme HydraxDepth
pass
{
lighting off
texture_unit
{
colour_op_ex modulate src_manual src_current 0 0 0
}
}
}
Overcome this annoying problems, you can go forward to tweak hydrax sun's reflects with caelum sun's position, colour, etc.
What we want to do?
We want making sun's reflects move over hydrax water plane, and change its colour in base of the current time (day, night etc). We also want change water
colour to make it more dark when night fall.
To do this, the first thing we need is the sun position. There are two way to calculate it.
1. use this function directly from nature demo (you can find it in the showcase forum):
Ogre::Vector3 sunPosition = camera->getDerivedPosition();
sunPosition -= mCaelumSystem->getSun()->getLightDirection() * 80000;
However, in my opinion, this function is not very accurate.
2. it's what I suggest, edit Caelum source adding a getter method for the abstract class BaseSkyLight scene node. In this way you can know the exact
position of every object that extend the BaseSkyLight class, as Sun and Moon , it's very simple.
In SkyLight.h (around row 103) add this prototype:
/// get current scene node
Ogre::SceneNode *getSceneNode() const;
in SkyLight.cpp (around row 97) add this method definition:
Ogre::SceneNode* BaseSkyLight::getSceneNode() const{
return mNode;
}
Recompile Caelum library, exchanging the old dll in your project with the newest and rebuild your project.
Now all you had to do to get sun or moon position is write a simple function like this:
Ogre::Vector3 getSunPosition(){
return caelumManager->getSun()->getSceneNode()->getPosition();
}
More clearly and more accurated, in my opinion.
So now that we can know tha sun position we need to set some hydrax parameters every frame (before calling Hydrax::update();).
They are:
Hydrax::setSunArea();
Hydrax::setWaterColor();
Hydrax::setSunPosition();
Hydrax::setSunColor();
setSunPosition:
Use one the method descibed above.
setSunArea:
This is a value you can edit or not, I prefer to edit it making the sun area more big when getSunPosition().y is around 0.0
and more small when getSunPosition().y is around his max value (midday), to do this I use a simple linear interpolation.
Note: more small is the value of the sunArea and more big will be it.
setSunColor:
I set this value with "caelumManager->getSun()->getBodyColour()" value.
setWaterColor:
To set this value refer to this thread: http://www.ogre3d.org/phpBB2addons/viewtopic.php?t=8420
in the end, this are the result I have achieved:
http://www.youtube.com/watch?v=TzPpZ1HK-FY
I hope you can do the same, or better and sharing your result with us.
ps: sorry for my bad english, any correction is appreciated.
ps2: thanks to xavyiy for his patience and the help he gave me.
---- EDIT -----
I implement another tweak to avoid that sun reflects is shown on water when sky is cloudy.
There are many solution to do this, but this is the fastest and easiest
solution I have found.
The easiest way was to decrement the alpha value of sun colour in base of the increment of the cloud, this would have made sun reflects fading to trasparent/opaque.
But how xavy told, all the colour in hydrax are contained into a Vector3 instead of a ColourValue to optimize shader calculation (float3 is more fast than float4).
So here my method:
First of all you had to calculate you water "darkest" colour (the colour you would use at sun 0.0 heigth). Call it sunTransparentColour.
After you have done this, when sky is cloudy (choices a value of cloud cover to define it cloudy, for example cloudCover=0.5) instead of set sun colour position as described before, you can set the sun colour in this way:
mHydrax->setSunColor(getColourLinearInterpolation(0.0,hmHydrax->getSunColor(), 1.0, sunTransparentColour, mCaelum->getCloudCover()));
0.0 and 1.0 are the range of possible cloud cover (as defined in caelum).
getsuncolour is the actual sun color on the water.
suntrasparent colour is the colour calculated before.
getcloudcover is the current cloud cover of caelum.
here the code of the getColourLinearInterpolation:
Ogre::Vector3 GameSupport::getColourLinearInterpolation(Ogre::Real Xa,Ogre::Vector3 Ya,Ogre::Real Xb,Ogre::Vector3 Yb,Ogre::Real X){
const Ogre::Real k = Xa - Xb;
Ogre::Vector3 temp;
temp.x = ((((X-Xb)/k)*Ya.x)-(((X-Xa)/k)*Yb.x));
temp.y = ((((X-Xb)/k)*Ya.y)-(((X-Xa)/k)*Yb.y));
temp.z = ((((X-Xb)/k)*Ya.z)-(((X-Xa)/k)*Yb.z));
return temp;
}