我读取到的3ds,在获取模型时读取纹理经常时空值,导致后面总是会出现异常,以下是我的代码(其实就是别人读取.x模型的例子搬过来读取3ds,出问题了也不知道怎么改了):
public class MeshGeometry : DisposableClass { public class Subset { public int VertexStart; public int VertexCount; public int FaceStart; public int FaceCount; } private Buffer _vb; private Buffer _ib; private int _vertexStride; private List<Subset> _subsetTable; private bool _disposed; protected override void Dispose(bool disposing) { if (!_disposed) { if (disposing) { Util.ReleaseCom(ref _vb); Util.ReleaseCom(ref _ib); } _disposed = true; } base.Dispose(disposing); } }
///
public void SetVertices<TVertexType>(Device device, List<TVertexType> vertices) where TVertexType : struct { Util.ReleaseCom(ref _vb); _vertexStride = Marshal.SizeOf(typeof (TVertexType)); var vbd = new BufferDescription( _vertexStride*vertices.Count, ResourceUsage.Immutable, BindFlags.VertexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0 ); _vb = new Buffer(device, new DataStream(vertices.ToArray(), false, false), vbd); } public void SetIndices(Device device, List<short> indices) { var ibd = new BufferDescription( sizeof (short)*indices.Count, ResourceUsage.Immutable, BindFlags.IndexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0 ); _ib = new Buffer(device, new DataStream(indices.ToArray(), false, false), ibd); } public void SetSubsetTable(List<Subset> subsets) { _subsetTable = subsets; }
///
public void Draw(DeviceContext dc, int subsetId) { const int offset = 0; dc.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(_vb, _vertexStride, offset)); dc.InputAssembler.SetIndexBuffer(_ib, Format.R16_UInt, 0); dc.DrawIndexed(_subsetTable[subsetId].FaceCount*3, _subsetTable[subsetId].FaceStart*3, 0); }
///
public class BasicModel : DisposableClass { private bool _disposed; private readonly List<MeshGeometry.Subset> _subsets; private readonly List<PosNormalTexTan> _vertices; private readonly List<short> _indices; private MeshGeometry _modelMesh; public List<Material> Materials { get; private set; } public List<ShaderResourceView> DiffuseMapSRV { get; private set; } public List<ShaderResourceView> NormalMapSRV { get; private set; } public BoundingBox BoundingBox { get; private set; } public MeshGeometry ModelMesh { get { return _modelMesh; } } public int SubsetCount { get { return _subsets.Count; } } protected override void Dispose(bool disposing) { if (!_disposed) { if (disposing) { Util.ReleaseCom(ref _modelMesh); } _disposed = true; } base.Dispose(disposing); } }
///
public BasicModel(Device device, TextureManager texMgr, string filename, string texturePath) { _subsets = new List<MeshGeometry.Subset>(); _vertices = new List<PosNormalTexTan>(); _indices = new List<short>(); DiffuseMapSRV = new List<ShaderResourceView>(); NormalMapSRV = new List<ShaderResourceView>(); Materials = new List<Material>(); _modelMesh = new MeshGeometry(); var importer = new AssimpImporter(); if (!importer.IsImportFormatSupported(Path.GetExtension(filename))) { throw new ArgumentException("Model format "+Path.GetExtension(filename)+" is not supported! Cannot load {1}", "filename"); } var model = importer.ImportFile(filename, PostProcessSteps.GenerateSmoothNormals | PostProcessSteps.CalculateTangentSpace);
///
foreach (var mesh in model.Meshes) { var verts = new List<PosNormalTexTan>(); var subset = new MeshGeometry.Subset { VertexCount = mesh.VertexCount, VertexStart = _vertices.Count, FaceStart = _indices.Count / 3, FaceCount = mesh.FaceCount }; _subsets.Add(subset); // bounding box corners var min = new Vector3(float.MaxValue); var max = new Vector3(float.MinValue); for (var i = 0; i < mesh.VertexCount; i++) { var pos = mesh.HasVertices ? mesh.Vertices[i].ToVector3() : new Vector3(); min = Vector3.Minimize(min, pos); max = Vector3.Maximize(max, pos); var norm = mesh.HasNormals ? mesh.Normals[i] : new Vector3D(); var texC = mesh.HasTextureCoords(0) ? mesh.GetTextureCoords(0)[i] : new Vector3D(); var tan = mesh.HasTangentBasis ? mesh.Tangents[i] : new Vector3D(); var v = new PosNormalTexTan(pos, norm.ToVector3(), texC.ToVector2(), tan.ToVector3()); verts.Add(v); } BoundingBox = new BoundingBox(min, max); _vertices.AddRange(verts); var indices = mesh.GetIndices().Select(i => (short)(i + (uint)subset.VertexStart)).ToList(); _indices.AddRange(indices);
///
public static Vector3 ToVector3(this Vector4 v) { return new Vector3(v.X, v.Y, v.Z); } public static Vector3 ToVector3(this Vector3D v) { return new Vector3(v.X, v.Y, v.Z); } public static Vector2 ToVector2(this Vector3D v) { return new Vector2(v.X, v.Y); } public static Material ToMaterial(this Assimp.Material m) { var ret = new Material { Ambient = new Color4(m.ColorAmbient.A, m.ColorAmbient.R, m.ColorAmbient.G, m.ColorAmbient.B), Diffuse = new Color4(m.ColorDiffuse.A, m.ColorAmbient.R, m.ColorAmbient.G, m.ColorAmbient.B), Specular = new Color4(m.Shininess, m.ColorSpecular.R, m.ColorSpecular.G, m.ColorSpecular.B), Reflect = new Color4(m.ColorReflective.A, m.ColorReflective.R, m.ColorReflective.G, m.ColorReflective.B) }; if (ret.Ambient == new Color4(0, 0, 0, 0)) { ret.Ambient = Color.Gray; } if (ret.Diffuse == new Color4(0, 0, 0, 0) || ret.Diffuse == Color.Black) { ret.Diffuse = Color.White; } if (m.ColorSpecular == new Color4D(0, 0, 0, 0) || m.ColorSpecular == new Color4D(0,0,0)) { ret.Specular = new Color4(ret.Specular.Alpha, 0.5f, 0.5f, 0.5f); } return ret; } public static Matrix ToMatrix(this Matrix4x4 m) { var ret = Matrix.Identity; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { ret[i, j] = m[i+1, j+1]; } } return ret; } public static Quaternion ToQuat(this Assimp.Quaternion q) { return new Quaternion(q.X, q.Y, q.Z, q.W); }///
///
var mat = model.Materials[mesh.MaterialIndex]; var material = mat.ToMaterial(); Materials.Add(material); var diffusePath = mat.GetTexture(TextureType.Diffuse, 0).FilePath; //diffusePath 经常是NULL,所以后面总是会索引超了
if (Path.GetExtension(diffusePath) == ".tga") { // DirectX doesn't like to load tgas, so you will need to convert them to pngs yourself with an image editor diffusePath = diffusePath.Replace(".tga", ".png"); } if (!string.IsNullOrEmpty(diffusePath)) { DiffuseMapSRV.Add(texMgr.CreateTexture(Path.Combine(texturePath, diffusePath))); } var normalPath = mat.GetTexture(TextureType.Normals, 0).FilePath; if (!string.IsNullOrEmpty(normalPath)) { NormalMapSRV.Add(texMgr.CreateTexture(Path.Combine(texturePath, normalPath))); } else { var normalExt = Path.GetExtension(diffusePath); normalPath = Path.GetFileNameWithoutExtension(diffusePath) + "_nmap" + normalExt; NormalMapSRV.Add(texMgr.CreateTexture(Path.Combine(texturePath, normalPath))); }
}
_modelMesh.SetSubsetTable(_subsets); _modelMesh.SetVertices(device, _vertices); _modelMesh.SetIndices(device, _indices);
///
public class TextureManager :DisposableClass { private bool _disposed; private Device _device; private readonly Dictionary<string, ShaderResourceView> _textureSRVs; public TextureManager() { _textureSRVs = new Dictionary<string, ShaderResourceView>(); } protected override void Dispose(bool disposing) { if (!_disposed) { if (disposing) { foreach (var key in _textureSRVs.Keys) { var shaderResourceView = _textureSRVs[key]; Util.ReleaseCom(ref shaderResourceView); } _textureSRVs.Clear(); } _disposed = true; } base.Dispose(disposing); } public void Init(Device device) { _device = device; } public ShaderResourceView CreateTexture(string path) { if (!_textureSRVs.ContainsKey(path)) { if (File.Exists(path)) { _textureSRVs[path] = ShaderResourceView.FromFile(_device, path); } else { return null; } } return _textureSRVs[path]; } }
///
public struct BasicModelInstance { public BasicModel Model; public Matrix World; public BoundingBox BoundingBox { get { return new BoundingBox( Vector3.TransformCoordinate(Model.BoundingBox.Minimum, World), Vector3.TransformCoordinate(Model.BoundingBox.Maximum, World) ); } } }
///
public void Draw(DeviceContext dc, EffectPass effectPass, Matrix viewProj) { var world = World; var wit = MathF.InverseTranspose(world); var wvp = world * viewProj; Effects.NormalMapFX.SetWorld(world); Effects.NormalMapFX.SetWorldInvTranspose(wit); Effects.NormalMapFX.SetWorldViewProj(wvp); Effects.NormalMapFX.SetTexTransform(Matrix.Identity);
//主要是在这里报错了 SubsetCount 总是计数为610,DiffuseMapSRV最大值总是为58,索引总是超了 for (int i = 0; i < Model.SubsetCount; i++) { Effects.NormalMapFX.SetMaterial(Model.Materials[i]); Effects.NormalMapFX.SetDiffuseMap(Model.DiffuseMapSRV[i]); Effects.NormalMapFX.SetNormalMap(Model.NormalMapSRV[i]); effectPass.Apply(dc); Model.ModelMesh.Draw(dc, i); } }
///
class AssimpModelDemo : D3DApp { private TextureManager _texMgr; private BasicModel _carModel; private BasicModelInstance _modelInstance; private readonly DirectionalLight[] _dirLights; private readonly FpsCamera _camera; private Point _lastMousePos; private bool _disposed; }
///
public override bool Init() { if (!base.Init()) return false; Effects.InitAll(Device); InputLayouts.InitAll(Device); RenderStates.InitAll(Device); _texMgr = new TextureManager(); _texMgr.Init(Device); _carModel = new BasicModel(Device, _texMgr, "Models/car.3ds", "Textures");
for (int i = 0; i < _treeModel.Materials.Count; i++)
{
_Model.Materials[i] = new Material()
{
Ambient = Color.DarkGray,
Diffuse = Color.White,
Specular = new Color4(128, 1f, 1.0f, 1.0f),
Reflect=new Color4(128, 1f, 1.0f, 1.0f)
};
}
_modelInstance = new BasicModelInstance { Model = _carModel, World = Matrix.RotationX(MathF.PI / 2) }; return true; }
///
public override void DrawScene() { base.DrawScene(); ImmediateContext.ClearRenderTargetView(RenderTargetView, Color.Silver); ImmediateContext.ClearDepthStencilView( DepthStencilView, DepthStencilClearFlags.Depth | DepthStencilClearFlags.Stencil, 1.0f, 0); ImmediateContext.InputAssembler.InputLayout = InputLayouts.PosNormalTexTan; ImmediateContext.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList; _camera.UpdateViewMatrix(); var viewProj = _camera.ViewProj; Effects.NormalMapFX.SetDirLights(_dirLights); Effects.NormalMapFX.SetEyePosW(_camera.Position); var activeTech = Effects.NormalMapFX.Light3TexTech; for (int p = 0; p < activeTech.Description.PassCount; p++) { var pass = activeTech.GetPassByIndex(p); _modelInstance.Draw(ImmediateContext, pass, viewProj); } SwapChain.Present(0, PresentFlags.None); }
当跳过错误渲染出来的车模型,只有几个零部件,哪个大牛能够告诉我为什么呢?你们能够停下来看一下,哪怕没帮我解决问题也非常感激。