在我的项目中,我展示了很多领域。
要显示球体,我会加载一些带有某些值的文件。 因此它可能是1600球。现在我在渲染时出现性能问题...... :(
在这部分中,我初始化了我的设备对象:
try
{
meshList = new List<Sphere>();
// Erstellt die PresentParameters für weitere Einstellungen des Device
PresentParameters presParams = new PresentParameters()
{
Windowed = true, // Device nur innerhalbe des Fensterhandels benutzen
SwapEffect = SwapEffect.Discard, // Grafikkarte entscheidet selbst wie sie den Backbuffer zur anzeige bringt
EnableAutoDepthStencil = true, // Boolean zum Merken der Tiefe
AutoDepthStencilFormat = DepthFormat.D16 // Format der Tiefe
};
// Erzeugt eine Instanz von dem Device
device = new Device(0, // Nummer fuer den Grafikadapter der verwendet wird
DeviceType.Hardware, // Parameter über die Garfikkarte oder CPU ausführen
panel1, // Fensterhadel für das Device
CreateFlags.HardwareVertexProcessing, // Einstellung des Device. Gibt an, dass die Vertices nur per Software verarbeitet werden
presParams); // Gibt die weiteren Einstellungen mit
// Wenn das Device neupositioniert wird
device.DeviceReset += new System.EventHandler(this.OnResetDevice);
// Führt das Reset aus
OnResetDevice(device, null);
// Definiert keine Vor und Rückseite
device.RenderState.CullMode = Cull.Clockwise;
// Direct3D-Beleuchtung deaktivieren
device.RenderState.Lighting = false;
// Beschreibt einen festen Füllmodus
device.RenderState.FillMode = FillMode.Solid;
// Erstellt den Buffer für die Vertices (Lab Koordinatensystem)
vertexBuffer = new VertexBuffer(typeof(CustomVertex.PositionColored), // Typ der Vertices
18, // Anzahl der Vertices
device, // Gerätekontext unser device
0, // Anzahl der Flags zur Verarbeitung der Vertice
CustomVertex.PositionColored.Format, // Typ der Vertices (Weil man auch eigene Strukturen definieren kann)
Pool.Default); // Speicherung der Vertices
// Event welches aufgerufen wird wenn der Vertexbuffer erstellt wurde
vertexBuffer.Created += new System.EventHandler(this.OnCreateVertexBuffer);
// Event wird von Hand aufgerufen
this.OnCreateVertexBuffer(vertexBuffer, null);
return true; // Device wurde erstellt
}
catch { return false; } // Device konnte nicht erstellt werden
在这部分中,我渲染所有顶点:
public void Render()
{
// Fragt ob das Device erstellt wurde und noch gültig ist
if (device == null)
return;
// Inhalt des Backbuffers löschen und das ganze mit einer Farbe einfärben
device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, // Die entsprechende Oberfläche
System.Drawing.Color.Black, // Die Farbe
1.0f, // Abstand vom Betrachter, an dem die Oberfläche gelöscht wird und einen Wert, ...
0); // ...der in jedem Stencil-Buffer-Eintrag gespeichert wird.
// Anfang der Szene
device.BeginScene();
// Matrizen aufsetzen
SetupMatrices();
// Bindet den Buffer an das Device
device.SetStreamSource(0, // Nummer des Streams
vertexBuffer,// Der Buffer
0); // StartOffset in dem Buffer
// Teilt dem Device das Format der Vertices mit
device.VertexFormat = CustomVertex.PositionColored.Format;
// Zeichnet die Dreiecke
device.DrawPrimitives(PrimitiveType.LineList, // Typ der Primitive
0, // Eintrag des ersten Vertex
3); // Anzahl der Primetive
// Zeichnet jedes einzelne Sphere
foreach (Sphere mesh in meshList)
{
mesh.labMesh.DrawSubset(0);
}
// Ende der Szene
device.EndScene();
// Bringt die Zeichnung auf das Fensterhandle
device.Present();
}
这是创建每个球体的类:
/// <summary>
/// Die Klasse Sphere
/// </summary>
public class Sphere
{
// Radius der Kugel
private const float radius = 4f;
// Die Anzahl der Ebenen einer Kugel
private const int slices = 40;
// Die Anzalh der Flächen einer Ebene
private const int stacks = 40;
// Das Mesh zum Darstellen der Kugel
private Mesh mesh = null;
private Vector3 vec;
public Vector3 min;
public Vector3 max;
/// <summary>
/// Gibt den Mesh zurück
/// </summary>
public Mesh labMesh
{
get { return mesh; }
}
public Vector3 labVector
{
get { return vec; }
}
/// <summary>
/// Erstellt das Mesh
/// </summary>
/// <param name="device">Das 3D Device</param>
/// <param name="color">Die Farbe der Kugel</param>
/// <param name="labValues">Die Lab Werte der Kugel</param>
public void createMesh(Device device, Color color, params float[] labValues)
{
// Erstellt die Kugel mit der Anbindung an das Device
mesh = Mesh.Sphere(device, radius, slices, stacks);
// Kopiert das Mesh zum Erstellen des VertexArrays
Mesh tempMesh = mesh.Clone(mesh.Options.Value, Vertex.FVF_Flags, device);
// Erstellt den VertexArray
Vertex[] vertData = (Vertex[])tempMesh.VertexBuffer.Lock(0, typeof(Vertex), LockFlags.None, tempMesh.NumberVertices);
// Weist jedem Vertex die Farbe und die Position zu
for (int i = 0; i < vertData.Length; ++i)
{
vertData[i].color = color.ToArgb();
vertData[i].x += labValues[1];
vertData[i].y += labValues[0] - 50f;
vertData[i].z += labValues[2];
}
min = new Vector3(labValues[1], labValues[0] + 100f, labValues[2]);
max = new Vector3(labValues[1], labValues[0] - 100f, labValues[2]);
// Gibt den VertexBuffer in der Kopie frei
tempMesh.VertexBuffer.Unlock();
// Löscht den Mesh aus dem Speicher
mesh.Dispose();
// Legt die Kopie in der Meshinstanz ab
mesh = tempMesh;
Vector3 v = new Vector3(labValues[1], labValues[0], labValues[2]);
vec = v;
}
}
/// <summary>
/// Vertex für die Kugel
/// </summary>
struct Vertex
{
public float x, y, z; // Position of vertex in 3D space
public int color; // Diffuse color of vertex
/// <summary>
/// Konstruktor der Vertex
/// </summary>
/// <param name="_x">X(A) - Position</param>
/// <param name="_y">Y(L) - Position</param>
/// <param name="_z">Z(B) - Position</param>
/// <param name="_color">Die Farbe</param>
public Vertex(float _x, float _y, float _z, int _color)
{
x = _x; y = _y; z = _z;
color = _color;
}
// Das Format des Vertex
public static readonly VertexFormats FVF_Flags = VertexFormats.Position | VertexFormats.Diffuse;
}
我不知道如何通过渲染1600个球体来提高性能! 我认为在游戏中也必须是一个解决方案。
我希望你有一个想法来帮助我!
答案 0 :(得分:2)
我建议您通过分析器运行代码并查看代码中瓶颈的位置并进行优化。
检查this question以查找C#的配置文件。
答案 1 :(得分:2)
首先,我必须说Managed DirectX不受微软的支持。你最好还是使用像XNA这样的东西或更好的SlimDX。
一种方法是仅使用一个球体,然后设置包含矩阵数据的第二个顶点流。然后,您可以使用一个单一的绘制调用渲染实例化的球体。这应该会显着提高性能。
另一种方法是构建一个包含尽可能多的球体的巨型顶点缓冲区,以便减少DrawSubset
。这将提高性能。
那说1600画面调用一帧很高但 显着,所以应该可以获得不错的性能。
要尝试的一些方法是在mesh.Clone
电话中添加以下标记:
还要确保关闭alpha混合(这可能值得一试)。
理想情况下,从前到后渲染球体将优化溢出(写入像素的次数也应尽可能低),但这通常会占用比GPU时间更多的CPU。
要记住的其他事项是你的球体有多复杂。他们可以减少tris的数量吗?
除了使用Caesar建议的某种调试器(从来没有我输入;))是一个很好的前进方法。可能只是Managed DirectX的性能不足以为您提供您所追求的结果......
答案 2 :(得分:0)
在此示例中,绘制调用的数量是瓶颈,而不是GPU性能。 您应该明确减少绘制调用的次数。对于一个完整的高端游戏,在PC上,绘图调用的nubmer很少超过2000,这是一个非常优化的管道。在笔记本电脑上,这仍然是一个非常高的数字。使用C#时最多可以进行1000次绘制调用。
为了解决您的问题,有一些选择。
第一个选项是将所有数据放入单个缓冲区。您应该将顶点缓冲区视为发送到gpu的数据块,并且您希望尽可能少地向gpu发送数据,因为此处的开销很大。您应该将所有球体放在一个缓冲区或几个缓冲区中。这将解决您的性能问题。 合并静态对象是游戏引擎中的常见做法。
第二个选项是,如果你需要可移动的球体,你可以使用实例化。实例化是一种技术,您可以在其中多次渲染相同的数据,每个实例都有一些额外的数据。这只需要一次平局调用。现在,所有GPU都支持实例化,因此如果需要移动对象或参数化对象,请使用此实例。快速谷歌肯定会提供更多信息。
最后注意,就像已经提到的那样,托管的directx多年来已经死了。它很慢,只有dx9。使用c#时应切换到SlimDX(XNA也已死)。