Я использовал Bullet Physics на устройствах iOS для создания игры в кости.Чтобы получить более реалистично выглядящие кости, я создал объект «RoundedCube», который представляет собой просто куб со скошенными краями.Вот код Objective-C, который я написал для создания вершин
//
// Created by John Carter on 4/9/09.
//
#import "RoundedCube.h"
static const GLfloat voffset[] =
{
// Front Face (counterclockwise winding)
+1.0f, +1.0f, +1.0f,
-1.0f, +1.0f, +1.0f,
-1.0f, -1.0f, +1.0f,
+1.0f, +1.0f, +1.0f,
-1.0f, -1.0f, +1.0f,
+1.0f, -1.0f, +1.0f,
// Back Face (clockwise winding)
+1.0f, +1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, +1.0f, -1.0f,
+1.0f, +1.0f, -1.0f,
+1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
// Top Face (counterclockwise winding)
-1.0f, +1.0f, +1.0f,
+1.0f, +1.0f, -1.0f,
-1.0f, +1.0f, -1.0f,
-1.0f, +1.0f, +1.0f,
+1.0f, +1.0f, +1.0f,
+1.0f, +1.0f, -1.0f,
// Bottom Face (clockwise winding)
-1.0f, -1.0f, +1.0f,
-1.0f, -1.0f, -1.0f,
+1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, +1.0f,
+1.0f, -1.0f, -1.0f,
+1.0f, -1.0f, +1.0f,
// Right Face (clockwise winding)
+1.0f, -1.0f, +1.0f,
+1.0f, +1.0f, -1.0f,
+1.0f, +1.0f, +1.0f,
+1.0f, -1.0f, +1.0f,
+1.0f, -1.0f, -1.0f,
+1.0f, +1.0f, -1.0f,
// Left Face (counterclockwise winding)
-1.0f, -1.0f, +1.0f,
-1.0f, +1.0f, +1.0f,
-1.0f, +1.0f, -1.0f,
-1.0f, +1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, +1.0f,
};
// Private Methods
//
@interface RoundedCube()
- (void) computeRoundedCubeNormals;
@end
@implementation RoundedCube
- (void) dealloc
{
[super dealloc];
}
- (void) computeRoundedCubeNormals
{
int i;
xMinVertex = FLT_MAX;
yMinVertex = FLT_MAX;
zMinVertex = FLT_MAX;
xMaxVertex = -FLT_MAX;
yMaxVertex = -FLT_MAX;
zMaxVertex = -FLT_MAX;
for (i=0; i<vertexDataCount; i+=3)
{
if ( vertexData[i+0] < xMinVertex )
xMinVertex = vertexData[i+0] ;
if ( vertexData[i+1] < yMinVertex )
yMinVertex = vertexData[i+1] ;
if ( vertexData[i+2] < zMinVertex )
zMinVertex = vertexData[i+2] ;
if ( vertexData[i+0] > xMaxVertex )
xMaxVertex = vertexData[i+0] ;
if ( vertexData[i+1] > yMaxVertex )
yMaxVertex = vertexData[i+1] ;
if ( vertexData[i+2] > zMaxVertex )
zMaxVertex = vertexData[i+2] ;
}
xVertexRange = fabs(xMaxVertex - xMinVertex);
yVertexRange = fabs(yMaxVertex - yMinVertex);
zVertexRange = fabs(zMaxVertex - zMinVertex);
for (i=0; i<vertexDataCount; i+=9)
{
btVector3 V0 = btVector3( vertexData[i+0], vertexData[i+1], vertexData[i+2] );
btVector3 V1 = btVector3( vertexData[i+3], vertexData[i+4], vertexData[i+5] );
btVector3 V2 = btVector3( vertexData[i+6], vertexData[i+7], vertexData[i+8] );
btVector3 delta1 = (V1) - (V0);
btVector3 delta2 = (V2) - (V0);
btVector3 vertexNormal = delta1.cross(delta2);
vertexNormal = vertexNormal.normalize();
if ( useAbsNormals )
{
vertexNormal = vertexNormal.absolute();
}
normalData[i+0] = vertexNormal[0];
normalData[i+1] = vertexNormal[1];
normalData[i+2] = vertexNormal[2];
normalData[i+3] = vertexNormal[0];
normalData[i+4] = vertexNormal[1];
normalData[i+5] = vertexNormal[2];
normalData[i+6] = vertexNormal[0];
normalData[i+7] = vertexNormal[1];
normalData[i+8] = vertexNormal[2];
}
}
- (void) addBeveledCorner:(int)bevelPlane At:(btVector3)bevelLocation Size:(btVector3)bevelSize Rotation:(double)rotationOrigin
{
btVector3 vertexPoint[6];
double delta;
double theta0;
double theta1;
double phi0;
double phi1;
int vp;
int i;
int j;
int k;
delta = (double)M_PI_2 / (double)smoothFactor;
// vertical segments
//
for( i=0; i<smoothFactor; i++)
{
theta0 = (double)i * (double)delta;
theta1 = (double)(i+1) * (double)delta;
if ( bevelPlane==1 )
{
theta0 += M_PI;
theta1 += M_PI;
}
// horizontal segments
//
for( j=0; j<smoothFactor; j++)
{
phi0 = (double)j * (double)delta;
phi1 = (double)(j+1) * (double)delta;
phi0 += rotationOrigin;
phi1 += rotationOrigin;
if ( bevelPlane==1 )
{
phi0 += M_PI;
phi1 += M_PI;
}
vp=0;
if ( bevelPlane==0 )
{
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0]*btScalar(sin(theta0)*cos(phi0)), bevelLocation[1]+bevelSize[1]*btScalar(cos(theta0)), bevelLocation[2]+bevelSize[2]*btScalar(sin(theta0)*sin(phi0)));
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0]*btScalar(sin(theta0)*cos(phi1)), bevelLocation[1]+bevelSize[1]*btScalar(cos(theta0)), bevelLocation[2]+bevelSize[2]*btScalar(sin(theta0)*sin(phi1)));
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0]*btScalar(sin(theta1)*cos(phi1)), bevelLocation[1]+bevelSize[1]*btScalar(cos(theta1)), bevelLocation[2]+bevelSize[2]*btScalar(sin(theta1)*sin(phi1)));
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0]*btScalar(sin(theta0)*cos(phi0)), bevelLocation[1]+bevelSize[1]*btScalar(cos(theta0)), bevelLocation[2]+bevelSize[2]*btScalar(sin(theta0)*sin(phi0)));
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0]*btScalar(sin(theta1)*cos(phi1)), bevelLocation[1]+bevelSize[1]*btScalar(cos(theta1)), bevelLocation[2]+bevelSize[2]*btScalar(sin(theta1)*sin(phi1)));
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0]*btScalar(sin(theta1)*cos(phi0)), bevelLocation[1]+bevelSize[1]*btScalar(cos(theta1)), bevelLocation[2]+bevelSize[2]*btScalar(sin(theta1)*sin(phi0)));
}
else
{
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0]*btScalar(sin(theta0)*cos(phi0)), bevelLocation[1]+bevelSize[1]*btScalar(cos(theta0)), bevelLocation[2]+bevelSize[2]*btScalar(sin(theta0)*sin(phi0)));
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0]*btScalar(sin(theta1)*cos(phi1)), bevelLocation[1]+bevelSize[1]*btScalar(cos(theta1)), bevelLocation[2]+bevelSize[2]*btScalar(sin(theta1)*sin(phi1)));
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0]*btScalar(sin(theta0)*cos(phi1)), bevelLocation[1]+bevelSize[1]*btScalar(cos(theta0)), bevelLocation[2]+bevelSize[2]*btScalar(sin(theta0)*sin(phi1)));
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0]*btScalar(sin(theta0)*cos(phi0)), bevelLocation[1]+bevelSize[1]*btScalar(cos(theta0)), bevelLocation[2]+bevelSize[2]*btScalar(sin(theta0)*sin(phi0)));
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0]*btScalar(sin(theta1)*cos(phi0)), bevelLocation[1]+bevelSize[1]*btScalar(cos(theta1)), bevelLocation[2]+bevelSize[2]*btScalar(sin(theta1)*sin(phi0)));
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0]*btScalar(sin(theta1)*cos(phi1)), bevelLocation[1]+bevelSize[1]*btScalar(cos(theta1)), bevelLocation[2]+bevelSize[2]*btScalar(sin(theta1)*sin(phi1)));
}
for ( k=0; k<6; k++ )
{
vertexData[coordinateElement++] = vertexPoint[k][0];
vertexData[coordinateElement++] = vertexPoint[k][1];
vertexData[coordinateElement++] = vertexPoint[k][2];
colorData[colorElement++] = rgba[0];
colorData[colorElement++] = rgba[1];
colorData[colorElement++] = rgba[2];
colorData[colorElement++] = rgba[3];
}
}
}
}
- (void) addBeveledEdge:(int)bevelPlane At:(btVector3)bevelLocation Size:(btVector3)bevelSize Rotation:(double)rotationOrigin
{
btVector3 vertexPoint[6];
double origin;
double delta;
double theta0;
double theta1;
int vp;
int i;
int j;
delta = (double)(M_PI_2) / (double)smoothFactor;
for ( i=0; i<smoothFactor; i++ )
{
theta0 = (double)i * (double)delta;
theta1 = (double)(i+1) * (double)delta;
theta0 += rotationOrigin;
theta1 += rotationOrigin;
origin = (double)0.0;
vp=0;
switch( bevelPlane )
{
case 0:
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0], bevelLocation[1]+bevelSize[1]*btScalar(sin(theta0+origin)), bevelLocation[2]+bevelSize[2]*btScalar(cos(theta0+origin)) );
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0], bevelLocation[1]+bevelSize[1]*btScalar(sin(theta1+origin)), bevelLocation[2]+bevelSize[2]*btScalar(cos(theta1+origin)) );
vertexPoint[vp++] = btVector3( bevelLocation[0]-bevelSize[0], bevelLocation[1]+bevelSize[1]*btScalar(sin(theta1+origin)), bevelLocation[2]+bevelSize[2]*btScalar(cos(theta1+origin)) );
vertexPoint[vp++] = btVector3( bevelLocation[0]-bevelSize[0], bevelLocation[1]+bevelSize[1]*btScalar(sin(theta0+origin)), bevelLocation[2]+bevelSize[2]*btScalar(cos(theta0+origin)) );
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0], bevelLocation[1]+bevelSize[1]*btScalar(sin(theta0+origin)), bevelLocation[2]+bevelSize[2]*btScalar(cos(theta0+origin)) );
vertexPoint[vp++] = btVector3( bevelLocation[0]-bevelSize[0], bevelLocation[1]+bevelSize[1]*btScalar(sin(theta1+origin)), bevelLocation[2]+bevelSize[2]*btScalar(cos(theta1+origin)) );
break;
case 1:
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0]*btScalar(sin(theta0+origin)), bevelLocation[1]+bevelSize[1], bevelLocation[2]+bevelSize[2]*btScalar(cos(theta0+origin)) );
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0]*btScalar(sin(theta1+origin)), bevelLocation[1]-bevelSize[1], bevelLocation[2]+bevelSize[2]*btScalar(cos(theta1+origin)) );
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0]*btScalar(sin(theta1+origin)), bevelLocation[1]+bevelSize[1], bevelLocation[2]+bevelSize[2]*btScalar(cos(theta1+origin)) );
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0]*btScalar(sin(theta0+origin)), bevelLocation[1]-bevelSize[1], bevelLocation[2]+bevelSize[2]*btScalar(cos(theta0+origin)) );
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0]*btScalar(sin(theta1+origin)), bevelLocation[1]-bevelSize[1], bevelLocation[2]+bevelSize[2]*btScalar(cos(theta1+origin)) );
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0]*btScalar(sin(theta0+origin)), bevelLocation[1]+bevelSize[1], bevelLocation[2]+bevelSize[2]*btScalar(cos(theta0+origin)) );
break;
case 2:
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0]*btScalar(sin(theta0+origin)), bevelLocation[1]+bevelSize[1]*btScalar(cos(theta0+origin)), bevelLocation[2]+bevelSize[2] );
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0]*btScalar(sin(theta1+origin)), bevelLocation[1]+bevelSize[1]*btScalar(cos(theta1+origin)), bevelLocation[2]+bevelSize[2] );
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0]*btScalar(sin(theta1+origin)), bevelLocation[1]+bevelSize[1]*btScalar(cos(theta1+origin)), bevelLocation[2]-bevelSize[2] );
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0]*btScalar(sin(theta0+origin)), bevelLocation[1]+bevelSize[1]*btScalar(cos(theta0+origin)), bevelLocation[2]-bevelSize[2] );
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0]*btScalar(sin(theta0+origin)), bevelLocation[1]+bevelSize[1]*btScalar(cos(theta0+origin)), bevelLocation[2]+bevelSize[2] );
vertexPoint[vp++] = btVector3( bevelLocation[0]+bevelSize[0]*btScalar(sin(theta1+origin)), bevelLocation[1]+bevelSize[1]*btScalar(cos(theta1+origin)), bevelLocation[2]-bevelSize[2] );
break;
}
for ( j=0; j<6; j++ )
{
vertexData[coordinateElement++] = vertexPoint[j][0];
vertexData[coordinateElement++] = vertexPoint[j][1];
vertexData[coordinateElement++] = vertexPoint[j][2];
colorData[colorElement++] = rgba[0];
colorData[colorElement++] = rgba[1];
colorData[colorElement++] = rgba[2];
colorData[colorElement++] = rgba[3];
}
}
}
- (RoundedCube *) Length:(GLfloat)initLength Width:(GLfloat)initWidth Height:(GLfloat)initHeight Bevel:(GLfloat)initBevel SmoothFactor:(int)initSmoothFactor RGBA:(GLubyte *)initRGBA AbsNormals:(BOOL)initUseAbsNormals
{
int i;
smoothFactor = initSmoothFactor;
useAbsNormals = initUseAbsNormals;
shape = (id *)self;
length = initLength;
width = initWidth;
height = initHeight;
bevel = initBevel;
coordinateElement=0;
colorElement=0;
for (i=0; i<24; i++)
rgba[i] = initRGBA[i];
vertexCount = 36 + (12 * 6 * smoothFactor) + (smoothFactor * smoothFactor * 6 * 8);
modelType = MT_BOX;
constructMode = GL_TRIANGLES;
showColorAndTexture = NO;
vertexDataCount = vertexCount * 3;
colorDataCount = vertexCount * 4;
normalDataCount = vertexCount * 3;
[self setSurfaceToDefault];
vertexData = (GLfloat *)malloc(sizeof(GLfloat) * vertexDataCount);
memset(vertexData, (unsigned int)0, sizeof(GLfloat) * vertexDataCount);
normalData = (GLfloat *)malloc(sizeof(GLfloat) * normalDataCount);
memset(normalData, (unsigned int)0, sizeof(GLfloat) * normalDataCount);
colorData = (GLubyte *)malloc(sizeof(GLubyte) * colorDataCount);
memset(colorData, (unsigned int)0, sizeof(GLubyte) * colorDataCount);
int cubeSide;
int trianglesPerSide;
int pointsPerTriangle;
for ( cubeSide=0; cubeSide<6; cubeSide++ )
{
for ( trianglesPerSide=0; trianglesPerSide<2; trianglesPerSide++ )
{
for ( pointsPerTriangle=0; pointsPerTriangle<3; pointsPerTriangle++ )
{
switch( cubeSide )
{
case 0:
case 1:
vertexData[coordinateElement+0] = voffset[coordinateElement+0] * (length - bevel);
vertexData[coordinateElement+1] = voffset[coordinateElement+1] * (width - bevel);
vertexData[coordinateElement+2] = voffset[coordinateElement+2] * height;
break;
case 2:
case 3:
vertexData[coordinateElement+0] = voffset[coordinateElement+0] * (length - bevel);
vertexData[coordinateElement+1] = voffset[coordinateElement+1] * width;
vertexData[coordinateElement+2] = voffset[coordinateElement+2] * (height - bevel);
break;
case 4:
case 5:
vertexData[coordinateElement+0] = voffset[coordinateElement+0] * length;
vertexData[coordinateElement+1] = voffset[coordinateElement+1] * (width - bevel);
vertexData[coordinateElement+2] = voffset[coordinateElement+2] * (height - bevel);
break;
}
coordinateElement += 3;
colorData[colorElement++] = rgba[(cubeSide*4) + 0]; // 1 RGBA color set per side
colorData[colorElement++] = rgba[(cubeSide*4) + 1]; // 1 RGBA color set per side
colorData[colorElement++] = rgba[(cubeSide*4) + 2]; // 1 RGBA color set per side
colorData[colorElement++] = rgba[(cubeSide*4) + 3]; // 1 RGBA color set per side
}
}
}
[self addBeveledEdge:2 At:btVector3((length-bevel), (width-bevel), 0) Size:btVector3(bevel,bevel,height-bevel) Rotation:(double)0.0];
[self addBeveledEdge:2 At:btVector3(-(length-bevel), (width-bevel), 0) Size:btVector3(bevel,bevel,height-bevel) Rotation:(double)-M_PI_2];
[self addBeveledEdge:2 At:btVector3(-(length-bevel), -(width-bevel), 0) Size:btVector3(bevel,bevel,height-bevel) Rotation:(double)-M_PI];
[self addBeveledEdge:2 At:btVector3((length-bevel), -(width-bevel), 0) Size:btVector3(bevel,bevel,height-bevel) Rotation:(double)M_PI_2];
[self addBeveledEdge:1 At:btVector3((length-bevel), 0, (height-bevel)) Size:btVector3(bevel,width-bevel,bevel) Rotation:(double)0.0];
[self addBeveledEdge:1 At:btVector3(-(length-bevel), 0, (height-bevel)) Size:btVector3(bevel,width-bevel,bevel) Rotation:(double)-M_PI_2];
[self addBeveledEdge:1 At:btVector3(-(length-bevel), 0, -(height-bevel)) Size:btVector3(bevel,width-bevel,bevel) Rotation:(double)-M_PI];
[self addBeveledEdge:1 At:btVector3((length-bevel), 0, -(height-bevel)) Size:btVector3(bevel,width-bevel,bevel) Rotation:(double)M_PI_2];
[self addBeveledEdge:0 At:btVector3(0, (width-bevel), (height-bevel)) Size:btVector3(length-bevel,bevel,bevel) Rotation:(double)0.0];
[self addBeveledEdge:0 At:btVector3(0, -(width-bevel), (height-bevel)) Size:btVector3(length-bevel,bevel,bevel) Rotation:(double)-M_PI_2];
[self addBeveledEdge:0 At:btVector3(0, -(width-bevel), -(height-bevel)) Size:btVector3(length-bevel,bevel,bevel) Rotation:(double)-M_PI];
[self addBeveledEdge:0 At:btVector3(0, (width-bevel), -(height-bevel)) Size:btVector3(length-bevel,bevel,bevel) Rotation:(double)M_PI_2];
[self addBeveledCorner:0 At:btVector3((length-bevel), (width-bevel), (height-bevel)) Size:btVector3(bevel,bevel,bevel) Rotation:(double)0.0];
[self addBeveledCorner:0 At:btVector3((length-bevel), (width-bevel), -(height-bevel)) Size:btVector3(bevel,bevel,bevel) Rotation:(double)-M_PI_2];
[self addBeveledCorner:0 At:btVector3(-(length-bevel), (width-bevel), (height-bevel)) Size:btVector3(bevel,bevel,bevel) Rotation:(double)M_PI_2];
[self addBeveledCorner:0 At:btVector3(-(length-bevel), (width-bevel), -(height-bevel)) Size:btVector3(bevel,bevel,bevel) Rotation:(double)M_PI];
[self addBeveledCorner:1 At:btVector3((length-bevel), -(width-bevel), (height-bevel)) Size:btVector3(bevel,bevel,bevel) Rotation:(double)0.0];
[self addBeveledCorner:1 At:btVector3((length-bevel), -(width-bevel), -(height-bevel)) Size:btVector3(bevel,bevel,bevel) Rotation:(double)-M_PI_2];
[self addBeveledCorner:1 At:btVector3(-(length-bevel), -(width-bevel), (height-bevel)) Size:btVector3(bevel,bevel,bevel) Rotation:(double)M_PI_2];
[self addBeveledCorner:1 At:btVector3(-(length-bevel), -(width-bevel), -(height-bevel)) Size:btVector3(bevel,bevel,bevel) Rotation:(double)M_PI];
[self computeRoundedCubeNormals];
return self;
}
@ end
Если у вас есть устройство iOS, вы можете увидеть пример того, как это выглядит в моем бесплатном приложении Удивительные кости HD на iTunes