Vegetation SceneNode
Vegetation SceneNode
Below is a vegetation scenenode along with a small demo program showing it's use.
the model files that I use are from Arteria3D and are not public domain so I cannot share them.
theory :
terrain created.
vegetation layer created.
add mesh templates to vegetation layer
process vegetation layer (using terrain as base to determine position and height)
1) create array of positions, types, rotations, and scales
2) populate the arrays in the process() function
2a) calls functions for density, rotation, type and scale of the meshes
during scenenode render call
calculate a slightly expanded camera frustum
check position array to determine if mesh should be visible
if so then create mesh of proper type, position, scale, and rotation
sandbox program creates 6 vegetation layers
I use many models for the vegetation, however, any model will do. (i used dwarfs.x as for testing)
thanks to the forum for all of the ideas for making this faster. I used many examples to speed things up.
a small video showing it in action
https://www.youtube.com/watch?v=1gPSPg4OFGw
media files
https://www.dropbox.com/sh/72dj1338mt63 ... gS2Oa?dl=0
the model files that I use are from Arteria3D and are not public domain so I cannot share them.
theory :
terrain created.
vegetation layer created.
add mesh templates to vegetation layer
process vegetation layer (using terrain as base to determine position and height)
1) create array of positions, types, rotations, and scales
2) populate the arrays in the process() function
2a) calls functions for density, rotation, type and scale of the meshes
during scenenode render call
calculate a slightly expanded camera frustum
check position array to determine if mesh should be visible
if so then create mesh of proper type, position, scale, and rotation
sandbox program creates 6 vegetation layers
I use many models for the vegetation, however, any model will do. (i used dwarfs.x as for testing)
thanks to the forum for all of the ideas for making this faster. I used many examples to speed things up.
a small video showing it in action
https://www.youtube.com/watch?v=1gPSPg4OFGw
media files
https://www.dropbox.com/sh/72dj1338mt63 ... gS2Oa?dl=0
Last edited by Seven on Mon Aug 16, 2021 3:42 pm, edited 3 times in total.
Re: Vegetation SceneNode
Code: Select all
#pragma once
#include "Irrlicht.h"
using namespace irr;
using namespace video;
using namespace core;
using namespace gui;
using namespace scene;
using namespace io;
namespace IGE
{
// if color is below this value thn no node is present
#define CUTOFF 50
#define YCUTOFF 0
// simple rendom number generators
extern int getRandomInteger(int min, int max);
extern float getRandomFloat(float min, float max);
// simple structure to hold a template node and the YOffset to apply when positioning the node
struct IGE_MeshTemplate
{
IGE_MeshTemplate(IMeshSceneNode* node, float yoffset) : m_Node(node), m_YOffset(yoffset) {}
IMeshSceneNode* m_Node = nullptr;
float m_YOffset = 0.0f;
};
/*
* the scenenode class
* once the scenenode is instantiated
* add as many templates as desired (these are the different nodes to be used)
*
*
*/
class IGE_SceneNode_Vegetation : public ISceneNode
{
public:
ITerrainSceneNode* m_Terrain = nullptr; // the terrain scenenode we are attached to
IImage* m_LayoutImage = nullptr; // the layout image - used to determine whether a node/object is at any given position
array<IGE_MeshTemplate> m_MeshTemplate; // list of nodes being used
array<ISceneNode*> m_Nodes; // list of visible nodes
array<short int> m_NodeType; // list of node types (index into the MeshTemplates)
array<vector3df> m_NodePos; // list of node positions
array<vector3df> m_NodeScale; // list of node scales
array<vector3df> m_NodeRotation; // list of node rotations
array<bool> m_IsNodePosFree; // list of open and closed slots in the node list
float m_ViewDistance = 1000; // distance from camera at which nodes become visible
f32 m_VisibleOffset = 200.f; // resize the camera frustum by this amount, you can use the maximal radius of your mesh to prevent close plane popping
vector3df m_LayoutRandomness = vector3df(0,0,0); // add some randomness to the layout procedure
int m_HelperForDeleting = false; // variable used during update
bool m_UseLight = false; // simple variable to track light use
bool m_UseFog = false; // simple variable to track fog use
public:
// add a node template
void addMeshTemplate(stringc meshfilename, float YOffset);
// using the terrain as the location base and the layout functions to determine position, rotation and scale of nodes
void processLayout();
// clear all lists
void clear();
// called each tick. determine which nodes should be visible based on the camera position and rotation
void update(vector3df center, ICameraSceneNode* camera);
// use color information to determine the density, style, rotation and scale of the nodes
virtual int getDensityFromLayoutImageColor(SColor pixel);
virtual int getStyleFromLayoutImageColor(SColor pixel, int templatesize, vector3df pos);
virtual vector3df getRotationFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos);
virtual vector3df getScaleFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos);
// simple getter functions
float getViewDistance() { return m_ViewDistance; }
bool getUseLight() { return m_UseLight; }
bool getUseFog() { return m_UseFog; }
// toggle light, fog and visibility
virtual void setViewDistance(float d) { m_ViewDistance = d; }
virtual void setUseLight(bool v);
virtual void setUseFog(bool v);
virtual void setVisible(bool v);
private:
// is the point visible within the camera frustum
bool canBeSeenByCamPyramidPlanes(const SViewFrustum& frust, const vector3df& pos);
public:
//! constructor
IGE_SceneNode_Vegetation(ITerrainSceneNode* parent, stringc layoutimagefilename, float viewdistance, vector3df layoutRandomness, bool uselight, bool usefog, ISceneManager* smgr, s32 id);
//! destructor
virtual ~IGE_SceneNode_Vegetation();
//! frame
virtual void OnRegisterSceneNode() _IRR_OVERRIDE_;
//! renders the node.
virtual void render() _IRR_OVERRIDE_;
//! returns the axis aligned bounding box of this node
virtual const core::aabbox3d<f32>& getBoundingBox() const _IRR_OVERRIDE_;
//! Writes attributes of the scene node.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options = 0) const _IRR_OVERRIDE_;
//! Reads attributes of the scene node.
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options = 0) _IRR_OVERRIDE_;
//! Returns type of the scene node
virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_MESH; }
protected:
core::aabbox3d<f32> Box;
};
} // end namespace IGE
Code: Select all
#include "IGE_SceneNode_Vegetation.h"
namespace IGE
{
int getRandomInteger(int min, int max) { return rand() % (max - min + 1) + min; } //return int((double)rand() / (RAND_MAX + 1) * (max - min) + min);
float getRandomFloat(float min, float max) { return float((double)rand() / (RAND_MAX + 1) * (max - min) + min); }
//! constructor
IGE_SceneNode_Vegetation::IGE_SceneNode_Vegetation(ITerrainSceneNode* parent, stringc layoutimagefilename, float viewdistance, vector3df layoutRandomness, bool uselight, bool usefog,
ISceneManager* smgr, s32 id)
: ISceneNode(parent, smgr, id, vector3df(),vector3df(), vector3df(1,1,1)),m_Terrain(parent),m_ViewDistance(viewdistance),m_LayoutRandomness(layoutRandomness),m_UseLight(uselight),m_UseFog(usefog)
{
#ifdef _DEBUG
setDebugName("IGE_SceneNode_Vegetation");
#endif
Box = parent->getBoundingBox();
m_LayoutImage = smgr->getVideoDriver()->createImageFromFile(layoutimagefilename.c_str());
}
//! destructor
IGE_SceneNode_Vegetation::~IGE_SceneNode_Vegetation()
{
if (m_LayoutImage) m_LayoutImage->drop(); m_LayoutImage = 0;
clear();
}
//! frame
void IGE_SceneNode_Vegetation::OnRegisterSceneNode()
{
if (IsVisible)
{
SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
ISceneNode::OnRegisterSceneNode();
}
}
//! renders the node.
void IGE_SceneNode_Vegetation::render()
{
update(SceneManager->getActiveCamera()->getPosition(), SceneManager->getActiveCamera());
// ISceneNodeList::Iterator it = Children.begin();
// for (; it != Children.end(); ++it)
// (*it)->render();
}
//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& IGE_SceneNode_Vegetation::getBoundingBox() const
{
return Box;
}
//! Writes attributes of the scene node.
void IGE_SceneNode_Vegetation::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
ISceneNode::serializeAttributes(out, options);
}
//! Reads attributes of the scene node.
void IGE_SceneNode_Vegetation::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
ISceneNode::deserializeAttributes(in, options);
}
// add a new template to the list
void IGE_SceneNode_Vegetation::addMeshTemplate(stringc meshfilename, float YOffset)
{
// load the mesh
IMesh* Mesh = SceneManager->getMesh(meshfilename.c_str());
// if the mesh is valid we will use it
if (Mesh)
{
IMeshSceneNode* node = SceneManager->addMeshSceneNode(Mesh);
node->setPosition(vector3df(0, -99999, 0));
node->getMesh()->setHardwareMappingHint(EHM_STATIC);
node->setName("plsDoNotDeleteMe");
node->setMaterialFlag(EMF_FOG_ENABLE, m_UseFog);
node->setMaterialFlag(EMF_LIGHTING, m_UseLight);
node->setMaterialType(EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
// add the mesh to the list
IGE_MeshTemplate t(node, YOffset);
m_MeshTemplate.push_back(t);
}
}
// clear everything
void IGE_SceneNode_Vegetation::clear()
{
// clear the visible nodes / objects
if (!m_Nodes.empty())
{
for (u32 x = 0; x < m_Nodes.size(); x++)
{
if (m_Nodes[x] != NULL)
{
m_Nodes[x]->remove();
m_Nodes[x] = nullptr;
}
}
}
// clear all of the lists
m_Nodes.clear();
m_Nodes.reallocate(0, true);
m_NodePos.clear();
m_NodePos.reallocate(0, true);
m_NodeScale.clear();
m_NodeScale.reallocate(0, true);
m_NodeRotation.clear();
m_NodeRotation.reallocate(0, true);
m_NodeType.clear();
m_NodeType.reallocate(0, true);
m_IsNodePosFree.clear();
m_IsNodePosFree.reallocate(0, true);
}
void IGE_SceneNode_Vegetation::processLayout()
{
// if we dont have any node / object efinitions to use then bail
if (!(m_MeshTemplate.size() > 0))
{
printf("WARNING! IGE_SceneNode_Vegetation::processLayout() no plane templates found!\n");
return;
}
// if we dont have a terrain then bail
if (!m_Terrain)
{
printf("ERROR! IGE_SceneNode_Vegetation::processLayout() no terrain object found!\n");
return;
}
// make sure that we have a layout image else bail
if (!m_LayoutImage)
{
printf("ERROR! IGE_SceneNode_Vegetation::processLayout() no layout image\n");
return;
}
// get the edges of the terrain scenenode
aabbox3d<f32> terrainBox = m_Terrain->getBoundingBox();
Box = terrainBox;
float minX = terrainBox.MinEdge.X;
float minZ = terrainBox.MinEdge.Z;
m_Terrain->updateAbsolutePosition();
float terrainX = m_Terrain->getPosition().X;
float terrainZ = m_Terrain->getPosition().Z;
// get the parsing scale of the layout image vs the terrain sizes
float scaleX = terrainBox.getExtent().X / m_LayoutImage->getDimension().Width;
float scaleZ = terrainBox.getExtent().Z / m_LayoutImage->getDimension().Height;
float density = 1.0f;
// based on the density, run throught the lists
for (float i = minX; i < minX + terrainBox.getExtent().X; i+=density)
{
for (float ii = minZ; ii < minZ + terrainBox.getExtent().Z; )
{
// randomize the position a bit to prevent straight lines
vector3df randomness(
getRandomFloat(-m_LayoutRandomness.X, m_LayoutRandomness.X),
getRandomFloat(-m_LayoutRandomness.Y, 0),
getRandomFloat(-m_LayoutRandomness.Z, m_LayoutRandomness.Z));
// get the height of the terrain at the current position
float height = m_Terrain->getHeight(i + randomness.X, ii + randomness.Z);
if (height > -99990)
{
// get the layout image pixel color at the point relative to the terrain
int x2 = (int)(i / scaleX);
int y2 = (int)(ii / scaleZ);
SColor pixel = m_LayoutImage->getPixel(x2, y2);
vector3df pos(terrainX + i + randomness.X, height + randomness.Y, terrainZ + ii + randomness.Z);
// let the user select a style based on the color
int style = getStyleFromLayoutImageColor(pixel, m_MeshTemplate.size(), pos);
vector3df scale = getScaleFromLayoutImageColor(pixel, m_MeshTemplate.size(), style, pos);
vector3df rotation = getRotationFromLayoutImageColor(pixel, m_MeshTemplate.size(), style, pos);
density = getDensityFromLayoutImageColor(pixel);
ii += density;
// if there is a style then a node should be created at this position
// add at least a NULL to each list to make sure the lists sizes are matched
if (style != -2)
{
pos.Y -= m_MeshTemplate[style].m_YOffset;
m_Nodes.push_back(nullptr);
m_NodeType.push_back(style);
m_NodePos.push_back(pos);
m_NodeScale.push_back(scale);
m_NodeRotation.push_back(rotation);
m_IsNodePosFree.push_back(true);
}
}
}
}
}
// check if a point is inside the viewfromcamera view frustrum
bool IGE_SceneNode_Vegetation::canBeSeenByCamPyramidPlanes(const SViewFrustum& frust, const vector3df& pos)
{
for (s32 i = 0; i < scene::SViewFrustum::VF_PLANE_COUNT; ++i)
{
if (frust.planes[i].classifyPointRelation(pos) == core::ISREL3D_FRONT)
return false;
}
return true;
}
// called each frame to update what is visible and what is not
void IGE_SceneNode_Vegetation::update(vector3df center, ICameraSceneNode* camera)
{
if (!isVisible()) return;
if (m_HelperForDeleting == 0) m_HelperForDeleting = 1; else m_HelperForDeleting = 0;
// make the frustum a little bigger to stop popping near the front plane
SViewFrustum origFrustum = *camera->getViewFrustum();
SViewFrustum frustum = origFrustum;
for (int i = 0; i < scene::SViewFrustum::VF_PLANE_COUNT; ++i)
{
frustum.planes[i].recalculateD(frustum.planes[i].getMemberPoint() + frustum.planes[i].Normal * m_VisibleOffset);
}
frustum.recalculateBoundingBox();
for (u32 i = m_HelperForDeleting; i < m_NodePos.size(); i += 2)
{
line3d<f32> ray;
ray.start = center;
ray.end = m_NodePos[i];
float d = ray.getLength();
if (m_IsNodePosFree[i] && d < m_ViewDistance && canBeSeenByCamPyramidPlanes(frustum, m_NodePos[i]))
{
if (m_MeshTemplate[m_NodeType[i]].m_Node != nullptr)
{
m_Nodes[i] = m_MeshTemplate[m_NodeType[i]].m_Node->clone();
m_Nodes[i]->setPosition(m_NodePos[i]);
m_Nodes[i]->setRotation(m_NodeRotation[i]);
m_Nodes[i]->setScale(m_NodeScale[i]);
m_Nodes[i]->setMaterialFlag(EMF_LIGHTING, m_UseLight);
m_Nodes[i]->setMaterialFlag(EMF_FOG_ENABLE, m_UseFog);
m_IsNodePosFree[i] = false;
}
}
else
{
if (d > m_ViewDistance || !canBeSeenByCamPyramidPlanes(frustum, m_NodePos[i]))
{
if (m_Nodes[i] != nullptr) m_Nodes[i]->remove(); m_Nodes[i] = nullptr;
m_IsNodePosFree[i] = true;
}
}
}
}
int IGE_SceneNode_Vegetation::getDensityFromLayoutImageColor(SColor pixel)
{
return 1;
}
int IGE_SceneNode_Vegetation::getStyleFromLayoutImageColor(SColor pixel, int templatesize, vector3df pos)
{
return (getRandomInteger(1,templatesize))-1;
}
vector3df IGE_SceneNode_Vegetation::getRotationFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos)
{
return vector3df(0, getRandomFloat(0, 360), 0);
}
vector3df IGE_SceneNode_Vegetation::getScaleFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos)
{
return vector3df(getRandomFloat(1, 3), getRandomFloat(1, 3), getRandomFloat(1, 3));
}
void IGE_SceneNode_Vegetation::setUseLight(bool v)
{
m_UseLight = v;
for (u32 i = 0; i < m_Nodes.size(); i++)
if (m_Nodes[i] != nullptr)
m_Nodes[i]->setMaterialFlag(E_MATERIAL_FLAG::EMF_LIGHTING, v);
for (u32 i = 0; i < m_MeshTemplate.size(); i++)
m_MeshTemplate[i].m_Node->setMaterialFlag(E_MATERIAL_FLAG::EMF_LIGHTING, v);
}
void IGE_SceneNode_Vegetation::setUseFog(bool v)
{
m_UseFog = v;
for (u32 i = 0; i < m_Nodes.size(); i++)
if (m_Nodes[i] != nullptr)
m_Nodes[i]->setMaterialFlag(E_MATERIAL_FLAG::EMF_FOG_ENABLE, v);
for (u32 i = 0; i < m_MeshTemplate.size(); i++)
m_MeshTemplate[i].m_Node->setMaterialFlag(E_MATERIAL_FLAG::EMF_FOG_ENABLE, v);
}
void IGE_SceneNode_Vegetation::setVisible(bool v)
{
if (isVisible() == v) return;
ISceneNode::setVisible(v);
for (u32 i = 0; i < m_Nodes.size(); i++)
if (m_Nodes[i] != nullptr)
m_Nodes[i]->setVisible(v);
for (u32 i = 0; i < m_MeshTemplate.size(); i++)
m_MeshTemplate[i].m_Node->setVisible(v);
}
} // end namspace IGE
Re: Vegetation SceneNode
Code: Select all
#include <irrlicht.h>
#include "driverChoice.h"
#include "exampleHelper.h"
#include "IGE_SceneNode_Vegetation.h"
#include <conio.h>
using namespace irr;
using namespace video;
using namespace core;
using namespace gui;
using namespace scene;
using namespace io;
using namespace IGE;
// globals are easier for simple demos
IrrlichtDevice* device = 0;
video::IVideoDriver* driver = 0;
scene::ISceneManager* smgr = 0;
gui::IGUIEnvironment* env = 0;
// a few global variables specific to this demo
ITerrainSceneNode* terrain = 0; // the terrain to cover with grass
scene::ICameraSceneNode* camera = 0; // the main FPS camera
scene::ICameraSceneNode* camera2 = 0; // a test camera to check grass rendering through
scene::ICameraSceneNode* viewfromcamera = 0; // which camera to check grass rendering through
bool useLight = false;
bool useFog = false;
// some view distances for each layer of vegetation
float VIEW_DISTANCE_GRASS = 10000;
float VIEW_DISTANCE_FLOWERS = 5000;
float VIEW_DISTANCE_SHRUBS = 7000;
float VIEW_DISTANCE_SMALLTREES = 8000;
float VIEW_DISTANCE_LARGETREES = 10000;
float VIEW_DISTANCE_ROCKS = 10000;
// the terrain scale
#define TERRAIN_SCALE vector3df(400.f, 4.4f, 400.f)
// the vegetation layers
array<IGE_SceneNode_Vegetation*> vegetationLayers;
/// /////////////////////////////////////////////////////////////////////
// create 6 new scenenodes, each derived from the IGE_SceneNode_Vegetation class
// this allows us to setup each layer independently
// I commented the first layer (grass) extensively but the others are the same just used for different scenenodes
/// /////////////////////////////////////////////////////////////////////
class IGE_SceneNode_Vegetation_Grass : public IGE_SceneNode_Vegetation
{
public:
//! constructor - do nothing constructor
IGE_SceneNode_Vegetation_Grass(ITerrainSceneNode* parent, stringc layoutimagefilename, float viewdistance, vector3df layoutrandomness, bool uselight, bool usefog, ISceneManager* smgr, s32 id)
: IGE_SceneNode_Vegetation(parent, layoutimagefilename, viewdistance,layoutrandomness, uselight, usefog, smgr, id)
{}
//! destructor - do nothing destructor
virtual ~IGE_SceneNode_Vegetation_Grass() {}
// override to provide scenenode with layout values based on pixel colors
// in this case we are just hard coding the values, but you could use the pizel color to determine each attribute
virtual int getDensityFromLayoutImageColor(SColor pixel) { return 200; }
// override to provide scenenode with layout values based on pixel colors
// in this case, if the pixel color green attribute is greater that 100 then return one of the grass templates
// otherwise return -2 which is interpreted as no grass node in this area
virtual int getStyleFromLayoutImageColor(SColor pixel, int templatesize, vector3df pos)
{
if (pixel.getGreen() > 100) return getRandomInteger(1, templatesize) - 1;
else return -2;
}
// override to provide scenenode with layout values based on pixel colors
// in this case we are just hard coding the values, but you could use the pizel color to determine each attribute
virtual vector3df getRotationFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(0, getRandomFloat(0, 360), 0); }
// override to provide scenenode with layout values based on pixel colors
// in this case we are just hard coding the values, but you could use the pizel color to determine each attribute
virtual vector3df getScaleFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(3, getRandomInteger(1,3), 3); }
};
class IGE_SceneNode_Vegetation_Flowers : public IGE_SceneNode_Vegetation
{
public:
//! constructor
IGE_SceneNode_Vegetation_Flowers(ITerrainSceneNode* parent, stringc layoutimagefilename, float viewdistance, vector3df layoutrandomness, bool uselight, bool usefog, ISceneManager* smgr, s32 id)
: IGE_SceneNode_Vegetation(parent, layoutimagefilename, viewdistance, layoutrandomness, uselight, usefog, smgr, id)
{}
//! destructor
virtual ~IGE_SceneNode_Vegetation_Flowers() {}
// override to provide scenenode with layout values based on pixel colors
virtual int getDensityFromLayoutImageColor(SColor pixel) { return 2000; }
virtual int getStyleFromLayoutImageColor(SColor pixel, int templatesize, vector3df pos) { return (getRandomInteger(1, templatesize)) - 1; }
virtual vector3df getRotationFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(0, getRandomFloat(0, 360), 0); }
virtual vector3df getScaleFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(3, 8, 3); }
};
class IGE_SceneNode_Vegetation_Shrubs : public IGE_SceneNode_Vegetation
{
public:
//! constructor
IGE_SceneNode_Vegetation_Shrubs(ITerrainSceneNode* parent, stringc layoutimagefilename, float viewdistance, vector3df layoutrandomness, bool uselight, bool usefog, ISceneManager* smgr, s32 id)
: IGE_SceneNode_Vegetation(parent, layoutimagefilename, viewdistance, layoutrandomness, uselight, usefog, smgr, id)
{}
//! destructor
virtual ~IGE_SceneNode_Vegetation_Shrubs() {}
// override to provide scenenode with layout values based on pixel colors
virtual int getDensityFromLayoutImageColor(SColor pixel) { return 1000; }
virtual int getStyleFromLayoutImageColor(SColor pixel, int templatesize, vector3df pos) { return (getRandomInteger(1, templatesize)) - 1; }
virtual vector3df getRotationFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(0, getRandomFloat(0, 360), 0); }
virtual vector3df getScaleFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(5, 5, 5); }
};
class IGE_SceneNode_Vegetation_SmallTrees : public IGE_SceneNode_Vegetation
{
public:
//! constructor
IGE_SceneNode_Vegetation_SmallTrees(ITerrainSceneNode* parent, stringc layoutimagefilename, float viewdistance, vector3df layoutrandomness, bool uselight, bool usefog, ISceneManager* smgr, s32 id)
: IGE_SceneNode_Vegetation(parent, layoutimagefilename, viewdistance, layoutrandomness, uselight, usefog, smgr, id)
{}
//! destructor
virtual ~IGE_SceneNode_Vegetation_SmallTrees() {}
// override to provide scenenode with layout values based on pixel colors
virtual int getDensityFromLayoutImageColor(SColor pixel) { return 3000; }
virtual int getStyleFromLayoutImageColor(SColor pixel, int templatesize, vector3df pos) { return (getRandomInteger(1, templatesize)) - 1; }
virtual vector3df getRotationFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(0, getRandomFloat(0, 360), 0); }
virtual vector3df getScaleFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(8, 8, 8); }
};
class IGE_SceneNode_Vegetation_LargeTrees : public IGE_SceneNode_Vegetation
{
public:
//! constructor
IGE_SceneNode_Vegetation_LargeTrees(ITerrainSceneNode* parent, stringc layoutimagefilename, float viewdistance, vector3df layoutrandomness, bool uselight, bool usefog, ISceneManager* smgr, s32 id)
: IGE_SceneNode_Vegetation(parent, layoutimagefilename, viewdistance, layoutrandomness, uselight, usefog, smgr, id)
{}
//! destructor
virtual ~IGE_SceneNode_Vegetation_LargeTrees() {}
// override to provide scenenode with layout values based on pixel colors
virtual int getDensityFromLayoutImageColor(SColor pixel) { return 4000; }
virtual int getStyleFromLayoutImageColor(SColor pixel, int templatesize, vector3df pos) { return (getRandomInteger(1, templatesize)) - 1; }
virtual vector3df getRotationFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(0, getRandomFloat(0, 360), 0); }
virtual vector3df getScaleFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(14,14,14); }
};
class IGE_SceneNode_Vegetation_Rocks : public IGE_SceneNode_Vegetation
{
public:
//! constructor
IGE_SceneNode_Vegetation_Rocks(ITerrainSceneNode* parent, stringc layoutimagefilename, float viewdistance, vector3df layoutrandomness, bool uselight, bool usefog, ISceneManager* smgr, s32 id)
: IGE_SceneNode_Vegetation(parent, layoutimagefilename, viewdistance, layoutrandomness, uselight, usefog, smgr, id)
{}
//! destructor
virtual ~IGE_SceneNode_Vegetation_Rocks() {}
// override to provide scenenode with layout values based on pixel colors
virtual int getDensityFromLayoutImageColor(SColor pixel) { return 5000; }
virtual int getStyleFromLayoutImageColor(SColor pixel, int templatesize, vector3df pos) { return (getRandomInteger(1, templatesize)) - 1; }
virtual vector3df getRotationFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(0, getRandomFloat(0, 360), 0); }
virtual vector3df getScaleFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(2, 2, 2); }
};
// create all of the vegetation
// in this case, we create 6 different scenenodes and add mesh templates to each
void createVegetation()
{
// if ther is no terrain then bail
if (!terrain)
{
printf("terrain node is not valid!");
return;
}
// clear any existing vegetation layers
for (u32 i = 0; i < vegetationLayers.size(); i++) vegetationLayers[i]->remove(); vegetationLayers.clear();
// create the layer and add some templates to it
IGE_SceneNode_Vegetation_Grass* grass = new IGE_SceneNode_Vegetation_Grass(terrain, "media/_Assets/_Foliage/_LayoutImages/grasslayout.jpg",VIEW_DISTANCE_GRASS, vector3df(5, 0, 5), useLight, useFog, smgr, 0);
grass->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/misc/trop_grass(region).b3d", 0);
vegetationLayers.push_back(grass);
// create the layer and add some templates to it
IGE_SceneNode_Vegetation_Flowers* flowers = new IGE_SceneNode_Vegetation_Flowers(terrain, "media/_Assets/_Foliage/_LayoutImages/flowerslayout.jpg",VIEW_DISTANCE_FLOWERS, vector3df(50, 0, 50), useLight, useFog, smgr, 0);
flowers->addMeshTemplate("media/_assets/_Models/_Foliage/tropical/arteria3d_tropicalpack/flowers/flower 1.x", 0);
flowers->addMeshTemplate("media/_assets/_Models/_Foliage/tropical/arteria3d_tropicalpack/flowers/flower 2.x", 0);
flowers->addMeshTemplate("media/_assets/_Models/_Foliage/tropical/arteria3d_tropicalpack/flowers/flower 3.x", 0);
flowers->addMeshTemplate("media/_assets/_Models/_Foliage/tropical/arteria3d_tropicalpack/flowers/flower 4.x", 0);
flowers->addMeshTemplate("media/_assets/_Models/_Foliage/tropical/arteria3d_tropicalpack/flowers/flower 5.x", 0);
flowers->addMeshTemplate("media/_assets/_Models/_Foliage/tropical/arteria3d_tropicalpack/flowers/flower 6.x", 0);
flowers->addMeshTemplate("media/_assets/_Models/_Foliage/tropical/arteria3d_tropicalpack/flowers/flower 7.x", 0);
vegetationLayers.push_back(flowers);
// create the layer and add some templates to it
IGE_SceneNode_Vegetation_Shrubs* shrubs = new IGE_SceneNode_Vegetation_Shrubs(terrain, "media/_Assets/_Foliage/_LayoutImages/shrubslayout.jpg", VIEW_DISTANCE_SHRUBS, vector3df(500, 0, 500), useLight, useFog, smgr, 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/fan plant.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/fan plant version 2.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/fan plant version 3.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant a.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant b.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant c.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant d.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant e.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant g.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant h.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant k.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant l.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant m.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant n.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant n version2.b3d", 0);
vegetationLayers.push_back(shrubs);
// create the layer and add some templates to it
IGE_SceneNode_Vegetation_SmallTrees* SmallTrees = new IGE_SceneNode_Vegetation_SmallTrees(terrain, "media/_Assets/_Foliage/_LayoutImages/smalltreeslayout.jpg", VIEW_DISTANCE_SMALLTREES, vector3df(500, 0, 500), useLight, useFog, smgr, 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/bananatree.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/bananatree version2.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/bananatree version2 b.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/floorpalm.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/floorpalm 2.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/palm1.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/palm2.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/palm3.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/palm3 B.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/palm3 C.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/palm4.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/palm5.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/palm6.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/worn palm.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/yuka.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/yuka 2.b3d", 0);
vegetationLayers.push_back(SmallTrees);
// create the layer and add some templates to it
IGE_SceneNode_Vegetation_LargeTrees* LargeTrees = new IGE_SceneNode_Vegetation_LargeTrees(terrain, "media/_Assets/_Foliage/_LayoutImages/largetreeslayout.jpg", VIEW_DISTANCE_LARGETREES, vector3df(500, 0, 500), useLight, useFog, smgr, 0);
LargeTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/bananatree.b3d", 0);
LargeTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/bananatree version2.b3d", 0);
LargeTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/bananatree version2 b.b3d", 0);
LargeTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/floorpalm.b3d", 0);
LargeTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/floorpalm 2.b3d", 0);
vegetationLayers.push_back(LargeTrees);
// create the layer and add some templates to it
IGE_SceneNode_Vegetation_Rocks* rocks = new IGE_SceneNode_Vegetation_Rocks(terrain, "media/_Assets/_Foliage/_LayoutImages/rockslayout.jpg", VIEW_DISTANCE_ROCKS, vector3df(500, 0, 500), useLight, useFog, smgr, 0);
rocks->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/rocks/rock1.x", 0);
rocks->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/rocks/rock2.x", 0);
rocks->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/rocks/rock3.x", 0);
rocks->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/rocks/rock4.x", 0);
vegetationLayers.push_back(rocks);
// now process all of the layers
// each layer will scan the layout image and create node positions, rotations and scales based on the layout image
for (u32 i = 0; i < vegetationLayers.size(); i++)
vegetationLayers[i]->processLayout();
}
// simple method to toggle lighting
void toggleUseLight()
{
useLight = !useLight;
for (u32 i = 0; i < vegetationLayers.size(); i++)
vegetationLayers[i]->setUseLight(useLight);
if (terrain) terrain->setMaterialFlag(E_MATERIAL_FLAG::EMF_LIGHTING, useLight);
}
// simple method to toggle fog
void toggleUseFog()
{
useFog = !useFog;
for (u32 i = 0; i < vegetationLayers.size(); i++)
vegetationLayers[i]->setUseFog(useFog);
if (terrain) terrain->setMaterialFlag(E_MATERIAL_FLAG::EMF_FOG_ENABLE, useFog);
}
// create everything specific to this demo
// we use two cameras so that the user can see the frustum in action if desired (press Q or W to toggle which camera the vegetation is referencing)
void createScene()
{
// add a test camera with a cube to show us where it is at
camera2 = smgr->addCameraSceneNode();
// add the primary user controlled camera
camera = smgr->addCameraSceneNodeFPS(0, 100.0f, 1.2f);
camera->setPosition(core::vector3df(0, 500, 500));
camera->setTarget(core::vector3df(0, 0, 0));
camera->setFarValue(42000.0f);
camera->setInputReceiverEnabled(false);
// start the demo using the user controlled camera
viewfromcamera = camera;
// add some lighting and fog
smgr->addLightSceneNode(camera, vector3df(0, -50, 0), SColorf(0.5, 1, 1, 1), 4000);
driver->setFog(SColor(0,0,0,0),EFT_FOG_LINEAR,2000,8000);
// enable the mouse cursor
device->getCursorControl()->setVisible(true);
// add terrain scene node
terrain = smgr->addTerrainSceneNode(
"media/_assets/_terrain/heightmaps/terrain-plains.jpg",
0, // parent node
-1, // node id
core::vector3df(0.f, 0.f, 0.f), // position
core::vector3df(0.f, 0.f, 0.f), // rotation
TERRAIN_SCALE, // scale
video::SColor(255, 255, 255, 255), // vertexColor
5, // maxLOD
scene::ETPS_17, // patchSize
4 // smoothFactor
);
terrain->setMaterialFlag(video::EMF_LIGHTING, false);
terrain->setMaterialTexture(0, driver->getTexture("media/_assets/_terrain/textures/aerial_grass_rock_diff_4k.jpg"));
terrain->setMaterialTexture(1,driver->getTexture("media/detailmap3.jpg"));
terrain->setMaterialTexture(1, driver->getTexture("media/_assets/_terrain/textures/aerial_grass_rock_diff_4k.jpg"));
terrain->setMaterialType(video::EMT_DETAIL_MAP);
terrain->scaleTexture(1.0f, 20.0f);
// create the vegetation
createVegetation();
// turn on lighting and fog for the scene
toggleUseLight();
toggleUseFog();
}
void createGui()
{
}
// simple eventhandler
class MyEventReceiver : public IEventReceiver
{
private:
public:
MyEventReceiver() : IEventReceiver()
{
}
virtual bool OnEvent(const SEvent& event)
{
switch (event.EventType)
{
// toggle camera isinputreceiving with the right mouse button
case EEVENT_TYPE::EET_MOUSE_INPUT_EVENT:
if (event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)
smgr->getActiveCamera()->setInputReceiverEnabled(!smgr->getActiveCamera()->isInputReceiverEnabled());
break;
case EEVENT_TYPE::EET_KEY_INPUT_EVENT:
if (event.KeyInput.PressedDown)
{
switch (event.KeyInput.Key)
{
case KEY_KEY_F: toggleUseFog(); break; // toggle fog use
case KEY_KEY_L: toggleUseLight(); break; // toggle light use
case KEY_KEY_Q: viewfromcamera = camera; break; // toggle which camera the vegetation is referencing
case KEY_KEY_W: viewfromcamera = camera2; break; // toggle which camera the vegetation is referencing
// render further away
case KEY_PLUS :
for (u32 i = 0; i < vegetationLayers.size(); i++)
vegetationLayers[i]->setViewDistance(vegetationLayers[i]->getViewDistance() + 1000);
break;
// render closer
case KEY_MINUS:
for (u32 i = 0; i < vegetationLayers.size(); i++)
vegetationLayers[i]->setViewDistance(vegetationLayers[i]->getViewDistance() - 1000);
break;
// toggle individual vegetation layer visibility
case KEY_KEY_1:
vegetationLayers[0]->setVisible(!vegetationLayers[0]->isVisible());
break;
case KEY_KEY_2:
vegetationLayers[1]->setVisible(!vegetationLayers[1]->isVisible());
break;
case KEY_KEY_3:
vegetationLayers[2]->setVisible(!vegetationLayers[2]->isVisible());
break;
case KEY_KEY_4:
vegetationLayers[3]->setVisible(!vegetationLayers[3]->isVisible());
break;
case KEY_KEY_5:
vegetationLayers[4]->setVisible(!vegetationLayers[4]->isVisible());
break;
case KEY_KEY_6:
vegetationLayers[5]->setVisible(!vegetationLayers[5]->isVisible());
break;
}
}
break;
}
return false;
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// everything below here is just setting up the program
MyEventReceiver receiver;
bool genericDemoSetup()
{
// create device with full flexibility over creation parameters
// you can add more parameters if desired, check irr::SIrrlichtCreationParameters
irr::SIrrlichtCreationParameters params;
params.DriverType = EDT_OPENGL;
params.WindowSize = core::dimension2d<u32>(640, 480);
device = createDeviceEx(params);
if (device == 0) return false;
driver = device->getVideoDriver();
smgr = device->getSceneManager();
env = device->getGUIEnvironment();
driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true);
// create event receiver
device->setEventReceiver(&receiver);
return true;
}
int main()
{
// setup the demo
if (!genericDemoSetup()) return 1;
// create all of the items specific to this demo
createScene();
createGui();
// run the demo
int lastFPS = -1;
while (device->run())
if (device->isWindowActive())
{
driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0));
smgr->drawAll();
env->drawAll();
driver->endScene();
// display frames per second in window title
int fps = driver->getFPS();
if (lastFPS != fps)
{
core::stringw str = "FPS:"; str += fps;
str += " #Primitive Drawn = "; str += driver->getPrimitiveCountDrawn();
str += " Method = ";
if (viewfromcamera == camera) str += " camera1";
if (viewfromcamera == camera2) str += " camera2";
device->setWindowCaption(str.c_str());
lastFPS = fps;
}
}
device->drop();
printf("Press any key to continue, press any other ley to quit.........");
_getch();
return 0;
}
Re: Vegetation SceneNode
Video looks good. Guess to run demo I'd have to work a bit on replacing models, not done yet ;-)
Tiny hints:
- include "irrlicht.h" not "Irrlicht.h", otherwise it won't compile on systems which don't ignore the difference (aka Unix).
- terrain detailmap texture is set twice (kinda doesn't matter probably which one you set...)
- "using namespace" should never be in a header file. Yes, that means you have to type full type-names always in headers. But otherwise it's no longer possible to use competing namespaces as soon as you include such a header, which kills the reason to have namespaces in the first place.
edit: Thinking a bit more about it - although everyone always says don't use "using namespace" in a header - it still should only be valid in a scope. So if you put those using namepace calls inside the "namespace IGE" scope it should be fine and you can avoid typing all types. So just move it a bit.
Thanks for the code!
Tiny hints:
- include "irrlicht.h" not "Irrlicht.h", otherwise it won't compile on systems which don't ignore the difference (aka Unix).
- terrain detailmap texture is set twice (kinda doesn't matter probably which one you set...)
- "using namespace" should never be in a header file. Yes, that means you have to type full type-names always in headers. But otherwise it's no longer possible to use competing namespaces as soon as you include such a header, which kills the reason to have namespaces in the first place.
edit: Thinking a bit more about it - although everyone always says don't use "using namespace" in a header - it still should only be valid in a scope. So if you put those using namepace calls inside the "namespace IGE" scope it should be fine and you can avoid typing all types. So just move it a bit.
Thanks for the code!
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Re: Vegetation SceneNode
here is test code using only dwarf.x file
you have to imagine what is a tree, rock etc
you have to imagine what is a tree, rock etc

Code: Select all
// to use a single model for all of this uncomment this line
#define USE_SINGLE_MODEL
#define MODELNAME "media/dwarf.x"
#include <irrlicht.h>
#include "driverChoice.h"
#include "exampleHelper.h"
#include "IGE_SceneNode_Vegetation.h"
#include <conio.h>
using namespace irr;
using namespace video;
using namespace core;
using namespace gui;
using namespace scene;
using namespace io;
using namespace IGE;
// globals are easier for simple demos
IrrlichtDevice* device = 0;
video::IVideoDriver* driver = 0;
scene::ISceneManager* smgr = 0;
gui::IGUIEnvironment* env = 0;
// a few global variables specific to this demo
ITerrainSceneNode* terrain = 0; // the terrain to cover with grass
scene::ICameraSceneNode* camera = 0; // the main FPS camera
scene::ICameraSceneNode* camera2 = 0; // a test camera to check grass rendering through
scene::ICameraSceneNode* viewfromcamera = 0; // which camera to check grass rendering through
bool useLight = false;
bool useFog = false;
// some view distances for each layer of vegetation
float VIEW_DISTANCE_GRASS = 10000;
float VIEW_DISTANCE_FLOWERS = 5000;
float VIEW_DISTANCE_SHRUBS = 7000;
float VIEW_DISTANCE_SMALLTREES = 8000;
float VIEW_DISTANCE_LARGETREES = 10000;
float VIEW_DISTANCE_ROCKS = 10000;
// the terrain scale
#define TERRAIN_SCALE vector3df(400.f, 4.4f, 400.f)
// the vegetation layers
array<IGE_SceneNode_Vegetation*> vegetationLayers;
/// /////////////////////////////////////////////////////////////////////
// create 6 new scenenodes, each derived from the IGE_SceneNode_Vegetation class
// this allows us to setup each layer independently
// I commented the first layer (grass) extensively but the others are the same just used for different scenenodes
/// /////////////////////////////////////////////////////////////////////
class IGE_SceneNode_Vegetation_Grass : public IGE_SceneNode_Vegetation
{
public:
//! constructor - do nothing constructor
IGE_SceneNode_Vegetation_Grass(ITerrainSceneNode* parent, stringc layoutimagefilename, float viewdistance, vector3df layoutrandomness, bool uselight, bool usefog, ISceneManager* smgr, s32 id)
: IGE_SceneNode_Vegetation(parent, layoutimagefilename, viewdistance,layoutrandomness, uselight, usefog, smgr, id)
{}
//! destructor - do nothing destructor
virtual ~IGE_SceneNode_Vegetation_Grass() {}
// override to provide scenenode with layout values based on pixel colors
// in this case we are just hard coding the values, but you could use the pizel color to determine each attribute
virtual int getDensityFromLayoutImageColor(SColor pixel) { return 200; }
// override to provide scenenode with layout values based on pixel colors
// in this case, if the pixel color green attribute is greater that 100 then return one of the grass templates
// otherwise return -2 which is interpreted as no grass node in this area
virtual int getStyleFromLayoutImageColor(SColor pixel, int templatesize, vector3df pos)
{
if (pixel.getGreen() > 100) return getRandomInteger(1, templatesize) - 1;
else return -2;
}
// override to provide scenenode with layout values based on pixel colors
// in this case we are just hard coding the values, but you could use the pizel color to determine each attribute
virtual vector3df getRotationFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(0, getRandomFloat(0, 360), 0); }
// override to provide scenenode with layout values based on pixel colors
// in this case we are just hard coding the values, but you could use the pizel color to determine each attribute
virtual vector3df getScaleFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(3, getRandomInteger(1,3), 3); }
};
class IGE_SceneNode_Vegetation_Flowers : public IGE_SceneNode_Vegetation
{
public:
//! constructor
IGE_SceneNode_Vegetation_Flowers(ITerrainSceneNode* parent, stringc layoutimagefilename, float viewdistance, vector3df layoutrandomness, bool uselight, bool usefog, ISceneManager* smgr, s32 id)
: IGE_SceneNode_Vegetation(parent, layoutimagefilename, viewdistance, layoutrandomness, uselight, usefog, smgr, id)
{}
//! destructor
virtual ~IGE_SceneNode_Vegetation_Flowers() {}
// override to provide scenenode with layout values based on pixel colors
virtual int getDensityFromLayoutImageColor(SColor pixel) { return 2000; }
virtual int getStyleFromLayoutImageColor(SColor pixel, int templatesize, vector3df pos) { return (getRandomInteger(1, templatesize)) - 1; }
virtual vector3df getRotationFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(0, getRandomFloat(0, 360), 0); }
virtual vector3df getScaleFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(3, 8, 3); }
};
class IGE_SceneNode_Vegetation_Shrubs : public IGE_SceneNode_Vegetation
{
public:
//! constructor
IGE_SceneNode_Vegetation_Shrubs(ITerrainSceneNode* parent, stringc layoutimagefilename, float viewdistance, vector3df layoutrandomness, bool uselight, bool usefog, ISceneManager* smgr, s32 id)
: IGE_SceneNode_Vegetation(parent, layoutimagefilename, viewdistance, layoutrandomness, uselight, usefog, smgr, id)
{}
//! destructor
virtual ~IGE_SceneNode_Vegetation_Shrubs() {}
// override to provide scenenode with layout values based on pixel colors
virtual int getDensityFromLayoutImageColor(SColor pixel) { return 1000; }
virtual int getStyleFromLayoutImageColor(SColor pixel, int templatesize, vector3df pos) { return (getRandomInteger(1, templatesize)) - 1; }
virtual vector3df getRotationFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(0, getRandomFloat(0, 360), 0); }
virtual vector3df getScaleFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(5, 5, 5); }
};
class IGE_SceneNode_Vegetation_SmallTrees : public IGE_SceneNode_Vegetation
{
public:
//! constructor
IGE_SceneNode_Vegetation_SmallTrees(ITerrainSceneNode* parent, stringc layoutimagefilename, float viewdistance, vector3df layoutrandomness, bool uselight, bool usefog, ISceneManager* smgr, s32 id)
: IGE_SceneNode_Vegetation(parent, layoutimagefilename, viewdistance, layoutrandomness, uselight, usefog, smgr, id)
{}
//! destructor
virtual ~IGE_SceneNode_Vegetation_SmallTrees() {}
// override to provide scenenode with layout values based on pixel colors
virtual int getDensityFromLayoutImageColor(SColor pixel) { return 3000; }
virtual int getStyleFromLayoutImageColor(SColor pixel, int templatesize, vector3df pos) { return (getRandomInteger(1, templatesize)) - 1; }
virtual vector3df getRotationFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(0, getRandomFloat(0, 360), 0); }
virtual vector3df getScaleFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(8, 8, 8); }
};
class IGE_SceneNode_Vegetation_LargeTrees : public IGE_SceneNode_Vegetation
{
public:
//! constructor
IGE_SceneNode_Vegetation_LargeTrees(ITerrainSceneNode* parent, stringc layoutimagefilename, float viewdistance, vector3df layoutrandomness, bool uselight, bool usefog, ISceneManager* smgr, s32 id)
: IGE_SceneNode_Vegetation(parent, layoutimagefilename, viewdistance, layoutrandomness, uselight, usefog, smgr, id)
{}
//! destructor
virtual ~IGE_SceneNode_Vegetation_LargeTrees() {}
// override to provide scenenode with layout values based on pixel colors
virtual int getDensityFromLayoutImageColor(SColor pixel) { return 4000; }
virtual int getStyleFromLayoutImageColor(SColor pixel, int templatesize, vector3df pos) { return (getRandomInteger(1, templatesize)) - 1; }
virtual vector3df getRotationFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(0, getRandomFloat(0, 360), 0); }
virtual vector3df getScaleFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(14,14,14); }
};
class IGE_SceneNode_Vegetation_Rocks : public IGE_SceneNode_Vegetation
{
public:
//! constructor
IGE_SceneNode_Vegetation_Rocks(ITerrainSceneNode* parent, stringc layoutimagefilename, float viewdistance, vector3df layoutrandomness, bool uselight, bool usefog, ISceneManager* smgr, s32 id)
: IGE_SceneNode_Vegetation(parent, layoutimagefilename, viewdistance, layoutrandomness, uselight, usefog, smgr, id)
{}
//! destructor
virtual ~IGE_SceneNode_Vegetation_Rocks() {}
// override to provide scenenode with layout values based on pixel colors
virtual int getDensityFromLayoutImageColor(SColor pixel) { return 5000; }
virtual int getStyleFromLayoutImageColor(SColor pixel, int templatesize, vector3df pos) { return (getRandomInteger(1, templatesize)) - 1; }
virtual vector3df getRotationFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(0, getRandomFloat(0, 360), 0); }
virtual vector3df getScaleFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(2, 2, 2); }
};
// create all of the vegetation
// in this case, we create 6 different scenenodes and add mesh templates to each
void createVegetation()
{
// if ther is no terrain then bail
if (!terrain)
{
printf("terrain node is not valid!");
return;
}
// clear any existing vegetation layers
for (u32 i = 0; i < vegetationLayers.size(); i++) vegetationLayers[i]->remove(); vegetationLayers.clear();
// create the layer and add some templates to it
IGE_SceneNode_Vegetation_Grass* grass = new IGE_SceneNode_Vegetation_Grass(terrain, "media/_Assets/_Foliage/_LayoutImages/grasslayout.jpg",VIEW_DISTANCE_GRASS, vector3df(5, 0, 5), useLight, useFog, smgr, 0);
#ifdef USE_SINGLE_MODEL
grass->addMeshTemplate(MODELNAME, 0);
#else
grass->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/misc/trop_grass(region).b3d", 0);
#endif
vegetationLayers.push_back(grass);
// create the layer and add some templates to it
IGE_SceneNode_Vegetation_Flowers* flowers = new IGE_SceneNode_Vegetation_Flowers(terrain, "media/_Assets/_Foliage/_LayoutImages/flowerslayout.jpg",VIEW_DISTANCE_FLOWERS, vector3df(50, 0, 50), useLight, useFog, smgr, 0);
#ifdef USE_SINGLE_MODEL
grass->addMeshTemplate(MODELNAME, 0);
#else
flowers->addMeshTemplate("media/_assets/_Models/_Foliage/tropical/arteria3d_tropicalpack/flowers/flower 1.x", 0);
flowers->addMeshTemplate("media/_assets/_Models/_Foliage/tropical/arteria3d_tropicalpack/flowers/flower 2.x", 0);
flowers->addMeshTemplate("media/_assets/_Models/_Foliage/tropical/arteria3d_tropicalpack/flowers/flower 3.x", 0);
flowers->addMeshTemplate("media/_assets/_Models/_Foliage/tropical/arteria3d_tropicalpack/flowers/flower 4.x", 0);
flowers->addMeshTemplate("media/_assets/_Models/_Foliage/tropical/arteria3d_tropicalpack/flowers/flower 5.x", 0);
flowers->addMeshTemplate("media/_assets/_Models/_Foliage/tropical/arteria3d_tropicalpack/flowers/flower 6.x", 0);
flowers->addMeshTemplate("media/_assets/_Models/_Foliage/tropical/arteria3d_tropicalpack/flowers/flower 7.x", 0);
#endif
vegetationLayers.push_back(flowers);
// create the layer and add some templates to it
IGE_SceneNode_Vegetation_Shrubs* shrubs = new IGE_SceneNode_Vegetation_Shrubs(terrain, "media/_Assets/_Foliage/_LayoutImages/shrubslayout.jpg", VIEW_DISTANCE_SHRUBS, vector3df(500, 0, 500), useLight, useFog, smgr, 0);
#ifdef USE_SINGLE_MODEL
grass->addMeshTemplate(MODELNAME, 0);
#else
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/fan plant.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/fan plant version 2.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/fan plant version 3.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant a.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant b.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant c.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant d.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant e.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant g.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant h.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant k.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant l.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant m.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant n.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant n version2.b3d", 0);
#endif
vegetationLayers.push_back(shrubs);
// create the layer and add some templates to it
IGE_SceneNode_Vegetation_SmallTrees* SmallTrees = new IGE_SceneNode_Vegetation_SmallTrees(terrain, "media/_Assets/_Foliage/_LayoutImages/smalltreeslayout.jpg", VIEW_DISTANCE_SMALLTREES, vector3df(500, 0, 500), useLight, useFog, smgr, 0);
#ifdef USE_SINGLE_MODEL
grass->addMeshTemplate(MODELNAME, 0);
#else
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/bananatree.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/bananatree version2.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/bananatree version2 b.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/floorpalm.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/floorpalm 2.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/palm1.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/palm2.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/palm3.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/palm3 B.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/palm3 C.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/palm4.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/palm5.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/palm6.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/worn palm.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/yuka.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/yuka 2.b3d", 0);
#endif
vegetationLayers.push_back(SmallTrees);
// create the layer and add some templates to it
IGE_SceneNode_Vegetation_LargeTrees* LargeTrees = new IGE_SceneNode_Vegetation_LargeTrees(terrain, "media/_Assets/_Foliage/_LayoutImages/largetreeslayout.jpg", VIEW_DISTANCE_LARGETREES, vector3df(500, 0, 500), useLight, useFog, smgr, 0);
#ifdef USE_SINGLE_MODEL
grass->addMeshTemplate(MODELNAME, 0);
#else
LargeTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/bananatree.b3d", 0);
LargeTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/bananatree version2.b3d", 0);
LargeTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/bananatree version2 b.b3d", 0);
LargeTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/floorpalm.b3d", 0);
LargeTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/floorpalm 2.b3d", 0);
#endif
vegetationLayers.push_back(LargeTrees);
// create the layer and add some templates to it
IGE_SceneNode_Vegetation_Rocks* rocks = new IGE_SceneNode_Vegetation_Rocks(terrain, "media/_Assets/_Foliage/_LayoutImages/rockslayout.jpg", VIEW_DISTANCE_ROCKS, vector3df(500, 0, 500), useLight, useFog, smgr, 0);
#ifdef USE_SINGLE_MODEL
grass->addMeshTemplate(MODELNAME, 0);
#else
rocks->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/rocks/rock1.x", 0);
rocks->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/rocks/rock2.x", 0);
rocks->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/rocks/rock3.x", 0);
rocks->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/rocks/rock4.x", 0);
#endif
vegetationLayers.push_back(rocks);
// now process all of the layers
// each layer will scan the layout image and create node positions, rotations and scales based on the layout image
for (u32 i = 0; i < vegetationLayers.size(); i++)
vegetationLayers[i]->processLayout();
}
// simple method to toggle lighting
void toggleUseLight()
{
useLight = !useLight;
for (u32 i = 0; i < vegetationLayers.size(); i++)
vegetationLayers[i]->setUseLight(useLight);
if (terrain) terrain->setMaterialFlag(E_MATERIAL_FLAG::EMF_LIGHTING, useLight);
}
// simple method to toggle fog
void toggleUseFog()
{
useFog = !useFog;
for (u32 i = 0; i < vegetationLayers.size(); i++)
vegetationLayers[i]->setUseFog(useFog);
if (terrain) terrain->setMaterialFlag(E_MATERIAL_FLAG::EMF_FOG_ENABLE, useFog);
}
// create everything specific to this demo
// we use two cameras so that the user can see the frustum in action if desired (press Q or W to toggle which camera the vegetation is referencing)
void createScene()
{
// add a test camera with a cube to show us where it is at
camera2 = smgr->addCameraSceneNode();
// add the primary user controlled camera
camera = smgr->addCameraSceneNodeFPS(0, 100.0f, 1.2f);
camera->setPosition(core::vector3df(0, 500, 500));
camera->setTarget(core::vector3df(0, 0, 0));
camera->setFarValue(42000.0f);
camera->setInputReceiverEnabled(false);
// start the demo using the user controlled camera
viewfromcamera = camera;
// add some lighting and fog
smgr->addLightSceneNode(camera, vector3df(0, -50, 0), SColorf(0.5, 1, 1, 1), 4000);
driver->setFog(SColor(0,0,0,0),EFT_FOG_LINEAR,2000,8000);
// enable the mouse cursor
device->getCursorControl()->setVisible(true);
// add terrain scene node
terrain = smgr->addTerrainSceneNode(
"media/_assets/_terrain/heightmaps/terrain-plains.jpg",
0, // parent node
-1, // node id
core::vector3df(0.f, 0.f, 0.f), // position
core::vector3df(0.f, 0.f, 0.f), // rotation
TERRAIN_SCALE, // scale
video::SColor(255, 255, 255, 255), // vertexColor
5, // maxLOD
scene::ETPS_17, // patchSize
4 // smoothFactor
);
terrain->setMaterialFlag(video::EMF_LIGHTING, false);
terrain->setMaterialTexture(0, driver->getTexture("media/_assets/_terrain/textures/aerial_grass_rock_diff_4k.jpg"));
terrain->setMaterialTexture(1, driver->getTexture("media/_assets/_terrain/textures/aerial_grass_rock_diff_4k.jpg"));
terrain->setMaterialType(video::EMT_DETAIL_MAP);
terrain->scaleTexture(1.0f, 20.0f);
// create the vegetation
createVegetation();
// turn on lighting and fog for the scene
toggleUseLight();
toggleUseFog();
}
void createGui()
{
}
// simple eventhandler
class MyEventReceiver : public IEventReceiver
{
private:
public:
MyEventReceiver() : IEventReceiver()
{
}
virtual bool OnEvent(const SEvent& event)
{
switch (event.EventType)
{
// toggle camera isinputreceiving with the right mouse button
case EEVENT_TYPE::EET_MOUSE_INPUT_EVENT:
if (event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)
smgr->getActiveCamera()->setInputReceiverEnabled(!smgr->getActiveCamera()->isInputReceiverEnabled());
break;
case EEVENT_TYPE::EET_KEY_INPUT_EVENT:
if (event.KeyInput.PressedDown)
{
switch (event.KeyInput.Key)
{
case KEY_KEY_F: toggleUseFog(); break; // toggle fog use
case KEY_KEY_L: toggleUseLight(); break; // toggle light use
case KEY_KEY_Q: viewfromcamera = camera; break; // toggle which camera the vegetation is referencing
case KEY_KEY_W: viewfromcamera = camera2; break; // toggle which camera the vegetation is referencing
// render further away
case KEY_PLUS :
for (u32 i = 0; i < vegetationLayers.size(); i++)
vegetationLayers[i]->setViewDistance(vegetationLayers[i]->getViewDistance() + 1000);
break;
// render closer
case KEY_MINUS:
for (u32 i = 0; i < vegetationLayers.size(); i++)
vegetationLayers[i]->setViewDistance(vegetationLayers[i]->getViewDistance() - 1000);
break;
// toggle individual vegetation layer visibility
case KEY_KEY_1:
vegetationLayers[0]->setVisible(!vegetationLayers[0]->isVisible());
break;
case KEY_KEY_2:
vegetationLayers[1]->setVisible(!vegetationLayers[1]->isVisible());
break;
case KEY_KEY_3:
vegetationLayers[2]->setVisible(!vegetationLayers[2]->isVisible());
break;
case KEY_KEY_4:
vegetationLayers[3]->setVisible(!vegetationLayers[3]->isVisible());
break;
case KEY_KEY_5:
vegetationLayers[4]->setVisible(!vegetationLayers[4]->isVisible());
break;
case KEY_KEY_6:
vegetationLayers[5]->setVisible(!vegetationLayers[5]->isVisible());
break;
}
}
break;
}
return false;
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// everything below here is just setting up the program
MyEventReceiver receiver;
bool genericDemoSetup()
{
// create device with full flexibility over creation parameters
// you can add more parameters if desired, check irr::SIrrlichtCreationParameters
irr::SIrrlichtCreationParameters params;
params.DriverType = EDT_OPENGL;
params.WindowSize = core::dimension2d<u32>(640, 480);
device = createDeviceEx(params);
if (device == 0) return false;
driver = device->getVideoDriver();
smgr = device->getSceneManager();
env = device->getGUIEnvironment();
driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true);
// create event receiver
device->setEventReceiver(&receiver);
return true;
}
int main()
{
// setup the demo
if (!genericDemoSetup()) return 1;
// create all of the items specific to this demo
createScene();
createGui();
// run the demo
int lastFPS = -1;
while (device->run())
if (device->isWindowActive())
{
driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0));
smgr->drawAll();
env->drawAll();
driver->endScene();
// display frames per second in window title
int fps = driver->getFPS();
if (lastFPS != fps)
{
core::stringw str = "FPS:"; str += fps;
str += " #Primitive Drawn = "; str += driver->getPrimitiveCountDrawn();
str += " Method = ";
if (viewfromcamera == camera) str += " camera1";
if (viewfromcamera == camera2) str += " camera2";
device->setWindowCaption(str.c_str());
lastFPS = fps;
}
}
device->drop();
printf("Press any key to continue, press any other ley to quit.........");
_getch();
return 0;
}
Re: Vegetation SceneNode
OK, got it working with own files.
Another tiny bug: if (height > -99990) can lead to and endless loop. Probably with my terrain-file and it somehow hitting outside or something like that. So ii never increased. But just removing that line things worked (or probably could add density to ii in every loop instead).
Another tiny bug: if (height > -99990) can lead to and endless loop. Probably with my terrain-file and it somehow hitting outside or something like that. So ii never increased. But just removing that line things worked (or probably could add density to ii in every loop instead).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Re: Vegetation SceneNode
glad to hear it is working for you. I noticed that the 2nd camera isnt working here. I will investigate.
in the mean time I would be interested in any thoughts you have on it all.
in the mean time I would be interested in any thoughts you have on it all.
Re: Vegetation SceneNode
Final version...........
IGE_SceneNode_Vegetation.h
IGE_SceneNode_Vegetation.cpp
IGE_SceneNode_Vegetation.h
Code: Select all
#pragma once
#include "Irrlicht.h"
using namespace irr;
using namespace video;
using namespace core;
using namespace gui;
using namespace scene;
using namespace io;
namespace IGE
{
// if color is below this value thn no node is present
#define CUTOFF 50
#define YCUTOFF 0
// simple rendom number generators
extern int getRandomInteger(int min, int max);
extern float getRandomFloat(float min, float max);
// simple structure to hold a template node and the YOffset to apply when positioning the node
struct IGE_MeshTemplate
{
IGE_MeshTemplate(IMeshSceneNode* node, float yoffset) : m_Node(node), m_YOffset(yoffset) {}
IMeshSceneNode* m_Node = nullptr;
float m_YOffset = 0.0f;
};
/*
* the scenenode class
* once the scenenode is instantiated
* add as many templates as desired (these are the different nodes to be used)
*
*
*/
class IGE_SceneNode_Vegetation : public ISceneNode
{
public:
ITerrainSceneNode* m_Terrain = nullptr; // the terrain scenenode we are attached to
IImage* m_LayoutImage = nullptr; // the layout image - used to determine whether a node/object is at any given position
array<IGE_MeshTemplate> m_MeshTemplate; // list of nodes being used
array<ISceneNode*> m_Nodes; // list of visible nodes
array<short int> m_NodeType; // list of node types (index into the MeshTemplates)
array<vector3df> m_NodePos; // list of node positions
array<vector3df> m_NodeScale; // list of node scales
array<vector3df> m_NodeRotation; // list of node rotations
array<bool> m_IsNodePosFree; // list of open and closed slots in the node list
float m_ViewDistance = 1000; // distance from camera at which nodes become visible
f32 m_VisibleOffset = 200.f; // resize the camera frustum by this amount, you can use the maximal radius of your mesh to prevent close plane popping
vector3df m_LayoutRandomness = vector3df(0,0,0); // add some randomness to the layout procedure
int m_HelperForDeleting = false; // variable used during update
bool m_UseLight = false; // simple variable to track light use
bool m_UseFog = false; // simple variable to track fog use
ICameraSceneNode* m_CameraToUse = 0; // camera to use for determining node visibility
public:
// add a node template
void addMeshTemplate(stringc meshfilename, float YOffset);
// using the terrain as the location base and the layout functions to determine position, rotation and scale of nodes
void processLayout();
// clear all lists
void clear();
// set which camera we use for determining node visibility
void setCameraToUse(ICameraSceneNode* CameraToUse) { m_CameraToUse = CameraToUse; };
// called each tick. determine which nodes should be visible based on the camera position and rotation
void update(vector3df center, ICameraSceneNode* camera);
// use color information to determine the density, style, rotation and scale of the nodes
virtual int getDensityFromLayoutImageColor(SColor pixel);
virtual int getStyleFromLayoutImageColor(SColor pixel, int templatesize, vector3df pos);
virtual vector3df getRotationFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos);
virtual vector3df getScaleFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos);
// simple getter functions
float getViewDistance() { return m_ViewDistance; }
bool getUseLight() { return m_UseLight; }
bool getUseFog() { return m_UseFog; }
// toggle light, fog and visibility
virtual void setViewDistance(float d) { m_ViewDistance = d; }
virtual void setUseLight(bool v);
virtual void setUseFog(bool v);
virtual void setVisible(bool v);
private:
// is the point visible within the camera frustum
bool canBeSeenByCamPyramidPlanes(const SViewFrustum& frust, const vector3df& pos);
public:
//! constructor
IGE_SceneNode_Vegetation(ITerrainSceneNode* parent, stringc layoutimagefilename, float viewdistance, vector3df layoutRandomness, bool uselight, bool usefog, ISceneManager* smgr, s32 id);
//! destructor
virtual ~IGE_SceneNode_Vegetation();
//! frame
virtual void OnRegisterSceneNode() _IRR_OVERRIDE_;
//! renders the node.
virtual void render() _IRR_OVERRIDE_;
//! returns the axis aligned bounding box of this node
virtual const core::aabbox3d<f32>& getBoundingBox() const _IRR_OVERRIDE_;
//! Writes attributes of the scene node.
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options = 0) const _IRR_OVERRIDE_;
//! Reads attributes of the scene node.
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options = 0) _IRR_OVERRIDE_;
//! Returns type of the scene node
virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_MESH; }
protected:
core::aabbox3d<f32> Box;
};
} // end namespace IGE
Code: Select all
#include "IGE_SceneNode_Vegetation.h"
namespace IGE
{
int getRandomInteger(int min, int max) { return rand() % (max - min + 1) + min; } //return int((double)rand() / (RAND_MAX + 1) * (max - min) + min);
float getRandomFloat(float min, float max) { return float((double)rand() / (RAND_MAX + 1) * (max - min) + min); }
//! constructor
IGE_SceneNode_Vegetation::IGE_SceneNode_Vegetation(ITerrainSceneNode* parent, stringc layoutimagefilename, float viewdistance, vector3df layoutRandomness, bool uselight, bool usefog,
ISceneManager* smgr, s32 id)
: ISceneNode(parent, smgr, id, vector3df(),vector3df(), vector3df(1,1,1)),m_Terrain(parent),m_ViewDistance(viewdistance),m_LayoutRandomness(layoutRandomness),m_UseLight(uselight),m_UseFog(usefog)
{
#ifdef _DEBUG
setDebugName("IGE_SceneNode_Vegetation");
#endif
Box = parent->getBoundingBox();
m_LayoutImage = smgr->getVideoDriver()->createImageFromFile(layoutimagefilename.c_str());
}
//! destructor
IGE_SceneNode_Vegetation::~IGE_SceneNode_Vegetation()
{
if (m_LayoutImage) m_LayoutImage->drop(); m_LayoutImage = 0;
clear();
}
//! frame
void IGE_SceneNode_Vegetation::OnRegisterSceneNode()
{
if (IsVisible)
{
SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
ISceneNode::OnRegisterSceneNode();
}
}
//! renders the node.
void IGE_SceneNode_Vegetation::render()
{
if (m_CameraToUse != 0)
{
update(m_CameraToUse->getPosition(), m_CameraToUse);
}
else
{
update(SceneManager->getActiveCamera()->getPosition(), SceneManager->getActiveCamera());
}
// ISceneNodeList::Iterator it = Children.begin();
// for (; it != Children.end(); ++it)
// (*it)->render();
}
//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& IGE_SceneNode_Vegetation::getBoundingBox() const
{
return Box;
}
//! Writes attributes of the scene node.
void IGE_SceneNode_Vegetation::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
ISceneNode::serializeAttributes(out, options);
}
//! Reads attributes of the scene node.
void IGE_SceneNode_Vegetation::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
ISceneNode::deserializeAttributes(in, options);
}
// add a new template to the list
void IGE_SceneNode_Vegetation::addMeshTemplate(stringc meshfilename, float YOffset)
{
// load the mesh
IMesh* Mesh = SceneManager->getMesh(meshfilename.c_str());
// if the mesh is valid we will use it
if (Mesh)
{
IMeshSceneNode* node = SceneManager->addMeshSceneNode(Mesh);
node->setPosition(vector3df(0, -99999, 0));
node->getMesh()->setHardwareMappingHint(EHM_STATIC);
node->setName("plsDoNotDeleteMe");
node->setMaterialFlag(EMF_FOG_ENABLE, m_UseFog);
node->setMaterialFlag(EMF_LIGHTING, m_UseLight);
node->setMaterialType(EMT_TRANSPARENT_ALPHA_CHANNEL_REF);
// add the mesh to the list
IGE_MeshTemplate t(node, YOffset);
m_MeshTemplate.push_back(t);
}
}
// clear everything
void IGE_SceneNode_Vegetation::clear()
{
// clear the visible nodes / objects
if (!m_Nodes.empty())
{
for (u32 x = 0; x < m_Nodes.size(); x++)
{
if (m_Nodes[x] != NULL)
{
m_Nodes[x]->remove();
m_Nodes[x] = nullptr;
}
}
}
// clear all of the lists
m_Nodes.clear();
m_Nodes.reallocate(0, true);
m_NodePos.clear();
m_NodePos.reallocate(0, true);
m_NodeScale.clear();
m_NodeScale.reallocate(0, true);
m_NodeRotation.clear();
m_NodeRotation.reallocate(0, true);
m_NodeType.clear();
m_NodeType.reallocate(0, true);
m_IsNodePosFree.clear();
m_IsNodePosFree.reallocate(0, true);
}
void IGE_SceneNode_Vegetation::processLayout()
{
// if we dont have any node / object efinitions to use then bail
if (!(m_MeshTemplate.size() > 0))
{
printf("WARNING! IGE_SceneNode_Vegetation::processLayout() no plane templates found!\n");
return;
}
// if we dont have a terrain then bail
if (!m_Terrain)
{
printf("ERROR! IGE_SceneNode_Vegetation::processLayout() no terrain object found!\n");
return;
}
// make sure that we have a layout image else bail
if (!m_LayoutImage)
{
printf("ERROR! IGE_SceneNode_Vegetation::processLayout() no layout image\n");
return;
}
// get the edges of the terrain scenenode
aabbox3d<f32> terrainBox = m_Terrain->getBoundingBox();
Box = terrainBox;
float minX = terrainBox.MinEdge.X;
float minZ = terrainBox.MinEdge.Z;
m_Terrain->updateAbsolutePosition();
float terrainX = m_Terrain->getPosition().X;
float terrainZ = m_Terrain->getPosition().Z;
// get the parsing scale of the layout image vs the terrain sizes
float scaleX = terrainBox.getExtent().X / m_LayoutImage->getDimension().Width;
float scaleZ = terrainBox.getExtent().Z / m_LayoutImage->getDimension().Height;
float density = 1.0f;
// based on the density, run throught the lists
for (float i = minX; i < minX + terrainBox.getExtent().X; i+=density)
{
for (float ii = minZ; ii < minZ + terrainBox.getExtent().Z; )
{
// randomize the position a bit to prevent straight lines
vector3df randomness(
getRandomFloat(-m_LayoutRandomness.X, m_LayoutRandomness.X),
getRandomFloat(-m_LayoutRandomness.Y, 0),
getRandomFloat(-m_LayoutRandomness.Z, m_LayoutRandomness.Z));
// get the height of the terrain at the current position
float height = m_Terrain->getHeight(i + randomness.X, ii + randomness.Z);
//if (height > -99990)
{
// get the layout image pixel color at the point relative to the terrain
int x2 = (int)(i / scaleX);
int y2 = (int)(ii / scaleZ);
SColor pixel = m_LayoutImage->getPixel(x2, y2);
vector3df pos(terrainX + i + randomness.X, height + randomness.Y, terrainZ + ii + randomness.Z);
// let the user select a style based on the color
int style = getStyleFromLayoutImageColor(pixel, m_MeshTemplate.size(), pos);
vector3df scale = getScaleFromLayoutImageColor(pixel, m_MeshTemplate.size(), style, pos);
vector3df rotation = getRotationFromLayoutImageColor(pixel, m_MeshTemplate.size(), style, pos);
density = getDensityFromLayoutImageColor(pixel);
ii += density;
// if there is a style then a node should be created at this position
// add at least a NULL to each list to make sure the lists sizes are matched
if (style != -2)
{
pos.Y -= m_MeshTemplate[style].m_YOffset;
m_Nodes.push_back(nullptr);
m_NodeType.push_back(style);
m_NodePos.push_back(pos);
m_NodeScale.push_back(scale);
m_NodeRotation.push_back(rotation);
m_IsNodePosFree.push_back(true);
}
}
}
}
}
// check if a point is inside the viewfromcamera view frustrum
bool IGE_SceneNode_Vegetation::canBeSeenByCamPyramidPlanes(const SViewFrustum& frust, const vector3df& pos)
{
for (s32 i = 0; i < scene::SViewFrustum::VF_PLANE_COUNT; ++i)
{
if (frust.planes[i].classifyPointRelation(pos) == core::ISREL3D_FRONT)
return false;
}
return true;
}
// called each frame to update what is visible and what is not
void IGE_SceneNode_Vegetation::update(vector3df center, ICameraSceneNode* camera)
{
if (!isVisible()) return;
if (m_HelperForDeleting == 0) m_HelperForDeleting = 1; else m_HelperForDeleting = 0;
// make the frustum a little bigger to stop popping near the front plane
SViewFrustum origFrustum = *camera->getViewFrustum();
SViewFrustum frustum = origFrustum;
for (int i = 0; i < scene::SViewFrustum::VF_PLANE_COUNT; ++i)
{
frustum.planes[i].recalculateD(frustum.planes[i].getMemberPoint() + frustum.planes[i].Normal * m_VisibleOffset);
}
frustum.recalculateBoundingBox();
for (u32 i = m_HelperForDeleting; i < m_NodePos.size(); i += 2)
{
line3d<f32> ray;
ray.start = center;
ray.end = m_NodePos[i];
float d = ray.getLength();
if (m_IsNodePosFree[i] && d < m_ViewDistance && canBeSeenByCamPyramidPlanes(frustum, m_NodePos[i]))
{
if (m_MeshTemplate[m_NodeType[i]].m_Node != nullptr)
{
m_Nodes[i] = m_MeshTemplate[m_NodeType[i]].m_Node->clone();
m_Nodes[i]->setPosition(m_NodePos[i]);
m_Nodes[i]->setRotation(m_NodeRotation[i]);
m_Nodes[i]->setScale(m_NodeScale[i]);
m_Nodes[i]->setMaterialFlag(EMF_LIGHTING, m_UseLight);
m_Nodes[i]->setMaterialFlag(EMF_FOG_ENABLE, m_UseFog);
m_IsNodePosFree[i] = false;
}
}
else
{
if (d > m_ViewDistance || !canBeSeenByCamPyramidPlanes(frustum, m_NodePos[i]))
{
if (m_Nodes[i] != nullptr) m_Nodes[i]->remove(); m_Nodes[i] = nullptr;
m_IsNodePosFree[i] = true;
}
}
}
}
int IGE_SceneNode_Vegetation::getDensityFromLayoutImageColor(SColor pixel)
{
return 1;
}
int IGE_SceneNode_Vegetation::getStyleFromLayoutImageColor(SColor pixel, int templatesize, vector3df pos)
{
return (getRandomInteger(1,templatesize))-1;
}
vector3df IGE_SceneNode_Vegetation::getRotationFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos)
{
return vector3df(0, getRandomFloat(0, 360), 0);
}
vector3df IGE_SceneNode_Vegetation::getScaleFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos)
{
return vector3df(getRandomFloat(1, 3), getRandomFloat(1, 3), getRandomFloat(1, 3));
}
void IGE_SceneNode_Vegetation::setUseLight(bool v)
{
m_UseLight = v;
for (u32 i = 0; i < m_Nodes.size(); i++)
if (m_Nodes[i] != nullptr)
m_Nodes[i]->setMaterialFlag(E_MATERIAL_FLAG::EMF_LIGHTING, v);
for (u32 i = 0; i < m_MeshTemplate.size(); i++)
m_MeshTemplate[i].m_Node->setMaterialFlag(E_MATERIAL_FLAG::EMF_LIGHTING, v);
}
void IGE_SceneNode_Vegetation::setUseFog(bool v)
{
m_UseFog = v;
for (u32 i = 0; i < m_Nodes.size(); i++)
if (m_Nodes[i] != nullptr)
m_Nodes[i]->setMaterialFlag(E_MATERIAL_FLAG::EMF_FOG_ENABLE, v);
for (u32 i = 0; i < m_MeshTemplate.size(); i++)
m_MeshTemplate[i].m_Node->setMaterialFlag(E_MATERIAL_FLAG::EMF_FOG_ENABLE, v);
}
void IGE_SceneNode_Vegetation::setVisible(bool v)
{
if (isVisible() == v) return;
ISceneNode::setVisible(v);
for (u32 i = 0; i < m_Nodes.size(); i++)
if (m_Nodes[i] != nullptr)
m_Nodes[i]->setVisible(v);
for (u32 i = 0; i < m_MeshTemplate.size(); i++)
m_MeshTemplate[i].m_Node->setVisible(v);
}
} // end namspace IGE
Re: Vegetation SceneNode
and the final test program...........
Code: Select all
// to use a single model for all of this uncomment this line
// #define USE_SINGLE_MODEL
#define MODELNAME "media/_Assets/_Models/_Foliage/Seven/wheat1.obj"
#include <irrlicht.h>
#include "driverChoice.h"
#include "exampleHelper.h"
#include "IGE_SceneNode_Vegetation.h"
#include <conio.h>
using namespace irr;
using namespace video;
using namespace core;
using namespace gui;
using namespace scene;
using namespace io;
using namespace IGE;
// globals are easier for simple demos
IrrlichtDevice* device = 0;
video::IVideoDriver* driver = 0;
scene::ISceneManager* smgr = 0;
gui::IGUIEnvironment* env = 0;
// a few global variables specific to this demo
ITerrainSceneNode* terrain = 0; // the terrain to cover with grass
scene::ICameraSceneNode* MainCamera = 0; // the main FPS camera
scene::ICameraSceneNode* Camera2 = 0; // a test camera to check grass rendering through
bool useLight = false;
bool useFog = false;
// some view distances for each layer of vegetation
float VIEW_DISTANCE_GRASS = 10000;
float VIEW_DISTANCE_FLOWERS = 5000;
float VIEW_DISTANCE_SHRUBS = 7000;
float VIEW_DISTANCE_SMALLTREES = 8000;
float VIEW_DISTANCE_LARGETREES = 10000;
float VIEW_DISTANCE_ROCKS = 10000;
// the terrain scale
#define TERRAIN_SCALE vector3df(400.f, 4.4f, 400.f)
// the vegetation layers
array<IGE_SceneNode_Vegetation*> vegetationLayers;
/// /////////////////////////////////////////////////////////////////////
// create 6 new scenenodes, each derived from the IGE_SceneNode_Vegetation class
// this allows us to setup each layer independently
// I commented the first layer (grass) extensively but the others are the same just used for different scenenodes
/// /////////////////////////////////////////////////////////////////////
class IGE_SceneNode_Vegetation_Grass : public IGE_SceneNode_Vegetation
{
public:
//! constructor - do nothing constructor
IGE_SceneNode_Vegetation_Grass(ITerrainSceneNode* parent, stringc layoutimagefilename, float viewdistance, vector3df layoutrandomness, bool uselight, bool usefog, ISceneManager* smgr, s32 id)
: IGE_SceneNode_Vegetation(parent, layoutimagefilename, viewdistance,layoutrandomness, uselight, usefog, smgr, id)
{}
//! destructor - do nothing destructor
virtual ~IGE_SceneNode_Vegetation_Grass() {}
// override to provide scenenode with layout values based on pixel colors
// in this case we are just hard coding the values, but you could use the pizel color to determine each attribute
virtual int getDensityFromLayoutImageColor(SColor pixel) { return 200; }
// override to provide scenenode with layout values based on pixel colors
// in this case, if the pixel color green attribute is greater that 100 then return one of the grass templates
// otherwise return -2 which is interpreted as no grass node in this area
virtual int getStyleFromLayoutImageColor(SColor pixel, int templatesize, vector3df pos)
{
if (pixel.getGreen() > 100) return getRandomInteger(1, templatesize) - 1;
else return -2;
}
// override to provide scenenode with layout values based on pixel colors
// in this case we are just hard coding the values, but you could use the pizel color to determine each attribute
virtual vector3df getRotationFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(0, getRandomFloat(0, 360), 0); }
// override to provide scenenode with layout values based on pixel colors
// in this case we are just hard coding the values, but you could use the pizel color to determine each attribute
virtual vector3df getScaleFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(3, getRandomInteger(1,10), 3); }
};
class IGE_SceneNode_Vegetation_Flowers : public IGE_SceneNode_Vegetation
{
public:
//! constructor
IGE_SceneNode_Vegetation_Flowers(ITerrainSceneNode* parent, stringc layoutimagefilename, float viewdistance, vector3df layoutrandomness, bool uselight, bool usefog, ISceneManager* smgr, s32 id)
: IGE_SceneNode_Vegetation(parent, layoutimagefilename, viewdistance, layoutrandomness, uselight, usefog, smgr, id)
{}
//! destructor
virtual ~IGE_SceneNode_Vegetation_Flowers() {}
// override to provide scenenode with layout values based on pixel colors
virtual int getDensityFromLayoutImageColor(SColor pixel) { return 2000; }
virtual int getStyleFromLayoutImageColor(SColor pixel, int templatesize, vector3df pos) { return (getRandomInteger(1, templatesize)) - 1; }
virtual vector3df getRotationFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(0, getRandomFloat(0, 360), 0); }
virtual vector3df getScaleFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(3, 8, 3); }
};
class IGE_SceneNode_Vegetation_Shrubs : public IGE_SceneNode_Vegetation
{
public:
//! constructor
IGE_SceneNode_Vegetation_Shrubs(ITerrainSceneNode* parent, stringc layoutimagefilename, float viewdistance, vector3df layoutrandomness, bool uselight, bool usefog, ISceneManager* smgr, s32 id)
: IGE_SceneNode_Vegetation(parent, layoutimagefilename, viewdistance, layoutrandomness, uselight, usefog, smgr, id)
{}
//! destructor
virtual ~IGE_SceneNode_Vegetation_Shrubs() {}
// override to provide scenenode with layout values based on pixel colors
virtual int getDensityFromLayoutImageColor(SColor pixel) { return 1000; }
virtual int getStyleFromLayoutImageColor(SColor pixel, int templatesize, vector3df pos) { return (getRandomInteger(1, templatesize)) - 1; }
virtual vector3df getRotationFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(0, getRandomFloat(0, 360), 0); }
virtual vector3df getScaleFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(5, 5, 5); }
};
class IGE_SceneNode_Vegetation_SmallTrees : public IGE_SceneNode_Vegetation
{
public:
//! constructor
IGE_SceneNode_Vegetation_SmallTrees(ITerrainSceneNode* parent, stringc layoutimagefilename, float viewdistance, vector3df layoutrandomness, bool uselight, bool usefog, ISceneManager* smgr, s32 id)
: IGE_SceneNode_Vegetation(parent, layoutimagefilename, viewdistance, layoutrandomness, uselight, usefog, smgr, id)
{}
//! destructor
virtual ~IGE_SceneNode_Vegetation_SmallTrees() {}
// override to provide scenenode with layout values based on pixel colors
virtual int getDensityFromLayoutImageColor(SColor pixel) { return 3000; }
virtual int getStyleFromLayoutImageColor(SColor pixel, int templatesize, vector3df pos) { return (getRandomInteger(1, templatesize)) - 1; }
virtual vector3df getRotationFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(0, getRandomFloat(0, 360), 0); }
virtual vector3df getScaleFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(8, 8, 8); }
};
class IGE_SceneNode_Vegetation_LargeTrees : public IGE_SceneNode_Vegetation
{
public:
//! constructor
IGE_SceneNode_Vegetation_LargeTrees(ITerrainSceneNode* parent, stringc layoutimagefilename, float viewdistance, vector3df layoutrandomness, bool uselight, bool usefog, ISceneManager* smgr, s32 id)
: IGE_SceneNode_Vegetation(parent, layoutimagefilename, viewdistance, layoutrandomness, uselight, usefog, smgr, id)
{}
//! destructor
virtual ~IGE_SceneNode_Vegetation_LargeTrees() {}
// override to provide scenenode with layout values based on pixel colors
virtual int getDensityFromLayoutImageColor(SColor pixel) { return 4000; }
virtual int getStyleFromLayoutImageColor(SColor pixel, int templatesize, vector3df pos) { return (getRandomInteger(1, templatesize)) - 1; }
virtual vector3df getRotationFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(0, getRandomFloat(0, 360), 0); }
virtual vector3df getScaleFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(14,14,14); }
};
class IGE_SceneNode_Vegetation_Rocks : public IGE_SceneNode_Vegetation
{
public:
//! constructor
IGE_SceneNode_Vegetation_Rocks(ITerrainSceneNode* parent, stringc layoutimagefilename, float viewdistance, vector3df layoutrandomness, bool uselight, bool usefog, ISceneManager* smgr, s32 id)
: IGE_SceneNode_Vegetation(parent, layoutimagefilename, viewdistance, layoutrandomness, uselight, usefog, smgr, id)
{}
//! destructor
virtual ~IGE_SceneNode_Vegetation_Rocks() {}
// override to provide scenenode with layout values based on pixel colors
virtual int getDensityFromLayoutImageColor(SColor pixel) { return 5000; }
virtual int getStyleFromLayoutImageColor(SColor pixel, int templatesize, vector3df pos) { return (getRandomInteger(1, templatesize)) - 1; }
virtual vector3df getRotationFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(0, getRandomFloat(0, 360), 0); }
virtual vector3df getScaleFromLayoutImageColor(SColor pixel, int templatesize, int style, vector3df pos) { return vector3df(2, 2, 2); }
};
// create all of the vegetation
// in this case, we create 6 different scenenodes and add mesh templates to each
void createVegetation()
{
// if ther is no terrain then bail
if (!terrain)
{
printf("terrain node is not valid!");
return;
}
// clear any existing vegetation layers
for (u32 i = 0; i < vegetationLayers.size(); i++) vegetationLayers[i]->remove(); vegetationLayers.clear();
// create the layer and add some templates to it
IGE_SceneNode_Vegetation_Grass* grass = new IGE_SceneNode_Vegetation_Grass(terrain, "media/_Assets/_Foliage/_LayoutImages/grasslayout.jpg",VIEW_DISTANCE_GRASS, vector3df(5, 0, 5), useLight, useFog, smgr, 0);
#ifdef USE_SINGLE_MODEL
grass->addMeshTemplate(MODELNAME, 0);
#else
grass->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/misc/trop_grass(region).b3d", 0);
#endif
vegetationLayers.push_back(grass);
// create the layer and add some templates to it
IGE_SceneNode_Vegetation_Flowers* flowers = new IGE_SceneNode_Vegetation_Flowers(terrain, "media/_Assets/_Foliage/_LayoutImages/flowerslayout.jpg",VIEW_DISTANCE_FLOWERS, vector3df(50, 0, 50), useLight, useFog, smgr, 0);
#ifdef USE_SINGLE_MODEL
grass->addMeshTemplate(MODELNAME, 0);
#else
flowers->addMeshTemplate("media/_assets/_Models/_Foliage/tropical/arteria3d_tropicalpack/flowers/flower 1.x", 0);
flowers->addMeshTemplate("media/_assets/_Models/_Foliage/tropical/arteria3d_tropicalpack/flowers/flower 2.x", 0);
flowers->addMeshTemplate("media/_assets/_Models/_Foliage/tropical/arteria3d_tropicalpack/flowers/flower 3.x", 0);
flowers->addMeshTemplate("media/_assets/_Models/_Foliage/tropical/arteria3d_tropicalpack/flowers/flower 4.x", 0);
flowers->addMeshTemplate("media/_assets/_Models/_Foliage/tropical/arteria3d_tropicalpack/flowers/flower 5.x", 0);
flowers->addMeshTemplate("media/_assets/_Models/_Foliage/tropical/arteria3d_tropicalpack/flowers/flower 6.x", 0);
flowers->addMeshTemplate("media/_assets/_Models/_Foliage/tropical/arteria3d_tropicalpack/flowers/flower 7.x", 0);
#endif
vegetationLayers.push_back(flowers);
// create the layer and add some templates to it
IGE_SceneNode_Vegetation_Shrubs* shrubs = new IGE_SceneNode_Vegetation_Shrubs(terrain, "media/_Assets/_Foliage/_LayoutImages/shrubslayout.jpg", VIEW_DISTANCE_SHRUBS, vector3df(500, 0, 500), useLight, useFog, smgr, 0);
#ifdef USE_SINGLE_MODEL
grass->addMeshTemplate(MODELNAME, 0);
#else
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/fan plant.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/fan plant version 2.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/fan plant version 3.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant a.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant b.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant c.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant d.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant e.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant g.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant h.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant k.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant l.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant m.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant n.b3d", 0);
shrubs->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/plants/plant n version2.b3d", 0);
#endif
vegetationLayers.push_back(shrubs);
// create the layer and add some templates to it
IGE_SceneNode_Vegetation_SmallTrees* SmallTrees = new IGE_SceneNode_Vegetation_SmallTrees(terrain, "media/_Assets/_Foliage/_LayoutImages/smalltreeslayout.jpg", VIEW_DISTANCE_SMALLTREES, vector3df(500, 0, 500), useLight, useFog, smgr, 0);
#ifdef USE_SINGLE_MODEL
grass->addMeshTemplate(MODELNAME, 0);
#else
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/bananatree.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/bananatree version2.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/bananatree version2 b.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/floorpalm.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/floorpalm 2.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/palm1.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/palm2.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/palm3.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/palm3 B.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/palm3 C.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/palm4.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/palm5.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/palm6.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/worn palm.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/yuka.b3d", 0);
SmallTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/yuka 2.b3d", 0);
#endif
vegetationLayers.push_back(SmallTrees);
// create the layer and add some templates to it
IGE_SceneNode_Vegetation_LargeTrees* LargeTrees = new IGE_SceneNode_Vegetation_LargeTrees(terrain, "media/_Assets/_Foliage/_LayoutImages/largetreeslayout.jpg", VIEW_DISTANCE_LARGETREES, vector3df(500, 0, 500), useLight, useFog, smgr, 0);
#ifdef USE_SINGLE_MODEL
grass->addMeshTemplate(MODELNAME, 0);
#else
LargeTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/bananatree.b3d", 0);
LargeTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/bananatree version2.b3d", 0);
LargeTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/bananatree version2 b.b3d", 0);
LargeTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/floorpalm.b3d", 0);
LargeTrees->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/trees/floorpalm 2.b3d", 0);
#endif
vegetationLayers.push_back(LargeTrees);
// create the layer and add some templates to it
IGE_SceneNode_Vegetation_Rocks* rocks = new IGE_SceneNode_Vegetation_Rocks(terrain, "media/_Assets/_Foliage/_LayoutImages/rockslayout.jpg", VIEW_DISTANCE_ROCKS, vector3df(500, 0, 500), useLight, useFog, smgr, 0);
#ifdef USE_SINGLE_MODEL
grass->addMeshTemplate(MODELNAME, 0);
#else
rocks->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/rocks/rock1.x", 0);
rocks->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/rocks/rock2.x", 0);
rocks->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/rocks/rock3.x", 0);
rocks->addMeshTemplate("media/_assets/_models/_foliage/tropical/arteria3d_tropicalpack/rocks/rock4.x", 0);
#endif
vegetationLayers.push_back(rocks);
// now process all of the layers
// each layer will scan the layout image and create node positions, rotations and scales based on the layout image
for (u32 i = 0; i < vegetationLayers.size(); i++)
vegetationLayers[i]->processLayout();
}
// simple method to toggle lighting
void toggleUseLight()
{
useLight = !useLight;
for (u32 i = 0; i < vegetationLayers.size(); i++)
vegetationLayers[i]->setUseLight(useLight);
if (terrain) terrain->setMaterialFlag(E_MATERIAL_FLAG::EMF_LIGHTING, useLight);
}
// simple method to toggle fog
void toggleUseFog()
{
useFog = !useFog;
for (u32 i = 0; i < vegetationLayers.size(); i++)
vegetationLayers[i]->setUseFog(useFog);
if (terrain) terrain->setMaterialFlag(E_MATERIAL_FLAG::EMF_FOG_ENABLE, useFog);
}
// create everything specific to this demo
// we use two cameras so that the user can see the frustum in action if desired (press Q or W to toggle which camera the vegetation is referencing)
void createScene()
{
// add a test camera with a cube to show us where it is at
Camera2 = smgr->addCameraSceneNode();
Camera2->setFarValue(42000.0f);
// add the primary user controlled camera
MainCamera = smgr->addCameraSceneNodeFPS(0, 100.0f, 1.2f);
MainCamera->setPosition(core::vector3df(0, 500, 500));
MainCamera->setTarget(core::vector3df(0, 0, 0));
MainCamera->setFarValue(42000.0f);
MainCamera->setInputReceiverEnabled(false);
// add some lighting and fog
smgr->addLightSceneNode(MainCamera, vector3df(0, -50, 0), SColorf(0.5, 1, 1, 1), 4000);
smgr->addLightSceneNode(Camera2, vector3df(0, -50, 0), SColorf(0.5, 1, 1, 1), 4000);
driver->setFog(SColor(0,0,0,0),EFT_FOG_LINEAR,2000,8000);
// enable the mouse cursor
device->getCursorControl()->setVisible(true);
// add terrain scene node
terrain = smgr->addTerrainSceneNode(
"media/_assets/_terrain/heightmaps/terrain-plains.jpg",
0, // parent node
-1, // node id
core::vector3df(0.f, 0.f, 0.f), // position
core::vector3df(0.f, 0.f, 0.f), // rotation
TERRAIN_SCALE, // scale
video::SColor(255, 255, 255, 255), // vertexColor
5, // maxLOD
scene::ETPS_17, // patchSize
4 // smoothFactor
);
terrain->setMaterialFlag(video::EMF_LIGHTING, false);
terrain->setMaterialTexture(0, driver->getTexture("media/_assets/_terrain/textures/aerial_grass_rock_diff_4k.jpg"));
terrain->setMaterialTexture(1, driver->getTexture("media/_assets/_terrain/textures/aerial_grass_rock_diff_4k.jpg"));
terrain->setMaterialType(video::EMT_DETAIL_MAP);
terrain->scaleTexture(1.0f, 20.0f);
// create the vegetation
createVegetation();
// turn on lighting and fog for the scene
toggleUseLight();
toggleUseFog();
}
void createGui()
{
}
// simple eventhandler
class MyEventReceiver : public IEventReceiver
{
private:
public:
MyEventReceiver() : IEventReceiver()
{
}
virtual bool OnEvent(const SEvent& event)
{
switch (event.EventType)
{
// toggle camera isinputreceiving with the right mouse button
case EEVENT_TYPE::EET_MOUSE_INPUT_EVENT:
if (event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)
smgr->getActiveCamera()->setInputReceiverEnabled(!smgr->getActiveCamera()->isInputReceiverEnabled());
break;
case EEVENT_TYPE::EET_KEY_INPUT_EVENT:
if (event.KeyInput.PressedDown)
{
switch (event.KeyInput.Key)
{
case KEY_KEY_F: toggleUseFog(); break; // toggle fog use
case KEY_KEY_L: toggleUseLight(); break; // toggle light use
case KEY_KEY_Q:
for (u32 i = 0; i < vegetationLayers.size(); i++)
vegetationLayers[i]->setCameraToUse(MainCamera);
break; // toggle which camera the vegetation is referencing
case KEY_KEY_W:
Camera2->setPosition(MainCamera->getPosition());
Camera2->setTarget(MainCamera->getTarget());
Camera2->updateAbsolutePosition();
Camera2->render();
for (u32 i = 0; i < vegetationLayers.size(); i++)
vegetationLayers[i]->setCameraToUse(Camera2);
break; // toggle which camera the vegetation is referencing
// render further away
case KEY_PLUS :
for (u32 i = 0; i < vegetationLayers.size(); i++)
vegetationLayers[i]->setViewDistance(vegetationLayers[i]->getViewDistance() + 1000);
break;
// render closer
case KEY_MINUS:
for (u32 i = 0; i < vegetationLayers.size(); i++)
vegetationLayers[i]->setViewDistance(vegetationLayers[i]->getViewDistance() - 1000);
break;
// toggle individual vegetation layer visibility
case KEY_KEY_1:
vegetationLayers[0]->setVisible(!vegetationLayers[0]->isVisible());
break;
case KEY_KEY_2:
vegetationLayers[1]->setVisible(!vegetationLayers[1]->isVisible());
break;
case KEY_KEY_3:
vegetationLayers[2]->setVisible(!vegetationLayers[2]->isVisible());
break;
case KEY_KEY_4:
vegetationLayers[3]->setVisible(!vegetationLayers[3]->isVisible());
break;
case KEY_KEY_5:
vegetationLayers[4]->setVisible(!vegetationLayers[4]->isVisible());
break;
case KEY_KEY_6:
vegetationLayers[5]->setVisible(!vegetationLayers[5]->isVisible());
break;
}
}
break;
}
return false;
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// everything below here is just setting up the program
MyEventReceiver receiver;
bool genericDemoSetup()
{
// create device with full flexibility over creation parameters
// you can add more parameters if desired, check irr::SIrrlichtCreationParameters
irr::SIrrlichtCreationParameters params;
params.DriverType = EDT_OPENGL;
params.WindowSize = core::dimension2d<u32>(640, 480);
device = createDeviceEx(params);
if (device == 0) return false;
driver = device->getVideoDriver();
smgr = device->getSceneManager();
env = device->getGUIEnvironment();
driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true);
// create event receiver
device->setEventReceiver(&receiver);
return true;
}
int main()
{
// setup the demo
if (!genericDemoSetup()) return 1;
// create all of the items specific to this demo
createScene();
createGui();
// run the demo
int lastFPS = -1;
while (device->run())
if (device->isWindowActive())
{
driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0));
smgr->drawAll();
env->drawAll();
driver->endScene();
// display frames per second in window title
int fps = driver->getFPS();
if (lastFPS != fps)
{
core::stringw str = "FPS:"; str += fps;
str += " #Primitive Drawn = "; str += driver->getPrimitiveCountDrawn();
device->setWindowCaption(str.c_str());
lastFPS = fps;
}
}
device->drop();
printf("Press any key to continue, press any other ley to quit.........");
_getch();
return 0;
}
Re: Vegetation SceneNode
Keyboard entries :
1,2,3,4,5,6 hide / show layers
F - toggle using fog
L - toggle using light
Q - use main FPS camera for determining node visibility
W - place 2nd camera at FPS camera position and rotation (allows us to 'see' what the visibility frustum looks like
PLUS - increase visibility distance
MINUS - decrease visibility distance
right mouse - toggle FPS camera input receiver status
final thoughts :
I am pleased with the speed and the looks of the system. I like that it is now a scenenode also as I dont have to manage it in the program.
I am also pleased with the ability to control type, rotation and scale via images.
~ 400fps using 6 layers (grass, flowers, shrubs, small trees, large trees and rocks.
Processor Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz, 4008 Mhz, 4 Core(s), 8 Logical Processor(s)
NVidia GeForce GTX 1080 at 1920 x 1080 windowed mode
I think that I will create an octtree structure for holding node positions and whatnot. it might make it a little faster yet.
also will add feature to allow loading from file (maybe use XML to store mesh filenames)
oh well, off to work on the actual game program again.....
1,2,3,4,5,6 hide / show layers
F - toggle using fog
L - toggle using light
Q - use main FPS camera for determining node visibility
W - place 2nd camera at FPS camera position and rotation (allows us to 'see' what the visibility frustum looks like
PLUS - increase visibility distance
MINUS - decrease visibility distance
right mouse - toggle FPS camera input receiver status
final thoughts :
I am pleased with the speed and the looks of the system. I like that it is now a scenenode also as I dont have to manage it in the program.
I am also pleased with the ability to control type, rotation and scale via images.
~ 400fps using 6 layers (grass, flowers, shrubs, small trees, large trees and rocks.
Processor Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz, 4008 Mhz, 4 Core(s), 8 Logical Processor(s)
NVidia GeForce GTX 1080 at 1920 x 1080 windowed mode
I think that I will create an octtree structure for holding node positions and whatnot. it might make it a little faster yet.
also will add feature to allow loading from file (maybe use XML to store mesh filenames)
oh well, off to work on the actual game program again.....
Re: Vegetation SceneNode
Quadtree would be sufficient (basically same as octree but in 2d). Thought I prefer using grids in most cases (way simpler and often even faster). But that will improve speed only if the visibility checks are the bottleneck - if it's the sending to the gpu (which I'd suspect for this...) then it won't make a difference. With grids you might be able to merge similar objects together grid-wise so you have to send less nodes.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm