Page 1 of 1

IcoSphere Texturing

Posted: Fri Jun 12, 2015 11:02 pm
by Matix522
hi,
I'm working on my litlle solar system simulaion, where I use some icospheres to generate planets.
i use icospheres because i want to create dynamicly updateing planet surface, so in this case icospheres are better than UVspheres
As you probaly know when you try to appy uv's on sphere you will see very big seam on 180 degree. To solve it, firstly i try to create a shader but the seam become only smaller.
Eventualy i found a solution. I called it IcoSphereCubeMapCreator. The idea my was very simple, you must create uvsphere and apply texture on it (on uvsphere there are any seams )
Next you put 6 camera( each of them in difrent direction) inside this sphere and take a picture. I'm posting this because i didn't find any working solutions.
It looks nice.
http://zapodaj.net/c4892ac01b1be.jpg.html
SphereCubeMapCreator.h

Code: Select all

#pragma once
#include <Ogre.h>
using namespace Ogre;
class SphereCubeMapCreator : public Singleton<SphereCubeMapCreator>
{
private:
	SphereCubeMapCreator();
	~SphereCubeMapCreator();
public:
	

	String ConvertToCubeMap(String TexName, String dotFormat);
	void createSphere(const std::string& strName, const float r, const int nRings, const int nSegments);
	
	static SphereCubeMapCreator* create();

	static SphereCubeMapCreator& getSingleton(void);
	static SphereCubeMapCreator* getSingletonPtr(void);

	std::map<int,TexturePtr> mCubeMapTextures;
	int texNumber;
	SceneManager* mSceneManager;
	Camera* mCameras[6];

	std::map<std::string,int> mRenderTargetIndexes;
	void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt);
};
SphereCubeMapCreator.cpp

Code: Select all

#include "SphereCubeMapCreator.h"

template<> SphereCubeMapCreator* Ogre::Singleton<SphereCubeMapCreator>::msSingleton = 0;
SphereCubeMapCreator* SphereCubeMapCreator::getSingletonPtr(void)
{
	return msSingleton;
}
SphereCubeMapCreator& SphereCubeMapCreator::getSingleton(void)
{
	assert(msSingleton);  return (*msSingleton);
}

//------------------------------------------------------------------------------------------------------------------------------------
SphereCubeMapCreator::SphereCubeMapCreator() :texNumber(0)
{
	mSceneManager = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC, "SphereCubeMapCreator");
	for (int i = 0; i < 6; i++)
	{
		mCameras[i] = mSceneManager->createCamera("CameraCubeMap" + Ogre::StringConverter::toString(i));
		mCameras[i]->setNearClipDistance(0.1);
		mCameras[i]->setAspectRatio(1);
		mCameras[i]->setFOVy(Ogre::Radian(Ogre::Math::PI / 2));
		mCameras[i]->setDirection(1, 0, 0);
	}

	createSphere("Sphere", 10, 64, 64);

	Ogre::MaterialPtr mat =
		Ogre::MaterialManager::getSingleton().create(
		"SphereUV", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);

	mat->getTechnique(0)->getPass(0)->setLightingEnabled(false);
	Entity* sphereEntity = mSceneManager->createEntity("mySphereEntity", "Sphere");
	SceneNode* sphereNode = mSceneManager->getRootSceneNode()->createChildSceneNode();
	sphereEntity->setMaterialName("SphereUV");
	sphereNode->attachObject(sphereEntity);
}
//------------------------------------------------------------------------------------------------------------------------------------
SphereCubeMapCreator* SphereCubeMapCreator::create()
{
	if (!msSingleton)
		msSingleton = new SphereCubeMapCreator;
	return msSingleton;
}
SphereCubeMapCreator::~SphereCubeMapCreator()
{

}
String SphereCubeMapCreator::ConvertToCubeMap(String TexName,String dotFormat)
{
	Image img;
	img.load(TexName + dotFormat, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
	//img.flipAroundX();
	img.flipAroundY();
	TexturePtr tex1 = Ogre::TextureManager::getSingleton().createManual(TexName,
		Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
		Ogre::TEX_TYPE_2D, img.getWidth(), img.getHeight(), 0, 0, Ogre::PF_A8R8G8B8, Ogre::TU_RENDERTARGET);
	tex1->loadImage(img);
	auto tex = Ogre::TextureManager::getSingleton().createManual(TexName + "CubeMap", 
		Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
		Ogre::TEX_TYPE_CUBE_MAP, 512, 512, 0, 0, Ogre::PF_A8R8G8B8, Ogre::TU_RENDERTARGET);
	Ogre::MaterialManager::getSingleton().getByName("SphereUV")->getTechnique(0)->getPass(0)->removeAllTextureUnitStates();
	Ogre::MaterialManager::getSingleton().getByName("SphereUV")->getTechnique(0)->getPass(0)->createTextureUnitState(TexName);
	mCubeMapTextures[++texNumber] = tex;

	for (int i = 0; i < 6; i++)
	{
		Ogre::RenderTarget *renderTarget = mCubeMapTextures[texNumber]->getBuffer(i)->getRenderTarget();
		renderTarget->setAutoUpdated(false);
		switch (i)
		{
		case 0:
			mCameras[i]->yaw(Ogre::Radian(-Ogre::Math::PI / 2)); //right
			break;
		case 1:
			mCameras[i]->yaw(Ogre::Radian(Ogre::Math::PI / 2)); //left
			break;
		case 2:
			mCameras[i]->pitch(Ogre::Radian(Ogre::Math::PI / 2)); //up
			break;
		case 3:
			mCameras[i]->pitch(Ogre::Radian(-Ogre::Math::PI / 2)); //down
			break;
		case 4:
			break;//back
		case 5:
			mCameras[i]->yaw(Ogre::Radian(Ogre::Math::PI)); //front
			break; 
		}

		Ogre::Viewport *viewport = renderTarget->addViewport(mCameras[i]);
		viewport->setOverlaysEnabled(false);
		viewport->setClearEveryFrame(true);
		viewport->setBackgroundColour(ColourValue(1,0.8,0.8,1));
		renderTarget->update();

		mCameras[i]->setDirection(1, 0, 0);
	}
	return TexName + " CubeMap";
}

void SphereCubeMapCreator::createSphere(const std::string& strName, const float r, const int nRings = 16, const int nSegments = 16)
{
	MeshPtr pSphere = MeshManager::getSingleton().createManual(strName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
	SubMesh *pSphereVertex = pSphere->createSubMesh();

	pSphere->sharedVertexData = new VertexData();
	VertexData* vertexData = pSphere->sharedVertexData;

	// define the vertex format
	VertexDeclaration* vertexDecl = vertexData->vertexDeclaration;
	size_t currOffset = 0;
	// positions
	vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_POSITION);
	currOffset += VertexElement::getTypeSize(VET_FLOAT3);
	// normals
	vertexDecl->addElement(0, currOffset, VET_FLOAT3, VES_NORMAL);
	currOffset += VertexElement::getTypeSize(VET_FLOAT3);
	// two dimensional texture coordinates
	vertexDecl->addElement(0, currOffset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
	currOffset += VertexElement::getTypeSize(VET_FLOAT2);

	// allocate the vertex buffer
	vertexData->vertexCount = (nRings + 1) * (nSegments + 1);
	HardwareVertexBufferSharedPtr vBuf = HardwareBufferManager::getSingleton().createVertexBuffer(vertexDecl->getVertexSize(0), vertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
	VertexBufferBinding* binding = vertexData->vertexBufferBinding;
	binding->setBinding(0, vBuf);
	float* pVertex = static_cast<float*>(vBuf->lock(HardwareBuffer::HBL_DISCARD));

	// allocate index buffer
	pSphereVertex->indexData->indexCount = 6 * nRings * (nSegments + 1);
	pSphereVertex->indexData->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(HardwareIndexBuffer::IT_16BIT, pSphereVertex->indexData->indexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
	HardwareIndexBufferSharedPtr iBuf = pSphereVertex->indexData->indexBuffer;
	unsigned short* pIndices = static_cast<unsigned short*>(iBuf->lock(HardwareBuffer::HBL_DISCARD));

	float fDeltaRingAngle = (Math::PI / nRings);
	float fDeltaSegAngle = (2 * Math::PI / nSegments);
	unsigned short wVerticeIndex = 0;

	// Generate the group of rings for the sphere
	for (int ring = 0; ring <= nRings; ring++) {
		float r0 = r * sinf(ring * fDeltaRingAngle);
		float y0 = r * cosf(ring * fDeltaRingAngle);

		// Generate the group of segments for the current ring
		for (int seg = 0; seg <= nSegments; seg++) {
			float x0 = r0 * sinf(seg * fDeltaSegAngle);
			float z0 = r0 * cosf(seg * fDeltaSegAngle);

			// Add one vertex to the strip which makes up the sphere
			*pVertex++ = x0;
			*pVertex++ = y0;
			*pVertex++ = z0;

			Vector3 vNormal = Vector3(x0, y0, z0).normalisedCopy();
			*pVertex++ = -vNormal.x;
			*pVertex++ = -vNormal.y;
			*pVertex++ = -vNormal.z;

			*pVertex++ = (float)seg / (float)nSegments;
			*pVertex++ = (float)ring / (float)nRings;

			if (ring != nRings) {
				// each vertex (except the last) has six indices pointing to it
				*pIndices++ = wVerticeIndex + nSegments + 1;
				*pIndices++ = wVerticeIndex + nSegments;
				*pIndices++ = wVerticeIndex;
				
				*pIndices++ = wVerticeIndex + nSegments + 1;
				*pIndices++ = wVerticeIndex;
				*pIndices++ = wVerticeIndex + 1;
				wVerticeIndex++;
			}
		}; // end for seg
	} // end for ring

	// Unlock
	vBuf->unlock();
	iBuf->unlock();
	// Generate face list
	pSphereVertex->useSharedVertices = true;

	// the original code was missing this line:
	pSphere->_setBounds(AxisAlignedBox(Vector3(-r, -r, -r), Vector3(r, r, r)), false);
	pSphere->_setBoundingSphereRadius(r);
	// this line makes clear the mesh is loaded (avoids memory leaks)
	pSphere->load();
}
//------------------------------------------------------------------------------------------------------------------------------------
how to use

Code: Select all

SphereCubeMapCreator* sph = SphereCubeMapCreator::create();
// .......  // next use
SphereCubeMapCreator::getSingleton().ConvertToCubeMap("textureName",".png"); // this create Cube texture called "texturenNameCubeMap"