SuperEllipsoid

From Ogre Wiki

Jump to: navigation, search

By Ephon:

Code for creating a super ellipsoid. Using a super ellipsoid makes it easy to create simple 3d primitives such as cube, cylinder, sphere etc. To use this class use the approach lined out in http://www.ogre3d.org/wiki/index.php/ManualSphereMeshes to make a genuine Mesh, or subclass SimpleRenderable and make use of writeData method.

SuperEllipsoid.h

#ifndef _SUPERELLIPSOID_H_
#define _SUPERELLIPSOID_H_

#include <Ogre.h>

class SuperEllipsoid
{
public:
	typedef enum Shape {CUBE, ROUNDED_CUBE, CYLINDER, SPHERE};
	
	SuperEllipsoid();
	SuperEllipsoid(int samples, float n1, float n2, float scale = 1.0);
	SuperEllipsoid(Shape shape, int samples = 60, float scale = 1.0);
	~SuperEllipsoid();

	void createSuperEllipsoid(int samples, float n1, float n2, float scale = 1.0);
	void createSuperEllipsoid(Shape shape, int samples = 60, float scale = 1.0);
	int getNumVertices();
	float *getPointerToVertexData() const;
	Ogre::Vector3 getMaxPoint();
	Ogre::Vector3 getMinPoint();


private:
	float *vertexData;
	size_t vertexDataSize;
	Ogre::Vector3 maxPoint, minPoint;

	std::vector<Ogre::Vector3> vertices;
	std::vector<Ogre::Vector3> normals;
	Ogre::Vector3 sampleSuperEllipsoid(float phi, float beta, float n1, float n2,
		float scaleX=1.0, float scaleY=1.0, float scaleZ=1.0);
	Ogre::Vector3 calculateNormal(float phi, float beta, float n1, float n2,
		float scaleX, float scaleY, float scaleZ);
	Ogre::Vector3 calculateNormal(Ogre::Vector3 p1, Ogre::Vector3 p2, Ogre::Vector3 p3);
	void copyVertexDataToArray();
};

#endif

SuperEllipsoid.cpp

#include "Superellipsoid.h"
#include <cmath>

#define SIGN(r) Ogre::Math::Sign(r)


SuperEllipsoid::SuperEllipsoid()
{
	vertexData = NULL;
	vertexDataSize = 0;
}

SuperEllipsoid::SuperEllipsoid(int samples, float n1, float n2, float scale)
{
	vertexData = NULL;
	vertexDataSize = 0;
	createSuperEllipsoid(samples, n1, n2, scale);
}

SuperEllipsoid::SuperEllipsoid(Shape shape, int samples, float scale)
{
	vertexData = NULL;
	vertexDataSize = 0;
	createSuperEllipsoid(shape, samples, scale);
}

SuperEllipsoid::~SuperEllipsoid()
{
	delete [] vertexData;
}

void SuperEllipsoid::createSuperEllipsoid(int samples, float n1, float n2, float scale)
{
	float phi = 0.0, phi2 = 0.0, beta = 0.0;
	Ogre::Vector3 p1, p2, p3;
	
	float dB = Ogre::Math::TWO_PI/samples;
	float dP = Ogre::Math::TWO_PI/samples;

	phi = -Ogre::Math::HALF_PI;

	for(int j=0; j<=samples/2; j++)
	{
		beta = -Ogre::Math::PI;

		for(int i=0; i<=samples; i++)
		{
			//Triangle #1
			vertices.push_back(sampleSuperEllipsoid(phi, beta, n1, n2, scale, scale, scale));
			normals.push_back(calculateNormal(phi, beta, n1, n2, scale, scale, scale));
			vertices.push_back(sampleSuperEllipsoid(phi+dP, beta, n1, n2, scale, scale, scale));
			normals.push_back(calculateNormal(phi+dP, beta, n1, n2, scale, scale, scale));
			vertices.push_back(sampleSuperEllipsoid(phi+dP, beta+dB, n1, n2, scale, scale, scale));
			normals.push_back(calculateNormal(phi+dP, beta+dB, n1, n2, scale, scale, scale));

			//Triangle #2
			vertices.push_back(sampleSuperEllipsoid(phi, beta, n1, n2, scale, scale, scale));
			normals.push_back(calculateNormal(phi, beta, n1, n2, scale, scale, scale));
			vertices.push_back(sampleSuperEllipsoid(phi+dP, beta+dB, n1, n2, scale, scale, scale));
			normals.push_back(calculateNormal(phi+dP, beta+dB, n1, n2, scale, scale, scale));
			vertices.push_back(sampleSuperEllipsoid(phi, beta+dB, n1, n2, scale, scale, scale));
			normals.push_back(calculateNormal(phi, beta+dB, n1, n2, scale, scale, scale));

			beta += dB;
		}

		phi += dP;
	}

	copyVertexDataToArray();
} 

void SuperEllipsoid::createSuperEllipsoid(Shape shape, int samples, float scale)
{
	float n1, n2;

	switch(shape)
	{
	case CUBE:
		n1 = n2 = 0.0;
		break;
	case ROUNDED_CUBE:
		n1 = n2 = 0.2;
		break;
	case CYLINDER:
		n1 = 0.2;
		n2 = 1.0;
		break;
	case SPHERE:
		n1 = n2 = 1.0;
		break;
	}

	createSuperEllipsoid(samples, n1, n2, scale);
} 

int SuperEllipsoid::getNumVertices()
{
	return (int)vertices.size();
}

float *SuperEllipsoid::getPointerToVertexData() const
{
	return vertexData;
}

Ogre::Vector3 SuperEllipsoid::getMaxPoint()
{
	return maxPoint;
}

Ogre::Vector3 SuperEllipsoid::getMinPoint()
{
	return minPoint;
}

Ogre::Vector3 SuperEllipsoid::sampleSuperEllipsoid(float phi, float beta, float n1, float n2,
	float scaleX, float scaleY, float scaleZ)
{
	Ogre::Vector3 vertex;

	float cosPhi = cos(phi); float cosBeta = cos(beta);
	float sinPhi = sin(phi); float sinBeta = sin(beta);
	

	vertex.x = scaleX * SIGN(cosPhi) * pow(fabs(cosPhi), n1) * SIGN(cosBeta) * pow(fabs(cosBeta), n2);
	vertex.z = scaleY * SIGN(cosPhi) * pow(fabs(cosPhi), n1) * SIGN(sinBeta) * pow(fabs(sinBeta), n2);
	vertex.y = scaleZ * SIGN(sinPhi) * pow(fabs(sinPhi), n1);

	return vertex;
} 

Ogre::Vector3 SuperEllipsoid::calculateNormal(float phi, float beta, float n1, float n2,
	float scaleX, float scaleY, float scaleZ)
{ 
	Ogre::Vector3 normal;

	float cosPhi = cos(phi); float cosBeta = cos(beta);
	float sinPhi = sin(phi); float sinBeta = sin(beta);

	normal.x = SIGN(cosPhi) * pow(fabs(cosPhi), 2-n1) * SIGN(cosBeta) * pow(fabs(cosBeta), 2-n2) / scaleX;
	normal.z = SIGN(cosPhi) * pow(fabs(cosPhi), 2-n1) * SIGN(sinBeta) * pow(fabs(sinBeta), 2-n2) / scaleY;
	normal.y = SIGN(sinPhi) * pow(fabs(sinPhi), 2-n1) / scaleZ;

	normal.normalise();

	return normal;
}

void SuperEllipsoid::copyVertexDataToArray()
{
	size_t size = vertices.size() * 2 * 3; // vertices + normals

	if(vertexData == NULL)
		vertexData = new float[size];
	else if(vertexDataSize != size)
	{
		delete [] vertexData;
		vertexData = new float[size];
	}

	vertexDataSize = size;

	size_t numVertices = vertices.size();

	for(int i=0; i<numVertices; i++)
	{
		vertexData[i*6]   = vertices[i].x;
		vertexData[i*6+1] = vertices[i].y;
		vertexData[i*6+2] = vertices[i].z;

		vertexData[i*6+3] = normals[i].x;
		vertexData[i*6+4] = normals[i].y;
		vertexData[i*6+5] = normals[i].z;

		if(vertices[i].x < minPoint.x)
			minPoint.x = vertices[i].x;
		if(vertices[i].y < minPoint.y)
			minPoint.y = vertices[i].y;
		if(vertices[i].z < minPoint.z)
			minPoint.z = vertices[i].z;

		if(vertices[i].x > maxPoint.x)
			maxPoint.x = vertices[i].x;
		if(vertices[i].y > maxPoint.y)
			maxPoint.y = vertices[i].y;
		if(vertices[i].z > maxPoint.z)
			maxPoint.z = vertices[i].z;
	}		
}

This code hasnt been fully tested so errors may occur. If you see some errors or enhancements that can be done please let me know!

Personal tools
administration