Shader basic projects in managed code (VB.net)
|
Triangle
|
Simple triangles created via vertex buffer stream data. Vertex buffers require as vertex declaration, populating a vertex buffer, and then streaming points in the forms of points, lines, or triangles using drawprimitives.
Source as HTML for perusal: Form code | graph.vb | fps.vb | vs.fx
|
|
Ambient
|
Washed out
Sphere from
the same
program
above. Only
a few lines
of code
need to be
changed.
The sphere
is
particularly
uninteresting
because it
only has
ambient
light (it
shows no
lighting or
reflection
whatsoever).
No changes
to the
shader file
need to be
made. It
will
compute per
vertex.
Later,
pixel
shading
will be
added to
show rich
lighting. It requires only a few code changes from the above program. 1) Add a line to create a mesh object in the Form_Load event
3) Call displaymesh instead of displaybuff in the draw function
|
|
|
|
|
Ambient + Diffuse + Specular using Blinn Phong (See Wolfgang Engel text)
|
|
|
Bump mapping
[Bump mapped Venus implemented in DirectX 9.0, HLSL and Visual Basic.net.] Normal map from Celestia |
The source code to implement the main application can be found here. I ported Engel's C++ to VB.net The source code for the bump mapping HLSL (.fx file) can be found here.
As you can see in the picture, the light source is up and to the right of you, and it's shining down on the planet. What bump mapping does is reflect light as though the surface of the sphere actually had ridges and gullies; all of the reflection you see which appears to be mountain sides or gullies in the sun, and the resultant shadowing, is actually faked by the normal map which holds information on which way each pixel is facing.
|
As the fx files become more complicated, it may be best to get something like Nvidia FX composer, not to do any fancy graphics or anything, but just to be able to compile the HLSL files. I downloaded it today (11/5/07) and it certainly enables me to check the syntax errors in my fx files.
For the specular files and beyond this will be necessary==>Fx Composer Nvidia
I have to admit, it's nice to for the first time be able to see an IDE showing me obvious errors in my shader files.
![]()
|
(More to be added....) 11/2007
Per Vertex
|
|
[An example in CsGL per-vertex specular highlights (two lights): fixed function lighting, no shaders; you can subtlety see the difference between this and the next picture based on the "boxy" nature of the highlights here (per vertex) versus the per pixel continuous look below.] Below is the fixed function OpenGL CsGL .net code implemented in Visual Basic. It gives a basic demonstration of how to implement a simple simulation with a light or two, balls, points, lines, etc. CSGL Wrapper sample code for this prog. If you have used OpenGL, then this will be familiar
|
Per Pixel
|
|
[An example of DirectX per-pixel specular and diffuse lighting (one light). Not fixed function. All pixel manipulation done in shader code, and the highlights appear continuous rather than choppy. Per vertex versus per pixel.]
DirectX shader managed code for this prog. See specular lighting tutorial here=> |
OpenGL and DirectX since .net (including Java): Lighting, graphics, wrappers, and trying to get it all in one package
Although realism in computer graphics really began with the availability of the OpenGL API in 1992, early games (Doom Quake etc) didn't use it initially. However its use was popularized when John Carmack ported Quake to OpenGL (glQuake) in around 1996. Simultaneously, Microsoft was working its DirectX API which included a lot more than just graphics. It included everything a power app needs: graphics, sound, input etc. In time, DirectX would overtake OpenGL as the standard for 3D graphics, but even now they essentially offer the same features graphically.
OpenGL Resources
CsGL wrapper for .net
OpenGL Redbook tutorials. These are the basics of OpenGL and graphics in general.
For information on specular, ambient, diffuse lighting in an unintuitive and overwhelming way, see this Wikipedia page .
Resources for Unmanaged and Managed DirectX
Around Chapter 9 of Miller's book, you'll hit HLSL shading and you'll forget about the first 8 chapters and do everything over using shaders. It's a good way to learn the basics of graphics programming, which you need to know in order to get through shaders. This book does not go into a great amount of detail on HLSL. And Engel's book (below), is basically a collection of articles that explain how to do certain high level effects using HLSL.
What Miller does in his book is do everything in managed DirectX in both VB.net and C#. With that foundation, Engel's book can be used to implement all of the stuff in Engel's book with a little work. . Engel's book is in C++, so you will have to port your code from C++ to VB or C#.
Tom Miller's KickStart References for implementing shaders can be found in chapter 9+
Kris Gray's DirectX 9 Programmable Graphics Pipeline uses both the older GPU assembly-like code as well as the new c-like HLSL.
Bump mapping requires using shaders. Each pixel contains not only a light
component, but a normal component--a facing component. For the shader, the
projection Matrix, an Eye, direction Vectors, and colors for specular, diffuse,
and ambient lights, and any other things from the program as passed to the
shader and from there everything is computed by pixel and/or vertex (generally
both).
Kurt Bingham
KB 6/23/07
A quick aside on using HLSL for the graphical output:
|
Shaders 101
Basically, there are 3 things to keep in mind when outputting graphics using HLSL (assuming you already know how to do this with using fixed functions). The HLSL semantics, the Vertex Declaration, and the Vertexbuffer data. Review the tutorial (which is excellent) here to see a very simple C# vertexshader program. He creates a struct myowncustomvertex, whereas I plod onward using the pre-created CustomVertex class. Since CustomVertex.PositionColored doesn't have a structure I want (X,Y,Z, R,G,B), I'm going to funnel the data in through the CustomVertex.PositionNormal, which does.
The vertex declaration simply defines the kind of data your vertexbuffer will contain, and in what order. It also specifies a DeclarationUsage. This isn't really a fixed usage that the shader is going to force; just because you call it a COLOR, doesn't mean that shader will use it for COLOR, and in fact, unless you tell the shader to do something with this field info, it won't do anything with it.
It's just a way of putting your data in a slot that you can retrieve from the shader code. It's a way of passing variables through the buffer stream. But since a shader isn't like a typical program, things are slightly different. When you wind up your shader file and let it go, it won't return to the main program until its done processing all of the vertices in the buffers. So any special instructions (like color) applying to a specific vertex must be defined in the vertex declaration and contained in the vertexbuffer and specified for that point when you create the buffer.
The substitution below helps explain this.
Dim elements() As VertexElement = {New VertexElement(0, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Position, 0), _New VertexElement(0, 12, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Normal, 0), VertexElement.VertexDeclarationEnd} The DeclarationType.Float3 up top is my position for each point--remember the VertexElement defines the format of each member of a stream. The top one also has a UsageDeclaration of POSITION. I will access the float3 values there by requesting the POSITION channel information. The 2nd line is also a float3, and it's usage is DeclarationUsage.Normal.
When I fill the vertexbuffer, I'm going to use CustomVertex.PositionNormal, which has X,Y,Z, and NX,NY,NZ. The NX,NY,NZ which are usually the normals are going to instead contain my colors RGB.
vb = New VertexBuffer(GetType(CustomVertex.PositionNormal), UBound(myObjects.grid), myDevice, Usage.WriteOnly, CustomVertex.PositionNormal.Format, Pool.Managed) Dim verts As CustomVertex.PositionNormal() = CType(vb.Lock(0, 0), CustomVertex.PositionNormal()) For i = 0 To UBound(verts) Dim pc As CustomVertex.PositionNormal = New CustomVertex.PositionNormal _ (myObjects.grid(i).p.p.X, myObjects.grid(i).p.p.Y, myObjects.grid(i).p.p.Z, 0, 0, myObjects.grid(i).PPc) verts(i) = CType(pc, CustomVertex.PositionNormal) Next
The New CustomVertex.PositionNormal constructor allows me to put in my X,Y,Z values and then follow it by the normals, which I am using 0,0,PPc. In the shader, I will be able to reference my RGB float3 by requesting the Normal field values.
/************** this is the shader code ***************************/ float4x4 ProjectionMatrix;
struct VS_OUTPUT_POLYSHDR{ float4 Pos : POSITION; float4 Color : COLOR0; };
VS_OUTPUT_POLYSHDR POLYSHDR( float4 Pos : POSITION, float4 Color: NORMAL){ VS_OUTPUT_POLYSHDR Out = (VS_OUTPUT_POLYSHDR)0;
Out.Pos = mul(Pos, ProjectionMatrix);Out.Color = float4(Color.x,Color.y, Color.z,1.0f);
return Out; }
technique POLYSHDR{ pass P0 {
VertexShader = compile vs_1_1 POLYSHDR();
} } }
This is basically what was done for the coloring of the Polytrope program.
-------------------------------------------------------------------------------------------------------
On the other hand, if you want to be explicit, and you're willing to create your own custom vertex, you can implement the entire process with the following code. The only difference is that one uses the native CustomVertex type, and this next one does it old school style and creates a custom structure.
When you declare a 'single' in VB, that maps to a 'float' on the card. Again, a subtle difference is, when you make your vertex declaration, you don't get the option to use single3 (for a vector3), only float3. Yet, when you're creating your structure, you won't see float as a primitive type because there is no float in Visual Basic! You'll just declare them single and public.
All the shader is looking for, say for something coming in as a POSITION is x,y,z,w. If it's COLOR, it's r,g,b,a.
My vertex is really a PositionColored vertex. However, the PositionColored supplied by DirectX has an integer for the color. Doh, not helpful since I need 4 floats for a color in the shader, and I'm not about to convert them inside the shader at the shader's expense. Now, my vertex declaration corresponds with this data type: The shader is expecting to be able to access public XYZW from the POSITION component and RGBA from the COLOR component of the vertex stream. I will load it up as follows:
Myvertex has been defined. I now create a instance of it for each entry and send it to the shader. The shader now creates the right objects with the associated colors.
Of course there are several thing that need to be done in between all of these steps, including setting the matrices and setting parameters in the shader file (publics, like the worldviewProj matrix etc.), and these steps are not shown.
The entire little rotatable triangle program can be found at the links below: Form code | graph.vb | fps.vb | vs.fx
|
Shaders 101 07/06/2007
KB
Kurt Bingham 2/2008