Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 60 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
60
Dung lượng
1,41 MB
Nội dung
Ambient Wireframe Shader Demo The following program demonstrates the Ambient.fx effect with the FillMode property set to wireframe. You may selectively swap one type of mesh for another to see the sphere, teapot, cylinder, cube, or torus by making minor changes to the code. #include "stdafx.h" #include "Engine.h" using namespace std; using namespace Octane; LPD3DXMESH torus; LPD3DXMESH sphere; LPD3DXMESH cube; LPD3DXMESH teapot; LPD3DXMESH cylinder; Matrix matWorld; Font* font=NULL; Camera* camera=NULL; Effect* effect=NULL; float deltaTime=0; bool game_preload() { g_engine->setAppTitle("Ambient Wireframe Shader Demo"); g_engine->setScreen(800,600,32,false); return true; } bool game_init(HWND hwnd) { font = new Font("Arial Bold",18); if (!font) { debug ( "Error creating font" ( endl; return false; } //g_engine->setBackdropColor(D3DCOLOR_XRGB(0,250,250)); //create a camera 220 Chapter 8 n Rendering the Scene Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com camera = new Camera(); camera->setPosition(0, 0.0, 10.0); camera->setTarget(0,0,0); //load the ambient.fx effect effect = new Effect(); if (!effect->Load("ambient.fx")) { MessageBox(hwnd, "Error loading ambient.fx", "Error",0); return false; } matWorld.setIdentity(); //create stock meshes D3DXCreateTorus(g_engine->getDevice(), 2.0f, 4.0f, 20, 20, &torus, NULL); D3DXCreateTeapot(g_engine->getDevice(), &teapot, NULL); D3DXCreateSphere(g_engine->getDevice(), 2.0f, 10, 10, &sphere, NULL); D3DXCreateBox(g_engine->getDevice(), 2.0f, 2.0f, 2.0f, &cube, NULL); D3DXCreateCylinder(g_engine->getDevice(), 2.0f, 2.0f, 3.0f, 10, 10, &cylinder, NULL); return true; } void game_render3d() { //effect->setTechnique("Ambient"); effect->setViewMatrix( camera->getViewMatrix(), "View"); effect->setProjectionMatrix( camera->getProjMatrix(), "Projection"); //draw the cube { static float rot = 0; rot += 0.01f; matWorld.rotateX(rot); effect->Begin(); effect->setWorldMatrix( (D3DXMATRIX) matWorld , "World"); The Scene (World Matrix) 221 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com //choose which mesh to render here torus->DrawSubset(0); //cube->DrawSubset(0); //sphere->DrawSubset(0); //teapot->DrawSubset(0); //cylinder->DrawSubset(0); effect->End(); } } void game_end() { if (font) delete font; if (effect) delete effect; if (camera) delete camera; torus->Release(); teapot->Release(); cube->Release(); sphere->Release(); cylinder->Release(); } void game_update( float dltTime ) { deltaTime = dltTime; camera->Update(); //move the torus mesh in a circular pattern static float x = 0.0f; static float y = 0.0f; static float z = 0.0f; static float angle = 0.0f; } void game_render2d() { std::ostringstream out; out.setf(ios::fixed); out ( setprecision(4); 222 Chapter 8 n Rendering the Scene Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com out ( "Delta time = " ( deltaTime ( endl; out ( "Update = " ( g_engine->getCoreFrameRate() ( " fps" ( endl; out ( "Draw = " ( g_engine->getScreenFrameRate() ( " fps"; font->Print(0,0,out.str()); } void game_event( IEvent* e ) { switch( e->getID() ) { case EVENT_KEYPRESS: { KeyPressEvent* evt = (KeyPressEvent*) e; if (evt->keycode == DIK_ESCAPE) g_engine->Shutdown(); break; } case EVENT_MOUSEMOTION: { MouseMotionEvent* evt = (MouseMotionEvent*)e; camera->Look( evt->deltax/100.0f, evt->deltay/100.0f, 0 ); break; } case EVENT_MOUSEWHEEL: { MouseWheelEvent* evt = (MouseWheelEvent*) e; camera->Move(0, 0, (float)(-evt->wheel/200.0f) ); break; } } } Diffuse Lighting The ambient light shader in the previous example of this chapter was designed for illustration, meant to be easy to understand, but it is not very useful for a game. To correctly render a mesh we need to add a light source so that the mesh can reflect light realistically (while our ambient demo did no such reflection and could only really be seen in wireframe mode). Diffuse Lighting 223 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Diffuse light is light that is spread out or scattered over an area (such as the faces of a mesh), or light that is dim or bright depending on the type of surface it is shining on. While ambient light appears to reflect evenly from all surfaces, diffuse light lacks that perfect conciseness, which is precisely why it is a superior form of lighting. In a sense, all light other than ambient may be considered diffuse, but it is most often referred to as light from a directional light source. Directional Light A directional light mimics sunlight, in that rays appear to come from an infinitely far light source, are emitted parallel to each other, and strike an object or scene uniformly from that direction without any apparent radiant source (such as a light bulb or spotlight). Directional light will, therefore, appear to reflect on all objects in a scene uniformly (as long as every object is rendered with the directional light applied). To render a mesh with a directional light, in addition to the usual World/View/ Projection matrices, we must also supply a vector to the light source, the light’s color and intensity, and an inverse/transposed matrix. When calculating the lighting on the faces of a mesh we must calculate the normal and the light intensity. The normal is calculated from an inverse/transposed version of the World matrix. The light intensity is calculated by taking the dot product of the normal. Matrix Inverse/Transpose Calculating the inverse of a matrix is rather complex, involving some derivation that is beyond the scope of this book. In brief, the inverse of a matrix is such that when matrix A is inverted to B, both A times B and B times A will equal the identity matrix. As a result of the theory required to explain inverting a matrix, this is a calculation we cannot easily detach from the D3DX library at this time without further research. What we can do, however, is make use of the D3DXMatrixInverse function to perform this calculation. Transposing a matrix involves shifting the rows 90 degrees into the columns as illustrated in Figure 8.6. We can calculate the transposed matrix with the function D3DXMatrixTranspose. 224 Chapter 8 n Rendering the Scene Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Both the matrix inverse and transpose are needed to calculate how light will affect the faces of a mesh, taking into account the position of a light source. Assuming your world matrix represents the transforms for a given mesh, then this code will perform the calculation: D3DXMATRIX inverse, wit; D3DXMatrixInverse( &inverse, 0, &world ); D3DXMatrixTranspose( &wit, &inverse ); Both of these functions return the calculated matrix as a return value as well as passing the result back through the reference parameter, so the result can be carried on to a calling function. If you wish, you may combine the function calls like so: D3DXMatrixTranspose(&wit,D3DXMatrixInverse(&inverse,0,&world)); And, finally, assuming our effect has a global property so named, we can pass the inverted/transposed World matrix to the effect via our setParam() function: effect->setParam( "WorldInverseTranspose", wit ); Advice You will probably not want to calculate inverse/transpose inside your shader because those calculations will be repeated for every vertex and potentially every pixel being rendered. Instead, calculate the inverse/transpose once in the CPU and pass that calculation on to the effect for an entire mesh. Figure 8.6 Transposing a matrix. Diffuse Lighting 225 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Dot Product To calculate a dot product, the X,Y,Z properties of two vectors are multiplied by each other, and those products are then added together. The name “dot product” comes from the dot that is used to represent the calculation. Figure 8.7 shows an example of calculating using dot product. Directional Light Shader This effect source code adds a few more global properties compared to the previous ambient effect, to take into account directional lighting. Now we have these globals: Data Type Global Name float4x4 World float4x4 View float4x4 Projection float4x4 WorldInverseTranspose float3 LightVector float4 LightColor float LightPower Figure 8.7 Calculating the dot product of two vectors. 226 Chapter 8 n Rendering the Scene Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com It’s important to take note of these global properties because they must be set correctly in our source code—and case sensitivity must be observed. float4x4 World; float4x4 View; float4x4 Projection; float4x4 WorldInverseTranspose; float3 LightVector = float3(0, 0, 1); float4 LightColor = float4(1,1,1,1); float LightPower = 0.6; struct MyVertexInput { float4 position : POSITION; float2 texcoord : TEXCOORD0; float4 normal : NORMAL; }; struct MyVertexOutput { float4 position : POSITION; float2 texcoord : TEXCOORD0; float4 color : COLOR0; }; MyVertexOutput VertexShaderFunction( MyVertexInput input_param ) { MyVertexOutput output = (MyVertexOutput)0; //transform float4x4 viewProj = mul(View,Projection); float4x4 WorldViewProj = mul(World,viewProj); output.position = mul(input_param.position, WorldViewProj); //lighting float4 normal = mul( input_param.normal, WorldInverseTranspose ); float intensity = dot( normal, LightVector ); output.color = saturate( LightColor * LightPower * intensity ); return output; } Diffuse Lighting 227 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com float4 PixelShaderFunction(MyVertexOutput input_param) : COLOR0 { float4 light = saturate( input_param.color + LightColor * LightPower ); return light; } technique DirectionalLight { pass P0 { vertexShader = compile vs_2_0 VertexShaderFunction(); pixelShader = compile ps_2_0 PixelShaderFunction(); } } Directional Light Demo We have covered quite a bit of new material on diffuse lighting, and our first experiment is with a directional light source (the most common form of lighting after ambient). This example required quite a bit more work beyond the ambient light demo presented earlier in the chapter, including an inverse/transposed World matrix and properties for the directional light source (position vector, intensity value, and color value). Figure 8.8 shows the somewhat overused teapot mesh with a green directional light illuminating it. This program has some interactivity programmed in. By pressing the up/down arrows, you can rotate the mesh. The left/right arrows will rotate the light source around the scene (or more accurately, rotate the normalized vector pointing at the directional light). The þ/À keys on the numeric keypad increase and decrease the light intensity, respectively. The R, G, B, and A keys on the keyboard adjust the color values used for the directional light’s color. Figure 8.9 shows another stock mesh being rendered. Engine Enhancement: Color Class We’re going to need a new feature in the engine to make working with colored lighting more effective. The Direct3D color macros and functions could not be much more confusing to the uninitiated. At best you are likely to get the integer and floating-point color macros confused; at worst, nothing but a black scene will reward you for your hard work. A new Color class will alleviate these 228 Chapter 8 n Rendering the Scene Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com difficulties by abstracting color at a more basic level—just dealing with the basic four color components: Red, Green, Blue, Alpha. Here is the class definition: class Color { public: float r,g,b,a; virtual ~Color(); Color(); Color( const Color& color ); Color(int R,int G,int B,int A); Color(float R,float G,float B,float A); Color& Color::operator=(const Color& c); void Set(int R,int G,int B,int A); void Set(float R,float G,float B,float A); Figure 8.8 Directional lighting on a stock mesh with interactive controls. Diffuse Lighting 229 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com [...]... 20; - 25. 000000;- 25. 000000;0.000000;, 25. 000000;- 25. 000000;0.000000;, - 25. 000000; 25. 000000;0.000000;, 25. 000000; 25. 000000;0.000000;, - 25. 000000;- 25. 000000 ;50 .000000;, 25. 000000;- 25. 000000 ;50 .000000;, - 25. 000000; 25. 000000 ;50 .000000;, 25. 000000; 25. 000000 ;50 .000000;, - 25. 000000;- 25. 000000;0.000000;, 25. 000000;- 25. 000000;0.000000;, 25. 000000;- 25. 000000 ;50 .000000;, - 25. 000000;- 25. 000000 ;50 .000000;, 25. 000000; 25. 000000;0.000000;,... 25. 000000; 25. 000000;0.000000;, 25. 000000;- 25. 000000 ;50 .000000;, 25. 000000; 25. 000000;0.000000;, - 25. 000000; 25. 000000;0.000000;, - 25. 000000; 25. 000000 ;50 .000000;, 25. 000000; 25. 000000 ;50 .000000;, - 25. 000000; 25. 000000;0.000000;, - 25. 000000;- 25. 000000 ;50 .000000;; 12; 3;0,2,3;, 3;3,1,0;, Simpo PDF Merge and Split Unregistered Version -Loading and Rendering Mesh http://www.simpopdf.com 247 3;4 ,5, 7;, 3;7,6,4;,... -0.422214;4. 056 703;-2.418363;, 1.0992 65; 2.443709;-1.771478;, MeshNormals { 42; -0.188146;0.299602;-0.9 353 28;, -0 .53 0179;0.069419;-0.8 450 39;, -0.1437 05; -0. 158 832;-0.976791;, 0.292207;0.687314;-0.664991;, 0. 058 9 45; 0.37 053 7;-0.9269 45; , } MeshTextureCoords { 42; Simpo PDF Merge and Split Unregistered Version -Loading and Rendering Mesh http://www.simpopdf.com 251 0.3 756 72;0.480374;, 0.489480;0.47 451 3;,... false; } matWorld.setIdentity(); lightColor.Set(0, 255 ,0, 255 ); //create stock meshes D3DXCreateTorus(g _engine- >getDevice(), 0.3f, 1.0f, 80, 80, &torus, 0); D3DXCreateTeapot(g _engine- >getDevice(), &teapot, 0); D3DXCreateSphere(g _engine- >getDevice(), 1.0f, 80, 80, &sphere, 0); D3DXCreateBox(g _engine- >getDevice(), 1.0f, 1.0f, 1.0f, &cube, 0); D3DXCreateCylinder(g _engine- >getDevice(),1.0f,1.0f,3.0f,80,80,&cylinder,0);... Convert 0- 255 color values to 0.0-1.0 range **/ void Color::Set(int R,int G,int B,int A) { r = (float)R/ 256 .f; g = (float)G/ 256 .f; b = (float)B/ 256 .f; a = (float)A/ 256 .f; } void Color::Set(float R,float G,float B,float A) { r=R; g=G; b=B; a=A; } 232 Simpo 8 n Rendering Split Unregistered Version - http://www.simpopdf.com Chapter PDF Merge andthe Scene /** Convert from our 0.f-1.f color values to 0- 255 based... 3;1,12,7;, 3;7,13,1;, 3;14, 15, 16;, 3;16,17,14;, 3;18,0,19;, 3;19,6,18;; MeshNormals { 6; 0.000000;0.000000;-1.000000;, 0.000000;0.000000;1.000000;, 0.000000;-1.000000;0.000000;, 1.000000;0.000000;0.000000;, 0.000000;1.000000;0.000000;, -1.000000;0.000000;0.000000;; 12; 3;0,0,0;, 3;0,0,0;, 3;1,1,1;, 3;1,1,1;, 3;2,2,2;, 3;2,2,2;, 3;3,3,3;, 3;3,3,3;, 3;4,4,4;, 3;4,4,4;, 3 ;5, 5 ,5; , 3 ;5, 5 ,5; ; } MeshMaterialList... EffectInstance { STRING EffectFilename; [ .] } template EffectParamFloats { STRING ParamName; DWORD nFloats; array FLOAT Floats[nFloats]; } template EffectParamString { STRING ParamName; STRING Value; } template EffectParamDWord { STRING ParamName; DWORD... //cube->DrawSubset(0); //sphere->DrawSubset(0); //teapot->DrawSubset(0); //cylinder->DrawSubset(0); effect->End(); } } void game_ end() { if (font) delete font; if (effect) delete effect; if (camera) delete camera; torus->Release(); teapot->Release(); cube->Release(); sphere->Release(); cylinder->Release(); } void game_ update( float dltTime ) { deltaTime = dltTime; camera->Update(); } void game_ render2d() { std::ostringstream... Mesh::createSphere(double radius, int slices, int stacks) { D3DXCreateSphere(g _engine- >getDevice(), (float)radius, slices, stacks, &mesh, NULL); } void Mesh::createCube(double width, double height, double depth) { D3DXCreateBox(g _engine- >getDevice(), (float)width, (float)height, (float)depth, &mesh, NULL); } void Mesh::createTeapot() { D3DXCreateTeapot(g _engine- >getDevice(), &mesh, NULL); } void Mesh::splitPath(string&... -Loading and Rendering Mesh http://www.simpopdf.com 255 void Mesh::createTorus(float innerRadius, float outerRadius, int sides, int rings) { D3DXCreateTorus(g _engine- >getDevice(), innerRadius, outerRadius, sides, rings, &mesh, NULL); } void Mesh::createCylinder(float radius1, float radius2, float length, int slices, int stacks) { D3DXCreateCylinder(g _engine- >getDevice(), radius1, radius2, length, slices, . false; } matWorld.setIdentity(); lightColor.Set(0, 255 ,0, 255 ); //create stock meshes D3DXCreateTorus(g _engine- >getDevice(), 0.3f, 1.0f, 80, 80, &torus, 0); D3DXCreateTeapot(g _engine- >getDevice(), &teapot, 0); D3DXCreateSphere(g _engine- >getDevice(),. *this; } /** Convert 0- 255 color values to 0.0-1.0 range **/ void Color::Set(int R,int G,int B,int A) { r = (float)R/ 256 .f; g = (float)G/ 256 .f; b = (float)B/ 256 .f; a = (float)A/ 256 .f; } void Color::Set(float. meshes D3DXCreateTorus(g _engine- >getDevice(), 2.0f, 4.0f, 20, 20, &torus, NULL); D3DXCreateTeapot(g _engine- >getDevice(), &teapot, NULL); D3DXCreateSphere(g _engine- >getDevice(),