//---------------------------------------------------------------------------- void IntersectingBoxes::ModifyMesh (int i) { Vector3f center( 0.5f*(mBoxes[i].Min[0] + mBoxes[i].Max[0]), 0.5f*(mBoxes[i].Min[1] + mBoxes[i].Max[1]), 0.5f*(mBoxes[i].Min[2] + mBoxes[i].Max[2])); float xExtent = 0.5f*(mBoxes[i].Max[0] - mBoxes[i].Min[0]); float yExtent = 0.5f*(mBoxes[i].Max[1] - mBoxes[i].Min[1]); float zExtent = 0.5f*(mBoxes[i].Max[2] - mBoxes[i].Min[2]); Vector3f xTerm = xExtent*Vector3f::UNIT_X; Vector3f yTerm = yExtent*Vector3f::UNIT_Y; Vector3f zTerm = zExtent*Vector3f::UNIT_Z; TriMesh* mesh = StaticCast<TriMesh>(mScene->GetChild(i)); VertexBufferAccessor vba(mesh); vba.Position<Vector3f>(0) = center - xTerm - yTerm - zTerm; vba.Position<Vector3f>(1) = center + xTerm - yTerm - zTerm; vba.Position<Vector3f>(2) = center + xTerm + yTerm - zTerm; vba.Position<Vector3f>(3) = center - xTerm + yTerm - zTerm; vba.Position<Vector3f>(4) = center - xTerm - yTerm + zTerm; vba.Position<Vector3f>(5) = center + xTerm - yTerm + zTerm; vba.Position<Vector3f>(6) = center + xTerm + yTerm + zTerm; vba.Position<Vector3f>(7) = center - xTerm + yTerm + zTerm; mesh->UpdateModelSpace(Visual::GU_NORMALS); mRenderer->Update(mesh->GetVertexBuffer()); }
//---------------------------------------------------------------------------- TriMesh* StandardMesh::Cylinder (int axisSamples, int radialSamples, float radius, float height, bool open) { TriMesh* mesh; int unit; Float2 tcoord; if (open) { int numVertices = axisSamples*(radialSamples+1); int numTriangles = 2*(axisSamples-1)*radialSamples; int numIndices = 3*numTriangles; int stride = mVFormat->GetStride(); // Create a vertex buffer. VertexBuffer* vbuffer = new0 VertexBuffer(numVertices, stride, mUsage); VertexBufferAccessor vba(mVFormat, vbuffer); // Generate geometry. float invRS = 1.0f/(float)radialSamples; float invASm1 = 1.0f/(float)(axisSamples-1); float halfHeight = 0.5f*height; int r, a, aStart, i; // Generate points on the unit circle to be used in computing the // mesh points on a cylinder slice. float* cs = new1<float>(radialSamples + 1); float* sn = new1<float>(radialSamples + 1); for (r = 0; r < radialSamples; ++r) { float angle = Mathf::TWO_PI*invRS*r; cs[r] = Mathf::Cos(angle); sn[r] = Mathf::Sin(angle); } cs[radialSamples] = cs[0]; sn[radialSamples] = sn[0]; // Generate the cylinder itself. for (a = 0, i = 0; a < axisSamples; ++a) { float axisFraction = a*invASm1; // in [0,1] float z = -halfHeight + height*axisFraction; // Compute center of slice. APoint sliceCenter(0.0f, 0.0f, z); // Compute slice vertices with duplication at endpoint. int save = i; for (r = 0; r < radialSamples; ++r) { float radialFraction = r*invRS; // in [0,1) AVector normal(cs[r], sn[r], 0.0f); vba.Position<Float3>(i) = sliceCenter + radius*normal; if (mHasNormals) { if (mInside) { vba.Normal<Float3>(i) = -normal; } else { vba.Normal<Float3>(i) = normal; } } tcoord = Float2(radialFraction, axisFraction); for (unit = 0; unit < MAX_UNITS; ++unit) { if (mHasTCoords[unit]) { vba.TCoord<Float2>(unit, i) = tcoord; } } ++i; } vba.Position<Float3>(i) = vba.Position<Float3>(save); if (mHasNormals) { vba.Normal<Float3>(i) = vba.Normal<Float3>(save); } tcoord = Float2(1.0f, axisFraction); for (unit = 0; unit < MAX_UNITS; ++unit) { if (mHasTCoords[unit]) { vba.TCoord<Float2>(0, i) = tcoord; } } ++i; } TransformData(vba); // Generate indices. IndexBuffer* ibuffer = new0 IndexBuffer(numIndices, 4, mUsage); int* indices = (int*)ibuffer->GetData(); for (a = 0, aStart = 0; a < axisSamples-1; ++a) { int i0 = aStart; int i1 = i0 + 1; aStart += radialSamples + 1; int i2 = aStart; int i3 = i2 + 1; for (i = 0; i < radialSamples; ++i, indices += 6) { if (mInside) { indices[0] = i0++; indices[1] = i2; indices[2] = i1; indices[3] = i1++; indices[4] = i2++; indices[5] = i3++; } else // outside view { indices[0] = i0++; indices[1] = i1; indices[2] = i2; indices[3] = i1++; indices[4] = i3++; indices[5] = i2++; } } } delete1(cs); delete1(sn); mesh = new0 TriMesh(mVFormat, vbuffer, ibuffer); } else { mesh = Sphere(axisSamples, radialSamples, radius); VertexBuffer* vbuffer = mesh->GetVertexBuffer(); int numVertices = vbuffer->GetNumElements(); VertexBufferAccessor vba(mVFormat, vbuffer); // Flatten sphere at poles. float hDiv2 = 0.5f*height; vba.Position<Float3>(numVertices-2)[2] = -hDiv2; // south pole vba.Position<Float3>(numVertices-1)[2] = +hDiv2; // north pole // Remap z-values to [-h/2,h/2]. float zFactor = 2.0f/(axisSamples-1); float tmp0 = radius*(-1.0f + zFactor); float tmp1 = 1.0f/(radius*(+1.0f - zFactor)); for (int i = 0; i < numVertices-2; ++i) { Float3& pos = vba.Position<Float3>(i); pos[2] = hDiv2*(-1.0f + tmp1*(pos[2] - tmp0)); float adjust = radius*Mathf::InvSqrt(pos[0]*pos[0] + pos[1]*pos[1]); pos[0] *= adjust; pos[1] *= adjust; } TransformData(vba); if (mHasNormals) { mesh->UpdateModelSpace(Visual::GU_NORMALS); } } // The duplication of vertices at the seam causes the automatically // generated bounding volume to be slightly off center. Reset the bound // to use the true information. float maxDist = Mathf::Sqrt(radius*radius + height*height); mesh->GetModelBound().SetCenter(APoint::ORIGIN); mesh->GetModelBound().SetRadius(maxDist); return mesh; }
//---------------------------------------------------------------------------- TriMesh* StandardMesh::Box (float xExtent, float yExtent, float zExtent) { int numVertices = 8; int numTriangles = 12; int numIndices = 3*numTriangles; int stride = mVFormat->GetStride(); // Create a vertex buffer. VertexBuffer* vbuffer = new0 VertexBuffer(numVertices, stride, mUsage); VertexBufferAccessor vba(mVFormat, vbuffer); // Generate geometry. vba.Position<Float3>(0) = Float3(-xExtent, -yExtent, -zExtent); vba.Position<Float3>(1) = Float3(+xExtent, -yExtent, -zExtent); vba.Position<Float3>(2) = Float3(+xExtent, +yExtent, -zExtent); vba.Position<Float3>(3) = Float3(-xExtent, +yExtent, -zExtent); vba.Position<Float3>(4) = Float3(-xExtent, -yExtent, +zExtent); vba.Position<Float3>(5) = Float3(+xExtent, -yExtent, +zExtent); vba.Position<Float3>(6) = Float3(+xExtent, +yExtent, +zExtent); vba.Position<Float3>(7) = Float3(-xExtent, +yExtent, +zExtent); for (int unit = 0; unit < MAX_UNITS; ++unit) { if (mHasTCoords[unit]) { vba.TCoord<Float2>(unit, 0) = Float2(0.25f, 0.75f); vba.TCoord<Float2>(unit, 1) = Float2(0.75f, 0.75f); vba.TCoord<Float2>(unit, 2) = Float2(0.75f, 0.25f); vba.TCoord<Float2>(unit, 3) = Float2(0.25f, 0.25f); vba.TCoord<Float2>(unit, 4) = Float2(0.0f, 1.0f); vba.TCoord<Float2>(unit, 5) = Float2(1.0f, 1.0f); vba.TCoord<Float2>(unit, 6) = Float2(1.0f, 0.0f); vba.TCoord<Float2>(unit, 7) = Float2(0.0f, 0.0f); } } TransformData(vba); // Generate indices (outside view). IndexBuffer* ibuffer = new0 IndexBuffer(numIndices, 4, mUsage); int* indices = (int*)ibuffer->GetData(); indices[ 0] = 0; indices[ 1] = 2; indices[ 2] = 1; indices[ 3] = 0; indices[ 4] = 3; indices[ 5] = 2; indices[ 6] = 0; indices[ 7] = 1; indices[ 8] = 5; indices[ 9] = 0; indices[10] = 5; indices[11] = 4; indices[12] = 0; indices[13] = 4; indices[14] = 7; indices[15] = 0; indices[16] = 7; indices[17] = 3; indices[18] = 6; indices[19] = 4; indices[20] = 5; indices[21] = 6; indices[22] = 7; indices[23] = 4; indices[24] = 6; indices[25] = 5; indices[26] = 1; indices[27] = 6; indices[28] = 1; indices[29] = 2; indices[30] = 6; indices[31] = 2; indices[32] = 3; indices[33] = 6; indices[34] = 3; indices[35] = 7; if (mInside) { ReverseTriangleOrder(numTriangles, indices); } TriMesh* mesh = new0 TriMesh(mVFormat, vbuffer, ibuffer); if (mHasNormals) { mesh->UpdateModelSpace(Visual::GU_NORMALS); } return mesh; }
//---------------------------------------------------------------------------- void BoxSurface::UpdateSurface () { int permute[3]; TriMesh* mesh; VertexFormat* vformat; VertexBuffer* vbuffer; // u faces permute[0] = 1; permute[1] = 2; permute[2] = 0; // u = 0 mesh = StaticCast<TriMesh>(GetChild(0)); vformat = mesh->GetVertexFormat(); vbuffer = mesh->GetVertexBuffer(); UpdateFace(mNumWSamples, mNumVSamples, vformat, vbuffer, false, 0.0f, permute); mesh->UpdateModelSpace(Renderable::GU_NORMALS); Renderer::UpdateAll(vbuffer); // u = 1 mesh = StaticCast<TriMesh>(GetChild(1)); vformat = mesh->GetVertexFormat(); vbuffer = mesh->GetVertexBuffer(); UpdateFace(mNumWSamples, mNumVSamples, vformat, vbuffer, true, 1.0f, permute); mesh->UpdateModelSpace(Renderable::GU_NORMALS); Renderer::UpdateAll(vbuffer); // v faces permute[0] = 0; permute[1] = 2; permute[2] = 1; // v = 0 mesh = StaticCast<TriMesh>(GetChild(2)); vformat = mesh->GetVertexFormat(); vbuffer = mesh->GetVertexBuffer(); UpdateFace(mNumWSamples, mNumUSamples, vformat, vbuffer, true, 0.0f, permute); mesh->UpdateModelSpace(Renderable::GU_NORMALS); Renderer::UpdateAll(vbuffer); // v = 1 mesh = StaticCast<TriMesh>(GetChild(3)); vformat = mesh->GetVertexFormat(); vbuffer = mesh->GetVertexBuffer(); UpdateFace(mNumWSamples, mNumUSamples, vformat, vbuffer, false, 1.0f, permute); mesh->UpdateModelSpace(Renderable::GU_NORMALS); Renderer::UpdateAll(vbuffer); // w faces permute[0] = 0; permute[1] = 1; permute[2] = 2; // w = 0 mesh = StaticCast<TriMesh>(GetChild(4)); vformat = mesh->GetVertexFormat(); vbuffer = mesh->GetVertexBuffer(); UpdateFace(mNumVSamples, mNumUSamples, vformat, vbuffer, false, 0.0f, permute); mesh->UpdateModelSpace(Renderable::GU_NORMALS); Renderer::UpdateAll(vbuffer); // w = 1 mesh = StaticCast<TriMesh>(GetChild(5)); vformat = mesh->GetVertexFormat(); vbuffer = mesh->GetVertexBuffer(); UpdateFace(mNumVSamples, mNumUSamples, vformat, vbuffer, true, 1.0f, permute); mesh->UpdateModelSpace(Renderable::GU_NORMALS); Renderer::UpdateAll(vbuffer); }
//---------------------------------------------------------------------------- Node* SimplePendulumFriction::CreatePendulum () { VertexFormat* vformat = VertexFormat::Create(2, VertexFormat::AU_POSITION, VertexFormat::AT_FLOAT3, 0, VertexFormat::AU_NORMAL, VertexFormat::AT_FLOAT3, 0); StandardMesh sm(vformat); // Pendulum rod. TriMesh* rod = sm.Cylinder(2, 8, 0.05f, 12.0f, true); rod->LocalTransform.SetTranslate(APoint(0.0f, 0.0f, 10.0f)); // The pendulum bulb. Start with a sphere (to get the connectivity) and // then adjust the vertices to form a pair of joined cones. TriMesh* bulb = sm.Sphere(16, 32, 2.0f); VertexBufferAccessor vba(bulb); int numVertices = vba.GetNumVertices(); int i; for (i = 0; i < numVertices; ++i) { Float3& pos = vba.Position<Float3>(i); float r = Mathf::Sqrt(pos[0]*pos[0] + pos[1]*pos[1]); float z = pos[2] + 2.0f; if (z >= 2.0f) { z = 4.0f - r; } else { z = r; } pos[2] = z; } // Translate the pendulum joint to the origin for the purpose of // rotation. for (i = 0; i < numVertices; ++i) { vba.Position<Float3>(i)[2] -= 16.0f; } bulb->UpdateModelSpace(Visual::GU_NORMALS); vba.ApplyTo(rod); numVertices = vba.GetNumVertices(); for (i = 0; i < numVertices; ++i) { vba.Position<Float3>(i)[2] -= 16.0f; } rod->UpdateModelSpace(Visual::GU_NORMALS); // Group the objects into a single subtree. mPendulum = new0 Node(); mPendulum->AttachChild(rod); mPendulum->AttachChild(bulb); // Translate back to original model position. mPendulum->LocalTransform.SetTranslate(APoint(0.0f, 0.0f, 16.0f)); // Add a material for coloring. Float4 black(0.0f, 0.0f, 0.0f, 1.0f); Float4 white(1.0f, 1.0f, 1.0f, 1.0f); Material* material = new0 Material(); material->Emissive = black; material->Ambient = Float4(0.1f, 0.1f, 0.1f, 1.0f); material->Diffuse = Float4(0.99607f, 0.83920f, 0.67059f, 1.0f); material->Specular = black; // Use two lights to illuminate the pendulum. Light* light[2]; light[0] = new0 Light(Light::LT_DIRECTIONAL); light[0]->Ambient = white; light[0]->Diffuse = white; light[0]->Specular = black; light[0]->SetDirection(AVector(-1.0f, -1.0f, 0.0f)); light[1] = new0 Light(Light::LT_DIRECTIONAL); light[1]->Ambient = white; light[1]->Diffuse = white; light[1]->Specular = black; light[1]->SetDirection(AVector(+1.0f, -1.0f, 0.0f)); // TODO: The following code is used to piece together an effect with // two passes. It is better to write an effect whose vertex shader // has constants corresponding to the two lights (for a single-pass // effect). LightDirPerVerEffect* effect = new0 LightDirPerVerEffect(); VisualTechnique* technique = effect->GetTechnique(0); VisualPass* pass0 = technique->GetPass(0); VisualPass* pass1 = new0 VisualPass(); pass1->SetVertexShader(pass0->GetVertexShader()); pass1->SetPixelShader(pass0->GetPixelShader()); AlphaState* astate = new0 AlphaState(); astate->BlendEnabled = true; astate->SrcBlend = AlphaState::SBM_ONE; astate->DstBlend = AlphaState::DBM_ONE; pass1->SetAlphaState(astate); pass1->SetCullState(pass0->GetCullState()); pass1->SetDepthState(pass0->GetDepthState()); pass1->SetStencilState(pass0->GetStencilState()); pass1->SetOffsetState(pass0->GetOffsetState()); pass1->SetWireState(pass0->GetWireState()); technique->InsertPass(pass1); VisualEffectInstance* instance = new0 VisualEffectInstance(effect, 0); for (int pass = 0; pass < 2; ++pass) { instance->SetVertexConstant(pass, 0, new0 PVWMatrixConstant()); instance->SetVertexConstant(pass, 1, new0 CameraModelPositionConstant()); instance->SetVertexConstant(pass, 2, new0 MaterialEmissiveConstant(material)); instance->SetVertexConstant(pass, 3, new0 MaterialAmbientConstant(material)); instance->SetVertexConstant(pass, 4, new0 MaterialDiffuseConstant(material)); instance->SetVertexConstant(pass, 5, new0 MaterialSpecularConstant(material)); instance->SetVertexConstant(pass, 6, new0 LightModelDVectorConstant(light[pass])); instance->SetVertexConstant(pass, 7, new0 LightAmbientConstant(light[pass])); instance->SetVertexConstant(pass, 8, new0 LightDiffuseConstant(light[pass])); instance->SetVertexConstant(pass, 9, new0 LightSpecularConstant(light[pass])); instance->SetVertexConstant(pass, 10, new0 LightAttenuationConstant(light[pass])); } rod->SetEffectInstance(instance); bulb->SetEffectInstance(instance); return mPendulum; }
//---------------------------------------------------------------------------- TriMesh *UniMaterialMesh::ToTriMesh() { if (mVertexMapQuantity == 0) return 0; // VertexBuffer VertexFormat *vFormat = new0 VertexFormat(); vFormat->Add(VertexFormat::AU_POSITION, VertexFormat::AT_FLOAT3, 0); if (mNormalMap) { vFormat->Add(VertexFormat::AU_NORMAL, VertexFormat::AT_FLOAT3, 0); } if (mExportTargentBinormal) { vFormat->Add(VertexFormat::AU_TANGENT, VertexFormat::AT_FLOAT3, 0); vFormat->Add(VertexFormat::AU_BINORMAL, VertexFormat::AT_FLOAT3, 0); } if (mExportColor) { vFormat->Add(VertexFormat::AU_COLOR, VertexFormat::AT_FLOAT4, 0); } if (mTextureCoordMap) { if (1 == mNumTexcoordToExport) { vFormat->Add(VertexFormat::AU_TEXCOORD, VertexFormat::AT_FLOAT2, 0); } else if (2 == mNumTexcoordToExport) { vFormat->Add(VertexFormat::AU_TEXCOORD, VertexFormat::AT_FLOAT2, 0); vFormat->Add(VertexFormat::AU_TEXCOORD, VertexFormat::AT_FLOAT2, 1); } } if (mExportSkin) { vFormat->Add(VertexFormat::AU_TEXCOORD, VertexFormat::AT_FLOAT4, 1); vFormat->Add(VertexFormat::AU_TEXCOORD, VertexFormat::AT_FLOAT4, 2); } vFormat->Create(); PX2::VertexBuffer *vBuffer = new0 PX2::VertexBuffer(mVertexMapQuantity, vFormat->GetStride()); VertexBufferAccessor vBA(vFormat, vBuffer); for (int i=0; i<mVertexMapQuantity; i++) { vBA.Position<Float3>(i) = mVertexMap[i]; if (mNormalMap) { vBA.Normal<Float3>(i) = mNormalMap[i]; } if (mColorMap) { vBA.Color<Float4>(0, i) = Float4(mColorMap[i][0], mColorMap[i][1], mColorMap[i][2], mColorMap[i][3]); } else { if (mExportColor) vBA.Color<Float4>(0, i) = Float4::WHITE; } if (mAlphaMap) { vBA.Color<Float4>(0, i) = Float4(mColorMap[i][0], mColorMap[i][1], mColorMap[i][2], mAlphaMap[i]); } if (mTextureCoordMap) { if (mNumTexcoordToExport == 1) { vBA.TCoord<Float2>(0, i) = Float2(mTextureCoordMap[i][0], 1.0f-mTextureCoordMap[i][1]); } else if (mNumTexcoordToExport == 2) { Float2 texCoord0 = Float2(mTextureCoordMap[i][0], 1.0f-mTextureCoordMap[i][1]); vBA.TCoord<Float2>(0, i) = texCoord0; if (mTextureCoordMap1) { vBA.TCoord<Float2>(1, i) = Float2(mTextureCoordMap1[i][0], 1.0f-mTextureCoordMap1[i][1]); } else { vBA.TCoord<Float2>(1, i) = texCoord0; } } } } // IndexBuffer IndexBuffer *iBuffer = new0 IndexBuffer(3*mFQuantity, 2); unsigned short *iData = (unsigned short*)iBuffer->GetData(); for (int i=0; i<(int)3*mFQuantity; i++) { iData[i] = (unsigned short)mVFace[i]; } // 创建Mesh TriMesh *triMesh = new0 TriMesh(vFormat, vBuffer, iBuffer); triMesh->UpdateModelSpace(Renderable::GU_MODEL_BOUND_ONLY); if (mExportTargentBinormal) { triMesh->UpdateModelSpace(Renderable::GU_USE_GEOMETRY); } MaterialInstance *mi = 0; mi = mMaterialInstance; triMesh->SetMaterialInstance(mi); triMesh->SetShine(mShine); return triMesh; }