- Main Page
- Packages
- Classes
- Files

- File List
- File Members

# D:/guillaume/guillara/3D/DXGfx/DXGfxLib/MeshObjectWithLOD.cs

Go to the documentation of this file.

    00001 //BSD License
    00002 //DXGfx® - http://www.eteractions.com
    00003 //Copyright (c) 2005
    00004 //by Guillaume Randon
    00005 //Permission is hereby granted, free of charge, to any person obtaining a copy of this software
    00006 //and associated documentation files (the "Software"), to deal in the Software without restriction,
    00007 //including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
    00008 //and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
    00009 //subject to the following conditions:
    00010 //The above copyright notice and this permission notice shall be included in all copies or substantial
    00011 //portions of the Software.
    00012 //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    00013 //INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
    00014 //AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    00015 //DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    00016 //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    00017 using System;
    00018 using System.Collections.Generic;
    00019 using System.Text;
    00020 using Microsoft.DirectX;
    00021 using Microsoft.DirectX.Direct3D;
    00022 using Microsoft.Samples.DirectX.UtilityToolkit;
    00023
    00024 namespace DXGfxLib
    00025 {
    00026     public class MeshObjectWithLOD : MeshObject
    00027     {
    00031         public static float near = 20.0f;
    00032
    00036         public static float mid = 50.0f;
    00037
    00042         public static float far = 250.0f;
    00043
    00044         public bool visible = true;
    00045
    00049         protected ProgressiveMesh fullMesh = null;
    00050
    00054         protected ProgressiveMesh[] meshes = null;
    00055
    00059         protected int currentMeshIndex = 0;
    00060
    00064         protected int[] adjacencyBuffer;
    00065
    00074         public virtual void AttachWithLOD(Device d3ddevice, Mesh meshToAttach, int[] adjacencyBuffer, ExtendedMaterial[] materials,
    00075             EffectInstance[] effects)
    00076         {
    00077             Attach(meshToAttach);
    00078
    00079             this.adjacencyBuffer = adjacencyBuffer;
    00080
    00081             // Code below for generation of the progressive mesh
    00082             // is borowed more or less from the progressive Mesh sample of the DirectX SDK.
    00083             int use32Bit = (int)(originalMesh.Options.Value & MeshFlags.Use32Bit);
    00084
    00085             // Perform simple cleansing operations on mesh
    00086             int[] outAdjacency;
    00087
    00088             using (Mesh mesh = Mesh.Clean(CleanType.Simplification, originalMesh, adjacencyBuffer, out outAdjacency))
    00089             {
    00090                 // Perform a weld to try and remove excess vertices.
    00091                 // Weld the mesh using all epsilons of 0.0f.  A small epsilon like 1e-6 works well too
    00092                 WeldEpsilons epsilons = new WeldEpsilons();
    00093                 int[] outAdjacency2;
    00094                 int[] faceRemap;
    00095                 GraphicsStream vertexRemap;
    00096                 mesh.WeldVertices(0, epsilons, outAdjacency, out outAdjacency2, out faceRemap, out vertexRemap);
    00097
    00098                 // Verify validity of mesh for simplification
    00099                 mesh.Validate(outAdjacency2);
    00100
    00101                 // Allocate a material/texture arrays
    00102                 if (materials != null)
    00103                 {
    00104                     meshMaterials = new Material[materials.Length];
    00105                     meshTextures = new Texture[materials.Length];
    00106
    00107                     // Copy the materials and load the textures
    00108                     for (int i = 0; i < meshMaterials.Length; i++)
    00109                     {
    00110                         meshMaterials[i] = materials[i].Material3D;
    00111                         meshMaterials[i].AmbientColor = meshMaterials[i].DiffuseColor;
    00112
    00113                         if ((materials[i].TextureFilename != null) && (materials[i].TextureFilename.Length > 0))
    00114                         {
    00115                             // Create the texture
    00116                             meshTextures[i] = ResourceCache.GetGlobalInstance().CreateTextureFromFile(d3ddevice, materials[i].TextureFilename);
    00117                         }
    00118                     }
    00119                 }
    00120
    00121                 // Find the mesh's center, then generate a centering matrix
    00122                 using (VertexBuffer vb = mesh.VertexBuffer)
    00123                 {
    00124                     using (GraphicsStream stm = vb.Lock(0, 0, LockFlags.NoSystemLock))
    00125                     {
    00126                         try
    00127                         {
    00128                             objectRadius = Geometry.ComputeBoundingSphere(stm,
    00129                                 mesh.NumberVertices, mesh.VertexFormat, out objectCenter);
    00130                         }
    00131                         finally
    00132                         {
    00133                             vb.Unlock();
    00134                         }
    00135                     }
    00136                 }
    00137
    00138                 // If the mesh is missing normals, generate them.
    00139                 Mesh currentMesh = mesh;
    00140                 if ((mesh.VertexFormat & VertexFormats.Normal) == 0)
    00141                 {
    00142                     currentMesh = mesh.Clone(MeshFlags.Managed | (MeshFlags)use32Bit,
    00143                         mesh.VertexFormat | VertexFormats.Normal, d3ddevice);
    00144
    00145                     // Compute normals now
    00146                     currentMesh.ComputeNormals();
    00147                 }
    00148
    00149                 using (currentMesh)
    00150                 {
    00151                     // Generate Progressive Meshes
    00152                     using (Microsoft.DirectX.Direct3D.ProgressiveMesh pMesh = new Microsoft.DirectX.Direct3D.ProgressiveMesh(currentMesh, adjacencyBuffer, null, 1, MeshFlags.SimplifyVertex))
    00153                     {
    00154                         int minVerts = pMesh.MinVertices;
    00155                         int maxVerts = pMesh.MaxVertices;
    00156                         int vertsPerMesh = (maxVerts - minVerts + 10) / 10;
    00157
    00158                         // How many meshes should be in the array
    00159                         //int numMeshes = Math.Max(1, (int)Math.Ceiling((maxVerts - minVerts + 1) / (float)vertsPerMesh));
    00160                         int numMeshes = Math.Max(1, 3);
    00161                         meshes = new Microsoft.DirectX.Direct3D.ProgressiveMesh[numMeshes];
    00162
    00163                         // Clone full sized pmesh
    00164                         fullMesh = pMesh.Clone(MeshFlags.Managed | MeshFlags.VbShare, pMesh.VertexFormat, d3ddevice);
    00165
    00166                         // Clone all the separate pmeshes
    00167                         for (int iMesh = 0; iMesh < numMeshes; iMesh++)
    00168                         {
    00169                             meshes[iMesh] = pMesh.Clone(MeshFlags.Managed | MeshFlags.VbShare, pMesh.VertexFormat, d3ddevice);
    00170
    00171                             // Trim to appropriate space
    00172                             meshes[iMesh].TrimByVertices(minVerts + vertsPerMesh * iMesh, minVerts + vertsPerMesh * (iMesh + 1));
    00173                             meshes[iMesh].OptimizeBaseLevelOfDetail(MeshFlags.OptimizeVertexCache);
    00174                         }
    00175
    00176                         // Set the current to be max vertices
    00177                         currentMeshIndex = numMeshes - 1;
    00178                         meshes[currentMeshIndex].NumberVertices = maxVerts;
    00179                         fullMesh.NumberVertices = maxVerts;
    00180                     }
    00181                 }
    00182             }
    00183         }
    00184
    00193         public override void Update(Frustrum frustrum, float elapsedTime, double appTime, List<IDrawable> objectsToBeRendered)
    00194         {
    00195             base.Update(frustrum, elapsedTime, appTime, objectsToBeRendered);
    00196
    00197             if (fullMesh != null)
    00198             {
    00199                 // 20 m is near, 50 is medium, 100 is far!!
    00200                 float distToNearPlane = MathUtil.SignedDistance(frustrum.NearPlane, Position);
    00201
    00202                 if (distToNearPlane < near)
    00203                 {
    00204                     SetNumberVertices(fullMesh.MaxVertices);
    00205                     visible = true;
    00206                 }
    00207                 else if (distToNearPlane < mid)
    00208                 {
    00209                     SetNumberVertices((int)Math.Ceiling(0.7 * fullMesh.MaxVertices));
    00210                     visible = true;
    00211                 }
    00212                 else if (distToNearPlane < far)
    00213                 {
    00214                     SetNumberVertices((int)Math.Ceiling(0.4 * fullMesh.MaxVertices));
    00215                     visible = true;
    00216                 }
    00217                 else
    00218                 {
    00219                     SetNumberVertices(0);
    00220                     visible = false;
    00221                 }
    00222             }
    00223         }
    00224
    00230         private void SetNumberVertices(int numberVerts)
    00231         {
    00232             // Update the full mesh first
    00233             fullMesh.NumberVertices = numberVerts;
    00234
    00235             // If current pm valid for desired value, then set the number of vertices directly
    00236             if ((numberVerts >= meshes[currentMeshIndex].MinVertices) &&
    00237                 (numberVerts <= meshes[currentMeshIndex].MaxVertices))
    00238             {
    00239                 meshes[currentMeshIndex].NumberVertices = numberVerts;
    00240             }
    00241             else
    00242             {
    00243                 // Search for the right one
    00244                 currentMeshIndex = meshes.Length - 1;
    00245
    00246                 // Look for the correct "bin"
    00247                 while (currentMeshIndex > 0)
    00248                 {
    00249                     // If number of vertices is less than current max then we found one to fit
    00250                     if (numberVerts >= meshes[currentMeshIndex].MinVertices)
    00251                         break;
    00252
    00253                     currentMeshIndex--;
    00254                 }
    00255
    00256                 // Set the vertices on the newly selected mesh
    00257                 meshes[currentMeshIndex].NumberVertices = numberVerts;
    00258             }
    00259         }
    00260
    00261         public override void Draw(Device device)
    00262         {
    00263             if ((fullMesh != null)&&visible)
    00264             {
    00265                 for (int i = 0; i < originalMesh.NumberAttributes; i++)
    00266                 {
    00267                     device.SetTexture(i, meshTextures[i]);
    00268                     meshes[currentMeshIndex].DrawSubset(i);
    00269                 }
    00270             }
    00271         }
    00272
    00280         public override void DrawSubset(int index)
    00281         {
    00282             if (fullMesh != null)
    00283             {
    00284                 meshes[currentMeshIndex].DrawSubset(index);
    00285             }
    00286         }
    00287     }
    00288 }