Fourth Chapter Hello,shaders
In this chapter, the first shaders is written. Describes HLSL syntax, FX file format, data structure, and more. By the end of this chapter, you will have a basic knowledge of in-depth learning of graphics programming.
Your First Shader
The Classic programming example is used when writing the first program using a new programming language "hello,world! ", program output is a line of text" hello,world! ”。 We adhere to this historic tradition and write the first shader program "hello,shaders! ", but this time the output is a fixed color rendering to an object.
First, start the Nvidia FX composer and create a new project. Open the Assets Panel, right-click on the Materials icon and select the Add Material from New effect menu item. Then select HLSL FX in the Add Effect dialog box and click Next to proceed to the next step.
Figure 4.1 NVIDIA FX Composer Add Effect dialog box
In a dialog box, select the empty template and name Helloshader.fx (4.2).
Figure 4.2 NVIDIA FX Composer Select HLSL FX Template dialog box.
Click Finish in the final dialog box of the Effect Wizard (effect) to complete the effect Add. If each step is complete, you should be able to see the helloshaders.fx file in the editor panel and have the corresponding helloshaders and Helloshaders_material objects list in the assets panel. Note that the empty effect template created by the shader file is not an empty file, because the Nvidia FX composer automatically adds part of the code. This code is actually needed to write the first shader, but because it is for DirectX 9, it is removed and replaced with the content in Listing 4.1. And then step-by-step to explain this piece of code.
List 4.1 helloshaders.fx
Cbuffer cbufferperobject{float4x4 worldviewprojection:worldviewprojection;} Rasterizerstate disableculling{ cullmode = NONE;}; Float4 Vertex_shader (float3 objectposition:position): Sv_position{return mul (FLOAT4 (objectposition, 1), worldviewprojection);} FLOAT4 Pixel_shader (): sv_target{ return float4 (1, 0, 0, 1);} Technique10 main10{ Pass p0{ SetVertexShader (Compileshader (Vs_4_0, Vertex_shader ())); Setgeometryshader (NULL); SetPixelShader (Compileshader (Ps_4_0, Pixel_shader ())); Setrasterizerstate (disableculling); }}
Effect Files
The Shaders,direct3d pipeline phase is programmable through a separate compilation. For example, you can store vertex shader (usually a file suffix named. hlsl) in a file and store pixel shader in a different file. In this configuration, each file must contain a complete shader. In contrast, the HLSL effect file supports merging multiple shaders, functions, and render states into a single file. This file format is the format used in this book and is already used in Table 4.1.
Constant buffers
At the head of the helloshaders.fx file, there is a code that starts with Cbuffer fast. This represents a constant buffer, which is used to manage one or more shader constants. A shader constant is entered into the CPU and sent to the shader, and all primitives for a single draw call operation remain intact. On the other hand, Cbuffers stores variables and is constants. From the GPU perspective, cbuffers is constant during a single drawing operation Primitives, but from a CPU point of view, it is mutable from one draw call to the next.
In the helloshaders.fx file, only one cbuffer contains a shader constant, float4x4 type of worldviewprojection. This is a C-style variable that declares a 4x4 matrix of single-precision floating-point types. The worldviewprojection variable represents a matrix concatenated by World-view-projection and is used for each object. Recall that the second chapter, "A 3d/math Primer", the matrix only requires a single transformation can be vertices from object space to the world space and then to view space,homogeneous space. The World,view and projection three matrices are passed to effect, and then three different transformations are performed, which can produce the same result. Unless you have a special reason to do this, it is better to enter less data and execute fewer shader instructions.
Note that the variable declares the worldviewprojection literal after the colon, which is a semantic hint that this is the variable that the application that runs on the CPU wants to use. This semantics makes it possible for application developers to know the name of the shader constant without prior knowledge. For this example, you can name a variable of type float4x4 any WVP or worldviewprojection without worrying about the CPU program, because the CPU accesses the variable by WORLDVIEWPROJEC semantics instead of the variable name. There are a variety of common semantics in shader, and all semantics are optional for shader represented. However, the semantics of the Nvidia FX Composer,worldviewprojection are required and need to be associated with the shader constant to receive updates for each frame of the WVP composite matrix.
What's in a Name?
In helloshaders effect, constant buffer is named Cbufferperobject. The naming itself is nothing special, but it shows the update frequency of shader constants in Cbuffer. Perobject buffer indicates that the CPU is updating data for each object in the effect that corresponds to buffer.
In contrast, cbufferperframe means that the data for this buffer is updated every frame, allowing multiple objects to be rendered using the same shader constants.
Managing Cbuffers in this way allows for more efficient updates. When the CPU changes any of the shader constants in Cbuffer, the entire cbuffer needs to be updated. Therefore, the best approach is to group by the update frequency of the shader constants.
Render states
Shaders cannot define the behavior of the non-programmable phase of the Direct3D pipeline, but it can be customized by objects the rendering state. For example, you can customize the rendering state by using a Rasterizerstate object. Multiple render states can be set in shader, but are discussed in a later section. Now just need to know the Rasterizerstate object Disableculling (as shown in Listing 4.2).
List 4.2 Rasterizerstate declaration from HELLOSHADERS.FX
Rasterizerstate disableculling{cullmode = NONE;};
In chapter III, "Tools of the The trade", a brief description of the vertex around the sequence and the back elimination. DirectX By default, the counterclockwise display of the vertices as the back, and will not be drawn. However, the default model (Sphere,teapot,torus,plane) in the Nvidia FX composer has the opposite direction of the order. If you do not modify or disable culling Mode,direct3d the triangles we consider to be positive are eliminated. Because, in Nvidia FX composer, you only need to disable culling by specifying Cullmode = NONE.
Attention:
The culling issue exists in Nvidia FX composer because the FX composer supports both the DirectX and OpenGL rendering APIs. The two render libraries are not the same by default on the front, and Nvidia FX composer uses OpenGL by default.
The Vertex Shader
The next helloshaders code to analyze is Vertes shader, as shown in Listing 4.3.
list 4.3 The vertex shader from helloshaders.fx
Float4 Vertex_shader (float3 objectposition:position): Sv_position{return mul (FLOAT4 (objectposition, 1), worldviewprojection);}
The code is similar to a C-style function, but there are some key differences. First, vertex shader to do the work differently. Each vertex enters the shader with object space, and the worldviewprojection matrix transforms the vertex into homogeneous clip space. Under normal circumstances, is a vertes shader need to complete the least action.
The input to the Vertex shader is the data type FLOAT3 in HLSL, which is used to store 3 single-precision floating-point data, and the Objectpositon representation is a coordinate space. The semantics corresponding to the Objectpositon parameter are postion. Indicates that the variable includes a vertex postion. This is conceptually the same as the semantics used in the shader constants to indicate the usefulness of the arguments. However, these semantics are also used to connect shader inputs and outputs during the shader phase (for example, connecting Input-assembler and vertex shader stages), so variables require corresponding semantics. At the very least, vertex shader must accept a variable with postion semantics and return the sv_potion semantics.
Attention:
The semantics with the sv_ prefix are system-value semantics, originally proposed by Direct3D 10. These semantics specify a special meaning for the pipeline. For example, sv_position indicates that the corresponding output will contain a transformed vertex position for the rasterizer phase. The semantics of Non-system-value, including a series of standard semantics, are universal semantics that cannot be interpreted outside the pipeline.
In the vertex shader code, the HLSL built-in function mul is called. This function is used to multiply a matrix of two parameters. If the first argument is a vector, it is looked at a row vector (the second parameter is a row-first matrix). Conversely, if the first parameter is a matrix, it is treated as a column precedence matrix, and the second parameter is a column vector. Since most transformations use the row-first matrix, this uses the Mul function mul (vector, matrix).
It is important to note that the first parameter of the MUL function is a FLOAT4 type parameter that is caused by the objectposition (FLOAT3 type) and the number 1 construct. This step is necessary because the number of columns in the vector must match the number of rows in the matrix. Because the vector to be transformed is a position, you only need to specify the 4th float value (w component) as 1. If the vector represents a direction,w component, it should be set to 0.
The Pixel Shader
Like vertes shader, pixel shader in Helloshaders has only one line of code (such as listing 4.4).
List 4.4 The pixel shader from helloshaders.fx
FLOAT4 Pixel_shader (): Sv_target{return float4 (1, 0, 0, 1);}
The return value of Pixel shader is the FLOAT4 type and is specified as Sv_target semantics. Indicates that the output will be stored to the render target binding to the Output-merger stage. Typically, the render target is a texture that maps to the screen, called back buffer. The name comes from a double-buffered technique that uses two buffers to reduce the screen jitter generated when two (or more) frames are displayed simultaneously, as well as other artifacts. Instead, when the video device displays a front buffer, all the output is rendered to a back buffer. When a frame is rendered, the two buffer is swapped, and the newly rendered frame is displayed on the monitor. The swap operation is usually consistent with the display's refresh period to avoid shadowing.
The input of the Pixel shader is a 32-bit color value, Red,green,bluen, and Alpha (RGBA) four channels each accounted for 8-bit. All color values are floating-point, [0.0, 1.0] The shaping range is [0, 255]. In this example, the red channel is set to 1, which means that each pixel is rendered red. Because the color blending is not used, the value of the alpha channel has no effect. If a color Blending,alpha value of 1 is used, a completely opaque pixel is represented. In the 8th chapter, "Gleaming the Cube" will explain the color blending in detail.
Attention:
The pixel shader in helloshaders does not show the input parameters, but don't be confused. The homogenous clip space position, which is passed to pixel shader, is derived from the rasterizer phase. However, this process is performed in the background and does not show the input declared as pixel shader.
In the next chapter, you'll explain how to enter additional parameters in pixel shader.
Techniques
The last part of helloshaders effect is to use technique to integrate verter shader and pixel shader (see listing 4.5).
List 4.5 The technique from helloshaders.fx
Technique10 Main10{pass P0{setvertexshader (Compileshader (Vs_4_0, Vertex_shader ())); Setgeometryshader (NULL); SetPixelShader (Compileshader (Ps_4_0, Pixel_shader ())); Setrasterizerstate (disableculling);}}
A technique implements a specific rendering sequence through a set of effect passes. Each pass sets the rendering state and associates the shaders with the corresponding pipeline stage. In the helloshaders example, only one technique is used (named Main10) and there is only one pass (named P0). However, effects can contain techniques of the number of tasks, and each techniques can contain any number of passes. Currently, all techniques contain only one pass. In the fourth part, "Intermediate-level Rendering Topics", techniques with multiple passes will be discussed.
Note the keyword Technique10 used in the example, which indicates that this is a technique for Direct3D 10, Techniques for DirectX 9, but the techniques for DirectX 9 does not have a version suffix. The key word for Direct3D techniques is technique11. Unfortunately, the current version of NVIDIA FX composer does not support Direct3D 11. But in the beginning of learning shader development, there is no need to use the specific features in Direct3D 11, so this is not a problem. In the third part, "Rendering with DirectX", will use Direct3D one-techniques. The
also needs to be aware of the VS_4_0 and Ps_4_0 parameters in the SetVertexShader and SetPixelShader declarations. These parameter values specify the shader configuration used by the second parameter when calling the Compileshader function to compile shaders. Shader configuration, such as the shader model, defines the ability to support a graphics system corresponding to shaders. When writing this book, there are already 5 major shader versions (and some minor ones); The latest shader model is version 5. Each shader model extends the functionality of previous versions in a variety of ways. Typically, however, the functionality of shaders is increased with the new shader model. Direct3D 10 introduces the shader Model 4 for all Direct3D techniques. The Direct3D 11 introduces the shader model 5 and is used in all Direct3D techniques.
Hello, shaders!. Output
Now you can start to show the output of the helloshaders effect, first you need to compile effect, you can click Build,rebuild All or Build,compile helloshaders.fx menu. You can also use the shortcut key F6 (Rebuild All) or Ctrl+f7 (Compile Selected Effect). Recompile the code every time you modify it.
The next step is to specify that using the Direct3D 10 rendering API, you can choose from the drop-down menu in the toolbar (at the far right of the toolbar, which is probably Direct3D 9 by default). You can now open the render panel in the Nvidia FX composer, which is in the lower-right corner by default. Select Create-->sphere on the main menu or click the Sphere icon on the toolbar to create a sphere in the render panel. Finally, drag and drop helloshaders_material from the materials Panel or Assets panel onto the sphere object in the render panel. You can see something similar to the picture in Figure 4.3.
Figure 4.3 hellshaders.fx applied to a sphere in the NVIDIA FX Composer Render panel.
It may make you feel boring to spend so much energy doing so little, but it's actually done a lot. Take a moment to try the output of shader, change the RGB channel value of pixel shader, and see what happens.
Fourth Chapter Hello,shaders