Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

  • »CoookeiMonssterr« ist der Autor dieses Themas

Beiträge: 25

Wohnort: Schweiz

Beruf: Informatik-Lehrling

  • Private Nachricht senden

1

07.12.2014, 22:49

DirectX11 - Rendern

Hallo zusammen


Zuerst möchte ich denjenigen danken, die bei meinen letzten Fragen bzw. Problemen geholfen haben.
Dieses Mal habe ich kein Problem, sondern ein Frage:

Bei einem Spiel werden ja im Grund in der "Spiel-Schleife" einfach nur Events abgehört, Daten aktualisiert und Primitiven gerendert. So hab ich das zumindest verstanden.
Jetzt ist es ja nun so, das man (in einem vernünftigen Spiel) nun mal mehr als nur eins bis drei von diesen Primitiven hat. Mein Frage ist nun, ob man alle Daten sammelt und
diese dann zusammen mit einem einzigen Draw-Aufruft zeichnet (Zeichnet man in Spielen überhaupt mit der Draw-Funktion?, Wie macht man das sonst?).

So wie ich das in meinem Beispiel-Programm (welches ein Dreieck zeichnet) gemacht habe, werden diese Dreiecke einfach in einem std::vector<VERTEX> geschrieben, und dann über den Renderer gerndert. Dieser
schreibt die Daten in den Buffer und rendert diese. (Das Programm funktioniert)

Wie wird das nun in einem richtigen Spiel gemacht?

Kann mir jemand erklären, wie man das richtig macht? Oder kennt jemand ein gutes Tutorial bzw. Buch, welches mir das gut erklärt?



Mfg

CookeiMonssterr

2

08.12.2014, 03:58

.
"Wer Angst hat, dass ihm seine Ideen geklaut werden, der scheint nicht viele zu haben. "

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Mirac« (08.12.2014, 09:56)


BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

3

08.12.2014, 06:43

Nein man rendert normalerweise nicht die Szene mit einem einzigen Draw-Call.
Doch, wenn's möglich ist, macht man das eigentlich schon. Zumindest versucht man es.

zum Schluss wenn alle Objekte einer Szene in den Backbuffer gezeichnet sind, renderst du die Szene mittelsIDXGISwapChain::Present.
SwapChain::Present rendert überhaupt gar nichts.

du schreibst dir eine Klasse für ein Objekt, diese beinhalten einen Vertex- und einen Indexbuffer, sowie alle weiteren benötigten Daten (z.B. Poition, Rotation etc.)
Und wenn man das so macht, geht sämtliche Performance an hunderten Bind-Calls kaputt.

So wie ich das in meinem Beispiel-Programm (welches ein Dreieck zeichnet) gemacht habe, werden diese Dreiecke einfach in einem std::vector<VERTEX> geschrieben, und dann über den Renderer gerndert. Dieser
schreibt die Daten in den Buffer und rendert diese. (Das Programm funktioniert)
Klingt vernünftig. Z.B. XNA sammelt alle Vertex-Daten aller Objekte in einem gemeinsamen Buffer und rendert sie dann in einem einzigen Call.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Legend

Alter Hase

Beiträge: 731

Beruf: Softwareentwickler

  • Private Nachricht senden

4

08.12.2014, 09:39

Und wie bildet XNA dann verschiedene Texturen oder andere Zustände ab?
"Wir müssen uns auf unsere Kernkompetenzen konzentrieren!" - "Juhu, wir machen eine Farm auf!"

Netzwerkbibliothek von mir, C#, LGPL: https://sourceforge.net/projects/statetransmitt/

  • »CoookeiMonssterr« ist der Autor dieses Themas

Beiträge: 25

Wohnort: Schweiz

Beruf: Informatik-Lehrling

  • Private Nachricht senden

5

08.12.2014, 11:43

Mirac hat offenbar seine Antwort zensiert...

Vielen Dank an BlueCobold für die Antwort. Nun habe ich noch kurz eine weitere Frage:

Ich hab mir (weil es einfacher ist) eine Renderer Klasse geschrieben. Die Implementierung der Funktionen (die CRenderer.cpp-Datei) sieht so aus:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include "stdafx.h"
#include "CRenderer.h"

/*
* Constructor of CRenderer
* -----------------------
*
*/
CRenderer::CRenderer(CDirectX* p_directx) : m_directx(p_directx)
{};
/*
* Destructor of CRenderer
* ----------------------
*
*/
CRenderer::~CRenderer()
{};

/*
* Function CRenderer::Render
* --------------------------
*
* Renders the vertexes in the buffer
*
*/
void CRenderer::Render(std::vector<VERTEX>* p_ver)
{
    // Convert to Array
    VERTEX ver[MAX_PRIMITIVE];
    int i = 0;
    for(std::vector<VERTEX>::iterator it = p_ver->begin(); it != p_ver->end(); it++)
    {
        ver[i] = *it;
        i++;
    }
    
    // Create buffer
    D3D11_BUFFER_DESC bd;
    ZeroMemory(&bd, sizeof(bd));
    bd.Usage            = D3D11_USAGE_DYNAMIC;               
    bd.ByteWidth        = sizeof(VERTEX) * sizeof(ver)/sizeof(ver[0]);            
    bd.BindFlags        = D3D11_BIND_VERTEX_BUFFER;      
    bd.CPUAccessFlags   = D3D11_CPU_ACCESS_WRITE;   
    m_directx->dev->CreateBuffer(&bd, NULL, &m_directx->vbuffer);

    // Fillin buffer
    D3D11_MAPPED_SUBRESOURCE ms;
    m_directx->devcon->Map(m_directx->vbuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms);
    memcpy(ms.pData, ver, sizeof(ver));  
    m_directx->devcon->Unmap(m_directx->vbuffer, NULL); 

    // Render
    UINT stride = sizeof(VERTEX);
    UINT offset = 0;
    m_directx->devcon->IASetVertexBuffers(0, 1, &m_directx->vbuffer, &stride, &offset); 
    m_directx->devcon->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    m_directx->devcon->Draw(sizeof(ver)/sizeof(ver[0]), 0);

    // Delete the buffer
    SafeRelease(&m_directx->vbuffer);
};
/*
* Function CRenderer::Clear
* -------------------------
*
* Clears the screen
*
*/
void CRenderer::Clear(D3DXCOLOR p_color)
{
m_directx->devcon->ClearRenderTargetView(m_directx->backbuffer, p_color);
};
/*
* Function CRenderer::Present
* ---------------------------
*
* Presents the backbuffer as the frontbuffer
*
*/
void CRenderer::Present()
{
    m_directx->swapchain->Present(0, 0);
};

//


ist das eine Sinvolle-Art zu rendern?

Ich habe hier eigentlich für jeden Render()-Aufruf. Einen eigenen Buffer erstellt. Und dann aus diesem grendert (Draw rendert ja alle Daten, die sich im Buffer befinden).
Ich habe den Buffer dann gelöscht... (mit SafeRelease()). Ist dies überhaupt sinnvoll. Ich habe da einfach ein bisschen experimentiert... (Ist mein erstes Programm, welches ein Dreieck zeichnet, das funktioniert. Seid also nicht zu steng. ;( ).

mfg

CoookeiMonssterr

  • »CoookeiMonssterr« ist der Autor dieses Themas

Beiträge: 25

Wohnort: Schweiz

Beruf: Informatik-Lehrling

  • Private Nachricht senden

6

08.12.2014, 11:49

Hier ist meine main.cpp (Nur mal so zum Zeigen, da ich schon ein bisschen stolz drauf bin, es so aufgeräumt hin bekommen zu haben ;( ) :thumbsup:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include "stdafx.h"
#include "CWindow.h"   
#include "CDirectX.h"
#include "CRenderer.h"

/*
* Function WinMain
* ----------------
*
* This function ist the startpoint of our application
*
*/
int WINAPI WinMain(HINSTANCE p_hInstance, HINSTANCE p_hPrevInstance, LPSTR p_lpCmdLine, int p_nCmdShow)
{
    // Create Window
    CWindow window(p_hInstance);
    window.Create(L"DirectX Test", 800, 600);

    // Create DirectX
    CDirectX directx;
    directx.Init(&window);

    // Render
    CRenderer renderer(&directx);

    std::vector<VERTEX> ver;
    ver.push_back(VERTEX(0.0f, 0.5f, 0.0f, D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f)));
    ver.push_back(VERTEX(0.45f, -0.5, 0.0f, D3DXCOLOR(0.0f, 1.0f, 0.0f, 1.0f)));
    ver.push_back(VERTEX(-0.45f, -0.5f, 0.0f, D3DXCOLOR(0.0f, 0.0f, 1.0f, 1.0f)));

    // Enter the main loop
    MSG msg;
    while(window.IsOpen())
    {
        if(window.HasMsg())
        {
            msg = window.GetMsg();
            TranslateMessage(&msg);
            DispatchMessage(&msg);

            if(msg.message == WM_QUIT)
                window.Close();
        }
        renderer.Clear(D3DXCOLOR(0.0f, 1.0f, 0.5f, 1.0f));
        renderer.Render(&ver);
        renderer.Present();
    }

    return EXIT_SUCCESS;
};

//

Legend

Alter Hase

Beiträge: 731

Beruf: Softwareentwickler

  • Private Nachricht senden

7

08.12.2014, 12:25

Gut. Aus Performancesicht solltest du aber dringend den Vertexbuffer nicht in jedem Frame neu erstellen. Das ist sauteuer. ;)
"Wir müssen uns auf unsere Kernkompetenzen konzentrieren!" - "Juhu, wir machen eine Farm auf!"

Netzwerkbibliothek von mir, C#, LGPL: https://sourceforge.net/projects/statetransmitt/

  • »CoookeiMonssterr« ist der Autor dieses Themas

Beiträge: 25

Wohnort: Schweiz

Beruf: Informatik-Lehrling

  • Private Nachricht senden

8

08.12.2014, 12:32

Gut. Aus Performancesicht solltest du aber dringend den Vertexbuffer nicht in jedem Frame neu erstellen. Das ist sauteuer. ;)


Ja. stimmt eigentlich. Ist ja schnell geändert :vain:

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

9

08.12.2014, 13:41

Und wie bildet XNA dann verschiedene Texturen oder andere Zustände ab?
Dafür braucht's dann wieder einen neuen Batch + RenderCall. Mit dem richtigen Shader sollte das aber auch in einem gehen.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Schrompf

Alter Hase

Beiträge: 1 470

Wohnort: Dresden

Beruf: Softwareentwickler

  • Private Nachricht senden

10

08.12.2014, 14:14

Alles in einem DrawCall wird enorm schwierig. Mach Dir aber keine Gedanken darüber, das ist auch nicht notwendig. Ein paar hundert DrawCalls sind für die meisten Rechner da draußen kein Problem, nur mit WebGL und JavaScript solltest Du wohl besser bei ein paar Dutzend bleiben. Also bau erstmal Deinen Renderer. Danach siehst Du eh besser, wie und wo Du optimieren kannst.

Lose Empfehlungen für den Start:

- Bau eine Mesh-Klasse, die einen VertexBuffer und einen IndexBuffer kombiniert
- Bau eine Material-Klasse, die ein Set Shader mit einem Set Texturen und Parametern kombiniert
- Bau eine Entity-Klasse, die einen Mesh, ein Material und eine lokale Transformation kombiniert
- Bau eine Liste Entities, die Du erstmal plump runterrenderst.

Ab da wird's spannend, wenn es dann um Lichter-Integration, ShadowMap-Passes usw. geht. Aber für den Anfang ist das ne schlichte Struktur, die Dich vielleicht einen Nachmittag kostet und Dir schonmal einiges auf den Bildschirm zaubern kann. Die Struktur mit Daten zu füllen wird eh der kniffligere Teil.
Häuptling von Dreamworlds. Baut aktuell an nichts konkretem, weil das Vollzeitangestelltenverhältnis ihn fest im Griff hat. Baut daneben nur noch sehr selten an der Open Asset Import Library mit.

Werbeanzeige