You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/1-introduction/1-1-getting-started/1-1-0-overview.md
+3-1Lines changed: 3 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -25,7 +25,7 @@ A few words about how each project will look like.
25
25
26
26
Inside the project folder:
27
27
28
-
```
28
+
```bash
29
29
Assets/
30
30
Assets/Models/
31
31
Assets/Shaders/
@@ -45,3 +45,5 @@ x-x-x-project.vcxproj
45
45
-`obj/` contains all intermediate junk the compiler produced, to keep the folder structure clean
46
46
-`bin/` will contain the compiled program of the chapter along with all necessary `Assets`
47
47
-`Assets/` will contain all the used assets, such as models, shaders and textures and other things. It will be empty for the first few chapters, and we will copy it and its contents to the bin/Debug or bin/Release directory, depending on which configuration you chose
[`glfwSetFramebufferSizeCallback`](https://www.glfw.org/docs/3.3/group__window.html#gab3fb7c3366577daef18c0023e2a8591f) will tell `GLFW` what to do when we resize the window, in this case execute `HandleResize` which will fetch our application instance and all `OnResize` on it, where we can handle resizing in our application code.
480
480
481
-
## Abstraction into Application & D3D11Context
481
+
[Project on GitHub](https://github.com/GraphicsProgramming/learnd3d11/tree/main/src/Cpp/1-getting-started/1-1-2-HelloD3D11)
Copy file name to clipboardExpand all lines: docs/1-introduction/1-1-getting-started/1-1-3-hello-triangle.md
+35-5Lines changed: 35 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,8 @@ In the last chapter we initialized core components of `D3D11` and DXGI such as t
4
4
This time we'll be drawing our first triangle with a nice froge-like color.
5
5
6
6
## The Pipeline
7
-
The fundamental part of all graphic APIs is the "Graphics Pipeline". Everything from a single triangle, textured frog or the whole Elden Ring map goes through this pipeline. It is a series of functions that either exist in hardware, can be configured or are fully programmable. It transforms everything we draw in 3D space to the 2D space that is our monitor.
7
+
8
+
The fundamental part of all graphic APIs is the "Graphics Pipeline". Everything from a single triangle, textured frog or the whole Elden Ring map goes through this pipeline. It is a series of functions that either exist in hardware, can be configured or are fully programmable. It transforms everything we draw in 3D space to the 2D space that is our monitor.
8
9
9
10
All the steps in the graphics pipeline go from top to bottom and are shown below.
10
11
@@ -18,6 +19,7 @@ The Vertex and Pixel shaders are fully programmable and we'll write a very basic
18
19
The other two stages are not programmable but they are fairly easy to understand and configure, the **Input Assembler** is responsible for processing the vertices in an eventual vertex buffer into the primitive of our choice, which is of course, triangles in our case, and sending this processed output to the Vertex Shader. The **Output Merger** instead is responsible for combining the values written by the pixel shader, may that be depth, color or other things, into the one or more render targets that we provide to the OM, we only have one render target for now.
19
20
20
21
### Vertex Shader
22
+
21
23
The **Vertex Shader** is the stage where our vertices are processed however we want, although we don't do much processing here, and in the end they're transformed to [screen-space coordinates](link to the coordinate system chapter?)
22
24
23
25
The vertices are usually read from a **Vertex Buffer** which are laid out in a particular way. The vertex shader will be run however many times we tell it to run, which is specified in the first parameter of `ID3D11DeviceContext::Draw()` (more on this later), for instance if we call `Draw(3, 0)`, the vertex shader will run 3 times.
@@ -27,7 +29,9 @@ Since we only want to draw a triangle, we don't need to do much processing, we c
27
29
The vertex buffer can be omitted, for example if we want to draw a full screen triangle, instead of creating a vertex buffer, for simplicity we can just hardcode the vertices in the vertex shader without having to bind a vertex buffer.
28
30
29
31
Let's look at our basic vertex shader for this section:
32
+
30
33
#### Main.vs.hlsl
34
+
31
35
```hlsl
32
36
struct VSInput
33
37
{
@@ -49,29 +53,33 @@ VSOutput Main(VSInput input)
49
53
return output;
50
54
}
51
55
```
56
+
52
57
First off, we define 2 types, `VSInput` and `VSOutput` which represent the vertex shader's input and output.
53
58
54
59
The input is 2, `float3` (vector of 3 float components), the first is the "position" field, which are coordinates ranging from [-1.0, 1.0], if the values are outside this range they are clipped, and we won't see them on screen.
55
60
56
61
The second is the "color" field, which we also pass as the output of this stage onto the pixel shader.
57
62
58
-
Notice how all our fields have a colon and some identifier attached to them, these are "semantics".
59
-
Semantics that are preceded by `SV` are called "system-value semantics" and their meaning and usage is defined by D3D11. `SV_Position` for example means that the field `position` will be used by D3D11 as the actual output of the vertex shader.
63
+
Notice how all our fields have a colon and some identifier attached to them, these are "semantics".
64
+
Semantics that are preceded by `SV` are called "system-value semantics" and their meaning and usage is defined by D3D11. `SV_Position` for example means that the field `position` will be used by D3D11 as the actual output of the vertex shader.
60
65
Everything else are "user defined semantics" and their naming is up to us. These are used to pass data between shader stages.
61
66
62
67
Then we have our `VSOutput`, which has our vertices in the first field `position` and our color in the second field `color`.
63
68
64
69
Finally we have our main function, which takes in a single parameter which is our input in the form of `VSInput`, and returns our output in the form of a `VSOutput`. Since we don't do any processing, we simply make a new instance of `VSOutput`, initialize it all to 0 and forward our input position and color to the output.
65
70
66
71
### Pixel Shader
72
+
67
73
The **Pixel Shader** is the stage where we give the pixels on our render target color, it is invoked for each pixel that is covered by a triangle.
68
74
69
75
We use this stage to apply most of our shading techniques, from basic lighting, to textures and shadows, all the way to physically based rendering.
70
76
71
77
Since we did not specify any shader between the VS and the PS, our input here is the output of the VS, and the output is one or more render targets.
72
78
73
79
Let's look at our Pixel Shader now:
80
+
74
81
#### Main.ps.hlsl
82
+
75
83
```hlsl
76
84
struct PSInput
77
85
{
@@ -91,6 +99,7 @@ PSOutput Main(PSInput input)
91
99
return output;
92
100
}
93
101
```
102
+
94
103
Here as well we have an input `PSInput`, and an output `PSOutput`.
95
104
96
105
Since there aren't any other shaders in between the VS and the PS, the VS's output is the PS's input, the naming might be a bit confusing but that's the gist of it, PSInput should match the VSOutput in vertex shader, this isn't entirely required but not doing so is only advisable if you really know what you are doing.
@@ -99,16 +108,18 @@ Next we have our output, `D3D11` gives us the possibility to write to multiple r
99
108
100
109
Notice how we have another semantic string attached to the `color` field, this semantic string specifies which render target we want to be writing to, the `0` after `SV_Target` is the index of our render target, in our case, we have only one so we write `SV_Target0` or `SV_Target`.
101
110
102
-
`D3D11` lets us write up to 8 render targets simultaneously from the same pixel shader, those come in handy when implementing more advanced shading techniques, for example a popular technique that uses 4 or more
111
+
`D3D11` lets us write up to 8 render targets simultaneously from the same pixel shader, those come in handy when implementing more advanced shading techniques, for example a popular technique that uses 4 or more
103
112
104
113
And lastly, our `Main` function, following the same pattern as in the VS, we have one parameter, the input, and one return value, the output, again we create an instance of `PSOutput`, initialize everything to 0, and write the color we got from the input, to our output.
114
+
105
115
## Compiling shaders
106
116
107
117
Now that we wrote our shader code and saved it somewhere, we have to feed this to the GPU, to do that we'll have our D3DCompiler get to work.
108
118
109
119
First, we will declare some functions that will help us compile our shaders more quickly.
`CompileShader`: This function is the core for compiling shaders, it requires 3 input parameters:
@@ -140,9 +152,13 @@ Then:
140
152
`CreatePixelShader`: It does the same thing that `CreateVertexShader` does, except we don't need to pass a `ID3DBlob` here.
141
153
142
154
Now that we know how our new members look, we will see how we implemented them.
155
+
143
156
### HelloTriangle.cpp
157
+
144
158
First things first, let's see `CompileShader`:
159
+
145
160
#### CompileShader
161
+
146
162
```cpp
147
163
bool HelloTriangleApplication::CompileShader(
148
164
const std::wstring_view fileName,
@@ -188,7 +204,7 @@ Then we call for [`D3DCompileFromFile`](https://docs.microsoft.com/en-us/windows
188
204
-`pInclude`: optional, a pointer to a `ID3DInclude` object, it is useful to specify how to handle `#include` directives in shaders. It is common to just use `D3D_COMPILE_STANDARD_FILE_INCLUDE`, which is the default handler.
189
205
-`pEntrypoint`: a string containing the name of the main function in the shader.
190
206
-`pTarget`: a string containing the Shader Model version to use for this shader.
191
-
-`Flags1`: the flags that changes how to compile our shaders, for example we pass `D3DCOMPILE_ENABLE_STRICTNESS` which makes the compiler stricter in judging our code and disables legacy syntax support.
207
+
-`Flags1`: the flags that changes how to compile our shaders, for example we pass `D3DCOMPILE_ENABLE_STRICTNESS` which makes the compiler stricter in judging our code and disables legacy syntax support.
192
208
-`Flags2`: ignored, set to 0.
193
209
-`ppCode`: output, a pointer to a `ID3DBlob*`, this is where our compiled code will be stored.
194
210
-`ppErrorMsgs`: optional, output, a pointer to a `ID3DBlob*`, this is where the D3D compiler will store our errors, `nullptr` if everything went fine.
@@ -198,6 +214,7 @@ Then we do our usual checking, if there were errors, leave the output blob as is
198
214
Now let's see `CreateVertexShader` and `CreatePixelShader`:
@@ -228,6 +245,7 @@ As you can see here we are using our helper function `CompileShader` to avoid re
228
245
After we get our blob successfully, we can create a vertex shader out of it with `ID3D11Device::CreateVertexShader`, it takes a pointer to a buffer with the compiled code and its size as the input. The resulting vertex shader is the last parameter which is our output.
Pretty much the same thing as `CreateVertexShader`, the only thing that changes is the `profile` parameter, from `"vs_5_0"` to `"ps_5_0"`, since we're not compiling a vertex shader now, we have to change this to the "Pixel Shader Model 5.0".
257
276
258
277
After all of this, we can now call these functions, in `HelloTriangleApplication::Initialize()` you should now add:
As you can see, we go through the pipeline in an orderly fashion, and although we don't use all the stages, we can see the top-to-bottom execution of the stages, IA (Input Assembler) -> VS (Vertex Shader) -> RS (Rasterizer Stage) -> PS (Pixel Shader) -> OM (Output Merger).
488
510
489
511
You should now be able to run this and see your first triangle!
512
+
513
+
!!! error
514
+
515
+
Provide picture of window with triangle
516
+
517
+
[Project on GitHub](https://github.com/GraphicsProgramming/learnd3d11/tree/main/src/Cpp/1-getting-started/1-1-3-HelloTriangle)
Though keep in mind that using the latter function also resets stuff like the inputlayout, primitive topology and literally everything. This might require a bit more work in making sure all rendering state is setup correctly again afterwards
24
24
25
-
In pure performance terms it can be quite wasteful to reset a whole bunch of state (or re-set it) every draw/pass/frame which is why this is viewed as a debugging option.
25
+
In pure performance terms it can be quite wasteful to reset a whole bunch of state (or re-set it) every draw/pass/frame which is why this is viewed as a debugging option.
26
+
27
+
In the end, one generally should make sure their draws always set (or have set) their required state so they do not need to use a clear-state.
26
28
27
-
In the end, one generally should make sure their draws always set (or have set) their required state so they do not need to use a clear-state.
Copy file name to clipboardExpand all lines: docs/1-introduction/1-2-debug/1-2-4-renderdoc.md
+9-7Lines changed: 9 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,16 +1,16 @@
1
1
# RenderDoc
2
2
3
-
Typically while developing an application there will be complications that cannot be easily deduced by watching the program execute or by reading the code; in a situation like this one will use a debugger to monitor the state of the program to locate the bug, and this is no different for graphics programming.
3
+
Typically while developing an application there will be complications that cannot be easily deduced by watching the program execute or by reading the code; in a situation like this one will use a debugger to monitor the state of the program to locate the bug, and this is no different for graphics programming.
4
4
5
-
Graphics programmers will use what is called a "graphics debugger" when working with a graphics API to monitor API calls, pipeline state, data within the pipeline, etc.
5
+
Graphics programmers will use what is called a "graphics debugger" when working with a graphics API to monitor API calls, pipeline state, data within the pipeline, etc.
6
6
7
7
While there are multiple graphics debuggers provided by multiple vendors such as Nvidia's Nsight, AMD's Radeon Graphics Profiler (Does not directly support DX11), Intel's Graphics Performance Analyzers, and Microsoft's PIX, we will instead be using a cross-platform open-source option, RenderDoc.
8
8
9
9
To download RenderDoc, [click here](https://renderdoc.org/) and follow the instructions on the webpage.
The event browser displays a generalization of the API calls called in the form of events, an event is one or more API calls that have been grouped together by relation.
31
+
The event browser displays a generalization of the API calls called in the form of events, an event is one or more API calls that have been grouped together by relation.
32
32
33
33
There is not much going on in this example, but it can be helpful when debugging scenes making hundreds or even thousands of draws and dispatches a frame.
34
34
@@ -38,14 +38,16 @@ The API Inspector displays the contents of an event by listing out the API calls
The Pipeline State tab displays the state of each active pipeline stage in addition to bound resources for the currently selected event.
41
+
The Pipeline State tab displays the state of each active pipeline stage in addition to bound resources for the currently selected event.
42
42
43
-
In this instance, the hull, domain, and geometry shader stages are grayed out because they were not used for that draw.
43
+
In this instance, the hull, domain, and geometry shader stages are grayed out because they were not used for that draw.
44
44
45
45
The compute shader stage is called with its own dispatch commands and therefore is never active with the other stages; it is not a part of the rasterization pipeline.
The Resource Inspector presents a list of all the resources used to render the frame on the right side of the window with information pertaining to its usage within the frame, related resources, and the functions used to initialize the resource.
49
+
The Resource Inspector presents a list of all the resources used to render the frame on the right side of the window with information pertaining to its usage within the frame, related resources, and the functions used to initialize the resource.
50
50
51
51
To learn more about RenderDoc, [click here](https://renderdoc.org/docs/index.html) for its documentation.
0 commit comments