A few questions from a first-timer
A few questions from a first-timer
Hi,
I've been looking for a decent 3D engine for a project of mine, and irrlicht looks very impressive and *almost* what I'm after. But I'm not quite sure yet if it meets my requirements, and would greatly appreciate it if someone could put my mind at rest. I'm too lazy to wade through all the documentation, and I don't really need much of the functionality of irrlicht, although the speed is *very* nice.
What I'm trying to do is display an arbitrary rectangular heightmap in three dimensions, similar to but not quite the same as the terrain demo (#12), with one distant light source, and with an arbitrary colour for each point. For example, the heightmap could represent of a landscape, with the colours representing quantized levels (as in an atlas map) and the light source representing the Sun, or it could be the solution to an equation in three dimensions with an arbitrary image overlaid. So:
1. Currently, the code only seems to accept square heightmaps. Is there a way to allow rectangular heightmaps too?
2. The file CTerrainSceneMap.cpp has two very similar functions for loading heightmaps, one which reads from a bitmap and one which reads raw data. Would it be possible to move the code which sets the individual heights into its own function, so that it's easy to add support for other formats without having to copy the entire function verbatim?
3. How would I set a single light source to cast shadows?
4. How would I associate a particular colour with a single point in the heightmap?
I hope this makes some kind of sense! Thanks in advance for any help.
I've been looking for a decent 3D engine for a project of mine, and irrlicht looks very impressive and *almost* what I'm after. But I'm not quite sure yet if it meets my requirements, and would greatly appreciate it if someone could put my mind at rest. I'm too lazy to wade through all the documentation, and I don't really need much of the functionality of irrlicht, although the speed is *very* nice.
What I'm trying to do is display an arbitrary rectangular heightmap in three dimensions, similar to but not quite the same as the terrain demo (#12), with one distant light source, and with an arbitrary colour for each point. For example, the heightmap could represent of a landscape, with the colours representing quantized levels (as in an atlas map) and the light source representing the Sun, or it could be the solution to an equation in three dimensions with an arbitrary image overlaid. So:
1. Currently, the code only seems to accept square heightmaps. Is there a way to allow rectangular heightmaps too?
2. The file CTerrainSceneMap.cpp has two very similar functions for loading heightmaps, one which reads from a bitmap and one which reads raw data. Would it be possible to move the code which sets the individual heights into its own function, so that it's easy to add support for other formats without having to copy the entire function verbatim?
3. How would I set a single light source to cast shadows?
4. How would I associate a particular colour with a single point in the heightmap?
I hope this makes some kind of sense! Thanks in advance for any help.
-
- Admin
- Posts: 14143
- Joined: Wed Apr 19, 2006 9:20 pm
- Location: Oldenburg(Oldb), Germany
- Contact:
I think the problem is that no one really understood what you intend to do. The questions are not really that hard:
Improvability of the terrain scene node is rather hard to argue about, because it's a huge code basis which was written for this specific purpose. So I doubt that rectangular terrain maps are easily addable, but should be possible. However the terrain mesh should support this (and I guess that you don't need LOD anyway)!
You can load your heightmap manually into an IImage structure and pass that one to the terrain node. This allows arbitrary loaders. But if you have some suggestions we'll happily look into it.
Just create one light node and add the shadow volume node to your meshes that should cast a shadow.
You need access to the vertices (where you could add vertex colors) or use a texture which spans the terrain exactly.
Improvability of the terrain scene node is rather hard to argue about, because it's a huge code basis which was written for this specific purpose. So I doubt that rectangular terrain maps are easily addable, but should be possible. However the terrain mesh should support this (and I guess that you don't need LOD anyway)!
You can load your heightmap manually into an IImage structure and pass that one to the terrain node. This allows arbitrary loaders. But if you have some suggestions we'll happily look into it.
Just create one light node and add the shadow volume node to your meshes that should cast a shadow.
You need access to the vertices (where you could add vertex colors) or use a texture which spans the terrain exactly.
OK; thanks for reassuring me that I wasn't asking the impossible! Please excuse my ignorance of the workings of irrlicht; I will probably still have to ask too many stupid questions here.
Maybe I should explain my main problem a bit more clearly... I'm trying to do a few very simple things, but there is rather a lot of source code to read before I can figure out how to do them in irrlicht, even if it's just one line of code. So, while "RTFM" may be a reasonable answer, there is a lot of TFM to R, and I'm not sure where TFM actually is.
Anyway, if I start from the terrain demo, could you tell me the specific function calls would I need to add to it so that I can do the following, or at least point me in the right direction?
- load my rectangular heightmap from a file
- add a lightnode, move it around, and make it cast shadows
- add (or set?) vertex colours arbitrarily
Thanks again.
What is LOD? Load-on-demand???hybrid wrote:Improvability of the terrain scene node is rather hard to argue about, because it's a huge code basis which was written for this specific purpose. So I doubt that rectangular terrain maps are easily addable, but should be possible. However the terrain mesh should support this (and I guess that you don't need LOD anyway)!
What I'd ideally like is a function which loads a rectangular heightmap (or terrain node?) with 16-bit values from a file, which can be reimplemented to allow arbitrary file formats. I'm not sure if I'm looking at the right header file, but IImage.h talks about images, not anything obviously related to heightmaps.hybrid wrote:You can load your heightmap manually into an IImage structure and pass that one to the terrain node. This allows arbitrary loaders. But if you have some suggestions we'll happily look into it.
I'm sure this can be done with one line of code, but I'm at a loss to figure out howhybrid wrote:Just create one light node and add the shadow volume node to your meshes that should cast a shadow.
Adding vertex colours sounds like what I want to do.hybrid wrote:You need access to the vertices (where you could add vertex colors) or use a texture which spans the terrain exactly.
Maybe I should explain my main problem a bit more clearly... I'm trying to do a few very simple things, but there is rather a lot of source code to read before I can figure out how to do them in irrlicht, even if it's just one line of code. So, while "RTFM" may be a reasonable answer, there is a lot of TFM to R, and I'm not sure where TFM actually is.
Anyway, if I start from the terrain demo, could you tell me the specific function calls would I need to add to it so that I can do the following, or at least point me in the right direction?
- load my rectangular heightmap from a file
- add a lightnode, move it around, and make it cast shadows
- add (or set?) vertex colours arbitrarily
Thanks again.
-
- Admin
- Posts: 14143
- Joined: Wed Apr 19, 2006 9:20 pm
- Location: Oldenburg(Oldb), Germany
- Contact:
For the shadow you should check example 8 from the tutorials, should explain everything. The terrain mesh (which is not restricted in dimensions, but also doesn't feature things like LOD) can be added directly from the SceneManager. The online docs will help
http://irrlicht.sourceforge.net/docu/index.html
Since the terrain mesh (in contrast to the terrain scene node) is a simple IMesh, you can access it via the typical IMesh methods. Direct access to the vertices allows to alter those values, including the vertex colors.
heightmaps are simply images, usually greymaps. So creating an image from the heightmap is a pretty usual idea. Reading the data with the IReadFile methods is simple, so if you need a special RAW format it's not too much to implement.
http://irrlicht.sourceforge.net/docu/index.html
Since the terrain mesh (in contrast to the terrain scene node) is a simple IMesh, you can access it via the typical IMesh methods. Direct access to the vertices allows to alter those values, including the vertex colors.
heightmaps are simply images, usually greymaps. So creating an image from the heightmap is a pretty usual idea. Reading the data with the IReadFile methods is simple, so if you need a special RAW format it's not too much to implement.
Almost there...
OK, I think I just need to ask two more stupid questions, and I should be able to continue by myself.
1. Is it correct to use an IMeshManipulator to set the vertex colours?
2. The code below shows the current state of my program. I've set up a test mesh with a ripple-like pattern (that's the sin(sqrt(...)) bit) and am trying to look at it from directly above, with the light in the same place as the camera, but I see nothing. Setting all the mesh values to zero makes no difference. What have I forgotten to do?
Geoff
1. Is it correct to use an IMeshManipulator to set the vertex colours?
2. The code below shows the current state of my program. I've set up a test mesh with a ripple-like pattern (that's the sin(sqrt(...)) bit) and am trying to look at it from directly above, with the light in the same place as the camera, but I see nothing. Setting all the mesh values to zero makes no difference. What have I forgotten to do?
Geoff
Code: Select all
#include <irrlicht.h>
#include <iostream>
#include <math.h>
using namespace irr;
//////////////////////////////////////////////////////////////////////////////
class TMesh: public irr::scene::SMesh
{
private:
int w, h;
u32 **data;
u16 **I;
public:
TMesh(u16 w, u16 h) : irr::scene::SMesh()
{
u16 s = sqrt(w * w + h * h) / 4;
for(u16 i = 0; i < h; i ++)
{
u32 *data = new u32[w];
u16 *ind = new u16[w];
for(u16 j = 0; j < w; j ++)
{
u16 ww = j - w / 2, hh = i - h / 2;
data[j] = sin(sqrt(ww * ww + hh * hh) / s);
ind[j] = j;
}
scene::SMeshBuffer *buf = new scene::SMeshBuffer();
buf -> append(data, w, ind, w);
addMeshBuffer(buf);
}
}
};
//////////////////////////////////////////////////////////////////////////////
int main()
{
IrrlichtDevice* device = createDevice(video::EDT_OPENGL,
core::dimension2d<s32>(640, 480));
if(device == 0) return 1;
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
gui::IGUIEnvironment* env = device->getGUIEnvironment();
core::vector3df cam = core::vector3df( 0.f, 100.f, 0.f);
core::vector3df target = core::vector3df( 0.f, 0.f, 0.f);
scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(0, cam, target);
TMesh m = TMesh(32, 32);
smgr->addMeshSceneNode(&m);
smgr->addLightSceneNode(0, cam);
while(device->run())
{
if(!device->isWindowActive()) continue;
driver->beginScene(true, true, 0);
smgr->drawAll();
env->drawAll();
driver->endScene();
}
device->drop();
return 0;
}
//////////////////////////////////////////////////////////////////////////////
-
- Admin
- Posts: 14143
- Joined: Wed Apr 19, 2006 9:20 pm
- Location: Oldenburg(Oldb), Germany
- Contact:
Well, MeshBuffers don't take just a u32 as data, but a S3DVertex (how else should we render 3d data ) So look up the S3DVertex struct and use the following way to fill the buffer:
I hope I have put everything there now. I guess we should make a new tutorial with this code for people to know how to work with the SMesh and SMeshBuffer
Code: Select all
scene::SMeshBuffer *buf = new scene::SMeshBuffer();
buf->Vertices.reallocate(w*h);
addMeshBuffer(buf);
// in the i/j loop, check the other values on your own, normals are necessary for lighting and vertex color is directly accessible here :-)
buf->Vertices.pushback(S3DVertex(i,j,sin(sqrt(ww * ww + hh * hh) / s), ...);
// and after the loop
recalculateBoundingBox();
Still not there yet! Here's the revised definition of TMesh, which generates a completely flat surface with normals pointing straight up:
This still shows totally black, and changing the normals makes no difference. Although, if I ignore TMesh and do this instead:
I get something recognisable.
Code: Select all
class TMesh: public SMesh
{
private:
int w, h;
public:
TMesh(u16 w, u16 h) : SMesh()
{
SMeshBuffer *buf = new SMeshBuffer();
buf->Vertices.reallocate(w * h);
addMeshBuffer(buf);
for(u16 y = 0; y < h; y ++)
{
for(u16 x = 0; x < w; x ++)
{
f32 xx = 1.0 * (x - w / 2), yy = 1.0 * (y - h / 2);
f32 z = 0.0;
f32 nx = 0.0, ny = 1.0, nz = 0.0;
SColor c = SColor(255, 255, 255, 255);
S3DVertex v = S3DVertex(xx, yy, z, nx, ny, nz, c, 0, 0);
buf->Vertices.push_back(v);
}
}
buf -> recalculateBoundingBox();
recalculateBoundingBox();
}
};
Code: Select all
IAnimatedMesh* imesh = smgr->getMesh("sydney.md2");
IMesh *pmesh = imesh -> getMesh(0);
smgr->addMeshSceneNode(pmesh);
Yes, that would be very usefulhybrid wrote:I guess we should make a new tutorial with this code for people to know how to work with the SMesh and SMeshBuffer
Some progress, but much weirdness now. Here's the latest version of my code:
I found out that setting up the indices (buf -> Indices) caused some things to be displayed. However, I don't understand why it should be necessary to create a list which merely contains the nonnegative integers in sequence; why do you need an array like {0, 1, 2, 3, 4, 5}?
As before, the new mesh is supposed to be completely flat with normals at right angles to the line of sight. I'd expect to see a solid white square against a black background; however, what I actually see is four columns, slightly off the vertical, of little white lines which are longest at the bottom of the columns and degenerate to dots at the top. If I change the mesh size from 15x15 to 5x5, I see a small white triangle. If I change it to 7x7, 13x13, or 19x19 I see nothing; 9x9 gives two columns of lines, 11x11 gives three, and 17x17 gives five. What is happening here?
On a different note, if I change the driver to EDT_OPENGL, everything always comes up white regardless of what SColor c is set to.
Code: Select all
#include <irrlicht.h>
#include <iostream>
#include <math.h>
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
using namespace std;
//////////////////////////////////////////////////////////////////////////////
class TMesh: public SMesh
{
private:
int w, h;
public:
TMesh(u16 w, u16 h) : SMesh()
{
SMeshBuffer *buf = new SMeshBuffer();
addMeshBuffer(buf);
buf -> Vertices.reallocate(w * h);
buf -> Indices.reallocate( w * h);
SColor c = SColor(255, 255, 255, 255);
u16 n = 0;
for(s16 y = -h / 2; y < h / 2; y ++)
{
for(s16 x = -w / 2; x < w / 2; x ++)
{
vector3df pos = vector3df(x, 0, y);
vector3df norm = vector3df(1, 0, 0);
vector2d<f32> t = vector2d<f32>(0, 0);
buf -> Vertices.push_back(S3DVertex(pos, norm, c, t));
buf -> Indices.push_back(n ++);
}
}
buf -> recalculateBoundingBox();
recalculateBoundingBox();
}
};
//////////////////////////////////////////////////////////////////////////////
int main()
{
video::E_DRIVER_TYPE driverType = video::EDT_SOFTWARE;
IrrlichtDevice* device = createDevice(driverType,
core::dimension2d<s32>(640, 480));
if(device == 0) return 1;
IVideoDriver *driver = device -> getVideoDriver();
ISceneManager *smgr = device -> getSceneManager();
IGUIEnvironment *env = device -> getGUIEnvironment();
vector3df cam = vector3df( 0.f, 15.f, 0.f);
vector3df target = vector3df( 0.f, 0.f, 0.f);
vector3df light = vector3df(10.f, 0.f, 0.f);
TMesh mesh = TMesh(15, 15);
smgr -> addMeshSceneNode(&mesh);
smgr -> addCameraSceneNode(0, cam, target);
smgr -> addLightSceneNode(0, light);
while(device->run())
{
if(!device->isWindowActive()) continue;
driver->beginScene(true, true, SColor(0, 0, 0, 0));
smgr->drawAll();
env->drawAll();
driver->endScene();
}
device->drop();
return 0;
}
As before, the new mesh is supposed to be completely flat with normals at right angles to the line of sight. I'd expect to see a solid white square against a black background; however, what I actually see is four columns, slightly off the vertical, of little white lines which are longest at the bottom of the columns and degenerate to dots at the top. If I change the mesh size from 15x15 to 5x5, I see a small white triangle. If I change it to 7x7, 13x13, or 19x19 I see nothing; 9x9 gives two columns of lines, 11x11 gives three, and 17x17 gives five. What is happening here?
On a different note, if I change the driver to EDT_OPENGL, everything always comes up white regardless of what SColor c is set to.
then you realy should learn the basics of 3d arts !!!geoff wrote:I found out that setting up the indices (buf -> Indices) caused some things to be displayed. However, I don't understand why it should be necessary to create a list which merely contains the nonnegative integers in sequence; why do you need an array like {0, 1, 2, 3, 4, 5}?
look here, this might help you understanding this: http://irrlicht.sourceforge.net/phpBB2/ ... 367#171367
while(!asleep) sheep++;
IrrExtensions:
http://abusoft.g0dsoft.com
try Stendhal a MORPG written in Java
IrrExtensions:
http://abusoft.g0dsoft.com
try Stendhal a MORPG written in Java
-
- Admin
- Posts: 14143
- Joined: Wed Apr 19, 2006 9:20 pm
- Location: Oldenburg(Oldb), Germany
- Contact:
Oh yes, indices are mandatory. Sorry that I skipped this in the first place, but I really thought that you saw something unlit instead of just nothing
However, your indices are quite wrong, that's why you get the wrong results. You need to triangulate your plane, because SMeshBuffer requires triangles. Also note that you need to use clockwise orientation of the faces. So the following quad results in indices 0,1,2,1,3,2
And now indices also help to avoid using too many vertex duplicates, because in this example 1 and 2 are part of two faces, but need to be defined in the vertex array only once.
However, your indices are quite wrong, that's why you get the wrong results. You need to triangulate your plane, because SMeshBuffer requires triangles. Also note that you need to use clockwise orientation of the faces. So the following quad results in indices 0,1,2,1,3,2
Code: Select all
0---1
| / |
| / |
2---3