//----------------------------------------------------------------------- void Lathe::_latheBodyImpl(TriangleBuffer& buffer, const Shape* shapeToExtrude) const { int numSegShape = shapeToExtrude->getSegCount(); assert(numSegShape>1 && "Shape must contain at least two points"); int offset =0; //int numSeg = mClosed?mNumSeg+1:mNumSeg; int numSeg = mNumSeg+1; buffer.rebaseOffset(); buffer.estimateIndexCount(numSeg*numSegShape*6); buffer.estimateVertexCount((numSegShape+1)*(numSeg+1)); Radian angleEnd(mAngleEnd); if (mAngleBegin>mAngleEnd) angleEnd+=(Radian)Math::TWO_PI; for (int i=0;i<numSeg;i++) { Radian angle; if (mClosed) angle = i/(Real)mNumSeg*Math::TWO_PI; else angle = mAngleBegin + i/(Real)mNumSeg*(angleEnd-mAngleBegin); Quaternion q; q.FromAngleAxis(angle,Vector3::UNIT_Y); for (int j=0;j<=numSegShape;j++) { const Vector2& v0 = shapeToExtrude->getPoint(j); Vector3 vp(v0.x,v0.y,0); const Vector2& vp2direction = shapeToExtrude->getAvgDirection(j); Vector2 vp2normal = vp2direction.perpendicular(); Vector3 normal(vp2normal.x, vp2normal.y, 0); normal.normalise(); if (shapeToExtrude->getOutSide() == SIDE_RIGHT) normal = -normal; addPoint(buffer, q*vp, q*normal, Vector2(i/(Real)mNumSeg, j/(Real)numSegShape)); if (j <numSegShape && i <numSeg-1) { if (shapeToExtrude->getOutSide() == SIDE_RIGHT) { buffer.triangle(offset + numSegShape + 2, offset, offset + numSegShape + 1); buffer.triangle(offset + numSegShape + 2, offset + 1, offset); } else { buffer.triangle(offset + numSegShape + 2, offset + numSegShape + 1, offset); buffer.triangle(offset + numSegShape + 2, offset, offset + 1); } } offset ++; } } }
void PlaneGenerator::addToTriangleBuffer(TriangleBuffer& buffer) const { assert(mNumSegX>0 && mNumSegY>0 && "Num seg must be positive"); assert(!mNormal.isZeroLength() && "Normal must not be null"); assert(mSizeX>0. && mSizeY>0. && "Size must be positive"); buffer.rebaseOffset(); buffer.estimateVertexCount((mNumSegX+1)*(mNumSegY+1)); buffer.estimateIndexCount(mNumSegX*mNumSegY*6); int offset = 0; Vector3 vX = mNormal.perpendicular(); Vector3 vY = mNormal.crossProduct(vX); Vector3 delta1 = mSizeX / (Real)mNumSegX * vX; Vector3 delta2 = mSizeY / (Real)mNumSegY * vY; // build one corner of the square Vector3 orig = -0.5f*mSizeX*vX - 0.5f*mSizeY*vY; for (unsigned short i1 = 0; i1<=mNumSegX; i1++) for (unsigned short i2 = 0; i2<=mNumSegY; i2++) { addPoint(buffer, orig+i1*delta1+i2*delta2, mNormal, Vector2(i1/(Real)mNumSegX, i2/(Real)mNumSegY)); } bool reverse = false; if (delta1.crossProduct(delta2).dotProduct(mNormal)>0) reverse= true; for (unsigned short n1 = 0; n1<mNumSegX; n1++) { for (unsigned short n2 = 0; n2<mNumSegY; n2++) { if (reverse) { buffer.index(offset+0); buffer.index(offset+(mNumSegY+1)); buffer.index(offset+1); buffer.index(offset+1); buffer.index(offset+(mNumSegY+1)); buffer.index(offset+(mNumSegY+1)+1); } else { buffer.index(offset+0); buffer.index(offset+1); buffer.index(offset+(mNumSegY+1)); buffer.index(offset+1); buffer.index(offset+(mNumSegY+1)+1); buffer.index(offset+(mNumSegY+1)); } offset++; } offset++; } }
void PlaneGenerator::addToTriangleBuffer(TriangleBuffer& buffer) const { assert(numSegX>0 && numSegY>0 && "Num seg must be positive"); assert(!normal.isZeroLength() && "Normal must not be null"); assert(sizeX>0. && sizeY>0. && "Size must be positive"); buffer.rebaseOffset(); buffer.estimateVertexCount((numSegX+1)*(numSegY+1)); buffer.estimateIndexCount(numSegX*numSegY*6); int offset = 0; Ogre::Vector3 vX = normal.perpendicular(); Ogre::Vector3 vY = normal.crossProduct(vX); Ogre::Vector3 delta1 = sizeX / numSegX * vX; Ogre::Vector3 delta2 = sizeY / numSegY * vY; // build one corner of the square Ogre::Vector3 orig = -0.5*sizeX*vX - 0.5*sizeY*vY; for (int i1 = 0; i1<=numSegX; i1++) for (int i2 = 0; i2<=numSegY; i2++) { buffer.position(orig+i1*delta1+i2*delta2+position); buffer.textureCoord(i1/(Ogre::Real)numSegX*uTile, i2/(Ogre::Real)numSegY*vTile); buffer.normal(normal); } bool reverse = false; if (delta1.crossProduct(delta2).dotProduct(normal)>0) reverse= true; for (int n1 = 0; n1<numSegX; n1++) { for (int n2 = 0; n2<numSegY; n2++) { if (reverse) { buffer.index(offset+0); buffer.index(offset+(numSegY+1)); buffer.index(offset+1); buffer.index(offset+1); buffer.index(offset+(numSegY+1)); buffer.index(offset+(numSegY+1)+1); } else { buffer.index(offset+0); buffer.index(offset+1); buffer.index(offset+(numSegY+1)); buffer.index(offset+1); buffer.index(offset+(numSegY+1)+1); buffer.index(offset+(numSegY+1)); } offset++; } offset++; } }
void TorusKnotGenerator::addToTriangleBuffer(TriangleBuffer& buffer) const { assert(mNumSegSection>0 && mNumSegCircle>0 && "Num seg and circle must be positive"); assert(mRadius>0. && mSectionRadius>0. && "Radius and section radius must be positive"); assert(mP>0 && mQ>0 && "p and q must be positive"); buffer.rebaseOffset(); buffer.estimateVertexCount((mNumSegCircle*mP+1)*(mNumSegSection+1)); buffer.estimateIndexCount((mNumSegCircle*mP)*(mNumSegSection+1)*6); int offset = 0; for (int i = 0; i <= mNumSegCircle * mP;i++) { Real phi = Math::TWO_PI * i/(Real)mNumSegCircle; Real x0 = mRadius*(2 + cos(mQ*phi/(Real)mP)) * cos(phi) / 3.f; Real y0 = mRadius*sin(mQ*phi/(Real)mP) / 3.f; Real z0 = mRadius*(2 + cos(mQ*phi/(Real)mP)) * sin(phi) / 3.f; Real phi1 = Math::TWO_PI * (i+1)/(Real)mNumSegCircle; Real x1 = mRadius*(2 + cos(mQ*phi1/(Real)mP)) * cos(phi1) / 3.f; Real y1 = mRadius*sin(mQ*phi1/mP) / 3.f; Real z1 = mRadius*(2 + cos(mQ*phi1/(Real)mP)) * sin(phi1) / 3.f; Vector3 v0(x0,y0,z0); Vector3 v1(x1,y1,z1); Vector3 direction((v1-v0).normalisedCopy()); Quaternion q = Utils::_computeQuaternion(direction); for (int j =0;j<=mNumSegSection;j++) { Real alpha = Math::TWO_PI *j/mNumSegSection; Vector3 vp = mSectionRadius*(q * Vector3(cos(alpha), sin(alpha),0)); addPoint(buffer, v0+vp, vp.normalisedCopy(), Vector2(i/(Real)mNumSegCircle, j/(Real)mNumSegSection)); if (i != mNumSegCircle * mP) { buffer.index(offset + mNumSegSection + 1); buffer.index(offset + mNumSegSection); buffer.index(offset); buffer.index(offset + mNumSegSection + 1); buffer.index(offset); buffer.index(offset + 1); } offset ++; } } }
void Lathe::addToTriangleBuffer(TriangleBuffer& buffer) const { assert( mShapeToExtrude && "Shape must not be null!"); int numSegShape = mShapeToExtrude->getSegCount(); assert(numSegShape>1 && "Shape must contain at least two points"); int offset =0; buffer.rebaseOffset(); buffer.estimateIndexCount(mNumSeg*numSegShape*6); buffer.estimateVertexCount((numSegShape+1)*(mNumSeg+1)); for (int i=0;i<=mNumSeg;i++) { Real angle = i/(Real)mNumSeg*Math::TWO_PI; Quaternion q; q.FromAngleAxis((Radian)angle,Vector3::UNIT_Y); for (int j=0;j<=numSegShape;j++) { Vector2 v0 = mShapeToExtrude->getPoint(j); Vector3 vp(v0.x,v0.y,0); Vector2 vp2direction = mShapeToExtrude->getAvgDirection(j); Vector2 vp2normal = vp2direction.perpendicular(); Vector3 normal(vp2normal.x, vp2normal.y, 0); normal.normalise(); if (mShapeToExtrude->getOutSide() == SIDE_LEFT) { normal = -normal; } addPoint(buffer, q*vp, q*normal, Vector2(i/(Real)mNumSeg, j/(Real)numSegShape)); if (j <numSegShape && i <mNumSeg) { buffer.index(offset + numSegShape + 2); buffer.index(offset); buffer.index(offset + numSegShape + 1); buffer.index(offset + numSegShape + 2); buffer.index(offset + 1); buffer.index(offset); } offset ++; } } }
void SphereGenerator::addToTriangleBuffer(TriangleBuffer& buffer) const { assert(mNumRings>0 && mNumSegments>0 && "Num seg must be positive"); assert(mRadius>0 && "Radius must be positive"); buffer.rebaseOffset(); buffer.estimateVertexCount((mNumRings+1)*(mNumSegments+1)); buffer.estimateIndexCount(mNumRings*(mNumSegments+1)*6); Real fDeltaRingAngle = (Math::PI / mNumRings); Real fDeltaSegAngle = (Math::TWO_PI / mNumSegments); int offset = 0; // Generate the group of rings for the sphere for(unsigned int ring = 0; ring <= mNumRings; ring++ ) { Real r0 = mRadius * sinf (ring * fDeltaRingAngle); Real y0 = mRadius * cosf (ring * fDeltaRingAngle); // Generate the group of segments for the current ring for(unsigned int seg = 0; seg <= mNumSegments; seg++) { Real x0 = r0 * sinf(seg * fDeltaSegAngle); Real z0 = r0 * cosf(seg * fDeltaSegAngle); // Add one vertex to the strip which makes up the sphere addPoint(buffer, Vector3(x0, y0, z0), Vector3(x0, y0, z0).normalisedCopy(), Vector2((Real) seg / (Real) mNumSegments, (Real) ring / (Real) mNumRings)); if (ring != mNumRings) { // each vertex (except the last) has six indices pointing to it buffer.index(offset + mNumSegments + 1); buffer.index(offset); buffer.index(offset + mNumSegments); buffer.index(offset + mNumSegments + 1); buffer.index(offset + 1); buffer.index(offset); offset ++; } }; // end for seg } // end for ring }
void CylinderGenerator::addToTriangleBuffer(TriangleBuffer& buffer) const { assert(mHeight>0. && mRadius>0. && "height and radius must be positive"); assert(mNumSegBase>0 && mNumSegHeight>0 && "Num seg must be positive integers"); buffer.rebaseOffset(); if (mCapped) { buffer.estimateVertexCount((mNumSegHeight+1)*(mNumSegBase+1)+2*(mNumSegBase+1)+2); buffer.estimateIndexCount(mNumSegHeight*(mNumSegBase+1)*6+6*mNumSegBase); } else { buffer.estimateVertexCount((mNumSegHeight+1)*(mNumSegBase+1)); buffer.estimateIndexCount(mNumSegHeight*(mNumSegBase+1)*6); } Real deltaAngle = (Math::TWO_PI / mNumSegBase); Real deltaHeight = mHeight/(Real)mNumSegHeight; int offset = 0; for (int i = 0; i <=mNumSegHeight; i++) for (int j = 0; j<=mNumSegBase; j++) { Real x0 = mRadius * cosf(j*deltaAngle); Real z0 = mRadius * sinf(j*deltaAngle); addPoint(buffer, Vector3(x0, i*deltaHeight, z0), Vector3(x0,0,z0).normalisedCopy(), Vector2(j/(Real)mNumSegBase, i/(Real)mNumSegHeight)); if (i != mNumSegHeight) { buffer.index(offset + mNumSegBase + 1); buffer.index(offset); buffer.index(offset + mNumSegBase); buffer.index(offset + mNumSegBase + 1); buffer.index(offset + 1); buffer.index(offset); } offset ++; } if (mCapped) { //low cap int centerIndex = offset; addPoint(buffer, Vector3::ZERO, Vector3::NEGATIVE_UNIT_Y, Vector2::UNIT_Y); offset++; for (int j=0;j<=mNumSegBase;j++) { Real x0 = mRadius * cosf(j*deltaAngle); Real z0 = mRadius * sinf(j*deltaAngle); addPoint(buffer, Vector3(x0, 0.0f, z0), Vector3::NEGATIVE_UNIT_Y, Vector2(j/(Real)mNumSegBase,0.0)); if (j!=mNumSegBase) { buffer.index(centerIndex); buffer.index(offset); buffer.index(offset+1); } offset++; } // high cap centerIndex = offset; addPoint(buffer, Vector3(0,mHeight,0), Vector3::UNIT_Y, Vector2::ZERO); offset++; for (int j=0;j<=mNumSegBase;j++) { Real x0 = mRadius * cosf(j*deltaAngle); Real z0 = mRadius * sinf(j*deltaAngle); addPoint(buffer, Vector3(x0, mHeight, z0), Vector3::UNIT_Y, Vector2(j/(Real)mNumSegBase,1.)); if (j!=mNumSegBase) { buffer.index(centerIndex); buffer.index(offset+1); buffer.index(offset); } offset++; } } }
void CapsuleGenerator::addToTriangleBuffer(TriangleBuffer& buffer) const { assert(mNumRings>0 && mNumSegments>0 && mNumSegHeight>0 && "Num seg must be positive integers"); assert(mHeight>0. && mRadius>0. && "mHeight and radius must be positive"); buffer.rebaseOffset(); buffer.estimateVertexCount((2*mNumRings+2)*(mNumSegments+1) + (mNumSegHeight-1)*(mNumSegments+1)); buffer.estimateIndexCount((2*mNumRings+1)*(mNumSegments+1)*6 + (mNumSegHeight-1)*(mNumSegments+1)*6); Real fDeltaRingAngle = (Math::HALF_PI / mNumRings); Real fDeltaSegAngle = (Math::TWO_PI / mNumSegments); Real sphereRatio = mRadius / (2 * mRadius + mHeight); Real cylinderRatio = mHeight / (2 * mRadius + mHeight); int offset = 0; // Top half sphere // Generate the group of rings for the sphere for(unsigned int ring = 0; ring <= mNumRings; ring++ ) { Real r0 = mRadius * sinf ( ring * fDeltaRingAngle); Real y0 = mRadius * cosf (ring * fDeltaRingAngle); // Generate the group of segments for the current ring for(unsigned int seg = 0; seg <= mNumSegments; seg++) { Real x0 = r0 * cosf(seg * fDeltaSegAngle); Real z0 = r0 * sinf(seg * fDeltaSegAngle); // Add one vertex to the strip which makes up the sphere addPoint(buffer, Vector3(x0, 0.5f*mHeight + y0, z0), Vector3(x0, y0, z0).normalisedCopy(), Vector2((Real) seg / (Real) mNumSegments, (Real) ring / (Real) mNumRings * sphereRatio)); // each vertex (except the last) has six indices pointing to it buffer.index(offset + mNumSegments + 1); buffer.index(offset + mNumSegments); buffer.index(offset); buffer.index(offset + mNumSegments + 1); buffer.index(offset); buffer.index(offset + 1); offset ++; } // end for seg } // end for ring // Cylinder part Real deltaAngle = (Math::TWO_PI / mNumSegments); Real deltamHeight = mHeight/(Real)mNumSegHeight; for (unsigned short i = 1; i < mNumSegHeight; i++) for (unsigned short j = 0; j<=mNumSegments; j++) { Real x0 = mRadius * cosf(j*deltaAngle); Real z0 = mRadius * sinf(j*deltaAngle); addPoint(buffer, Vector3(x0, 0.5f*mHeight-i*deltamHeight, z0), Vector3(x0,0,z0).normalisedCopy(), Vector2(j/(Real)mNumSegments, i/(Real)mNumSegHeight * cylinderRatio + sphereRatio)); buffer.index(offset + mNumSegments + 1); buffer.index(offset + mNumSegments); buffer.index(offset); buffer.index(offset + mNumSegments + 1); buffer.index(offset); buffer.index(offset + 1); offset ++; } // Bottom half sphere // Generate the group of rings for the sphere for(unsigned int ring = 0; ring <= mNumRings; ring++) { Real r0 = mRadius * sinf (Math::HALF_PI + ring * fDeltaRingAngle); Real y0 = mRadius * cosf (Math::HALF_PI + ring * fDeltaRingAngle); // Generate the group of segments for the current ring for(unsigned int seg = 0; seg <= mNumSegments; seg++) { Real x0 = r0 * cosf(seg * fDeltaSegAngle); Real z0 = r0 * sinf(seg * fDeltaSegAngle); // Add one vertex to the strip which makes up the sphere addPoint(buffer, Vector3(x0, -0.5f*mHeight + y0, z0), Vector3(x0, y0, z0).normalisedCopy(), Vector2((Real) seg / (Real) mNumSegments, (Real) ring / (Real) mNumRings*sphereRatio + cylinderRatio + sphereRatio)); if (ring != mNumRings) { // each vertex (except the last) has six indices pointing to it buffer.index(offset + mNumSegments + 1); buffer.index(offset + mNumSegments); buffer.index(offset); buffer.index(offset + mNumSegments + 1); buffer.index(offset); buffer.index(offset + 1); } offset ++; } // end for seg } // end for ring }
void TubeGenerator::addToTriangleBuffer(TriangleBuffer& buffer) const { buffer.rebaseOffset(); buffer.estimateVertexCount((mNumSegHeight+1)*(mNumSegBase+1)*2+(mNumSegBase+1)*4); buffer.estimateIndexCount(6*(mNumSegBase+1)*mNumSegHeight*2+6*mNumSegBase*2); Real deltaAngle = (Math::TWO_PI / mNumSegBase); Real deltaHeight = mHeight/(Real)mNumSegHeight; int offset = 0; for (unsigned int i = 0; i <=mNumSegHeight; i++) for (unsigned int j = 0; j<=mNumSegBase; j++) { Real x0 = mOuterRadius * cosf(j*deltaAngle); Real z0 = mOuterRadius * sinf(j*deltaAngle); addPoint(buffer, Vector3(x0, i*deltaHeight, z0), Vector3(x0,0,z0).normalisedCopy(), Vector2(j/(Real)mNumSegBase, i/(Real)mNumSegHeight)); if (i != mNumSegHeight) { buffer.index(offset + mNumSegBase + 1); buffer.index(offset); buffer.index(offset + mNumSegBase); buffer.index(offset + mNumSegBase + 1); buffer.index(offset + 1); buffer.index(offset); } offset ++; } for (unsigned int i = 0; i <=mNumSegHeight; i++) for (unsigned int j = 0; j<=mNumSegBase; j++) { Real x0 = mInnerRadius * cosf(j*deltaAngle); Real z0 = mInnerRadius * sinf(j*deltaAngle); addPoint(buffer, Vector3(x0, i*deltaHeight, z0), -Vector3(x0,0,z0).normalisedCopy(), Vector2(j/(Real)mNumSegBase, i/(Real)mNumSegHeight)); if (i != mNumSegHeight) { buffer.index(offset + mNumSegBase + 1); buffer.index(offset + mNumSegBase); buffer.index(offset); buffer.index(offset + mNumSegBase + 1); buffer.index(offset); buffer.index(offset + 1); } offset ++; } //low cap for (unsigned int j=0; j<=mNumSegBase; j++) { Real x0 = mInnerRadius * cosf(j*deltaAngle); Real z0 = mInnerRadius * sinf(j*deltaAngle); addPoint(buffer, Vector3(x0, 0.0f, z0), Vector3::NEGATIVE_UNIT_Y, Vector2(j/(Real)mNumSegBase,1.)); x0 = mOuterRadius * cosf(j*deltaAngle); z0 = mOuterRadius * sinf(j*deltaAngle); addPoint(buffer, Vector3(x0, 0.0f, z0), Vector3::NEGATIVE_UNIT_Y, Vector2(j/(Real)mNumSegBase,0.)); if (j!=mNumSegBase) { buffer.index(offset); buffer.index(offset+1); buffer.index(offset+3); buffer.index(offset+2); buffer.index(offset); buffer.index(offset+3); } offset+=2; } //high cap for (unsigned int j=0; j<=mNumSegBase; j++) { Real x0 = mInnerRadius * cosf(j*deltaAngle); Real z0 = mInnerRadius * sinf(j*deltaAngle); addPoint(buffer, Vector3(x0, mHeight, z0), Vector3::UNIT_Y, Vector2(j/(Real)mNumSegBase,0.)); x0 = mOuterRadius * cosf(j*deltaAngle); z0 = mOuterRadius * sinf(j*deltaAngle); addPoint(buffer, Vector3(x0, mHeight, z0), Vector3::UNIT_Y, Vector2(j/(Real)mNumSegBase,1.)); if (j!=mNumSegBase) { buffer.index(offset+1); buffer.index(offset); buffer.index(offset+3); buffer.index(offset); buffer.index(offset+2); buffer.index(offset+3); } offset+=2; } }
//----------------------------------------------------------------------- void Extruder::_extrudeBodyImpl(TriangleBuffer& buffer, const Shape* shapeToExtrude) const { assert(mExtrusionPath && shapeToExtrude && "Shape and Path must not be null!"); unsigned int numSegPath = mExtrusionPath->getSegCount(); unsigned int numSegShape = shapeToExtrude->getSegCount(); assert(numSegPath>0 && numSegShape>0 && "Shape and path must contain at least two points"); Real totalPathLength = mExtrusionPath->getTotalLength(); Real totalShapeLength = shapeToExtrude->getTotalLength(); // Merge shape and path with tracks Ogre::Real lineicPos=0.; Path path = *mExtrusionPath; if (mRotationTrack) path = path.mergeKeysWithTrack(*mRotationTrack); if (mScaleTrack) path = path.mergeKeysWithTrack(*mScaleTrack); if (mPathTextureTrack) path = path.mergeKeysWithTrack(*mPathTextureTrack); numSegPath = path.getSegCount(); Shape shape = *shapeToExtrude; if (mShapeTextureTrack) shape = shape.mergeKeysWithTrack(*mShapeTextureTrack); numSegShape = shape.getSegCount(); // Estimate vertex and index count buffer.rebaseOffset(); buffer.estimateIndexCount(numSegShape*numSegPath*6); buffer.estimateVertexCount((numSegShape+1)*(numSegPath+1)); Vector3 oldup; for (unsigned int i = 0; i <= numSegPath; ++i) { Vector3 v0 = path.getPoint(i); Vector3 direction = path.getAvgDirection(i); Quaternion q = Utils::_computeQuaternion(direction); Radian angle = (q*Vector3::UNIT_Y).angleBetween(oldup); if (i>0 && angle>(Radian)Math::HALF_PI/2.) { q = Utils::_computeQuaternion(direction, oldup); } oldup = q * Vector3::UNIT_Y; Real scale=1.; if (i>0) lineicPos += (v0-path.getPoint(i-1)).length(); // Get the values of angle and scale if (mRotationTrack) { Real angle; angle = mRotationTrack->getValue(lineicPos, lineicPos / totalPathLength, i); q = q*Quaternion((Radian)angle, Vector3::UNIT_Z); } if (mScaleTrack) { scale = mScaleTrack->getValue(lineicPos, lineicPos / totalPathLength, i); } Real uTexCoord; if (mPathTextureTrack) uTexCoord = mPathTextureTrack->getValue(lineicPos, lineicPos / totalPathLength, i); else uTexCoord = lineicPos / totalPathLength; Real lineicShapePos = 0.; // Insert new points for (unsigned int j =0; j <= numSegShape; ++j) { Vector2 vp2 = shapeToExtrude->getPoint(j); //Vector2 vp2direction = shapeToExtrude->getAvgDirection(j); Vector2 vp2normal = shapeToExtrude->getAvgNormal(j); Vector3 vp(vp2.x, vp2.y, 0); Vector3 normal(vp2normal.x, vp2normal.y, 0); buffer.rebaseOffset(); Vector3 newPoint = v0+q*(scale*vp); if (j>0) lineicShapePos += (vp2 - shape.getPoint(j-1)).length(); Real vTexCoord; if (mShapeTextureTrack) vTexCoord = mShapeTextureTrack->getValue(lineicShapePos, lineicShapePos / totalShapeLength, j); else vTexCoord = lineicShapePos / totalShapeLength; addPoint(buffer, newPoint, q*normal, Vector2(uTexCoord, vTexCoord)); if (j <numSegShape && i <numSegPath) { if (shapeToExtrude->getOutSide() == SIDE_LEFT) { buffer.triangle(numSegShape + 1, numSegShape + 2, 0); buffer.triangle(0, numSegShape + 2, 1); } else { buffer.triangle(numSegShape + 2, numSegShape + 1, 0); buffer.triangle(numSegShape + 2, 0, 1); } } } } }
//----------------------------------------------------------------------- void Extruder::_extrudeCapImpl(TriangleBuffer& buffer) const { std::vector<int> indexBuffer; PointList pointList; buffer.rebaseOffset(); Triangulator t; if (mShapeToExtrude) t.setShapeToTriangulate(mShapeToExtrude); else t.setMultiShapeToTriangulate(mMultiShapeToExtrude); t.triangulate(indexBuffer, pointList); buffer.estimateIndexCount(2*indexBuffer.size()); buffer.estimateVertexCount(2*pointList.size()); //begin cap buffer.rebaseOffset(); Quaternion qBegin = Utils::_computeQuaternion(mExtrusionPath->getDirectionAfter(0)); if (mRotationTrack) { Real angle = mRotationTrack->getFirstValue(); qBegin = qBegin*Quaternion((Radian)angle, Vector3::UNIT_Z); } Real scaleBegin=1.; if (mScaleTrack) scaleBegin = mScaleTrack->getFirstValue(); for (size_t j =0;j<pointList.size();j++) { Vector2 vp2 = pointList[j]; Vector3 vp(vp2.x, vp2.y, 0); Vector3 normal = -Vector3::UNIT_Z; Vector3 newPoint = mExtrusionPath->getPoint(0)+qBegin*(scaleBegin*vp); addPoint(buffer, newPoint, qBegin*normal, vp2); } for (size_t i=0;i<indexBuffer.size()/3;i++) { buffer.index(indexBuffer[i*3]); buffer.index(indexBuffer[i*3+2]); buffer.index(indexBuffer[i*3+1]); } // end cap buffer.rebaseOffset(); Quaternion qEnd = Utils::_computeQuaternion(mExtrusionPath->getDirectionBefore(mExtrusionPath->getSegCount())); if (mRotationTrack) { Real angle = mRotationTrack->getLastValue(); qEnd = qEnd*Quaternion((Radian)angle, Vector3::UNIT_Z); } Real scaleEnd=1.; if (mScaleTrack) scaleEnd = mScaleTrack->getLastValue(); for (size_t j =0;j<pointList.size();j++) { Vector2 vp2 = pointList[j]; Vector3 vp(vp2.x, vp2.y, 0); Vector3 normal = Vector3::UNIT_Z; Vector3 newPoint = mExtrusionPath->getPoint(mExtrusionPath->getSegCount())+qEnd*(scaleEnd*vp); addPoint(buffer, newPoint, qEnd*normal, vp2); } for (size_t i=0;i<indexBuffer.size()/3;i++) { buffer.index(indexBuffer[i*3]); buffer.index(indexBuffer[i*3+1]); buffer.index(indexBuffer[i*3+2]); } }
void IcoSphereGenerator::addToTriangleBuffer(TriangleBuffer& buffer) const { assert(mRadius>0. && "Radius must me positive"); assert(mNumIterations>0 && "numIterations must be positive"); std::vector<Vector3> vertices; int offset = 0; /// Step 1 : Generate icosahedron Real phi = .5f*(1.f+sqrt(5.f)); Real invnorm = 1/sqrt(phi*phi+1); vertices.push_back(invnorm*Vector3(-1, phi, 0));//0 vertices.push_back(invnorm*Vector3( 1, phi, 0));//1 vertices.push_back(invnorm*Vector3(0, 1, -phi));//2 vertices.push_back(invnorm*Vector3(0, 1, phi));//3 vertices.push_back(invnorm*Vector3(-phi,0, -1));//4 vertices.push_back(invnorm*Vector3(-phi,0, 1));//5 vertices.push_back(invnorm*Vector3( phi,0, -1));//6 vertices.push_back(invnorm*Vector3( phi,0, 1));//7 vertices.push_back(invnorm*Vector3(0, -1, -phi));//8 vertices.push_back(invnorm*Vector3(0, -1, phi));//9 vertices.push_back(invnorm*Vector3(-1, -phi,0));//10 vertices.push_back(invnorm*Vector3( 1, -phi,0));//11 int firstFaces[] = {0,1,2, 0,3,1, 0,4,5, 1,7,6, 1,6,2, 1,3,7, 0,2,4, 0,5,3, 2,6,8, 2,8,4, 3,5,9, 3,9,7, 11,6,7, 10,5,4, 10,4,8, 10,9,5, 11,8,6, 11,7,9, 10,8,11, 10,11,9 }; std::vector<int> faces(firstFaces, firstFaces + sizeof(firstFaces)/sizeof(*firstFaces)); int size = 60; /// Step 2 : tessellate for (unsigned short iteration = 0; iteration<mNumIterations; iteration++) { size*=4; std::vector<int> newFaces; newFaces.clear(); //newFaces.resize(size); for (int i=0; i<size/12; i++) { int i1 = faces[i*3]; int i2 = faces[i*3+1]; int i3 = faces[i*3+2]; int i12 = vertices.size(); int i23 = i12+1; int i13 = i12+2; Vector3 v1 = vertices[i1]; Vector3 v2 = vertices[i2]; Vector3 v3 = vertices[i3]; //make 1 vertice at the center of each edge and project it onto the sphere vertices.push_back((v1+v2).normalisedCopy()); vertices.push_back((v2+v3).normalisedCopy()); vertices.push_back((v1+v3).normalisedCopy()); //now recreate indices newFaces.push_back(i1); newFaces.push_back(i12); newFaces.push_back(i13); newFaces.push_back(i2); newFaces.push_back(i23); newFaces.push_back(i12); newFaces.push_back(i3); newFaces.push_back(i13); newFaces.push_back(i23); newFaces.push_back(i12); newFaces.push_back(i23); newFaces.push_back(i13); } faces.swap(newFaces); } /// Step 3 : generate texcoords std::vector<Vector2> texCoords; for (unsigned short i=0;i<vertices.size();i++) { const Vector3& vec = vertices[i]; Real u, v; Real r0 = sqrtf(vec.x*vec.x+vec.z*vec.z); Real alpha; alpha = atan2f(vec.z,vec.x); u = alpha/Math::TWO_PI+.5f; v = atan2f(vec.y, r0)/Math::PI + .5f; texCoords.push_back(Vector2(u,v)); } /// Step 4 : fix texcoords // find vertices to split std::vector<int> indexToSplit; for (unsigned int i=0;i<faces.size()/3;i++) { Vector2& t0 = texCoords[faces[i*3+0]]; Vector2& t1 = texCoords[faces[i*3+1]]; Vector2& t2 = texCoords[faces[i*3+2]]; if (Math::Abs(t2.x-t0.x)>0.5) { if (t0.x<0.5) indexToSplit.push_back(faces[i*3]); else indexToSplit.push_back(faces[i*3+2]); } if (Math::Abs(t1.x-t0.x)>0.5) { if (t0.x<0.5) indexToSplit.push_back(faces[i*3]); else indexToSplit.push_back(faces[i*3+1]); } if (Math::Abs(t2.x-t1.x)>0.5) { if (t1.x<0.5) indexToSplit.push_back(faces[i*3+1]); else indexToSplit.push_back(faces[i*3+2]); } } //split vertices for (unsigned short i=0;i<indexToSplit.size();i++) { int index = indexToSplit[i]; //duplicate vertex Vector3 v = vertices[index]; Vector2 t = texCoords[index] + Vector2::UNIT_X; vertices.push_back(v); texCoords.push_back(t); int newIndex = vertices.size()-1; //reassign indices for (unsigned short j=0;j<faces.size();j++) { if (faces[j]==index) { int index1 = faces[(j+1)%3+(j/3)*3]; int index2 = faces[(j+2)%3+(j/3)*3]; if ((texCoords[index1].x>0.5) || (texCoords[index2].x>0.5)) { faces[j] = newIndex; } } } } /// Step 5 : realize buffer.rebaseOffset(); buffer.estimateVertexCount(vertices.size()); buffer.estimateIndexCount(size); for (unsigned short i=0; i<vertices.size(); i++) { addPoint(buffer, mRadius*vertices[i], vertices[i],//note : vertices are already normalised Vector2(texCoords[i].x,texCoords[i].y)); } for (unsigned short i=0; i<size; i++) { buffer.index(offset+faces[i]); } offset+=vertices.size(); }
void CapsuleGenerator::addToTriangleBuffer(TriangleBuffer& buffer) const { assert(numRings>0 && numSegments>0 && numSegHeight>0 && "Num seg must be positive integers"); assert(height>0. && radius>0. && "Height and radius must be positive"); buffer.rebaseOffset(); buffer.estimateVertexCount((2*numRings+2)*(numSegments+1) + (numSegHeight-1)*(numSegments+1)); buffer.estimateIndexCount((2*numRings+1)*(numSegments+1)*6 + (numSegHeight-1)*(numSegments+1)*6); Ogre::Real fDeltaRingAngle = (Ogre::Math::HALF_PI / numRings); Ogre::Real fDeltaSegAngle = (Ogre::Math::TWO_PI / numSegments); Ogre::Real sphereRatio = radius / (2 * radius + height); Ogre::Real cylinderRatio = height / (2 * radius + height); int offset = 0; // Top half sphere // Generate the group of rings for the sphere for(unsigned int ring = 0; ring <= numRings; ring++ ) { Ogre::Real r0 = radius * sinf ( ring * fDeltaRingAngle); Ogre::Real y0 = radius * cosf (ring * fDeltaRingAngle); // Generate the group of segments for the current ring for(unsigned int seg = 0; seg <= numSegments; seg++) { Ogre::Real x0 = r0 * cosf(seg * fDeltaSegAngle); Ogre::Real z0 = r0 * sinf(seg * fDeltaSegAngle); // Add one vertex to the strip which makes up the sphere buffer.position( x0, 0.5*height + y0, z0); if (enableNormals) buffer.normal(Ogre::Vector3(x0, y0, z0).normalisedCopy()); for (unsigned int tc=0;tc<numTexCoordSet;tc++) buffer.textureCoord((Ogre::Real) seg / (Ogre::Real) numSegments * uTile, (Ogre::Real) ring / (Ogre::Real) numRings * vTile * sphereRatio); // each vertex (except the last) has six indices pointing to it buffer.index(offset + numSegments + 1); buffer.index(offset + numSegments); buffer.index(offset); buffer.index(offset + numSegments + 1); buffer.index(offset); buffer.index(offset + 1); offset ++; } // end for seg } // end for ring // Cylinder part Ogre::Real deltaAngle = (Ogre::Math::TWO_PI / numSegments); Ogre::Real deltaHeight = height/(Ogre::Real)numSegHeight; for (int i = 1; i < numSegHeight; i++) for (int j = 0; j<=numSegments; j++) { Ogre::Real x0 = radius * cosf(j*deltaAngle); Ogre::Real z0 = radius * sinf(j*deltaAngle); buffer.position(x0, 0.5*height-i*deltaHeight, z0); buffer.normal(Ogre::Vector3(x0,0,z0).normalisedCopy()); buffer.textureCoord(j/(Ogre::Real)numSegments*uTile, i/(Ogre::Real)numSegHeight*vTile * cylinderRatio + sphereRatio); buffer.index(offset + numSegments + 1); buffer.index(offset + numSegments); buffer.index(offset); buffer.index(offset + numSegments + 1); buffer.index(offset); buffer.index(offset + 1); offset ++; } // Bottom half sphere // Generate the group of rings for the sphere for(unsigned int ring = 0; ring <= numRings; ring++) { Ogre::Real r0 = radius * sinf (Ogre::Math::HALF_PI + ring * fDeltaRingAngle); Ogre::Real y0 = radius * cosf (Ogre::Math::HALF_PI + ring * fDeltaRingAngle); // Generate the group of segments for the current ring for(unsigned int seg = 0; seg <= numSegments; seg++) { Ogre::Real x0 = r0 * cosf(seg * fDeltaSegAngle); Ogre::Real z0 = r0 * sinf(seg * fDeltaSegAngle); // Add one vertex to the strip which makes up the sphere buffer.position( x0, -0.5*height + y0, z0); if (enableNormals) buffer.normal(Ogre::Vector3(x0, y0, z0).normalisedCopy()); for (unsigned int tc=0;tc<numTexCoordSet;tc++) buffer.textureCoord((Ogre::Real) seg / (Ogre::Real) numSegments * uTile, (Ogre::Real) ring / (Ogre::Real) numRings * vTile*sphereRatio + cylinderRatio + sphereRatio); if (ring != numRings) { // each vertex (except the last) has six indices pointing to it buffer.index(offset + numSegments + 1); buffer.index(offset + numSegments); buffer.index(offset); buffer.index(offset + numSegments + 1); buffer.index(offset); buffer.index(offset + 1); } offset ++; } // end for seg } // end for ring }
void TubeGenerator::addToTriangleBuffer(TriangleBuffer& buffer) const { assert(height>0. && outerRadius>0. && innerRadius>0. && "Height and radius must be positive"); assert(innerRadius<outerRadius && "Outer radius must be bigger than inner radius"); assert(numSegBase>0 && numSegHeight>0 && "Num seg must be positive integers"); buffer.rebaseOffset(); buffer.estimateVertexCount((numSegHeight+1)*(numSegBase+1)*2+(numSegBase+1)*4); buffer.estimateIndexCount(6*(numSegBase+1)*numSegHeight*2+6*numSegBase*2); Ogre::Real deltaAngle = (Ogre::Math::TWO_PI / numSegBase); Ogre::Real deltaHeight = height/(Ogre::Real)numSegHeight; int offset = 0; for (int i = 0; i <=numSegHeight; i++) for (int j = 0; j<=numSegBase; j++) { Ogre::Real x0 = outerRadius * cosf(j*deltaAngle); Ogre::Real z0 = outerRadius * sinf(j*deltaAngle); buffer.position(x0, i*deltaHeight, z0); buffer.normal(Ogre::Vector3(x0,0,z0).normalisedCopy()); buffer.textureCoord(j/(Ogre::Real)numSegBase*uTile, i/(Ogre::Real)numSegHeight*vTile); if (i != numSegHeight) { buffer.index(offset + numSegBase + 1); buffer.index(offset); buffer.index(offset + numSegBase); buffer.index(offset + numSegBase + 1); buffer.index(offset + 1); buffer.index(offset); } offset ++; } for (int i = 0; i <=numSegHeight; i++) for (int j = 0; j<=numSegBase; j++) { Ogre::Real x0 = innerRadius * cosf(j*deltaAngle); Ogre::Real z0 = innerRadius * sinf(j*deltaAngle); buffer.position(x0, i*deltaHeight, z0); buffer.normal(-Ogre::Vector3(x0,0,z0).normalisedCopy()); buffer.textureCoord(j/(Ogre::Real)numSegBase*uTile, i/(Ogre::Real)numSegHeight*vTile); if (i != numSegHeight) { buffer.index(offset + numSegBase + 1); buffer.index(offset + numSegBase); buffer.index(offset); buffer.index(offset + numSegBase + 1); buffer.index(offset); buffer.index(offset + 1); } offset ++; } //low cap for (int j=0;j<=numSegBase;j++) { Ogre::Real x0 = innerRadius * cosf(j*deltaAngle); Ogre::Real z0 = innerRadius * sinf(j*deltaAngle); buffer.position(x0, 0.0f, z0); buffer.normal(Ogre::Vector3::NEGATIVE_UNIT_Y); buffer.textureCoord(j/(Ogre::Real)numSegBase*uTile,vTile); x0 = outerRadius * cosf(j*deltaAngle); z0 = outerRadius * sinf(j*deltaAngle); buffer.position(x0, 0.0f, z0); buffer.normal(Ogre::Vector3::NEGATIVE_UNIT_Y); buffer.textureCoord(j/(Ogre::Real)numSegBase*uTile,0.0); if (j!=numSegBase) { buffer.index(offset); buffer.index(offset+1); buffer.index(offset+3); buffer.index(offset+2); buffer.index(offset); buffer.index(offset+3); } offset+=2; } //high cap for (int j=0;j<=numSegBase;j++) { Ogre::Real x0 = innerRadius * cosf(j*deltaAngle); Ogre::Real z0 = innerRadius * sinf(j*deltaAngle); buffer.position(x0, height, z0); buffer.normal(Ogre::Vector3::UNIT_Y); buffer.textureCoord(j/(Ogre::Real)numSegBase*uTile,0.0); x0 = outerRadius * cosf(j*deltaAngle); z0 = outerRadius * sinf(j*deltaAngle); buffer.position(x0, height, z0); buffer.normal(Ogre::Vector3::UNIT_Y); buffer.textureCoord(j/(Ogre::Real)numSegBase*uTile,vTile); if (j!=numSegBase) { buffer.index(offset+1); buffer.index(offset); buffer.index(offset+3); buffer.index(offset); buffer.index(offset+2); buffer.index(offset+3); } offset+=2; } }
//----------------------------------------------------------------------- void Lathe::_latheCapImpl(TriangleBuffer& buffer) const { std::vector<int> indexBuffer; PointList pointList; buffer.rebaseOffset(); Triangulator t; Shape shapeCopy; MultiShape multishapeCopy; if (mShapeToExtrude) { shapeCopy = *mShapeToExtrude; shapeCopy.close(); t.setShapeToTriangulate(&shapeCopy); } else { multishapeCopy = *mMultiShapeToExtrude; multishapeCopy.close(); t.setMultiShapeToTriangulate(mMultiShapeToExtrude); } t.triangulate(indexBuffer, pointList); buffer.estimateIndexCount(2*indexBuffer.size()); buffer.estimateVertexCount(2*pointList.size()); //begin cap buffer.rebaseOffset(); Quaternion q; q.FromAngleAxis(mAngleBegin, Vector3::UNIT_Y); for (size_t j =0;j<pointList.size();j++) { Vector2 vp2 = pointList[j]; Vector3 vp(vp2.x, vp2.y, 0); Vector3 normal = Vector3::UNIT_Z; addPoint(buffer, q*vp, q*normal, vp2); } for (size_t i=0;i<indexBuffer.size()/3;i++) { buffer.index(indexBuffer[i*3]); buffer.index(indexBuffer[i*3+1]); buffer.index(indexBuffer[i*3+2]); } //end cap buffer.rebaseOffset(); q.FromAngleAxis(mAngleEnd, Vector3::UNIT_Y); for (size_t j =0;j<pointList.size();j++) { Vector2 vp2 = pointList[j]; Vector3 vp(vp2.x, vp2.y, 0); Vector3 normal = -Vector3::UNIT_Z; addPoint(buffer, q*vp, q*normal, vp2); } for (size_t i=0;i<indexBuffer.size()/3;i++) { buffer.index(indexBuffer[i*3]); buffer.index(indexBuffer[i*3+2]); buffer.index(indexBuffer[i*3+1]); } }