triangle strip好于triangle list:
所以通常意义上,能用strip就strip吧。
尤其是在程序生成的地方应该使用triangle strip的。
限制就是直接使用是需要带状的,任意形状需要用degenerate triangle来做,也就是使用有重复点的triangle。
(ABCDDFFEDC, which would be interpreted as triangles ABC CBD CDD DDF DFF FFE FED DEC)
需要注意的就是vertex shader里对于有同样点的triangle仍旧会做计算,当然如果cache hit就直接过,在rasterization阶段会对无面积的triangle干掉。
cache 命中的地方,大家都熟悉了,使用id3dxmesh::optimize会有不错的cache效率提升。
google的时候看见一个用triangle strip以螺旋的方式来做sphere construction的,挺有意思,贴它的代码吧:
#include <cmath> #include <vector> #include <gl/glut.h> const float PI = 3.14159265358979323846f; #pragma pack(1) template <typename TYPE> class GeometryVector { public: GeometryVector(const TYPE x_ = TYPE(), const TYPE y_ = TYPE(), const TYPE z_ = TYPE()); const TYPE x; const TYPE y; const TYPE z; }; #pragma pack() template <typename TYPE>GeometryVector<TYPE>::GeometryVector(const TYPE x_, const TYPE y_, const TYPE z_) : x(x_), y(y_), z(z_) {} class StackedSphere { public: StackedSphere(const float radius = 1.0f, const unsigned int stacks = 8, const unsigned int slices = 16); void render() const; private: std::vector<GeometryVector<float> > geometryData_; std::vector<unsigned short> indexData_; }; StackedSphere::StackedSphere(const float radius, const unsigned int stacks, const unsigned int slices) { for (unsigned int stackNumber = 0; stackNumber <= stacks; ++stackNumber) { for (unsigned int sliceNumber = 0; sliceNumber < slices; ++sliceNumber) { float theta = stackNumber * PI / stacks; float phi = sliceNumber * 2 * PI / slices; float sinTheta = std::sin(theta); float sinPhi = std::sin(phi); float cosTheta = std::cos(theta); float cosPhi = std::cos(phi); geometryData_.push_back(GeometryVector<float>(radius * cosPhi * sinTheta, radius * sinPhi * sinTheta, radius * cosTheta)); } } for (unsigned int stackNumber = 0; stackNumber < stacks; ++stackNumber) { for (unsigned int sliceNumber = 0; sliceNumber <= slices; ++sliceNumber) { indexData_.push_back((stackNumber * slices) + (sliceNumber % slices)); indexData_.push_back(((stackNumber + 1) * slices) + (sliceNumber % slices)); } } } void StackedSphere::render() const { glVertexPointer(3, GL_FLOAT, 0, &geometryData_[0]); glEnableClientState(GL_VERTEX_ARRAY); glDrawElements(GL_TRIANGLE_STRIP, indexData_.size(), GL_UNSIGNED_SHORT, &indexData_[0]); } class SpiralSphere { public: SpiralSphere(const float radius = 1.0f, const unsigned int loops = 8, const unsigned int segmentsPerLoop = 16); void render() const; private: std::vector<GeometryVector<float> > geometryData_; std::vector<unsigned short> indexData_; }; SpiralSphere::SpiralSphere(const float radius, const unsigned int loops, const unsigned int segmentsPerLoop) { for (unsigned int loopSegmentNumber = 0; loopSegmentNumber < segmentsPerLoop; ++loopSegmentNumber) { float theta = 0; float phi = loopSegmentNumber * 2 * PI / segmentsPerLoop; float sinTheta = std::sin(theta); float sinPhi = std::sin(phi); float cosTheta = std::cos(theta); float cosPhi = std::cos(phi); geometryData_.push_back(GeometryVector<float>(radius * cosPhi * sinTheta, radius * sinPhi * sinTheta, radius * cosTheta)); } for (unsigned int loopNumber = 0; loopNumber <= loops; ++loopNumber) { for (unsigned int loopSegmentNumber = 0; loopSegmentNumber < segmentsPerLoop; ++loopSegmentNumber) { float theta = (loopNumber * PI / loops) + ((PI * loopSegmentNumber) / (segmentsPerLoop * loops)); if (loopNumber == loops) { theta = PI; } float phi = loopSegmentNumber * 2 * PI / segmentsPerLoop; float sinTheta = std::sin(theta); float sinPhi = std::sin(phi); float cosTheta = std::cos(theta); float cosPhi = std::cos(phi); geometryData_.push_back(GeometryVector<float>(radius * cosPhi * sinTheta, radius * sinPhi * sinTheta, radius * cosTheta)); } } for (unsigned int loopSegmentNumber = 0; loopSegmentNumber < segmentsPerLoop; ++loopSegmentNumber) { indexData_.push_back(loopSegmentNumber); indexData_.push_back(segmentsPerLoop + loopSegmentNumber); } for (unsigned int loopNumber = 0; loopNumber < loops; ++loopNumber) { for (unsigned int loopSegmentNumber = 0; loopSegmentNumber < segmentsPerLoop; ++loopSegmentNumber) { indexData_.push_back(((loopNumber + 1) * segmentsPerLoop) + loopSegmentNumber); indexData_.push_back(((loopNumber + 2) * segmentsPerLoop) + loopSegmentNumber); } } } void SpiralSphere::render() const { glVertexPointer(3, GL_FLOAT, 0, &geometryData_[0]); glEnableClientState(GL_VERTEX_ARRAY); glDrawElements(GL_TRIANGLE_STRIP, indexData_.size(), GL_UNSIGNED_SHORT, &indexData_[0]); } StackedSphere sphere1(4, 8, 16);SpiralSphere sphere2(4, 8, 16); int r = 0; void reshape(int width, int height) { if (height == 0) { height = 1; } glMatrixMode(GL_PROJECTION); glLoadIdentity(); glViewport(0, 0, width, height); gluPerspective(45.0f, GLfloat(width) / GLfloat(height), 0.1f, 50.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glTranslatef(0, 0, -25); glPushMatrix(); glTranslatef(-5, 0, 0); glRotatef(r, 0, 1, 0); sphere1.render(); glPopMatrix(); glPushMatrix(); glTranslatef(5, 0, 0); glRotatef(r, 0, 1, 0); sphere2.render(); glPopMatrix(); glutSwapBuffers(); r++; } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); glutInitWindowPosition(0, 0); glutInitWindowSize(512,512); glutCreateWindow("Sphere Test"); glutReshapeFunc(reshape); glutDisplayFunc(display); glutIdleFunc(display); glPolygonMode(GL_FRONT, GL_LINE); glPolygonMode(GL_BACK, GL_LINE); glutMainLoop(); return 0; }