Adding Wind to Grass
-
- Goblin
- Posts: 272
- Joined: Thu Jun 10, 2004 4:19 am
- x 26
Adding Wind to Grass
-
- OGRE Team Member
- Posts: 5448
- Joined: Sat Jul 21, 2007 4:55 pm
- Location: Buenos Aires, Argentina
- x 1349
Re: Adding Wind to Grass
See this post which explains how an existing Hlms implementation was slightly customized to apply custom shader code only to a specific set of Items, which is how Colibri does its rendering (it derives from HlmsUnlit and applies regular HlmsUnlit for regular Items, and applies a specific shader for objects that belong to Colibri)
-
- OGRE Expert User
- Posts: 1148
- Joined: Sat Jul 06, 2013 10:59 pm
- Location: Chile
- x 169
Re: Adding Wind to Grass
https://www.dropbox.com/s/75crodirnat7i ... e.dds?dl=0
you just have to customize the hlms and add something like this to the vertex shader:
Code: Select all
@property( syntax == glsl )
uniform sampler3D texPerlinNoise;
@else
Texture3D texPerlinNoise : register( t14 );
SamplerState texPerlinNoiseSampler : register( s14 );
@end
Code: Select all
@property( syntax == glsl )
worldPos.xyz += ( texture( texPerlinNoise, 0.2*worldPos.xyz +
float3(passBuf.globalTime*0.3) ).xyz - 0.2 ) * colour.x * passBuf.windIntensity;
@else
worldPos.xyz += ( texPerlinNoise.SampleLevel( texPerlinNoiseSampler,
0.2*worldPos.xyz +
float3( passBuf.globalTime*0.3, passBuf.globalTime*0.3, passBuf.globalTime*0.3 ), 0 ).xyz -
float3( 0.2, 0.2, 0.2 ) ) * input.colour.x * passBuf.windIntensity;
@end
-
- Gnoll
- Posts: 660
- Joined: Mon Aug 06, 2007 12:53 pm
- Location: Saarland, Germany
- x 64
Re: Adding Wind to Grass
great ideas!
@dark_sylinc, would it be possible to add such samples to Ogre Samples? Like Wind on environment, Ocean Sample etc. ?
This would be gread showcases of Ogre in action!
Best Regards
Lax
http://www.lukas-kalinowski.com/Homepage/?page_id=1631
Please support Second Earth Technic Base built of Lego bricks for Lego ideas: https://ideas.lego.com/projects/81b9bd1 ... b97b79be62
-
- OGRE Expert User
- Posts: 1148
- Joined: Sat Jul 06, 2013 10:59 pm
- Location: Chile
- x 169
Re: Adding Wind to Grass
-
- OGRE Team Member
- Posts: 2129
- Joined: Sun Mar 30, 2014 2:51 pm
- x 1141
-
- Goblin
- Posts: 272
- Joined: Thu Jun 10, 2004 4:19 am
- x 26
Re: Adding Wind to Grass
Well, that is where I'm heading. I've created a webpage where I'll be sharing my ogre code and experiences, at some point I could add them to the wiki or w/e. For now I'm working on learning and implementing stuff, then I'll create some fleshed out posts.
-
- Ogre Magi
- Posts: 1172
- Joined: Mon Aug 04, 2008 7:51 pm
- Location: Manchester - England
- x 76
Re: Adding Wind to Grass
That one is definitely worth porting but I wonder if somethings should use ogres own instancing now.paroj wrote: ↑Wed Jul 08, 2020 3:47 pm you could port https://github.com/OGRECave/ogre-pagedg ... edgeometry
-
- OGRE Team Member
- Posts: 5448
- Joined: Sat Jul 21, 2007 4:55 pm
- Location: Buenos Aires, Argentina
- x 1349
Re: Adding Wind to Grass
Instancing is quite primitive/old-fashion when it comes to grass rendering.
By merely using SV_VertexID, it is possible to draw a grass blade in 2D, then randomly bend it a little to make it 3D.
This enables adaptive vertex-buffer-less high performance grass with very few instances.
The concept is very similar to hair rendering.
Codemasters does something similar (see page 17, blades are essentially 2D objects which are then bent in 3D).
Codemasters' implementation is a bit more complex because they use compute shaders to keep track of grass that has been stepped by the car tires (rather than being stateless).
The same can be repeated for medium-distance grass using SV_VertexID to generate the grass planes to draw grass using alpha discard (or alpha to coverage), rather than rendering the individual blades using vertex geometry (because at medium distance you'd otherwise process more than 1 vertex per pixel).
See Codemasters's PDF page 19.
At high distance, it's more efficient to use a terrain-like low tesselated object drawn on top of the terrain with low quality raymarching.
Trees would still have to be rendered traditionally though (although it may be possible to use vertex pulling and merge-instancing to increase the vertex_count / instance_count ratio)
-
- Goblin
- Posts: 272
- Joined: Thu Jun 10, 2004 4:19 am
- x 26
Re: Adding Wind to Grass
Code: Select all
class HlmsWindListener : public Ogre::HlmsListener {
protected:
#if OGRE_DEBUG_MODE
Ogre::SceneManager* mSceneManager;
#endif
const float mWindFactor{ 2 };
float mGlobalTime{ 0 };
public:
HlmsWindListener() {}
~HlmsWindListener() {}
virtual Ogre::uint32 getPassBufferSize(const Ogre::CompositorShadowNode* shadowNode, bool casterPass,
bool dualParaboloid, Ogre::SceneManager* sceneManager) const {
unsigned int fogSize = (4 * 2) * 4; // float4 + float4 in bytes
unsigned int windSize = (1) * 4;
unsigned int timeSize = (1) * 4;
return (!casterPass) ? fogSize + windSize + timeSize: 0u;
}
virtual float* preparePassBuffer(const Ogre::CompositorShadowNode* shadowNode, bool casterPass,
bool dualParaboloid, Ogre::SceneManager* sceneManager,
float* passBufferPtr) {
if (!casterPass )
{
//Linear Fog parameters
*passBufferPtr++ = sceneManager->getFogStart();
*passBufferPtr++ = sceneManager->getFogEnd();
*passBufferPtr++ = 0.0;
*passBufferPtr++ = 0.0f;
*passBufferPtr++ = sceneManager->getFogColour().r;
*passBufferPtr++ = sceneManager->getFogColour().g;
*passBufferPtr++ = sceneManager->getFogColour().b;
*passBufferPtr++ = 1.0f;
*passBufferPtr++ = mWindFactor;
mGlobalTime += 1;
if (mGlobalTime >= 1000) mGlobalTime = 0;
*passBufferPtr++ = mGlobalTime;
}
return passBufferPtr;
}
};
class HlmsWind : public Ogre::HlmsPbs {
HlmsWindListener mWindListener;
Ogre::DescriptorSetTexture const* m_descriptorSet{ nullptr };
Ogre::TextureGpu* mNoiseTexture{ nullptr };
void calculateHashForPreCreate(Ogre::Renderable* renderable, Ogre::PiecesMap* inOutPieces) override {
HlmsPbs::calculateHashForPreCreate(renderable, inOutPieces);
setProperty("wind_enabled", 1);
}
void loadNoiseTexture(Ogre::SceneManager* manager) {
Ogre::Image2 image;
image.load("windNoise.png", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
Ogre::TextureGpuManager* textureManager =
manager->getDestinationRenderSystem()->getTextureGpuManager();
mNoiseTexture = textureManager->createTexture(
"WindNoise",
Ogre::GpuPageOutStrategy::SaveToSystemRam,
Ogre::TextureFlags::ManualTexture,
Ogre::TextureTypes::Type2D);
mNoiseTexture->setResolution(image.getWidth(), image.getHeight());
mNoiseTexture->setPixelFormat(image.getPixelFormat());
mNoiseTexture->scheduleTransitionTo(Ogre::GpuResidency::Resident);
Ogre::StagingTexture* stagingTexture = textureManager->getStagingTexture(image.getWidth(),
image.getHeight(),
1u, 1u,
image.getPixelFormat());
stagingTexture->startMapRegion();
Ogre::TextureBox texBox = stagingTexture->mapRegion(image.getWidth(), image.getHeight(), 1u, 1u,
image.getPixelFormat());
//for( uint8 mip=0; mip<numMipmaps; ++mip )
texBox.copyFrom(image.getData(0));
stagingTexture->stopMapRegion();
stagingTexture->upload(texBox, mNoiseTexture, 0, 0, 0);
textureManager->removeStagingTexture(stagingTexture);
stagingTexture = 0;
mNoiseTexture->notifyDataIsReady();
}
public:
HlmsWind(Ogre::Archive* dataFolder, Ogre::ArchiveVec* libraryFolders)
: Ogre::HlmsPbs(dataFolder, libraryFolders)
{
mType = Ogre::HLMS_USER0;
mTypeName = "Wind";
mTypeNameStr = "Wind";
setListener(&mWindListener);
mReservedTexSlots = 1u;
}
virtual ~HlmsWind() {
// destroyDescriptorSet();
}
void setupNoiseTexture(Ogre::SceneManager* manager) {
loadNoiseTexture(manager);
createDescriptorSet();
}
void notifyPropertiesMergedPreGenerationStep(void)
{
HlmsPbs::notifyPropertiesMergedPreGenerationStep();
setTextureReg(Ogre::VertexShader, "WindNoise", 14);
}
static void getDefaultPaths(Ogre::String& outDataFolderPath, Ogre::StringVector& outLibraryFoldersPaths) {
//We need to know what RenderSystem is currently in use, as the
//name of the compatible shading language is part of the path
Ogre::RenderSystem* renderSystem = Ogre::Root::getSingleton().getRenderSystem();
Ogre::String shaderSyntax = "GLSL";
if (renderSystem->getName() == "Direct3D11 Rendering Subsystem")
shaderSyntax = "HLSL";
else if (renderSystem->getName() == "Metal Rendering Subsystem")
shaderSyntax = "Metal";
//Fill the library folder paths with the relevant folders
outLibraryFoldersPaths.clear();
outLibraryFoldersPaths.push_back("Hlms/Common/" + shaderSyntax);
outLibraryFoldersPaths.push_back("Hlms/Common/Any");
outLibraryFoldersPaths.push_back("Hlms/Pbs/Any");
outLibraryFoldersPaths.push_back("Hlms/Pbs/Any/Main");
outLibraryFoldersPaths.push_back("Hlms/Wind/Any");
//Fill the data folder path
outDataFolderPath = "Hlms/pbs/" + shaderSyntax;
}
void createDescriptorSet(void){
destroyDescriptorSet();
Ogre::DescriptorSetTexture descSet;
descSet.mTextures.push_back(mNoiseTexture);
descSet.mShaderTypeTexCount[Ogre::VertexShader] = 1u;
Ogre::HlmsManager* hlmsManager = Ogre::Root::getSingleton().getHlmsManager();
m_descriptorSet = hlmsManager->getDescriptorSetTexture(descSet);
}
//-----------------------------------------------------------------------------------
void destroyDescriptorSet(void) {
if (m_descriptorSet)
{
Ogre::HlmsManager* hlmsManager = Ogre::Root::getSingleton().getHlmsManager();
hlmsManager->destroyDescriptorSetTexture(m_descriptorSet);
m_descriptorSet = 0;
}
}
Ogre::uint32 fillBuffersFor(const Ogre::HlmsCache* cache, const Ogre::QueuedRenderable& queuedRenderable,
bool casterPass, Ogre::uint32 lastCacheHash,
Ogre::CommandBuffer* commandBuffer, bool isV1)
{
*commandBuffer->addCommand<Ogre::CbTextures>() =
Ogre::CbTextures(0, std::numeric_limits<Ogre::uint16>::max(), m_descriptorSet);
return Ogre::HlmsPbs::fillBuffersFor(cache, queuedRenderable, casterPass, lastCacheHash, commandBuffer, isV1);
}
};
shader pieces:
Code: Select all
@piece( custom_vs_preTransform )
@property(wind_enabled)
worldPos.xz += texPerlinNoise.SampleLevel( texPerlinNoiseSampler,
worldPos.xyz* passBuf.globalTime, 0 ).xyz * 100 ;
@end
@end
Code: Select all
@piece( custom_vs_uniformDeclaration)
Texture3D texPerlinNoise : register( t14 );
SamplerState texPerlinNoiseSampler : register( s14 );
@end
/// Extra per-pass global data we need for applying our fog
@piece( custom_passBuffer )
//Fog
float4 fogParams;
float4 fogColor;
float windFactor;
float globalTime;
@end
-
- OGRE Expert User
- Posts: 1148
- Joined: Sat Jul 06, 2013 10:59 pm
- Location: Chile
- x 169
Re: Adding Wind to Grass
-
- Goblin
- Posts: 272
- Joined: Thu Jun 10, 2004 4:19 am
- x 26
Re: Adding Wind to Grass
I loaded the dds like so:
Code: Select all
Ogre::TextureBox texBox = stagingTexture->mapRegion(image.getWidth(), image.getHeight(), image.getDepth(), image.getNumSlices(),
image.getPixelFormat());
texBox.copyFrom(image.getData(0));
-
- OGRE Expert User
- Posts: 1148
- Joined: Sat Jul 06, 2013 10:59 pm
- Location: Chile
- x 169
Re: Adding Wind to Grass
Code: Select all
Ogre::HlmsSamplerblock samplerblock;
samplerblock.mU = Ogre::TextureAddressingMode::TAM_WRAP;
samplerblock.mV = Ogre::TextureAddressingMode::TAM_WRAP;
samplerblock.mW = Ogre::TextureAddressingMode::TAM_WRAP;
samplerblock.mMaxAnisotropy = 8;
samplerblock.mMagFilter = Ogre::FO_ANISOTROPIC;
mSamplerblockWrap = Ogre::Root::getSingleton().getHlmsManager()->getSamplerblock(samplerblock);
mWindNoiseTexture = textureMgr->createOrRetrieveTexture(
"windNoise.dds",
Ogre::GpuPageOutStrategy::Discard,
Ogre::TextureFlags::PrefersLoadingFromFileAsSRGB,
Ogre::TextureTypes::Type3D,
Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME );
mWindNoiseTexture->scheduleTransitionTo( Ogre::GpuResidency::Resident );
Code: Select all
vsParams->setNamedConstant( "texPerlinNoise", 14 );
Code: Select all
*commandBuffer->addCommand<Ogre::CbTexture>() = Ogre::CbTexture( 14, const_cast<Ogre::TextureGpu*>(mWindNoiseTexture), mSamplerblockWrap );
-
- Goblin
- Posts: 272
- Joined: Thu Jun 10, 2004 4:19 am
- x 26
Re: Adding Wind to Grass
Code: Select all
Ogre::DescriptorSetTexture descSet;
descSet.mTextures.push_back(mNoiseTexture);
descSet.mShaderTypeTexCount[Ogre::VertexShader] = 1u;
descSet.mShaderTypeTexCount[Ogre::PixelShader] = 0u;
Ogre::HlmsManager* hlmsManager = Ogre::Root::getSingleton().getHlmsManager();
m_descriptorSet = hlmsManager->getDescriptorSetTexture(descSet);
Ogre::DescriptorSetSampler baseSet;
baseSet.mSamplers.push_back(m_samplerBlock);
baseSet.mShaderTypeSamplerCount[Ogre::VertexShader] = baseSet.mSamplers.size();
m_descriptorSetSampler = mHlmsManager->getDescriptorSetSampler(baseSet);
*commandBuffer->addCommand<Ogre::CbSamplers>() =
Ogre::CbSamplers(14, m_descriptorSetSampler);
*commandBuffer->addCommand<Ogre::CbTextures>() =
Ogre::CbTextures(14, std::numeric_limits<Ogre::uint16>::max(),
m_descriptorSet);
-
- Gnoll
- Posts: 660
- Joined: Mon Aug 06, 2007 12:53 pm
- Location: Saarland, Germany
- x 64
Re: Adding Wind to Grass
A wiki page would be great!
I would also like to use this feature, but have no idea how to get the code fragments working in a whole grass wind scenario.
Best Regards
Lax
http://www.lukas-kalinowski.com/Homepage/?page_id=1631
Please support Second Earth Technic Base built of Lego bricks for Lego ideas: https://ideas.lego.com/projects/81b9bd1 ... b97b79be62
-
- Goblin
- Posts: 272
- Joined: Thu Jun 10, 2004 4:19 am
- x 26
Re: Adding Wind to Grass
https://spotcpp.com/creating-a-custom-h ... d-and-fog/
*updated to remove windFactor texture
-
- Gnoll
- Posts: 660
- Joined: Mon Aug 06, 2007 12:53 pm
- Location: Saarland, Germany
- x 64
Re: Adding Wind to Grass
http://www.lukas-kalinowski.com/Homepage/?page_id=1631
Please support Second Earth Technic Base built of Lego bricks for Lego ideas: https://ideas.lego.com/projects/81b9bd1 ... b97b79be62
-
- Gnoll
- Posts: 660
- Joined: Mon Aug 06, 2007 12:53 pm
- Location: Saarland, Germany
- x 64
Re: Adding Wind to Grass
just a small question: Whats this for Grass1.mesh file? I cannot load that mesh properly. The used mesh serialized is:
Code: Select all
MeshSerializer_v2.1 R2
Best Regards
Lax
http://www.lukas-kalinowski.com/Homepage/?page_id=1631
Please support Second Earth Technic Base built of Lego bricks for Lego ideas: https://ideas.lego.com/projects/81b9bd1 ... b97b79be62
-
- Goblin
- Posts: 272
- Joined: Thu Jun 10, 2004 4:19 am
- x 26
Re: Adding Wind to Grass
OgreMeshTool Cerberus (2.2.3)
You cant load it? in Ogre-next?
-
- Goblin
- Posts: 272
- Joined: Thu Jun 10, 2004 4:19 am
- x 26
Re: Adding Wind to Grass
-
- Gnoll
- Posts: 660
- Joined: Mon Aug 06, 2007 12:53 pm
- Location: Saarland, Germany
- x 64
Re: Adding Wind to Grass
Now I must find out, why the textures are not loaded for the grass. I'm getting no warning, but the grass is white and it is not deforming (no wind).
I found out, that if I move the grass via translation gizmo, it starts deforming. That is strange...
What also does not work is fog...
Do you have fog working?
Best Regards
Lax
http://www.lukas-kalinowski.com/Homepage/?page_id=1631
Please support Second Earth Technic Base built of Lego bricks for Lego ideas: https://ideas.lego.com/projects/81b9bd1 ... b97b79be62
-
- Goblin
- Posts: 272
- Joined: Thu Jun 10, 2004 4:19 am
- x 26
Re: Adding Wind to Grass
Code: Select all
Ogre::Item* item = graphics.getSceneManager()->createItem("Grass1.mesh", Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME, Ogre::SCENE_STATIC);
Ogre::SceneNode* sn = graphics.getSceneManager()->getRootSceneNode()->createChildSceneNode(Ogre::SCENE_STATIC, position, orientation);
sn->scale(Ogre::Vector3(0.5, 0.5, 0.5)*sY);
sn->attachObject(item);
item->setRenderQueueGroup(254);
did you put the shader files in hlms/wind/any? Is ogre finding this path when you load the HlmsWind ?
are you using direct x? the shaders are in hlsl.
You also have to call scenemanager->setFog
Code: Select all
sceneManager->setFog(Ogre::FOG_LINEAR, Ogre::ColourValue(1, 0, 1),NULL,10 , 300.0f);
-
- OGRE Expert User
- Posts: 1148
- Joined: Sat Jul 06, 2013 10:59 pm
- Location: Chile
- x 169
Re: Adding Wind to Grass
that's a symptom of a bad passBuf alignment, make sure *passBufferPtr++ data fits perfectly with what you have in the shaders and of what you've added to custom_passBuffer. You can easily spot misalignment with renderdoc, set some very recognizable values to *passBufferPtr++ like 1,2,3,69,420... and in renderdoc see if it fits what you expect on your shader.. for example you might set the fogParams.x as 69, but you get the 69 value on the .y
this will also explain why you get no texture... you probably are getting texture but its being overwriten by some random color because maybe the fog intensity is 1 (because of a misalignment)
-
- Goblin
- Posts: 272
- Joined: Thu Jun 10, 2004 4:19 am
- x 26
Re: Adding Wind to Grass
Why would it be misaligned though?xrgo wrote: ↑Sat Jul 11, 2020 11:05 pmthat's a symptom of a bad passBuf alignment, make sure *passBufferPtr++ data fits perfectly with what you have in the shaders and of what you've added to custom_passBuffer. You can easily spot misalignment with renderdoc, set some very recognizable values to *passBufferPtr++ like 1,2,3,69,420... and in renderdoc see if it fits what you expect on your shader.. for example you might set the fogParams.x as 69, but you get the 69 value on the .y
this will also explain why you get no texture... you probably are getting texture but its being overwriten by some random color because maybe the fog intensity is 1 (because of a misalignment)
-
- OGRE Expert User
- Posts: 1148
- Joined: Sat Jul 06, 2013 10:59 pm
- Location: Chile
- x 169
Re: Adding Wind to Grass
I mean something like this:
Code: Select all
*passBufferPtr++ = fogStart
*passBufferPtr++ = fogEnd
*passBufferPtr++ = fogColor.r
*passBufferPtr++ = fogColor.g
*passBufferPtr++ = fogColor.b
*passBufferPtr++ = globalTimer
Code: Select all
@piece( custom_passBuffer )
float fogStart
float fogEnd
float globalTimer <<< error!! this should be after fogcolor
float3 fogColor
you can check the values on renderdoc as I mentioned
Edit: also (if everything looks aligned) I think that this buffer likes float4s (am I right dark_sylinc?), try adding two paddings so you have float4, float4, and float,float,float,float (its like a float4)
Code: Select all
@piece( custom_passBuffer )
//Fog
float4 fogParams;
float4 fogColor;
float windFactor;
float globalTime;
float padding0;
float padding1;
@end
and assign any value, since you'll not be using them