Wind effect on trees

sarmadm

23-12-2008 10:25:41

Is there any way to add wind on trees in pagedgeometry

sarmadm

23-12-2008 13:47:21

Ok i was able to do it myself after some searching on this forum. if someone needs help, please don't hesitate to ask

Fish

23-12-2008 17:13:03

Ok i was able to do it myself after some searching on this forum. if someone needs help, please don't hesitate to ask

Please share. :)

JohnJ

30-12-2008 01:23:21

Ok i was able to do it myself after some searching on this forum. if someone needs help, please don't hesitate to ask

Please share. :)

PagedGeometry has a wind technique implementation in the "WindBatchPage" class. Check WindBatchPage.h for info on how to use it. Basically it's a geometry page LOD similar to BatchPage, except WindBatchPage animates trees in a certain way.

mickey

30-12-2008 10:14:45

Hi John

I don't see a WindBatchPage class?

sarmadm

30-12-2008 12:07:15

Sorry guys for the late reply. here is the winbatchpage.h

//WindBatchPage.h
//WindBatchPage is child of BatchPage to include a wind effect.
//-------------------------------------------------------------------------------------

#ifndef __WindBatchPage_H__
#define __WindBatchPage_H__

#include "BatchPage.h"
#include "WindBatchedGeometry.h"

#include <OgrePrerequisites.h>
#include <OgreStringConverter.h>

namespace Forests
{

class PagedGeometry;
/**
+\brief The WindBatchPage class renders entities as StaticGeometry.
+
+This is one of the geometry page types included in the StaticGeometry engine. These
+page types should be added to a PagedGeometry object with PagedGeometry::addDetailLevel()
+so the PagedGeometry will know how you want your geometry displayed.
+
+To use this page type, use:
+\code
+PagedGeometry::addDetailLevel<WindBatchPage>(farRange);
+\endcode
+
+This page type uses batched geometry (Ogre::StaticGeometry) to represent the entities.
+Batched geometry is generally much faster than plain entities, since video card state
+changes and transform calculations can be minimized. Batched geometry can be anywhere
+from 2 to 20 times faster than plain entities.
+*/
class WindBatchPage: public BatchPage
{
public:
void init(PagedGeometry *geom);
// void build();

protected:

public :
void _updateShaders();
std::string entityName;
const PagedGeometry * mGeom;
};

}

#endif



//WindBatchPage.cpp

/*-------------------------------------------------------------------------------------
+Copyright (c) 2006 John Judnich
+
+This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
+ 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+-------------------------------------------------------------------------------------*/

//WindBatchPage.cpp
//WindBatchPage is an extension to PagedGeometry which displays entities as static geometry but that is affected by wind.
//-------------------------------------------------------------------------------------

#include "WindBatchPage.h"
#include "WindBatchedGeometry.h"

#include <OgreRoot.h>
#include <OgreCamera.h>
#include <OgreVector3.h>
#include <OgreQuaternion.h>
#include <OgreEntity.h>
#include <OgreRenderSystem.h>
#include <OgreRenderSystemCapabilities.h>
#include <OgreHighLevelGpuProgram.h>
#include <OgreHighLevelGpuProgramManager.h>

// to dump the shader source in a file
#include <fstream>
using namespace Ogre;

namespace Forests
{

//-------------------------------------------------------------------------------------


void WindBatchPage::init(PagedGeometry *geom)
{
mGeom = geom;
sceneMgr = geom->getSceneManager();
batch = new WindBatchedGeometry(sceneMgr, geom->getSceneNode());
dynamic_cast<WindBatchedGeometry*>(batch)->setGeom(geom);
fadeEnabled = false;
const RenderSystemCapabilities *caps = Root::getSingleton().getRenderSystem()->getCapabilities();
if (caps->hasCapability(RSC_VERTEX_PROGRAM))
shadersSupported = true;
else
shadersSupported = false;
++refCount;
}
// void WindBatchPage::build()
// {
// batch->build();
//
// BatchedGeometry::SubBatchIterator it = batch->getSubBatchIterator();
// while (it.hasMoreElements()){
// BatchedGeometry::SubBatch *subBatch = it.getNext();
// MaterialPtr mat = subBatch->getMaterial();
//
// //Disable specular unless a custom shader is being used.
// //This is done because the default shader applied by BatchPage
// //doesn't support specular, and fixed-function needs to look
// //the same as the shader (for computers with no shader support)
// for (int t = 0; t < mat->getNumTechniques(); ++t){
// Technique *tech = mat->getTechnique(t);
// for (int p = 0; p < tech->getNumPasses(); ++p){
// Pass *pass = tech->getPass(p);
// if (pass->getVertexProgramName() == "")
// pass->setSpecular(0, 0, 0, 1);
// }
// }
//
// //Store the original materials
// unfadedMaterials.push_back(subBatch->getMaterial());
// }
//
// _updateShaders();
//
// }
void WindBatchPage::_updateShaders()
{
if (!shadersSupported)
return;
uint32 i = 0;
BatchedGeometry::SubBatchIterator it = batch->getSubBatchIterator();
while (it.hasMoreElements())
{
WindBatchedGeometry::WindSubBatch *subBatch = dynamic_cast<WindBatchedGeometry::WindSubBatch*>(it.getNext());
MaterialPtr mat = unfadedMaterials[i++];
//Check if lighting should be enabled
bool lightingEnabled = false;
for (unsigned short t = 0; t < mat->getNumTechniques(); ++t){
Technique *tech = mat->getTechnique(t);
for (unsigned short p = 0; p < tech->getNumPasses(); ++p)
{
Pass *pass = tech->getPass(p);
if (pass->getLightingEnabled())
{
lightingEnabled = true;
break;
}
}
if (lightingEnabled)
break;
}
//Compile the CG shader script based on various material / fade options
StringUtil::StrStreamType tmpName;
tmpName << "BatchPage_";
if (fadeEnabled)
tmpName << "fade_";
if (lightingEnabled)
tmpName << "lit_";
if (subBatch->vertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL)
tmpName << "clr_";
for (unsigned short i = 0; i < subBatch->vertexData->vertexDeclaration->getElementCount(); ++i)
{
const VertexElement *el = subBatch->vertexData->vertexDeclaration->getElement(i);
if (el->getSemantic() == VES_TEXTURE_COORDINATES)
{
String uvType = "";
switch (el->getType())
{
case VET_FLOAT1: uvType = "1"; break;
case VET_FLOAT2: uvType = "2"; break;
case VET_FLOAT3: uvType = "3"; break;
case VET_FLOAT4: uvType = "4"; break;
}
tmpName << uvType << '_';
}
}
tmpName << "vp";
const String vertexProgName = tmpName.str();
//If the shader hasn't been created yet, create it
if (HighLevelGpuProgramManager::getSingleton().getByName(vertexProgName).isNull())
{
Pass *pass = mat->getTechnique(0)->getPass(0);
String vertexProgSource =
"void main( \n"
" float4 iPosition : POSITION, \n"
" float3 normal : NORMAL, \n"
" out float4 oPosition : POSITION, \n";
if (subBatch->vertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL) vertexProgSource +=
" float4 iColor : COLOR, \n";
int texNum = 0;
unsigned short texCoordCount = 0;
for (unsigned short j = 0; j < subBatch->vertexData->vertexDeclaration->getElementCount(); ++j)
{
const VertexElement *el = subBatch->vertexData->vertexDeclaration->getElement(j);
if (el->getSemantic() == VES_TEXTURE_COORDINATES)
{
++ texCoordCount;
}
}
for (unsigned short i = 0; i < subBatch->vertexData->vertexDeclaration->getElementCount(); ++i)
{
const VertexElement *el = subBatch->vertexData->vertexDeclaration->getElement(i);
if (el->getSemantic() == VES_TEXTURE_COORDINATES)
{
if (el->getIndex() == texCoordCount - 2)
{
vertexProgSource +=
" float4 params : TEXCOORD" + StringConverter::toString(texCoordCount-2) + ", \n";
}
else
{
if (el->getIndex() == texCoordCount - 1)
{
vertexProgSource +=
" float4 originPos : TEXCOORD" + StringConverter::toString(texCoordCount-1) + ", \n";
}
else
{
String uvType = "";
switch (el->getType())
{
case VET_FLOAT1: uvType = "float"; break;
case VET_FLOAT2: uvType = "float2"; break;
case VET_FLOAT3: uvType = "float3"; break;
case VET_FLOAT4: uvType = "float4"; break;
}
vertexProgSource += " " + uvType + " iUV" + StringConverter::toString(texNum) + " : TEXCOORD" + StringConverter::toString(texNum) + ", \n"
" out " + uvType + " oUV" + StringConverter::toString(texNum) + " : TEXCOORD" + StringConverter::toString(texNum) + ", \n";
}
++texNum;
}
}
}
vertexProgSource +=
" out float oFog : FOG, \n"
" out float4 oColor : COLOR, \n";
if (lightingEnabled) vertexProgSource +=
" uniform float4 objSpaceLight, \n"
" uniform float4 lightDiffuse, \n"
" uniform float4 lightAmbient, \n";
if (fadeEnabled) vertexProgSource +=
" uniform float3 camPos, \n";
vertexProgSource +=
" uniform float4x4 worldViewProj,\n"
" uniform float fadeGap, \n"
" uniform float invisibleDist, \n"
" uniform float time) \n "
"{ \n";
if (lightingEnabled)
{
//Perform lighting calculations (no specular)
vertexProgSource +=
" float3 light = normalize(objSpaceLight.xyz - (iPosition.xyz * objSpaceLight.w)); \n"
" float diffuseFactor = max(dot(normal, light), 0); \n";
if (subBatch->vertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL)
vertexProgSource += " oColor = (lightAmbient + diffuseFactor * lightDiffuse) * iColor; \n";
else
vertexProgSource += " oColor = (lightAmbient + diffuseFactor * lightDiffuse); \n";
}
else
{
if (subBatch->vertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE) != NULL)
vertexProgSource += " oColor = iColor; \n";
else
vertexProgSource += " oColor = float4(1, 1, 1, 1); \n";
}
if (fadeEnabled)
vertexProgSource +=
" float dist = distance(camPos.xz, iPosition.xz); \n"
" oColor.a *= (invisibleDist - dist) / fadeGap; \n";
for (unsigned short i = 0; i < texCoordCount - 2; ++i)
{
vertexProgSource +=
" oUV" + StringConverter::toString(i) + " = iUV" + StringConverter::toString(i) + "; \n";
}
vertexProgSource +=
" float radiusCoeff = params.x; \n"
" float heightCoeff = params.y; \n"
" float factorX = params.z; \n"
" float factorY = params.w; \n"
" float4 tmpPos = iPosition; \n"
/*
2 different methods are used to for the sin calculation :
- the first one gives a better effect but at the cost of a few fps because of the 2 sines
- the second one uses less ressources but is a bit less realistic
a sin approximation could be use to optimize performances
*/
#if 1
" tmpPos.y += sin(time + originPos.z + tmpPos.y + tmpPos.x) * radiusCoeff * radiusCoeff * factorY; \n"
" tmpPos.x += sin(time + originPos.z ) * heightCoeff * heightCoeff * factorX ;\n"
#else
" float sinval = sin(time + originPos.z ); \n"
" tmpPos.y += sinval * radiusCoeff * radiusCoeff * factorY; \n"
" tmpPos.x += sinval * heightCoeff * heightCoeff * factorX ;\n"
#endif
" oPosition = mul(worldViewProj, tmpPos); \n"
" oFog = oPosition.z; \n"
"}";
// test for shader source
//std::ofstream shaderOutput;
//shaderOutput.open((vertexProgName+std::string(".cg")).c_str());
//shaderOutput << vertexProgSource;
//shaderOutput.close();
// end test for shader source
String shaderLanguage;
if (Root::getSingleton().getRenderSystem()->getName() == "Direct3D9 Rendering Subsystem")
shaderLanguage = "hlsl";
else
shaderLanguage = "cg";
HighLevelGpuProgramPtr vertexShader = HighLevelGpuProgramManager::getSingleton().createProgram(
vertexProgName,
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
shaderLanguage, GPT_VERTEX_PROGRAM);
vertexShader->setSource(vertexProgSource);
if (shaderLanguage == "hlsl")
vertexShader->setParameter("target", "vs_1_1");
else
vertexShader->setParameter("profiles", "vs_1_1 arbvp1");
vertexShader->setParameter("entry_point", "main");
vertexShader->load();
}

//Now that the shader is ready to be applied, apply it
StringUtil::StrStreamType materialSignature;
materialSignature << "BatchMat|";
materialSignature << mat->getName() << "|";
if (fadeEnabled)
{
materialSignature << visibleDist << "|";
materialSignature << invisibleDist << "|";
}
//Search for the desired material
MaterialPtr generatedMaterial = MaterialManager::getSingleton().getByName(materialSignature.str());
if (generatedMaterial.isNull())
{
generatedMaterial = mat->clone(materialSignature.str());
//And apply the fade shader
for (unsigned short t = 0; t < generatedMaterial->getNumTechniques(); ++t)
{
Technique *tech = generatedMaterial->getTechnique(t);
for (unsigned short p = 0; p < tech->getNumPasses(); ++p)
{
Pass *pass = tech->getPass(p);
//Setup vertex program
if (pass->getVertexProgramName() == "")
pass->setVertexProgram(vertexProgName);

try{
GpuProgramParametersSharedPtr params = pass->getVertexProgramParameters();

if (lightingEnabled) {
params->setNamedAutoConstant("objSpaceLight", GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE);
params->setNamedAutoConstant("lightDiffuse", GpuProgramParameters::ACT_DERIVED_LIGHT_DIFFUSE_COLOUR);
params->setNamedAutoConstant("lightAmbient", GpuProgramParameters::ACT_DERIVED_AMBIENT_LIGHT_COLOUR);
//params->setNamedAutoConstant("matAmbient", GpuProgramParameters::ACT_SURFACE_AMBIENT_COLOUR);
}

params->setNamedConstantFromTime("time", 1);

params->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX);

if (fadeEnabled){
params->setNamedAutoConstant("camPos", GpuProgramParameters::ACT_CAMERA_POSITION_OBJECT_SPACE);

//Set fade ranges
params->setNamedAutoConstant("invisibleDist", GpuProgramParameters::ACT_CUSTOM);
params->setNamedConstant("invisibleDist", invisibleDist);

params->setNamedAutoConstant("fadeGap", GpuProgramParameters::ACT_CUSTOM);
params->setNamedConstant("fadeGap", invisibleDist - visibleDist);

if (pass->getAlphaRejectFunction() == CMPF_ALWAYS_PASS)
pass->setSceneBlending(SBT_TRANSPARENT_ALPHA);
}
}
catch (Ogre::Exception e)
{
// test for shader source
std::ofstream shaderOutput;
shaderOutput.open("exception.log");
shaderOutput << e.getDescription();
shaderOutput.close();
}
catch (...) {
OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Error configuring batched geometry transitions. If you're using materials with custom vertex shaders, they will need to implement fade transitions to be compatible with BatchPage.", "BatchPage::_updateShaders()");
}
}
}

}

//Apply the material
subBatch->setMaterial(generatedMaterial);
}

}
}

//WindBacthedGeometry.h

#ifndef __WindBatchedGeometry_H__
#define __WindBatchedGeometry_H__

#include "BatchedGeometry.h"

#include <OgrePrerequisites.h>
#include <OgreMovableObject.h>
#include <OgreSceneNode.h>
#include <OgreMaterialManager.h>

namespace Forests
{
class PagedGeometry;

class WindBatchedGeometry: public BatchedGeometry
{
public:
WindBatchedGeometry(Ogre::SceneManager *mgr, Ogre::SceneNode *rootSceneNode);
void addEntity(Ogre::Entity *ent, const Ogre::Vector3 &position, const Ogre::Quaternion &orientation = Ogre::Quaternion::IDENTITY, const Ogre::Vector3 &scale = Ogre::Vector3::UNIT_SCALE, const Ogre::ColourValue &color = Ogre::ColourValue::White);
inline void setGeom(const PagedGeometry * geom) { mGeom = geom; }
class WindSubBatch: public SubBatch
{
public:
WindSubBatch(WindBatchedGeometry *parent, Ogre::SubEntity *ent);
void build();
};
public:
const PagedGeometry * mGeom;
};
}

#endif

//WindBatchedGeometry.cpp

//-------------------------------------------------------------------------------------

#include "WindBatchedGeometry.h"
#include "PagedGeometry.h"

#include <OgreRoot.h>
#include <OgreRenderSystem.h>
#include <OgreCamera.h>
#include <OgreVector3.h>
#include <OgreQuaternion.h>
#include <OgreSceneNode.h>
#include <OgreString.h>
#include <OgreStringConverter.h>
#include <OgreEntity.h>
#include <OgreSubMesh.h>
#include <OgreSubEntity.h>
#include <OgreMesh.h>
#include <OgreMeshManager.h>
#include <OgreHardwareBufferManager.h>
#include <OgreHardwareBuffer.h>
#include <OgreMaterialManager.h>
#include <OgreMaterial.h>
using namespace Ogre;

namespace Forests {

//-------------------------------------------------------------------------------------

WindBatchedGeometry::WindBatchedGeometry(SceneManager *mgr, SceneNode *rootSceneNode):BatchedGeometry(mgr, rootSceneNode)
{}

void WindBatchedGeometry::addEntity(Entity *ent, const Vector3 &position, const Quaternion &orientation, const Vector3 &scale, const Ogre::ColourValue &color)
{
MeshPtr mesh = ent->getMesh();
if (mesh->sharedVertexData != NULL)
OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Shared vertex data not allowed", "BatchedGeometry::addEntity()");

//For each subentity
for (uint32 i = 0; i < ent->getNumSubEntities(); ++i){
//Get the subentity
SubEntity *subEntity = ent->getSubEntity(i);
SubMesh *subMesh = subEntity->getSubMesh();

//Generate a format string that uniquely identifies this material & vertex/index format
if (subMesh->vertexData == NULL)
OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "SubMesh vertex data not found!", "BatchedGeometry::addEntity()");

String formatStr = getFormatString(subEntity);

//If a batch using an identical format exists...
WindSubBatch *batch;
SubBatchMap::iterator batchIter = subBatchMap.find(formatStr);
if (batchIter != subBatchMap.end())
{
//Use the batch
batch = dynamic_cast<WindBatchedGeometry::WindSubBatch*>(batchIter->second);
} else {
//Otherwise create a new batch
batch = new WindSubBatch(this, subEntity);
subBatchMap.insert(std::pair<String, WindSubBatch*>(formatStr, batch));
}

//Now add the submesh to the compatible batch
batch->addSubEntity(subEntity, position, orientation, scale, color,ent);
}

//Update bounding box
Matrix4 mat(orientation);
mat.setScale(scale);
AxisAlignedBox entBounds = ent->getBoundingBox();
entBounds.transform(mat);

if (boundsUndefined)
{
bounds.setMinimum(entBounds.getMinimum() + position);
bounds.setMaximum(entBounds.getMaximum() + position);
boundsUndefined = false;
}
else
{
Vector3 min = bounds.getMinimum();
Vector3 max = bounds.getMaximum();
min.makeFloor(entBounds.getMinimum() + position);
max.makeCeil(entBounds.getMaximum() + position);
bounds.setMinimum(min);
bounds.setMaximum(max);
}

}

WindBatchedGeometry::WindSubBatch::WindSubBatch(WindBatchedGeometry *parent, SubEntity *ent):BatchedGeometry::SubBatch(parent, ent)
{}

void WindBatchedGeometry::WindSubBatch::build()
{
assert(!built);

//Misc. setup
Vector3 batchCenter = dynamic_cast<WindBatchedGeometry*>(parent)->center;

HardwareIndexBuffer::IndexType srcIndexType = meshType->indexData->indexBuffer->getType();
HardwareIndexBuffer::IndexType destIndexType;
if (vertexData->vertexCount > 0xFFFF || srcIndexType == HardwareIndexBuffer::IT_32BIT)
destIndexType = HardwareIndexBuffer::IT_32BIT;
else
destIndexType = HardwareIndexBuffer::IT_16BIT;

//Allocate the index buffer
indexData->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(destIndexType, indexData->indexCount + 1, HardwareBuffer::HBU_STATIC_WRITE_ONLY);

//Lock the index buffer
uint32 *indexBuffer32;
uint16 *indexBuffer16;
if (destIndexType == HardwareIndexBuffer::IT_32BIT)
indexBuffer32 = static_cast<uint32*>(indexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
else
indexBuffer16 = static_cast<uint16*>(indexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD));

//Allocate & lock the vertex buffers
std::vector<uchar*> vertexBuffers;
std::vector<VertexDeclaration::VertexElementList> vertexBufferElements;

VertexBufferBinding *vertBinding = vertexData->vertexBufferBinding;
VertexDeclaration *vertDecl = vertexData->vertexDeclaration;

unsigned short texCoordCount = 0;
for (unsigned short j = 0; j < vertexData->vertexDeclaration->getElementCount(); ++j)
{
const VertexElement *el = vertexData->vertexDeclaration->getElement(j);
if (el->getSemantic() == VES_TEXTURE_COORDINATES)
{
++ texCoordCount;
}
}
Ogre::ushort k = (Ogre::ushort)vertBinding->getBufferCount();

vertDecl->addElement(k-1, vertDecl->getVertexSize(0), VET_FLOAT4 , VES_TEXTURE_COORDINATES, texCoordCount);
vertDecl->addElement(k-1, vertDecl->getVertexSize(0), VET_FLOAT4 , VES_TEXTURE_COORDINATES, texCoordCount+1);

for (Ogre::ushort i = 0; i < vertBinding->getBufferCount(); ++i)
{
HardwareVertexBufferSharedPtr buffer = HardwareBufferManager::getSingleton()
.createVertexBuffer(vertDecl->getVertexSize(i), vertexData->vertexCount + 1, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
vertBinding->setBinding(i, buffer);

vertexBuffers.push_back(static_cast<uchar*>(buffer->lock(HardwareBuffer::HBL_DISCARD)));
vertexBufferElements.push_back(vertDecl->findElementsBySource(i));
}

//If no vertex colors are used, make sure the final batch includes them (so the shade values work)
if (requireVertexColors) {
if (!vertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE)) {
Ogre::ushort i = (Ogre::ushort)vertBinding->getBufferCount();

vertDecl->addElement(i, 0, VET_COLOUR, VES_DIFFUSE);

HardwareVertexBufferSharedPtr buffer = HardwareBufferManager::getSingleton()
.createVertexBuffer(vertDecl->getVertexSize(i), vertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
vertBinding->setBinding(i, buffer);

vertexBuffers.push_back(static_cast<uchar*>(buffer->lock(HardwareBuffer::HBL_DISCARD)));
vertexBufferElements.push_back(vertDecl->findElementsBySource(i));

}

Pass *p = material->getTechnique(0)->getPass(0);

p->setVertexColourTracking(TVC_AMBIENT);
}

std::string entityName;
Ogre::AxisAlignedBox entityBounds;

//For each queued mesh...
MeshQueueIterator it;
size_t indexOffset = 0;
for (it = meshQueue.begin(); it != meshQueue.end(); ++it) {
const QueuedMesh queuedMesh = (*it);
//const QueuedMesh queuedMesh = dynamic_cast<WindBatchedGeometry::WindSubBatch::QueuedMesh>((*it));
const IndexData *sourceIndexData = queuedMesh.mesh->indexData;
const VertexData *sourceVertexData = queuedMesh.mesh->vertexData;

Entity * ent = static_cast<Ogre::Entity*>(queuedMesh.userData);
entityName = ent->getName();
entityBounds = ent->getBoundingBox();

// vector to stock the original y value of every vertex because batchCenter doesn't take consider the height of the ground
Vector3 vertexPos;
float maxHeight = entityBounds.getMaximum().y;
float factorX = dynamic_cast<WindBatchedGeometry*>(parent)->mGeom->getCustomParam(entityName, "factorX", 0); // amplitude in X
float factorY = dynamic_cast<WindBatchedGeometry*>(parent)->mGeom->getCustomParam(entityName, "factorY", 0); // amplitude in Y

//Copy mesh vertex data into the vertex buffer
VertexBufferBinding *sourceBinds = sourceVertexData->vertexBufferBinding;
VertexBufferBinding *destBinds = vertexData->vertexBufferBinding;

for (Ogre::ushort i = 0; i < destBinds->getBufferCount(); ++i)
{
if (i < sourceBinds->getBufferCount()){
//Lock the input buffer
HardwareVertexBufferSharedPtr sourceBuffer = sourceBinds->getBuffer(i);
uchar *sourceBase = static_cast<uchar*>(sourceBuffer->lock(HardwareBuffer::HBL_READ_ONLY));

//Get the locked output buffer
uchar *destBase = vertexBuffers[i];

//Copy vertices
float *sourcePtr, *destPtr;
for (size_t v = 0; v < sourceVertexData->vertexCount; ++v)
{
// Iterate over vertex elements
VertexDeclaration::VertexElementList &elems = vertexBufferElements[i];
VertexDeclaration::VertexElementList::iterator ei;
for (ei = elems.begin(); ei != elems.end(); ++ei)
{
VertexElement &elem = *ei;
elem.baseVertexPointerToElement(sourceBase, &sourcePtr);
elem.baseVertexPointerToElement(destBase, &destPtr);

Vector3 tmp;
uint32 tmpColor;
uint8 tmpR, tmpG, tmpB, tmpA;

switch (elem.getSemantic())
{
case VES_POSITION:
tmp.x = *sourcePtr++;
tmp.y = *sourcePtr++;
tmp.z = *sourcePtr++;

//Transform
tmp = (queuedMesh.orientation * (tmp * queuedMesh.scale)) + queuedMesh.position;

vertexPos = tmp - queuedMesh.position;

tmp -= batchCenter; //Adjust for batch center

*destPtr++ = tmp.x;
*destPtr++ = tmp.y;
*destPtr++ = tmp.z;
break;

case VES_NORMAL:
tmp.x = *sourcePtr++;
tmp.y = *sourcePtr++;
tmp.z = *sourcePtr++;

//Rotate
tmp = queuedMesh.orientation * tmp;

*destPtr++ = tmp.x;
*destPtr++ = tmp.y;
*destPtr++ = tmp.z;
break;

case VES_DIFFUSE:
tmpColor = *((uint32*)sourcePtr++);
tmpR = ((tmpColor) & 0xFF) * queuedMesh.color.r;
tmpG = ((tmpColor >> 8) & 0xFF) * queuedMesh.color.g;
tmpB = ((tmpColor >> 16) & 0xFF) * queuedMesh.color.b;
tmpA = (tmpColor >> 24) & 0xFF;

tmpColor = tmpR | (tmpG << 8) | (tmpB << 16) | (tmpA << 24);
*((uint32*)destPtr++) = tmpColor;
break;

case VES_TANGENT:
case VES_BINORMAL:
tmp.x = *sourcePtr++;
tmp.y = *sourcePtr++;
tmp.z = *sourcePtr++;

//Rotate
tmp = queuedMesh.orientation * tmp;

*destPtr++ = tmp.x;
*destPtr++ = tmp.y;
*destPtr++ = tmp.z;
break;

case VES_TEXTURE_COORDINATES:
if (elem.getIndex() == texCoordCount)
{
// parameters to be passed to the shader
*destPtr++ = vertexPos.x; // radius coefficient
*destPtr++ = vertexPos.y / maxHeight; // height coefficient
*destPtr++ = factorX;
*destPtr++ = factorY;
}
else
{
if (elem.getIndex() == texCoordCount + 1 )
{
// original position for each vertex
*destPtr++ = queuedMesh.position.x;
*destPtr++ = queuedMesh.position.y;
*destPtr++ = queuedMesh.position.z;
*destPtr++ = 0;
}
else
{
memcpy(destPtr, sourcePtr, VertexElement::getTypeSize(elem.getType()));
}
}
break;
default:
//Raw copy
memcpy(destPtr, sourcePtr, VertexElement::getTypeSize(elem.getType()));
break;
};
}

// Increment both pointers
destBase += vertDecl->getVertexSize(i);
sourceBase += sourceBuffer->getVertexSize();
}

//Unlock the input buffer
vertexBuffers[i] = destBase;
sourceBuffer->unlock();
} else {
assert(requireVertexColors);

//Get the locked output buffer
uint32 *startPtr = (uint32*)vertexBuffers[vertBinding->getBufferCount()-1];
uint32 *endPtr = startPtr + sourceVertexData->vertexCount;

//Generate color
uint8 tmpR = queuedMesh.color.r * 255;
uint8 tmpG = queuedMesh.color.g * 255;
uint8 tmpB = queuedMesh.color.b * 255;
uint32 tmpColor = tmpR | (tmpG << 8) | (tmpB << 16) | (0xFF << 24);

//Copy colors
while (startPtr < endPtr) {
*startPtr++ = tmpColor;
}

vertexBuffers[vertBinding->getBufferCount()-1] += (sizeof(uint32) * sourceVertexData->vertexCount);
}
}


//Copy mesh index data into the index buffer
if (srcIndexType == HardwareIndexBuffer::IT_32BIT) {
//Lock the input buffer
uint32 *source = static_cast<uint32*>(sourceIndexData->indexBuffer->lock(
sourceIndexData->indexStart, sourceIndexData->indexCount, HardwareBuffer::HBL_READ_ONLY
));
uint32 *sourceEnd = source + sourceIndexData->indexCount;

//And copy it to the output buffer
while (source != sourceEnd) {
*indexBuffer32++ = static_cast<uint32>(*source++ + indexOffset);
}

//Unlock the input buffer
sourceIndexData->indexBuffer->unlock();

//Increment the index offset
indexOffset += sourceVertexData->vertexCount;
} else {
if (destIndexType == HardwareIndexBuffer::IT_32BIT){
//-- Convert 16 bit to 32 bit indices --
//Lock the input buffer
uint16 *source = static_cast<uint16*>(sourceIndexData->indexBuffer->lock(
sourceIndexData->indexStart, sourceIndexData->indexCount, HardwareBuffer::HBL_READ_ONLY
));
uint16 *sourceEnd = source + sourceIndexData->indexCount;

//And copy it to the output buffer
while (source != sourceEnd) {
uint32 indx = *source++;
*indexBuffer32++ = (indx + indexOffset);
}

//Unlock the input buffer
sourceIndexData->indexBuffer->unlock();

//Increment the index offset
indexOffset += sourceVertexData->vertexCount;
} else {
//Lock the input buffer
uint16 *source = static_cast<uint16*>(sourceIndexData->indexBuffer->lock(
sourceIndexData->indexStart, sourceIndexData->indexCount, HardwareBuffer::HBL_READ_ONLY
));
uint16 *sourceEnd = source + sourceIndexData->indexCount;

//And copy it to the output buffer
while (source != sourceEnd) {
*indexBuffer16++ = static_cast<uint16>(*source++ + indexOffset);
}

//Unlock the input buffer
sourceIndexData->indexBuffer->unlock();

//Increment the index offset
indexOffset += sourceVertexData->vertexCount;
}
}
}

//Unlock buffers
indexData->indexBuffer->unlock();
for (Ogre::ushort i = 0; i < vertBinding->getBufferCount(); ++i)
vertBinding->getBuffer(i)->unlock();

//Clear mesh queue
meshQueue.clear();

built = true;
}

}

sunrisefe

03-03-2009 08:12:13

Is there any document for this winbatchpage.h?
what 's the principle of making tree's movement?