public void AddGlyphPoints(List <PositionTextured> pointList, SizeF size, RectangleF position, RectangleF uv) { PositionTextured[] points = new PositionTextured[6]; Vector3d ul = new Vector3d(position.Left + rect.Left, position.Top + rect.Top, .9f); Vector3d ur = new Vector3d(position.Right + rect.Left, position.Top + rect.Top, .9f); Vector3d ll = new Vector3d(position.Left + rect.Left, position.Bottom + rect.Top, .9f); Vector3d lr = new Vector3d(position.Right + rect.Left, position.Bottom + rect.Top, .9f); points[0].Position = ul; points[0].Tu = uv.Left; points[0].Tv = uv.Top; points[2].Tu = uv.Left; points[2].Tv = uv.Bottom; points[2].Position = ll; points[1].Tu = uv.Right; points[1].Tv = uv.Top; points[1].Position = ur; points[3].Tu = uv.Right; points[3].Tv = uv.Bottom; points[3].Position = lr; points[5].Tu = uv.Right; points[5].Tv = uv.Top; points[5].Position = ur; points[4].Tu = uv.Left; points[4].Tv = uv.Bottom; points[4].Position = ll; pointList.AddRange(points); }
/// <summary> /// Construct a model class. /// </summary> /// <param name="sPath"></param> public SimpleModel(String sPath) { #region Material Sorted Mesh Import // Get the texture path. sPath = sPath.Replace('\\', '/'); int iIndex = sPath.LastIndexOf("/"); String sTexturePath = sPath.Substring(0, iIndex); Console.WriteLine("Texture Path = " + sTexturePath); // Import the file. Scene pScene = AssimpImporter.readFile(sPath, DefaultFlags); // If we had an error then throw an exception. if (pScene == null) throw new Exception(AssimpImporter.getErrorString()); // Order the meshes into a material-mesh array table. Dictionary<String, List<Assimp.ManagedAssimp.Mesh>> dTable = new Dictionary<String, List<Assimp.ManagedAssimp.Mesh>>(); // Sort the meshes into material (i.e. attribute order). int iVBufferSize = 0; int iIBufferSize = 0; foreach (Assimp.ManagedAssimp.Mesh pMesh in pScene.getMeshes()) { // Check we have the appropriate data. //if (!(pMesh.hasPositions() & pMesh.hasNormals() & pMesh.hasTangentsAndBitangents() & pMesh.hasTextureCoords(0) & pMesh.hasFaces())) // throw new Exception("Cannot import mesh. Required all, found: Positions=" + pMesh.hasPositions() + ", Normals=" + pMesh.hasNormals() + ", TangentsAndBitangents=" + pMesh.hasTangentsAndBitangents() + ", TextureCoords=" + pMesh.hasTextureCoords(0) + ", Faces=" + pMesh.hasFaces() + "."); // Convert the Assimp material to an Evolved material. Assimp.ManagedAssimp.Material pMat = pScene.getMaterial((int)pMesh.getMaterialIndex()); String sMaterial = pMat.getStringProperty("$tex.file"); if (sMaterial == null) sMaterial += "UnboundMaterial_" + (iNextMaterial++); else sMaterial = sTexturePath + "\\" + sMaterial; // Normalise the path address type. sMaterial = sMaterial.Replace('/', '\\'); // If this is the first entry - add to the list. List<Assimp.ManagedAssimp.Mesh> lMeshes = null; if (!dTable.TryGetValue(sMaterial, out lMeshes)) { lMeshes = new List<Assimp.ManagedAssimp.Mesh>(); dTable[sMaterial] = lMeshes; } // Work out the max vertex and face count. iVBufferSize += (int)pMesh.getNumVertices(); iIBufferSize += (int)pMesh.getNumFaces() * 3; // Insert the mesh under the appropriate material. lMeshes.Add(pMesh); } // Create the buffers and reset the stats. tVertex = new PositionTextured[iVBufferSize]; tIndex = new UInt32[iIBufferSize]; tAttibutes = new Attribute[dTable.Count]; tMaterials = new String[dTable.Count]; tTextures = new SlimDX.Direct3D9.Texture[dTable.Count]; dTable.Keys.CopyTo(tMaterials, 0); Radius = 0f; // Monitor global poisition in the vertex, index and attribute buffers. int iAttribute = 0; int iBVertex = 0; int iBIndex = 0; // For each material. foreach (String sMaterial in dTable.Keys) { // Create a new attribute. Attribute pAttrib = new Attribute(); tAttibutes[iAttribute] = pAttrib; // Store the buffer offsets into the attribute. pAttrib.iAttributeID = iAttribute; pAttrib.iVertexStart = iBVertex; pAttrib.iIndexStart = iBIndex; int iAVertex = 0; int iAFace = 0; // Copy the vertices and indicies of each mesh (updating the buffer counts). foreach (Assimp.ManagedAssimp.Mesh pMesh in dTable[sMaterial]) { // Copy verticies. int iMeshVerts = (int)pMesh.getNumVertices(); for (int iVertex = 0; iVertex < iMeshVerts; ++iVertex) { // Create the vertex. PositionTextured pVertex = new PositionTextured(); // Copy data. pVertex.Position = toDX9(pMesh.getPosition(iVertex)); pVertex.UV = toDX9UV(pMesh.getTextureCoordinate(0, iVertex)); // Update the radius. Radius = Math.Max(pVertex.Position.Length(), Radius); // Store. tVertex[iVertex + iBVertex] = pVertex; } // Increment the vertex count by the number of verticies we just looped over. iAVertex += iMeshVerts; iBVertex += iMeshVerts; // Copy indicies. int iMeshFaces = (int)pMesh.getNumFaces(); for (int iFace = 0; iFace < iMeshFaces; ++iFace) { uint[] tIndices = pMesh.getFace(iFace).getIndices(); if (tIndices.Length != 3) throw new Exception("Cannot load a mesh which does not have only triangluar faces."); tIndex[iBIndex++] = tIndices[0]; tIndex[iBIndex++] = tIndices[1]; tIndex[iBIndex++] = tIndices[2]; } // Increment the face count by the number of faces we just looped over. iAFace += iMeshFaces; } // Save the sizes. pAttrib.iFaceCount = iAFace; pAttrib.iVertexCount = iAVertex; // Increment the attribute counter. ++iAttribute; } #endregion }
//创建资源 private void LoadAssets() { //创建一个空的根签名 var rootSignatureDesc = new RootSignatureDescription( RootSignatureFlags.AllowInputAssemblerInputLayout, //根常量 new[] { new RootParameter(ShaderVisibility.All, //指定可以访问根签名绑定的内容的着色器,这里设置为顶点着色器 new DescriptorRange() { RangeType = DescriptorRangeType.ConstantBufferView, //指定描述符范围,这里的参数是CBV BaseShaderRegister = 0, //指定描述符范围内的基本着色器 OffsetInDescriptorsFromTableStart = int.MinValue, //描述符从根签名开始的偏移量 DescriptorCount = 1 //描述符范围内的描述符数 }) }); //表示该根签名需要一组顶点缓冲区来绑定 rootSignature = device.CreateRootSignature(rootSignatureDesc.Serialize()); //创建流水线状态,负责编译和加载着色器 #if DEBUG var vertexShader = new ShaderBytecode(SharpDX.D3DCompiler.ShaderBytecode.CompileFromFile("shaders.hlsl", "VS", "vs_5_0", SharpDX.D3DCompiler.ShaderFlags.Debug)); #else var vertexShader = new ShaderBytecode(SharpDX.D3DCompiler.ShaderBytecode.CompileFromFile("shaders.hlsl", "VS", "vs_5_0")); #endif //#if DEBUG // var pixelShader = new ShaderBytecode(SharpDX.D3DCompiler.ShaderBytecode.CompileFromFile("shaders.hlsl", "PS", "ps_5_0", SharpDX.D3DCompiler.ShaderFlags.Debug)); //#else // var pixelShader = new ShaderBytecode(SharpDX.D3DCompiler.ShaderBytecode.CompileFromFile("shaders.hlsl", "PS", "ps_5_0")); //#endif //描述输入装配器阶段的输入元素,这里定义顶点输入布局 var inputElementDescs = new[] { new InputElement("POSITION", 0, Format.R32G32B32_Float, 0, 0), new InputElement("TEXCOORD", 0, Format.R32G32_Float, 12, 0) }; //创建流水线状态对象(PSO) var psoDesc = new GraphicsPipelineStateDescription() { InputLayout = new InputLayoutDescription(inputElementDescs), //描述输入缓冲器 RootSignature = rootSignature, //根签名 VertexShader = vertexShader, //顶点着色器 //PixelShader = pixelShader,//像素着色器 RasterizerState = RasterizerStateDescription.Default(), //描述光栅器状态 BlendState = BlendStateDescription.Default(), //描述混合状态 DepthStencilFormat = SharpDX.DXGI.Format.D32_Float, //描述深度/模板格式(纹理资源) DepthStencilState = DepthStencilStateDescription.Default(), //描述深度模板状态 SampleMask = int.MaxValue, //混合状态的样本掩码 PrimitiveTopologyType = PrimitiveTopologyType.Triangle, //定义该管道的几何或外壳着色器的输入类型,这里是三角 RenderTargetCount = 1, //RTVFormat成员中的渲染目标格式数 Flags = PipelineStateFlags.None, //用于控制管道状态的标志,这里表示没有标志 SampleDescription = new SampleDescription(1, 0), //描述资源的多采样参数 StreamOutput = new StreamOutputDescription() //描述输出缓冲器 }; psoDesc.RenderTargetFormats[0] = Format.R8G8B8A8_UNorm; //描述渲染目标格式的数组 //设置管道 pipelineState = device.CreateGraphicsPipelineState(psoDesc); //创建命令列表 commandList = device.CreateCommandList( CommandListType.Direct, //指定命令列表的创建类型,Direct命令列表不会继承任何GPU状态 commandAllocator, //指向设备创建的命令列表对象的指针 pipelineState); //指向(管道)内存块的指针 commandList.Close(); float aspectRatio = viewPort.Width / viewPort.Height; //定义待绘制图形的几何形状 string bitmapPath = @"C:\Users\yulanli\Desktop\TerrainForm\heightMap.BMP"; Bitmap bitmap = new Bitmap(bitmapPath); xCount = (bitmap.Width - 1) / 2; yCount = (bitmap.Height - 1) / 2; cellWidth = bitmap.Width / xCount; cellHeight = bitmap.Height / yCount; var vertices = new PositionTextured[(xCount + 1) * (yCount + 1)];//定义顶点 for (int i = 0; i < yCount + 1; i++) { for (int j = 0; j < xCount + 1; j++) { System.Drawing.Color color = bitmap.GetPixel((int)(j * cellWidth), (int)(i * cellHeight)); float height = float.Parse(color.R.ToString()) + float.Parse(color.G.ToString()) + float.Parse(color.B.ToString()); height /= 10; vertices[j + i * (xCount + 1)].Position = new Vector3(j * cellWidth, height, i * cellHeight); vertices[j + i * (xCount + 1)].Texcoord = new Vector2((float)j / (xCount + 1), (float)i / (yCount + 1)); } } texture = TextureLoader.TextureLoader.CreateTextureFromDDS(device, @"C:\Users\yulanli\Desktop\TerrainForm\colorMapDDS.DDS"); //创建待绘制图形的顶点索引 indices = new int[6 * xCount * yCount]; for (int i = 0; i < yCount; i++) { for (int j = 0; j < xCount; j++) { indices[6 * (j + i * xCount)] = j + i * (xCount + 1); indices[6 * (j + i * xCount) + 1] = j + (i + 1) * (xCount + 1); indices[6 * (j + i * xCount) + 2] = j + i * (xCount + 1) + 1; indices[6 * (j + i * xCount) + 3] = j + i * (xCount + 1) + 1; indices[6 * (j + i * xCount) + 4] = j + (i + 1) * (xCount + 1); indices[6 * (j + i * xCount) + 5] = j + (i + 1) * (xCount + 1) + 1; } } //创建视锥体 //创建摄像机 CamTarget = new Vector3(bitmap.Width / 2, 0f, bitmap.Height / 2); view = Matrix.LookAtLH( CamPostion, //摄像机原点 CamTarget, //摄像机观察目标点 Vector3.UnitY); //当前世界的向上方向的向量,通常为(0,1,0),即这里的UnitY参数 proj = Matrix.Identity; proj = Matrix.PerspectiveFovLH( (float)Math.PI / 4.0f, //用弧度制表示垂直视场角,这里是45°角 aspectRatio, //纵横比 0.3f, //到近平面的距离 500.0f //到远平面的距离 ); var worldViewProj = Matrix.Multiply(proj, view); //使用上传堆来传递顶点缓冲区的数据 /*--------------------------------------------------* * 不推荐使用上传堆来传递像顶点缓冲区这样的静态数据 * * 这里使用上载堆是为了代码的简洁性,并且还因为需要 * * 传递的资源很少 * *--------------------------------------------------*/ var vertexBufferSize = Utilities.SizeOf(vertices); vertexBuffer = device.CreateCommittedResource( new HeapProperties(HeapType.Upload), HeapFlags.None, ResourceDescription.Buffer(vertexBufferSize), ResourceStates.GenericRead); //将顶点的数据复制到顶点缓冲区 IntPtr pVertexDataBegin = vertexBuffer.Map(0); Utilities.Write( pVertexDataBegin, vertices, 0, vertices.Length); vertexBuffer.Unmap(0); //初始化顶点缓冲区视图 vertexBufferView = new VertexBufferView(); vertexBufferView.BufferLocation = vertexBuffer.GPUVirtualAddress; vertexBufferView.StrideInBytes = Utilities.SizeOf <PositionTextured>(); vertexBufferView.SizeInBytes = vertexBufferSize; //使用上传堆来传递索引缓冲区的数据 int indexBufferSize = Utilities.SizeOf(indices); indexBuffer = device.CreateCommittedResource( new HeapProperties(HeapType.Upload), HeapFlags.None, ResourceDescription.Buffer(indexBufferSize), ResourceStates.GenericRead); //将索引的数据复制到索引缓冲区 IntPtr pIndexDataBegin = indexBuffer.Map(0); Utilities.Write( pIndexDataBegin, indices, 0, indices.Length); indexBuffer.Unmap(0); //初始化索引缓冲区视图 indexBufferView = new IndexBufferView(); indexBufferView.BufferLocation = indexBuffer.GPUVirtualAddress; indexBufferView.SizeInBytes = indexBufferSize; indexBufferView.Format = Format.R32_UInt; //创建bundle bundle = device.CreateCommandList( 0, CommandListType.Bundle, bundleAllocator, pipelineState); bundle.SetGraphicsRootSignature(rootSignature); bundle.PrimitiveTopology = SharpDX.Direct3D.PrimitiveTopology.TriangleList; bundle.SetVertexBuffer(0, vertexBufferView); bundle.SetIndexBuffer(indexBufferView); //bundle.DrawInstanced( // vertices.Length,//VertexCountPerInstance,要绘制的顶点数 // 1,//InstanceCount,要绘制的实例数,这里是1个 // 0,//StartVertexLocation,第一个顶点的索引,这里是0 // 0);//StartInstanceLocation,在从顶点缓冲区读取每个实例数据之前添加到每个索引的值 bundle.DrawIndexedInstanced( indices.Length, //IndexCountPerInstance,要绘制的索引数 1, //InstanceCount,要绘制的实例数,这里是1个 0, //StartIndexLocation,第一个顶点的索引,这里是0 0, //BaseVertexLocation,,从顶点缓冲区读取顶点之前添加到每个索引的值 0); //StartInstanceLocation,在从顶点缓冲区读取每个实例数据之前添加到每个索引的值 bundle.Close(); //使用上传堆来传递常量缓冲区的数据 /*--------------------------------------------------* * 不推荐使用上传堆来传递像垂直缓冲区这样的静态数据 * * 这里使用上载堆是为了代码的简洁性,并且还因为需要 * * 传递的资源很少 * *--------------------------------------------------*/ constantBuffer = device.CreateCommittedResource( new HeapProperties(HeapType.Upload), HeapFlags.None, ResourceDescription.Buffer(1024 * 64), ResourceStates.GenericRead); //创建SRV视图 var srvDesc = new ShaderResourceViewDescription(); srvDesc.Texture2D.MostDetailedMip = 0; srvDesc.Texture2D.ResourceMinLODClamp = 0.0f; device.CreateShaderResourceView(texture, srvDesc, shaderRenderViewHeap.CPUDescriptorHandleForHeapStart); //创建常量缓冲区视图(CBV) var cbvDesc = new ConstantBufferViewDescription() { BufferLocation = constantBuffer.GPUVirtualAddress, SizeInBytes = (Utilities.SizeOf <ConstantBuffer>() + 255) & ~255 }; device.CreateConstantBufferView( cbvDesc, constantBufferViewHeap.CPUDescriptorHandleForHeapStart); //初始化并映射常量缓冲区 /*--------------------------------------------------* * 直到应用程序关闭,我们才会取消映射,因此在资源的 * * 生命周期中保持映射是可以的 * *------------------------------------------------- */ constantBufferPointer = constantBuffer.Map(0); Utilities.Write(constantBufferPointer, ref worldViewProj); //创建同步对象 //创建围栏 fence = device.CreateFence( 0, //围栏的初始值 FenceFlags.None); //指定围栏的类型,None表示没有指定的类型 fenceValue = 1; //创建用于帧同步的事件句柄 fenceEvent = new AutoResetEvent(false); }
public void AddGlyphPoints(List<PositionTextured> pointList, SizeF size, RectangleF position, RectangleF uv) { PositionTextured[] points = new PositionTextured[6]; Vector3d ul = new Vector3d(position.Left+rect.Left, position.Top+rect.Top, .9f); Vector3d ur = new Vector3d(position.Right+rect.Left, position.Top+rect.Top, .9f); Vector3d ll = new Vector3d(position.Left+rect.Left, position.Bottom+rect.Top, .9f); Vector3d lr = new Vector3d(position.Right+rect.Left, position.Bottom+rect.Top, .9f); points[0].Position = ul; points[0].Tu = uv.Left; points[0].Tv = uv.Top; points[2].Tu = uv.Left; points[2].Tv = uv.Bottom; points[2].Position = ll; points[1].Tu = uv.Right; points[1].Tv = uv.Top; points[1].Position = ur; points[3].Tu = uv.Right; points[3].Tv = uv.Bottom; points[3].Position = lr; points[5].Tu = uv.Right; points[5].Tv = uv.Top; points[5].Position = ur; points[4].Tu = uv.Left; points[4].Tv = uv.Bottom; points[4].Position = ll; pointList.AddRange(points); }
/// <summary> /// Creates a model of a textured round disc with a hole in the middle. /// </summary> /// <param name="device">The <see cref="Device"/> to create the mesh in.</param> /// <param name="radiusInner">The radius of the inner circle of the ring.</param> /// <param name="radiusOuter">The radius of the outer circle of the ring.</param> /// <param name="height">The height of the ring.</param> /// <param name="segments">The number of segments the ring shall consist of.</param> public static Mesh Disc(Device device, float radiusInner, float radiusOuter, float height, int segments) { #region Sanity checks if (device == null) { throw new ArgumentNullException(nameof(device)); } #endregion const float tuInner = 0, tuOuter = 1; Log.Info("Generate predefined model: Disc"); var posInner = new Vector3(radiusInner, 0, 0); var posOuter = new Vector3(radiusOuter, 0, 0); #region Generate vertexes int vertCount = 0; var step = (float)(Math.PI * 2 / segments); var vertexes = new PositionTextured[segments * 4]; for (int i = 0; i < segments; i++) { vertexes[vertCount++] = new PositionTextured(posInner.X, posInner.Y - height / 2, posInner.Z, tuInner, 0); vertexes[vertCount++] = new PositionTextured(posInner.X, posInner.Y + height / 2, posInner.Z, tuInner, 0); vertexes[vertCount++] = new PositionTextured(posOuter.X, posOuter.Y - height / 2, posOuter.Z, tuOuter, 0); vertexes[vertCount++] = new PositionTextured(posOuter.X, posOuter.Y + height / 2, posOuter.Z, tuOuter, 0); // Increment rotation posInner = Vector3.TransformCoordinate(posInner, Matrix.RotationY(step)); posOuter = Vector3.TransformCoordinate(posOuter, Matrix.RotationY(step)); } #endregion #region Generate indexes int indexCount = 0; var indexes = new short[segments * 24]; for (int i = 0; i < segments; i++) { short innerBottom1 = (short)(i * 4), innerTop1 = (short)(i * 4 + 1); short outerBottom1 = (short)(i * 4 + 2), outerTop1 = (short)(i * 4 + 3); short innerBottom2 = (short)(i * 4 + 4), innerTop2 = (short)(i * 4 + 5); short outerBottom2 = (short)(i * 4 + 6), outerTop2 = (short)(i * 4 + 7); if (innerBottom2 >= vertexes.Length) { innerBottom2 -= (short)vertexes.Length; } if (innerTop2 >= vertexes.Length) { innerTop2 -= (short)vertexes.Length; } if (outerBottom2 >= vertexes.Length) { outerBottom2 -= (short)vertexes.Length; } if (outerTop2 >= vertexes.Length) { outerTop2 -= (short)vertexes.Length; } // Bottom 2 triangles indexes[indexCount++] = innerBottom1; indexes[indexCount++] = innerBottom2; indexes[indexCount++] = outerBottom2; indexes[indexCount++] = innerBottom1; indexes[indexCount++] = outerBottom2; indexes[indexCount++] = outerBottom1; // Top 2 triangles indexes[indexCount++] = innerTop1; indexes[indexCount++] = outerTop2; indexes[indexCount++] = innerTop2; indexes[indexCount++] = innerTop1; indexes[indexCount++] = outerTop1; indexes[indexCount++] = outerTop2; // Inner 2 triangles indexes[indexCount++] = innerTop1; indexes[indexCount++] = innerBottom2; indexes[indexCount++] = innerBottom1; indexes[indexCount++] = innerTop1; indexes[indexCount++] = innerTop2; indexes[indexCount++] = innerBottom2; // Outer 2 triangles indexes[indexCount++] = outerBottom1; indexes[indexCount++] = outerBottom2; indexes[indexCount++] = outerTop1; indexes[indexCount++] = outerBottom2; indexes[indexCount++] = outerTop2; indexes[indexCount++] = outerTop1; } #endregion var mesh = new Mesh(device, indexes.Length / 3, vertexes.Length, MeshFlags.Managed, PositionTextured.Format); BufferHelper.WriteVertexBuffer(mesh, vertexes); BufferHelper.WriteIndexBuffer(mesh, indexes); MeshHelper.GenerateNormalsAndTangents(device, ref mesh, false); return(mesh); }