#include "Ogre.h" class Grass { protected: StaticGeometry* mStaticGeom; Real mGrassHeight; Real mGrassWidth; String mGrassMeshName; String mGrassMaterial; Real mOffsetParam; SceneManager *mSceneMgr; Real mHeightPosition; Real mGrassFrequency; Real mGrassInterFrequency; Vector3 mGrassScaleRandomRangeMin; Vector3 mGrassScaleRandomRangeMax; Real mGrassLandscapeSizeX; Real mGrassLandscapeSizeZ; bool mShadowCaster; bool mGrassShadowReceiver; public: Grass() { mOffsetParam = 999; mGrassMeshName = String("grassblades"); mGrassMaterial = String("Examples/GrassBlades"); mShadowCaster = false; } void setGrassCastShadows(bool shadowCaster) { if (shadowCaster) { mStaticGeom->setCastShadows(true); mShadowCaster = true; } else { mStaticGeom->setCastShadows(false); mShadowCaster = false; } } void setGrassLandscapeSizeX(Real landscapeSizeX) { mGrassLandscapeSizeX = landscapeSizeX; } void setGrassLandscapeSizeZ(Real landscapeSizeZ) { mGrassLandscapeSizeZ = landscapeSizeZ; } Real getGrassLandscapeSizeX() { return mGrassLandscapeSizeX; } Real getGrassLandscapeSizeZ() { return mGrassLandscapeSizeZ; } void setGrassScaleRandomRangeMin(Vector3 scaleRRmin) { mGrassScaleRandomRangeMin = scaleRRmin; } Vector3 getGrassScaleRandomRangeMin() { return mGrassScaleRandomRangeMin; } void setGrassScaleRandomRangeMax(Vector3 scaleRRmax) { mGrassScaleRandomRangeMax = scaleRRmax; } Vector3 getGrassScaleRandomRangeMax() { return mGrassScaleRandomRangeMax; } void setGrassInterFrequency(Real interFrequency) { mGrassInterFrequency = interFrequency; } Real getGrassInterFrequency() { return mGrassInterFrequency; } void setGrassFrequency(Real frequency) { mGrassFrequency = frequency; } Real getGrassFrequency() { return mGrassFrequency; } void setGrassHeightPosition(Real heightPosition) { mHeightPosition = heightPosition; } Real getGrassHeightPosition() { return mHeightPosition; } void setSceneManager(SceneManager* sceneMgr) { mSceneMgr = sceneMgr; } Real getGrassHeight() { return mGrassHeight; } Real getGrassWidth() { return mGrassWidth; } String getGrassMeshName() { return mGrassMeshName; } String getGrassMaterial() { return mGrassMaterial; } StaticGeometry* getStaticGeometry() { return mStaticGeom; } void setGrassHeight(Real height) { mGrassHeight = height; } void setGrassWidth(Real width) { mGrassWidth = width; } void setGrassMeshName(String meshName) { mGrassMeshName = meshName; } void setGrassMaterial(String material) { mGrassMaterial = material; } void waveGrass(Real timeElapsed) { static Real xinc = Math::PI * 0.4; static Real zinc = Math::PI * 0.55; static Real xpos = Math::RangeRandom(-Math::PI, Math::PI); static Real zpos = Math::RangeRandom(-Math::PI, Math::PI); xpos += xinc * timeElapsed; zpos += zinc * timeElapsed; // Update vertex program parameters by binding a value to each renderable static Vector4 offset(0,0,0,0); StaticGeometry::RegionIterator rit = mStaticGeom->getRegionIterator(); while (rit.hasMoreElements()) { StaticGeometry::Region* reg = rit.getNext(); // a little randomness xpos += reg->getCentre().x * 0.001; zpos += reg->getCentre().z * 0.001; offset.x = Math::Sin(xpos) * 0.05; offset.z = Math::Sin(zpos) * 0.05; StaticGeometry::Region::LODIterator lodit = reg->getLODIterator(); while (lodit.hasMoreElements()) { StaticGeometry::LODBucket* lod = lodit.getNext(); StaticGeometry::LODBucket::MaterialIterator matit = lod->getMaterialIterator(); while (matit.hasMoreElements()) { StaticGeometry::MaterialBucket* mat = matit.getNext(); StaticGeometry::MaterialBucket::GeometryIterator geomit = mat->getGeometryIterator(); while (geomit.hasMoreElements()) { StaticGeometry::GeometryBucket* geom = geomit.getNext(); geom->setCustomParameter(mOffsetParam, offset); } } } } } void createGrassMesh() { // Each grass section is 3 planes at 60 degrees to each other // Normals point straight up to simulate correct lighting MeshPtr msh = MeshManager::getSingleton().createManual(mGrassMeshName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); SubMesh* sm = msh->createSubMesh(); sm->useSharedVertices = false; sm->vertexData = new VertexData(); sm->vertexData->vertexStart = 0; sm->vertexData->vertexCount = 12; VertexDeclaration* dcl = sm->vertexData->vertexDeclaration; size_t offset = 0; dcl->addElement(0, offset, VET_FLOAT3, VES_POSITION); offset += VertexElement::getTypeSize(VET_FLOAT3); dcl->addElement(0, offset, VET_FLOAT3, VES_NORMAL); offset += VertexElement::getTypeSize(VET_FLOAT3); dcl->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES); offset += VertexElement::getTypeSize(VET_FLOAT2); HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton() .createVertexBuffer( offset, 12, HardwareBuffer::HBU_STATIC_WRITE_ONLY); float* pReal = static_cast(vbuf->lock(HardwareBuffer::HBL_DISCARD)); Vector3 baseVec(mGrassWidth/2, 0, 0); Vector3 vec = baseVec; Quaternion rot; rot.FromAngleAxis(Degree(60), Vector3::UNIT_Y); int i; for (i = 0; i < 3; ++i) { // position *pReal++ = -vec.x; *pReal++ = mGrassHeight; *pReal++ = -vec.z; // normal *pReal++ = 0; *pReal++ = 1; *pReal++ = 0; // uv *pReal++ = 0; *pReal++ = 0; // position *pReal++ = vec.x; *pReal++ = mGrassHeight; *pReal++ = vec.z; // normal *pReal++ = 0; *pReal++ = 1; *pReal++ = 0; // uv *pReal++ = 1; *pReal++ = 0; // position *pReal++ = -vec.x; *pReal++ = 0; *pReal++ = -vec.z; // normal *pReal++ = 0; *pReal++ = 1; *pReal++ = 0; // uv *pReal++ = 0; *pReal++ = 1; // position *pReal++ = vec.x; *pReal++ = 0; *pReal++ = vec.z; // normal *pReal++ = 0; *pReal++ = 1; *pReal++ = 0; // uv *pReal++ = 1; *pReal++ = 1; vec = rot * vec; } vbuf->unlock(); sm->vertexData->vertexBufferBinding->setBinding(0, vbuf); sm->indexData->indexCount = 6*3; sm->indexData->indexBuffer = HardwareBufferManager::getSingleton() .createIndexBuffer(HardwareIndexBuffer::IT_16BIT, 6*3, HardwareBuffer::HBU_STATIC_WRITE_ONLY); uint16* pI = static_cast( sm->indexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD)); for (i = 0; i < 3; ++i) { int off = i*4; *pI++ = 0 + off; *pI++ = 3 + off; *pI++ = 1 + off; *pI++ = 0 + off; *pI++ = 2 + off; *pI++ = 3 + off; } sm->indexData->indexBuffer->unlock(); sm->setMaterialName(mGrassMaterial); MaterialPtr material = MaterialManager::getSingleton().getByName(mGrassMaterial); material->setReceiveShadows(mGrassShadowReceiver); msh->load(); } // This method should be called in the createScene method... void initGrass() { createGrassMesh(); Entity* e = mSceneMgr->createEntity("1", mGrassMeshName); StaticGeometry* s = mSceneMgr->createStaticGeometry("bing"); s->setRegionDimensions(Vector3(1000,1000,1000)); // Set the region origin so the centre is at 0 world s->setOrigin(Vector3(-500, 500, -500)); for (int x = -mGrassLandscapeSizeX; x < mGrassLandscapeSizeX; x += mGrassFrequency) { for (int z = -mGrassLandscapeSizeZ; z < mGrassLandscapeSizeZ; z += mGrassFrequency) { Vector3 pos( x + Math::RangeRandom(-mGrassInterFrequency,mGrassInterFrequency), mHeightPosition, z + Math::RangeRandom(-mGrassInterFrequency,mGrassInterFrequency)); Quaternion orientation; orientation.FromAngleAxis( Degree(Math::RangeRandom(0, 359)), Vector3::UNIT_Y); Vector3 grassScale = Vector3(Math::RangeRandom(mGrassScaleRandomRangeMin[0],mGrassScaleRandomRangeMax[0]), Math::RangeRandom(mGrassScaleRandomRangeMin[1],mGrassScaleRandomRangeMax[1]), Math::RangeRandom(mGrassScaleRandomRangeMin[2],mGrassScaleRandomRangeMax[2])); Vector3 scale(grassScale); s->addEntity(e, pos, orientation, scale); } } s->build(); mStaticGeom = s; } void setGrassShadowReceiver(bool value) { mGrassShadowReceiver = value; } };