SuperEllipsoid
From Ogre Wiki
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!

