spherical terrain node or height mapping a sphere?

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Granyte
Posts: 850
Joined: Tue Jan 25, 2011 11:07 pm
Contact:

spherical terrain node or height mapping a sphere?

Post by Granyte »

ive been trying to get a sphere to ajust based on a height map i have


but so far no way to make the height map work on a sphere(maybe i just havent found the right texture channel)

as for creatin as custom terrain node i guess i could write this but i would still need a hint in the right direction on how to write a such code
bitplane
Admin
Posts: 3204
Joined: Mon Mar 28, 2005 3:45 am
Location: England
Contact:

Post by bitplane »

See the special effects example. earth.x uses a bump/parallax map for this.

If you want to create a huge world with a sphere as the terrain, then you've stumbled into a rather hard problem.
Submit bugs/patches to the tracker!
Need help right now? Visit the chat room
Granyte
Posts: 850
Joined: Tue Jan 25, 2011 11:07 pm
Contact:

Post by Granyte »

you guessed i stumbeled in the second problem
i adapted the code in the example but since it does not modifie the mesh all the sphere remain under the water lvl
bitplane
Admin
Posts: 3204
Joined: Mon Mar 28, 2005 3:45 am
Location: England
Contact:

Post by bitplane »

The problem is that 32-bit floats can only hold 24 bits of information not including scale, the underlying graphics APIs work in 32-bit floats. If you want objects to be positioned with an accuracy of 1mm (at 60 frames per second a minimum speed of 6cm per second; 0.12 MPH) then you can only have a world that is 16.78km in size.

Irrlicht's scene manager holds positions in floats, so if you want a large world you'd need to separate the physical representation and graphical representation of your world, drawing distant objects first then near objects as their zones are in range. ultramedia is using latitude, longitude and altitude to hold positions on his world.

The heightmap of an earth-sized planet at one pixel per kilometre, using a 32-bit float for each one would be about 2GB. The mesh data would be much larger, maybe 200GB. You'd need to generate it using some fractal algorithm (again, see ultramedia's screenshots) or stream it from the Internet (if you're Google) rather than loading it from disk and just dumping it into RAM.

This is all pretty advanced stuff, you should probably work on an easier project if you're new to all this. If not, I hope I've pointed you in the right direction :)
Submit bugs/patches to the tracker!
Need help right now? Visit the chat room
Radikalizm
Posts: 1215
Joined: Tue Jan 09, 2007 7:03 pm
Location: Leuven, Belgium

Post by Radikalizm »

bitplane wrote: or stream it from the Internet (if you're Google)
That bit cracked me up ^^

I don't know if this would be of any help, but if you really want to develop this further, Nvidia shows a nice implementation of fractal terrain generation in one of their GPU Gems books, although I'm not sure whether this was D3D10-dependent or not (I should look that up)
Anthony
Posts: 121
Joined: Sun Jan 09, 2011 12:03 pm

Post by Anthony »

To create a sphere, take the vertices
1,0,0
0,1,0
0,0,1
-1,0,0
0,-1,0
0,0,-1

and create a cube via indices. Normalize them times ( radius + height ) and you get a perfect misformed cude if the heights ain't 0.

So you have six planes now but you want a sphere, take the middle of each edge and normalize it too (divide a triangle and you have 4 triangles). The more you divide the rounder it will be.

divide the six planes of the cude into patches for faster frustum culling. Also you would need six textures as heightmap (or a tiled one perhaps).

instead of having the heights in an array maybe - don't know how it impacts in speed - you could retrieve only the ones you need out of the bmp each frame.

then you can create the patches each frame with data out of the heightmap.

This won't take up 200GB, hence not even 2GB. At leased is you draw them with drawIndexedTriangleList in a recurive render list as you only draw one triangle at the time. (have to optimize this myself, propably much to do here)

Until here I get it myself 8)

Now to reduce the triangles even further I am trying to use the ROAM algorithm. For now just as a planar terrain to get the basics with easier calculations.

hope this helps a bit

EDIT: This isn't a full answer but just to give you some direction as I am only a few steps in front of you in this field ;)
EDIT: What you don't need i.e. the other side of the sphere's data, you can 'forget' about that. Thus having 6 planes as base of the sphere helps you here too. Hence everything you don't see the system doesn't need to know, only an alghorithme that will ping the system to get new data.
EDIT: hehe like to edit today ;)
talked about a dividing earlier like this.

Code: Select all

+-------
|  /|  /
| / | /
|/  |/
|---/
|  /
| /
|/
but you need to aim at dividing as the next for the ROAM alghorithme

Code: Select all

+-----+-----+
|\   /|    /|
| \ / |   / | 
|  X  |  /  | 
|   \ | /   | 
|    \|/    |
|     X     |
|    /      |
|   /       |
|  /        |
| /         |
|/          |
+-----------+
No :shock: I am no noob, just checking if your not one too :roll:

Thanks to Niko and all others that made Irrlicht possible.
Grz-
Posts: 62
Joined: Wed Dec 26, 2007 1:06 pm

Post by Grz- »

I made a scene node a while ago (based on the sphere scene node) which use that technic to apply a heightmap to a sphere:

http://ahuynh.posterous.com/article-1-g ... -in-opengl

It suck a bit tho (Anthony way to do it is far better) as there is holes on poles, i think the code run ok but maybe there is some bugs as i hacked that in few hours and abandonned it.

Polycount is unused as it use the width/height of the heightmap to adjust it automatically and to set the height of the terrain you have to modify this line (or add a method) in "createSphericalTerrainMesh":

Code: Select all

f32 maxHeight = 20.0f;
The heightmap have to be (preferably) transformed into polar coordinate and should look like this:

Image

CSphericalTerrainSceneNode.cpp:

Code: Select all

#include "CSphericalTerrainSceneNode.h"
#include "IVideoDriver.h"
#include "ISceneManager.h"
#include "S3DVertex.h"
#include "SMeshBuffer.h"
#include "SMesh.h"

namespace irr
{
namespace scene
{

//! constructor
CSphericalTerrainSceneNode::CSphericalTerrainSceneNode(const io::path& heightMapFileName, ISceneManager* mgr, f32 radius, u32 polyCountX, u32 polyCountY, ISceneNode* parent, s32 id,
			const core::vector3df& position, const core::vector3df& rotation, const core::vector3df& scale)
: IMeshSceneNode(parent, mgr, id, position, rotation, scale), Mesh(0),
	Radius(radius), PolyCountX(polyCountX), PolyCountY(polyCountY)
{
	#ifdef _DEBUG
	setDebugName("CSphericalTerrainSceneNode");
	#endif

	io::IReadFile* file = SceneManager->getFileSystem()->createAndOpenFile(heightMapFileName);
	HeightmapFile = file->getFileName();

	if(!file)
	{
//		os::Printer::log("Could not load spherical terrain, because file could not be opened.",
//		heightMapFileName, ELL_ERROR); ilogger
	}
    else
        Mesh = createSphericalTerrainMesh(SceneManager->getVideoDriver()->createImageFromFile(file), radius, polyCountX, polyCountY);

    if(file)
		file->drop();
}

CSphericalTerrainSceneNode::CSphericalTerrainSceneNode(io::IReadFile* heightMapFile, ISceneManager* mgr, f32 radius, u32 polyCountX, u32 polyCountY, ISceneNode* parent, s32 id,
			const core::vector3df& position, const core::vector3df& rotation, const core::vector3df& scale)
: IMeshSceneNode(parent, mgr, id, position, rotation, scale), Mesh(0),
	Radius(radius), PolyCountX(polyCountX), PolyCountY(polyCountY)
{
	#ifdef _DEBUG
	setDebugName("CSphericalTerrainSceneNode");
	#endif

    HeightmapFile = heightMapFile->getFileName();
	if(!heightMapFile)
	{
		//os::Printer::log("Could not load spherical terrain, because file could not be opened.", ELL_ERROR);
	}
	else
        Mesh = createSphericalTerrainMesh(SceneManager->getVideoDriver()->createImageFromFile(heightMapFile), radius, polyCountX, polyCountY);
}

//! destructor
CSphericalTerrainSceneNode::~CSphericalTerrainSceneNode()
{
	if (Mesh)
		Mesh->drop();
}


//! renders the node.
void CSphericalTerrainSceneNode::render()
{
	video::IVideoDriver* driver = SceneManager->getVideoDriver();

	if (Mesh && driver)
	{
		driver->setMaterial(Mesh->getMeshBuffer(0)->getMaterial());
		driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
		driver->drawMeshBuffer(Mesh->getMeshBuffer(0));
		if ( DebugDataVisible & scene::EDS_BBOX )
		{
			video::SMaterial m;
			m.Lighting = false;
			driver->setMaterial(m);
			driver->draw3DBox(Mesh->getMeshBuffer(0)->getBoundingBox(), video::SColor(255,255,255,255));
		}
	}
}



//! returns the axis aligned bounding box of this node
const core::aabbox3d<f32>& CSphericalTerrainSceneNode::getBoundingBox() const
{
	return Mesh ? Mesh->getBoundingBox() : Box;
}


void CSphericalTerrainSceneNode::OnRegisterSceneNode()
{
	if (IsVisible)
		SceneManager->registerNodeForRendering(this);

	ISceneNode::OnRegisterSceneNode();
}


//! returns the material based on the zero based index i. To get the amount
//! of materials used by this scene node, use getMaterialCount().
//! This function is needed for inserting the node into the scene hirachy on a
//! optimal position for minimizing renderstate changes, but can also be used
//! to directly modify the material of a scene node.
video::SMaterial& CSphericalTerrainSceneNode::getMaterial(u32 i)
{
	if (i>0 || !Mesh)
		return ISceneNode::getMaterial(i);
	else
		return Mesh->getMeshBuffer(i)->getMaterial();
}


//! returns amount of materials used by this scene node.
u32 CSphericalTerrainSceneNode::getMaterialCount() const
{
	return 1;
}


//! Writes attributes of the scene node.
void CSphericalTerrainSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
	ISceneNode::serializeAttributes(out, options);

	out->addFloat("Radius", Radius);
	out->addInt("PolyCountX", PolyCountX);
	out->addInt("PolyCountY", PolyCountY);
}


//! Reads attributes of the scene node.
void CSphericalTerrainSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
	f32 oldRadius = Radius;
	u32 oldPolyCountX = PolyCountX;
	u32 oldPolyCountY = PolyCountY;

	Radius = in->getAttributeAsFloat("Radius");
	PolyCountX = in->getAttributeAsInt("PolyCountX");
	PolyCountY = in->getAttributeAsInt("PolyCountY");
	// legacy values read for compatibility with older versions
	u32 polyCount = in->getAttributeAsInt("PolyCount");
	if (PolyCountX ==0 && PolyCountY == 0)
		PolyCountX = PolyCountY = polyCount;

	Radius = core::max_(Radius, 0.0001f);

	if ( !core::equals(Radius, oldRadius) || PolyCountX != oldPolyCountX || PolyCountY != oldPolyCountY)
	{
		if (Mesh)
			Mesh->drop();
//        Mesh = createSphericalTerrainMesh(Radius, PolyCountX, PolyCountY);
		//Mesh = SceneManager->getGeometryCreator()->createSphereMesh(Radius, PolyCountX, PolyCountY);
	}

	ISceneNode::deserializeAttributes(in, options);
}

//! Creates a clone of this scene node and its children.
ISceneNode* CSphericalTerrainSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager)
{
	if (!newParent)
		newParent = Parent;
	if (!newManager)
		newManager = SceneManager;

    io::IReadFile* file = SceneManager->getFileSystem()->createAndOpenFile(HeightmapFile.c_str());
	CSphericalTerrainSceneNode* nb = new CSphericalTerrainSceneNode(file, newManager, Radius, PolyCountX, PolyCountY, newParent,
		ID, RelativeTranslation);
    if(file)
    {
        file->drop();
    }

	nb->cloneMembers(this, newManager);
	nb->getMaterial(0) = Mesh->getMeshBuffer(0)->getMaterial();

	if ( newParent )
		nb->drop();
	return nb;
}

IMesh* CSphericalTerrainSceneNode::createSphericalTerrainMesh(video::IImage* heightMap, f32 radius, u32 polyCountX, u32 polyCountY)
{
	// thanks to Alfaz93 who made his code available for Irrlicht on which
	// this one is based!

	// we are creating the sphere mesh here.

	if (!heightMap)
        return 0;

    const core::dimension2d<u32> hMapSize= heightMap->getDimension();

    polyCountX = hMapSize.Width-1;
    polyCountY = hMapSize.Height-1;
    f32 maxHeight = 20.0f;
    maxHeight /= 255.0f;

	if (polyCountX < 2)
		polyCountX = 2;
	if (polyCountY < 2)
		polyCountY = 2;
	while (polyCountX * polyCountY > 32767) // prevent u16 overflow
	{
		polyCountX /= 2;
		polyCountY /= 2;
	}

	const u32 polyCountXPitch = polyCountX+1; // get to same vertex on next level

	SMeshBuffer* buffer = new SMeshBuffer();

	buffer->Indices.reallocate((polyCountX * polyCountY) * 6);

	const video::SColor clr(100, 255,255,255);

	u32 level = 0;

	for (u32 p1 = 0; p1 < polyCountY-1; ++p1)
	{
		//main quads, top to bottom
		for (u32 p2 = 0; p2 < polyCountX - 1; ++p2)
		{
			const u32 curr = level + p2;
			buffer->Indices.push_back(curr + polyCountXPitch);
			buffer->Indices.push_back(curr);
			buffer->Indices.push_back(curr + 1);
			buffer->Indices.push_back(curr + polyCountXPitch);
			buffer->Indices.push_back(curr+1);
			buffer->Indices.push_back(curr + 1 + polyCountXPitch);
		}

		// the connectors from front to end
		buffer->Indices.push_back(level + polyCountX - 1 + polyCountXPitch);
		buffer->Indices.push_back(level + polyCountX - 1);
		buffer->Indices.push_back(level + polyCountX);

		buffer->Indices.push_back(level + polyCountX - 1 + polyCountXPitch);
		buffer->Indices.push_back(level + polyCountX);
		buffer->Indices.push_back(level + polyCountX + polyCountXPitch);
		level += polyCountXPitch;
	}

	const u32 polyCountSq = polyCountXPitch * polyCountY; // top point
	const u32 polyCountSq1 = polyCountSq + 1; // bottom point
	const u32 polyCountSqM1 = (polyCountY - 1) * polyCountXPitch; // last row's first vertex

	for (u32 p2 = 0; p2 < polyCountX - 1; ++p2)
	{
		// create triangles which are at the top of the sphere

		buffer->Indices.push_back(polyCountSq);
		buffer->Indices.push_back(p2 + 1);
		buffer->Indices.push_back(p2);

		// create triangles which are at the bottom of the sphere

		buffer->Indices.push_back(polyCountSqM1 + p2);
		buffer->Indices.push_back(polyCountSqM1 + p2 + 1);
		buffer->Indices.push_back(polyCountSq1);
	}

	// create final triangle which is at the top of the sphere

	buffer->Indices.push_back(polyCountSq);
	buffer->Indices.push_back(polyCountX);
	buffer->Indices.push_back(polyCountX-1);

	// create final triangle which is at the bottom of the sphere

	buffer->Indices.push_back(polyCountSqM1 + polyCountX - 1);
	buffer->Indices.push_back(polyCountSqM1);
	buffer->Indices.push_back(polyCountSq1);

	// calculate the angle which separates all points in a circle
	const f64 AngleX = 2 * core::PI / polyCountX;
	const f64 AngleY = core::PI / polyCountY;

	u32 i=0;
	f64 axz;

	// we don't start at 0.

	f64 ay = 0;//AngleY / 2;

	buffer->Vertices.set_used((polyCountXPitch * polyCountY) + 2);
	for (u32 y = 0; y < polyCountY; ++y)
	{
		ay += AngleY;
		const f64 sinay = sin(ay);
		axz = 0;

		// calculate the necessary vertices without the doubled one
		for (u32 xz = 0;xz < polyCountX; ++xz)
		{
		    // get height
            f32 height = heightMap->getPixel(xz, y).getAverage() * maxHeight;

			// calculate points position

            core::vector3df pos(static_cast<f32>(radius * cos(axz) * sinay),
						static_cast<f32>(radius * cos(ay)),
						static_cast<f32>(radius * sin(axz) * sinay));
            pos.setLength(radius + height);

			// for spheres the normal is the position
			core::vector3df normal(pos);
			normal.normalize();

			// calculate texture coordinates via sphere mapping
			// tu is the same on each level, so only calculate once
			f32 tu = 0.5f;
			if (y==0)
			{
				if (normal.Y != -1.0f && normal.Y != 1.0f)
					tu = static_cast<f32>(acos(core::clamp(normal.X/sinay, -1.0, 1.0)) * 0.5 *core::RECIPROCAL_PI64);
				if (normal.Z < 0.0f)
					tu=1-tu;
			}
			else
				tu = buffer->Vertices[i-polyCountXPitch].TCoords.X;
			buffer->Vertices[i] = video::S3DVertex(pos.X, pos.Y, pos.Z,
						normal.X, normal.Y, normal.Z,
						clr, tu,
						static_cast<f32>(ay*core::RECIPROCAL_PI64));
			++i;
			axz += AngleX;
		}
		// This is the doubled vertex on the initial position
		buffer->Vertices[i] = video::S3DVertex(buffer->Vertices[i-polyCountX]);
		buffer->Vertices[i].TCoords.X=1.0f;
		++i;
	}

	// the vertex at the top of the sphere
	buffer->Vertices[i] = video::S3DVertex(0.0f,radius,0.0f, 0.0f,1.0f,0.0f, clr, 0.5f, 0.0f);

	// the vertex at the bottom of the sphere
	++i;
	buffer->Vertices[i] = video::S3DVertex(0.0f,-radius,0.0f, 0.0f,-1.0f,0.0f, clr, 0.5f, 1.0f);

	// recalculate bounding box

	buffer->BoundingBox.reset(buffer->Vertices[i].Pos);
	buffer->BoundingBox.addInternalPoint(buffer->Vertices[i-1].Pos);
	buffer->BoundingBox.addInternalPoint(radius,0.0f,0.0f);
	buffer->BoundingBox.addInternalPoint(-radius,0.0f,0.0f);
	buffer->BoundingBox.addInternalPoint(0.0f,0.0f,radius);
	buffer->BoundingBox.addInternalPoint(0.0f,0.0f,-radius);

	SMesh* mesh = new SMesh();
	mesh->addMeshBuffer(buffer);
	buffer->drop();

	mesh->setHardwareMappingHint(EHM_STATIC);
	mesh->recalculateBoundingBox();

	heightMap->drop();

	return mesh;
}

} // end namespace scene
} // end namespace irr
CSphericalTerrainSceneNode.h:

Code: Select all

#ifndef __C_SPHERICAL_TERRAIN_SCENE_NODE_H_INCLUDED__
#define __C_SPHERICAL_TERRAIN_SCENE_NODE_H_INCLUDED__

#include "IMeshSceneNode.h"
#include "IMesh.h"
#include "IReadFile.h"
#include "IFileSystem.h"
#include "IImage.h"

namespace irr
{
namespace scene
{
	class CSphericalTerrainSceneNode : public IMeshSceneNode
	{
	public:

		//! constructor
		CSphericalTerrainSceneNode(const io::path& heightMapFileName, ISceneManager* mgr, f32 size = 5.0f, u32 polyCountX = 16, u32 polyCountY = 16, ISceneNode* parent = 0, s32 id = -1,
			const core::vector3df& position = core::vector3df(0,0,0),
			const core::vector3df& rotation = core::vector3df(0,0,0),
			const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f));

		CSphericalTerrainSceneNode(io::IReadFile* heightMapFile, ISceneManager* mgr, f32 size = 5.0f, u32 polyCountX = 16, u32 polyCountY = 16, ISceneNode* parent = 0, s32 id = -1,
			const core::vector3df& position = core::vector3df(0,0,0),
			const core::vector3df& rotation = core::vector3df(0,0,0),
			const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f));

		//! destructor
		virtual ~CSphericalTerrainSceneNode();

		virtual void OnRegisterSceneNode();

		//! renders the node.
		virtual void render();

		//! returns the axis aligned bounding box of this node
		virtual const core::aabbox3d<f32>& getBoundingBox() const;

		//! returns the material based on the zero based index i. To get the amount
		//! of materials used by this scene node, use getMaterialCount().
		//! This function is needed for inserting the node into the scene hirachy on a
		//! optimal position for minimizing renderstate changes, but can also be used
		//! to directly modify the material of a scene node.
		virtual video::SMaterial& getMaterial(u32 i);

		//! returns amount of materials used by this scene node.
		virtual u32 getMaterialCount() const;

		//! Returns type of the scene node
		virtual ESCENE_NODE_TYPE getType() const { return ESNT_SPHERE; }

		//! Writes attributes of the scene node.
		virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const;

		//! Reads attributes of the scene node.
		virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0);

		//! Creates a clone of this scene node and its children.
		virtual ISceneNode* clone(ISceneNode* newParent=0, ISceneManager* newManager=0);

		//! The mesh cannot be changed
		virtual void setMesh(IMesh* mesh) {}

		//! Returns the current mesh
		virtual IMesh* getMesh() { return Mesh; }

		//! Sets if the scene node should not copy the materials of the mesh but use them in a read only style.
		/* In this way it is possible to change the materials a mesh causing all mesh scene nodes
		referencing this mesh to change too. */
		virtual void setReadOnlyMaterials(bool readonly) {}

		//! Returns if the scene node should not copy the materials of the mesh but use them in a read only style
		virtual bool isReadOnlyMaterials() const { return false; }

	private:
        IMesh* createSphericalTerrainMesh(video::IImage* heightMap, f32 radius, u32 polyCountX, u32 polyCountY);

		IMesh* Mesh;
		io::path HeightmapFile;
		core::aabbox3d<f32> Box;
		f32 Radius;
		u32 PolyCountX;
		u32 PolyCountY;
	};

} // end namespace scene
} // end namespace irr

#endif
then to use it:

Code: Select all

    scene::ISceneNode* sphericalTerrainNode = new scene::CSphericalTerrainSceneNode("heightmap.png", smgr, 5.0f, 128, 128, smgr->getRootSceneNode(), -1);
	if (sphericalTerrainNode)
	{
		sphericalTerrainNode->setPosition(core::vector3df(0,0,30));
		sphericalTerrainNode->setMaterialTexture(0, driver->getTexture("surface.jpg"));
		sphericalTerrainNode->setMaterialFlag(video::EMF_LIGHTING, false);
		sphericalTerrainNode->getMaterial(0).setFlag(video::EMF_TRILINEAR_FILTER, true);
        sphericalTerrainNode->getMaterial(0).setFlag(video::EMF_ANISOTROPIC_FILTER, true);
	}
Result:

Image

Feel free to use it/improve it as you wish if that is usefull.
bitplane
Admin
Posts: 3204
Joined: Mon Mar 28, 2005 3:45 am
Location: England
Contact:

Post by bitplane »

Hey that's pretty cool, they would make nice asteroids. One suggestion though: is there really a need for this to be a custom scene node? As it doesn't have dynamic LoD, it would be better to just expose createSphericalTerrainMesh and use a mesh scene node.

I guess we'd also need a way to serialize such things though, which of course applies to all meshes which come from geometry creators. Currently the file name seems to be the most sensible way to do this. Open to suggestions here, maybe I'll start a thread in open discussion.
Submit bugs/patches to the tracker!
Need help right now? Visit the chat room
Granyte
Posts: 850
Joined: Tue Jan 25, 2011 11:07 pm
Contact:

Post by Granyte »

wow thanks alot its even better then what i was hoping


ill test it and post some result back

im using a perlin noise algorythm to generate a height map so for now transforming the height map is far from a consern but ill get onto it next

as for the realistic size of a world ill dwelve into modding the code so that it add details on the fly but that will be much later as im still fighting on how to manage to avoid writing the map to a file and pass it stragiht from my generating function to the using one (doing so would also skip the writing/loading time aswell as having 200 gb writen on a users computer)


eventualy ill move my generating algorythme to the gpu through hlsl but for now im staying of of thils as i burnt my self last time
Anthony
Posts: 121
Joined: Sun Jan 09, 2011 12:03 pm

Post by Anthony »

the 200GB and 2GB I took from a reply stated in an earlier reply. There is no need to have bmps that big too as you can smooth things out. So having just a bmp with resolution x by x can create a plane with a resolution x2 by x2 or even x10 by x10029.

Don't know the perling noise that good but I am trying to create a terrain that will be usable by the user - at least to some extend.
as for the realistic size of a world...
Well that size, I ain't aiming at a presicion of mm but metres. It is a simulation and not the real world. The terrain is only aproxematly and by that not noticable. For details I would place objects i.e. buildings, trees, rocks and animals/npcs.

For a planet I would like to have water wich would take the same class actually but with a heightmap replaced by an alghorithme wich propably would be a simple cos*sin function times wind or something.

For clouds a little modifycation of the same class to have depth in the clouds if you want to fly up. Or just another class to draw quads to stick a texture there.

For this kind of procedurally created data a scenenode would be way to slow as you are moving within the world and thus 99.9% of the data you would like to have doesn't matter (Perlin Noise would be cool here). It just does't exist anywhere and is the biggest mistake people like us make - I think I know because I am trying to leave that place at this very moment.

For height you have several options and you choose Perlin Noise. But that is only the height, you also have the x and z direction 8) so you would need to take a look at ROAM or CLOD. Both are great and propably outdated.

Code: Select all

Both have the feature of not drawing:
+---------+---------+---------+ <--
|\  /|\  /|\  /|\  /|\  /|\  /|    |
| \/ | \/ | \/ | \/ | \/ | \/ |    |
| /\ | /\ | /\ | /\ | /\ | /\ |    |
|/  \|/  \|/  \|/  \|/  \|/  \|    |
+---------+---------+---------+    |-- patch (3x)
|\  /|\  /|\  /|\  /|\  /|\  /|    |
| \/ | \/ | \/ | \/ | \/ | \/ |    |
| /\ | /\ | /\ | /\ | /\ | /\ |    |
|/  \|/  \|/  \|/  \|/  \|/  \|    |
+---------+---------+---------+ <--
|\  /|\  /|\  /|\  /|\  /|\  /|
| \/ | \/ | \/ | \/ | \/ | \/ |
| /\ | /\ | /\ | /\ | /\ | /\ |
|/  \|/  \|/  \|/  \|/  \|/  \|
+---------+---------+---------+
|\  /|\  /|\  /|\  /|\  /|\  /|
| \/ | \/ | \/ | \/ | \/ | \/ |
| /\ | /\ | /\ | /\ | /\ | /\ |
|/  \|/  \|/  \|/  \|/  \|/  \|
+---------+---------+---------+
|\  /|\  /|\  /|\  /|\  /|\  /|
| \/ | \/ | \/ | \/ | \/ | \/ |
| /\ | /\ | /\ | /\ | /\ | /\ |
|/  \|/  \|/  \|/  \|/  \|/  \|
+---------+---------+---------+
|\  /|\  /|\  /|\  /|\  /|\  /|
| \/ | \/ | \/ | \/ | \/ | \/ |
| /\ | /\ | /\ | /\ | /\ | /\ |
|/  \|/  \|/  \|/  \|/  \|/  \|
+---------+---------+---------+



+---------+---------+---------+ <--  <--------------
|        /|        /|        /|    |                |
|       / |       / |       / |    |                |
|      /  |      /  |      /  |    |                |
|     /   |     /   |     /   |    |                |
|    /    |    /    |    /    |    | patch (3x)     |
|   /     |   /     |   /     |    |                |
|  /      |  /      |  /      |    |                |
| /       | /       | /       |    |                |
|/        |/        |/        |    |                |
+---------+---------+---------+ <--                 |
|        /|\  /|\  /|        /|                     |
|       / | \/ | \/ |       / |                     |
|      /  | /\ | /\ |      /  |                     |
|     /   |/  \|/  \|     /   |                     |
|    /    +----+----+    /    | <-- you're          |-- 1/6 of a sphere
|   /     |   /|\  /|   /     |     standing        |   when using 
|  /      |  / | \/ |  /      |     at the middle   |   vector.normalize * (radius + height)
| /       | /  |  \ | /       |     patch           |
|/        |/   |   \|/        |                     |
+---------+---------+---------+                     |
|        /|        /|        /|                     |
|       / |       / |       / |                     |
|      /  |      /  |      /  |                     |
|     /   |     /   |     /   |                     |
|    /    |    /    |    /    |                     |
|   /     |   /     |   /     |                     |
|  /      |  /      |  /      |                     |
| /       | /       | /       |                     |
|/        |/        |/        |                     |
+---------+---------+---------+      <--------------
don't even bother to calculate the 8 surounding patches. Well if you're in the upperleft corner of the middle patch propably.

if you render all patches, you have to render 144 triangles with the first but the second counts only 21. By not storing any position until the actual drawing you save both memory and time. You can do this by using a TriNodeTree (bing it) or CLOD, procedural, ROAM and try to figure out what is happening there, why it is effective, then you can actactly get what you seek and that is cool.
If you move this asside you'd better move your idea aside for the time being and focus on the logic of a computer. Because that would be the problem you stumbled upon last time.

Whatever you do, good luck with it. When I look at some thing on the computer then I know why mathmatics are called mathmagicians sometimes.
No :shock: I am no noob, just checking if your not one too :roll:

Thanks to Niko and all others that made Irrlicht possible.
Granyte
Posts: 850
Joined: Tue Jan 25, 2011 11:07 pm
Contact:

Post by Granyte »

aiiming at a precision of mm or cm is just plain ridiculous but being able to have a world that does not looks flat (to flat) at a human scale would be great

i adealy have a water as long as the terrain sphere get ajusted acordingly to the height map (gonna need to rework the shader the reflexion is not working in the rightway but i got a water level sphere)


here is an example of what i could get going in 2d based on the perlin algorithme its quite fast the longest part of the program is that it save and then load data back from the hard drive

Image


but if i get right you are generating a sphere based on manualy created verticle thier number and position is adjusted on the fly i guess id need alot of help to get to this as even if i understand the theorie to create the sphere the practice seen to me like a dangerous and scary thing

actualy having the height in the computer memory is faster then loading them from the hard drive especialy as idealy i would generate them on the fly using the noise algorithme
Anthony
Posts: 121
Joined: Sun Jan 09, 2011 12:03 pm

Post by Anthony »

like a dangerous and scary thing
well, dangerous, absolutly not. It's quite save, you can't fall of the world anymore. Scary, yes it's terrefying got to agree.

About the height data, am not going to create it manually but using another algorithm by Hugo Elias wich is quit small. My goal is that you can adjust it ingame. Building a house needs a flat bed things like that.

Code: Select all

PSEUDO:
loop

    n = random vector				; see method above
    m = randomly either -1 or 1

    loop through each vertex of the sphere

	p = coordinates of this vertex		
	v = p - n
        d = dotproduct(n , v)			; is this vertex infront of 
						; or behind the plane?

	if d > 0 then				; if infront then
	    move this vertex by m
	else					; if behind then
	    move this vertex by -m
	end if
    end loop

end loop
Didn't look at perlin yet. However I did read something as seeding - just a start parameter - it so you would get the same result each time.

For the file, you could use fopen and fclose and leave it open all the time. fseek for going back and forth. Don't know how fast or slow it would be, just a theory. But you could load part of the file in memory and trigger a function to read another section when you come near to the border.

Also something else to consider wich I am currently thinking of is how hard it would be to calculate a distance because of the curve of the planet. And how it would affect the rest of the physics. Oh my why did I think of a planet :? rather then a plane.

I am certain it would be quit easier _and_ faster to use a planar terrain wich will be infinite i.e. using patches you can add two rows and colums at the sides. The first is the last patch and visa versa for the visual effect and when actually walking onto one of those extras you simply add or substract the terrain size to the axis of the objects.

My reason to have a phere is simple due to the realism of walking around the world and see mountains, buildings and the sky just disapear behind to horizon. And while I am trying to share my thoughts and findings I think about really leaving the sphere (2nd time though) and going to use planar terrain and use fog to fade out distance.

Hehe, fog make it scary too :shock:

EDIT: btw cool picture but what are those whole under water? Are they holes or is that some sort of detail map?
No :shock: I am no noob, just checking if your not one too :roll:

Thanks to Niko and all others that made Irrlicht possible.
Granyte
Posts: 850
Joined: Tue Jan 25, 2011 11:07 pm
Contact:

Post by Granyte »

thanks for all the time you are consacring to explaining me

I now realise that its my math knowledge thats a bit rusty

i found that

http://local.wasp.uwa.edu.au/~pbourke/m ... _cylinder/

but i have a hard time assenbling the sphere with that the vertice and indice thing get em comppletely lost any one know a tutorial in the right direction id like to do it my self so i could understand

my reason for going to a sphere is for high level atmospheric flight or low orbit with a idealy a seamless transition




and there is no holes yes its the default terrain detail map provided in the irrlicht tutorial my graphic artist is still in school so no texture for me lol
Anthony
Posts: 121
Joined: Sun Jan 09, 2011 12:03 pm

Post by Anthony »

rusty too
3d artist left school but me too :(
EDIT: cruell, after posting it I saw you wanted a tutorial, I don't know one. So consider this one as a tutorial. And for the LOD 'Rendering Massive Terrains using Chunked Level of Detail Control DRAFT' by Thatcher Ulrich
EDIT: found this to on a french forum. It is a source but for terrain, did help me much. C++ Irrlicht 1.3 Moteur de Terrain avec Vertex Alpha.

Well when trying to help you I am helping myself too, so no problem.

The cos*sin thing you don't need here as I would really urge you to already lay down a foundation to implement some LOD system. Maybe that cos*sin thing can be used but then I don't know. Another point is with that, take a look at the poles and the equator. You see a sphere but the quads are very distorted. All fine when sticking a texture of earth on it but when applying a heightmap to it it gets real distorted.

Code: Select all

pseudo
// vertices
planesize = 16
loop cycle z axis planesize + 1
loop cycle x axis planesize + 1
n = ( x - planesize / 2, planesize / 2, z - planesize / 2 ) // divide by two for the normalizing. outlining arount the center
pos = n.normalize * ( radius + height )
end loop
end loop

// indices
loop cycle z axis planesize
loop cycle x axis planesize
i = z * planesize + x
i = z * planesize + x + 1
i = z * planesize + x + planesize // a vertex on the next row
i = z * planesize + x + 1
i = z * planesize + x + planesize // a vertex on the next row
i = z * planesize + x + planesize + 1 // a vertex on the next row
btw this can have an error but is very approxamatly the way to go
hint: dig up your math as you need it everywhere 8)

the above creates the top plane of this sphere (you should divide them into at least 4x4 patches thus meshbuffers):
ImageFor this you need six heightmaps and six texturemap, yeah problems problems and again problems. That makes life fun. seemless tiling, six axis and then again math

The next image I tried too, it is propably the easiest easy to create a sphere but as easy that isthat painly to keep track of the data. Therfore you should be at least a mathmagicians apprentice.
Image
No :shock: I am no noob, just checking if your not one too :roll:

Thanks to Niko and all others that made Irrlicht possible.
Granyte
Posts: 850
Joined: Tue Jan 25, 2011 11:07 pm
Contact:

Post by Granyte »

thats wierd as i would have seen the cosin way to be easier to implement a lod and a maybe more drastic lod system as well as a height maping system

in the cosin way as i locate more easeily the parameter to change to rcreate just part of the sphere
by rendering only part of the sphere wich is potentialy visible wich implies that when the camera is to close to the surface not all the sphere need to exist so you calculate how much of the surface is potentialy visible the question is would i do it by adding the missing vertice and indice or redrawing the scene node

and also doing it this way make it easier for integration with the perlin noise becasue with each time i have to redraw the node to add detail i just make an aditional octave of noise that i suplement

and the heightmap would be distorned because the higher and lower part take less place on the sphere so it would be distorded like that rather then separated http://earthobservatory.nasa.gov/Featur ... 0x2700.jpg
Post Reply