1. Trang chủ
  2. » Công Nghệ Thông Tin

Multi-Threaded Game Engine Design phần 6 pptx

60 271 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 60
Dung lượng 1,57 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

The following topics are covered in this chapter: n Textured point light shader n Textured spotlight shader n Specular reflection shader n Textured specular reflection shader Textured Po

Trang 1

if (font) delete font;

if (effect) delete effect;

if (camera) delete camera;

if (mesh) delete mesh;

//load the ambient.fx effect

effect = new Effect();

if (!effect->Load("directional_textured.fx"))

{

debug "Error loading effect file\n";

Trang 2

effect->setViewMatrix( camera->getViewMatrix(), "View");

effect->setProjectionMatrix( camera->getProjMatrix(), "Projection");

effect->setWorldMatrix( (D3DXMATRIX) mesh->getMatrix(), "World");

//mesh->Render( effect, "Texture" );

//calculate combined inverse transpose matrix

D3DXMATRIX inverse, wit;

D3DXMatrixInverse( &inverse, 0, (D3DXMATRIX*) &mesh->getMatrix() );

D3DXMatrixTranspose( &wit, &inverse );

effect->setParam( "WorldInverseTranspose", wit );

//move the light source

Trang 3

//set the light color

out "Delta time = "  deltaTime  endl;

out "Update = "  g_engine->getCoreFrameRate()  " fps\n";

out "Draw = "  g_engine->getScreenFrameRate()  " fps\n";

out "Light pos = "  lightVector.x  ","  lightVector.y  ","

 lightVector.z  endl;

out "Light angle = "  lightAngle  endl;

out "Light RGBA = "  lightColor.r  ","  lightColor.g  ","

 lightColor.b  ","  lightColor.a  endl;

out "Light intensity = "  lightPower  endl;

font->Print(0,0,out.str());

Trang 4

int w = g_engine->getScreenWidth();

font->Print(w-200,0,"left/right : light angle");

font->Print(w-200,20,"up/down : mesh angle");

font->Print(w-200,40,"+/- : light intensity");

font->Print(w-200,60,"rgba : cycle color values");

case DIK_ESCAPE: g_engine->Shutdown(); break;

//left/right arrow keys rotate light sourcecase DIK_LEFT: lightAngle -= 0.1f; break;

case DIK_RIGHT: lightAngle += 0.1f; break;

//up/down arrow keys rotate the meshcase DIK_UP: objectAngle -= 0.02f; break;

case DIK_DOWN: objectAngle += 0.02f; break;

//+/- keys change light powercase DIK_NUMPADPLUS: lightPower += 0.01f; break;

case DIK_NUMPADMINUS: lightPower -= 0.01f; break;

//rgba keys cycle color valuescase DIK_R: lightColor.r += 0.01f; break;

case DIK_G: lightColor.g += 0.01f; break;

case DIK_B: lightColor.b += 0.01f; break;

case DIK_A: lightColor.a += 0.01f; break;

}

break;

}

Trang 5

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;

}}

}

Summary

We now have the ability to load and render a simple mesh with several types of lighting, which is a good addition to our engine’s rendering system that was started in the previous chapter (with materials-based effects) The next chapter goes into more detail by describing how to render with point lights and spot- lights, which are quite a bit more difficult than a directional light, but extremely important for any renderer! Following that, we have two more chapters on rendering to address terrain and hierarchical (i.e., “skeleton”) mesh animation.

Trang 6

Advanced Lighting

Effects

This chapter continues the study of shader-based lighting with some new, advanced lighting effects such as point lights, spotlights, and specular reflection, which dramatically improves the appearance and realism of a mesh.

The following topics are covered in this chapter:

n Textured point light shader

n Textured spotlight shader

n Specular reflection shader

n Textured specular reflection shader

Textured Point Light Shader

When transitioning from a somewhat mundane (and common) directional light

to a more exotic light source such as a point light, a shift to per-pixel lighting is essential in order for the light source to illuminate a mesh properly Since the lighting can be subtle, the next two examples will use a white background so that the lighting on the mesh can be seen on the printed page The point light source shader will take a few steps beyond the directional light shader, adding light properties that will be used more commonly, such as the ambient lighting level,

as well as specular (reflectivity).

chapter 10

285

Trang 7

Point Lights

A point light is a single light source that emits in all directions like a light bulb You set the position, color, and attenuation, which is the amount of a decrease in light over distance The range is the maximum distance that the light will illuminate your 3D objects Positioning the light source (as a vector), setting its light range, and setting its light strength or power is all there is to a point light—

it will light up every mesh within range.

A d v i c e

This chapter’s resource files can be downloaded from www.jharbour.com/forum or www.courseptr.com/downloads Please note that not every line of code will be in print due to space considerations:only the most important sections of code are covered in each chapter

We begin with the global variable definitions in the effect file The usual

float4x4 matrices are found here: World, View, Projection, and Transpose, as well as the usualTexturevariable For the specific variables needed for the point light, we have float3 LightPositionand float LightRadius Those are the most important variables in the point light shader The remaining ones will differ based on the type of rendering desired In the case of our example here, we’ll be rendering with specular highlights added to the diffuse and ambient values.

Trang 8

float4 SpecularMaterial;

float4 SpecularLight;

float MaterialSheen;

The texture sampler now has some additional quality-setting properties, which

are part of the HLSL sampler feature set, and include the magfilter, minfilter,

and mipfilter—all of which define how anti-aliasing of lines is performed—as

well as texture coordinate options.

Our shader calculates quite a few variables internally, so there will be more

properties in the output struct than the input struct —which needs to supply

only the position, surface normal, and texture coordinate Output adds diffuse

and specular light levels, view direction (which determines the specular highlight

angle), and source light direction.

struct VS_INPUT

{

float3 Position : POSITION0;

float3 Normal : NORMAL;

float2 TexCoord : TEXCOORD0;

};

struct VS_OUTPUT

{

float4 Position : POSITION0;

float2 TexCoord : TEXCOORD0;

float3 Normal : TEXCOORD2;

float3 ViewDir : TEXCOORD3;

float3 LightDirection : TEXCOORD4;

Trang 9

float4 Diffuse : COLOR0;

float4 Specular : COLOR1;

VS_OUTPUT vertexShader(VS_INPUT IN)

{

VS_OUTPUT OUT;

float4x4 worldViewProjection = mul(mul(World, View), Projection);

float3 WorldPosition = mul(float4(IN.Position, 1.0f), World).xyz;

OUT.Position = mul(float4(IN.Position, 1.0f), worldViewProjection);

OUT.TexCoord = IN.TexCoord;

OUT.ViewDir = LightPosition - WorldPosition;

OUT.LightDirection = (LightPosition - WorldPosition) / LightRadius;

OUT.Normal = mul(IN.Normal, (float3x3)WorldInverseTranspose);

OUT.Diffuse = DiffuseMaterial * DiffuseLight;

OUT.Specular = SpecularMaterial * SpecularLight;

return OUT;

}

The pixel shader function is up next We have quite a bit more code in the pixel shader this time around because we want a smooth transition from the center of the specular highlight to its outer edges, while the vertex shader produces only face-level lighting without smooth gradients The pixel shader function accepts the output struct from the vertex shader and calculates normals —for the vertex, light direction, view direction, and combined result Next, dot product is used to produce that gradient blend around the specular highlight to produce a high- quality light reflection based on the light position and view direction (which comes from the camera) Finally, each pixel is lit using the Phong method by adding the ambient, light attenuation, and specular values to arrive at a final color value This is passed to the part of the GPU that draws pixels.

float4 pixelShader(VS_OUTPUT IN) : COLOR

{

Trang 10

float Attenuation = saturate(1.0f

-dot(IN.LightDirection, IN.LightDirection));

//Finds normals of the vertex normal, light direction,

//view direction, and combined light and view direction

float3 N = normalize(IN.Normal);

float3 L = normalize(IN.LightDirection);

float3 V = normalize(IN.ViewDir);

float3 H = normalize(L + V);

//find saturated dot product of the light direction

//normal and the combined light and view direction normal

float NDotL = saturate(dot(N, L));

float NDotH = saturate(dot(N, H));

//find the gloss factor of the specular property

float Power = (NDotL == 0.0f) ? 0.0f : pow(NDotH, MaterialSheen);

//calculates the color and amount of the vertexes pixels

//lighting by using a modified Phong method

float4 color = (AmbientMaterial * (GlobalAmbient +

(Attenuation * AmbientLightColor))) +

(IN.Diffuse * NDotL * Attenuation) +

(IN.Specular * Power * Attenuation);

//Returns pixel color modified by lighting color and amount

return color * tex2D(TextureSampler, IN.TexCoord);

VertexShader = compile vs_2_0 vertexShader();

PixelShader = compile ps_2_0 pixelShader();

}

}

Textured Point Light Shader Demo

The Textured Point Light Shader Demo has quite a few more new parameters to

contend with than any previous program, but the end result is a much higher

Trang 11

quality render Figure 10.1 shows the output from the program Use the left and right arrow keys to rotate the light source around the barrel mesh to see how the dynamic lighting looks!

Trang 12

Effect* effect=NULL;

Vector3 lightVector;

Color globalAmbient = Color(0.1f,0.1f,0.1f,1.0f);

Color ambientMaterial = Color(0.1f,0.1f,0.1f,1.0f);

Color ambientLightColor = Color(1.0f,1.0f,1.0f,1.0f);

Color diffuseMaterial = Color(1.0f,1.0f,1.0f,1.0f);

Color diffuseLight = Color(1.0f,1.0f,1.0f,1.0f);

Color specularMaterial = Color(0.1f,0.1f,0.1f,1.0f);

Color specularLight = Color(1,1,1,1);

D3DCOLOR BLACK = D3DCOLOR_XRGB(0,0,0);

//load the ambient.fx effect

effect = new Effect();

Trang 13

//load the mesh

barrel = new Mesh();

effect->setWorldMatrix( (D3DXMATRIX) barrel->getMatrix());

//calculate combined inverse transpose matrixD3DXMATRIX inverse, wit;

D3DXMatrixInverse( &inverse, 0, (D3DXMATRIX*)&barrel->getMatrix() );D3DXMatrixTranspose( &wit, &inverse );

effect->setParam( "WorldInverseTranspose", wit );

//move the light sourcelightVector.x = cosf(lightAngle) * 100.0f;

Trang 14

if (font) delete font;

if (effect) delete effect;

if (camera) delete camera;

if (barrel) delete barrel;

out "Delta time = "  deltaTime  endl;

out "Update = "  g_engine->getCoreFrameRate()  " fps\n";

out "Draw = "  g_engine->getScreenFrameRate()  " fps\n";

out "Light pos = "  lightVector.x  ","  lightVector.y

 ","  lightVector.z  endl;

out "Light angle = "  lightAngle  endl;

font->Print(0,0,out.str(),BLACK);

Trang 15

int w = g_engine->getScreenWidth();

font->Print(w-200,0,"left/right : light angle",BLACK);

font->Print(w-200,20,"up/down : mesh angle",BLACK);

switch(evt->keycode){

case DIK_ESCAPE: g_engine->Shutdown(); break;

//left/right arrow keys rotate light sourcecase DIK_LEFT: lightAngle -= 0.1f; break;

case DIK_RIGHT: lightAngle += 0.1f; break;

//up/down arrow keys rotate the meshcase DIK_UP: objectAngle -= 1.0f; break;

case DIK_DOWN: objectAngle += 1.0f; break;

}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;

}

Trang 16

Specular Reflection Shader

We have been using a specular effect in the last two examples to improve the

appearance of the point light and spotlight, but with all of the other types of

lighting also being used in those examples, it’s not clear what exactly the

specular effect adds to the render on its own, so we’ll go over specular reflection

now with a pair of smaller demos The first one renders a high-poly asteroid

mesh without its texture, since the firstspecular.fxfile ignores the texture map,

resulting in a chrome-like effect The second example renders the same mesh

with its texture for a brightly polished look that is quite remarkable Figure 10.2

shows the first example that renders a material-only mesh.

Figure 10.2

This mesh is being rendered with a specular shader that gives it a reflective quality

Trang 17

There are so few parameters needed this time, illustrating the value of setting initial values for the global properties in an effect file, since that allows the effect

to function with minimal input from the C þþ side (in the event that you forget

to pass a particular parameter) The specular reflection shader uses a dot product calculation to create a reflective highlight based on the light source and the view position.

Some of the globals in the effect file will be familiar to you by now, such as the usual world, view, projection, world inverse transform, ambient, and so on Where the specular effect comes in is with the shininess, specular color, and specular intensity properties I encourage you to tweak these values to see what interesting changes you can create in the rendered mesh The shininess property, for instance:

float3 DiffuseLightDirection = float3(0, 0, 1);

float4 DiffuseColor = float4(1, 1, 1, 1);

float4 Position : POSITION0;

float4 Normal : NORMAL0;

Trang 18

float4 Color : COLOR0;

float3 Normal : TEXCOORD0;

};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)

{

VertexShaderOutput output;

float4 worldPosition = mul(input.Position, World);

float4 viewPosition = mul(worldPosition, View);

output.Position = mul(viewPosition, Projection);

float4 normal = normalize(mul(input.Normal, WorldInverseTranspose));

float lightIntensity = dot(normal, DiffuseLightDirection);

output.Color = saturate(DiffuseColor * DiffuseIntensity *

float3 light = normalize(DiffuseLightDirection);

float3 normal = normalize(input.Normal);

float3 r = normalize(2 * dot(light, normal) * normal - light);

float3 v = normalize(mul(normalize(ViewVector), World));

float dotProduct = abs(dot(r, v));

float4 specular = SpecularIntensity * SpecularColor

* max(pow(dotProduct, Shininess), 0) * length(input.Color);

return saturate(input.Color + AmbientColor *

Trang 19

VertexShader = compile vs_2_0 VertexShaderFunction();

PixelShader = compile ps_2_0 PixelShaderFunction();

}

}

Specular Light Demo

The source code for this program is similar to the previous program but with the addition of the texture property, which is now actually used by the effect.

//set the camera and perspective

camera = new Camera();

camera->setPosition(0.0f, 3.0f, 6.0f);

camera->setTarget(0.0f, 0.0f, 0.0f);

camera->Update();

//create effect object

effect = new Effect();

if (!effect->Load("specular.fx"))

{

Trang 20

debug "Error loading effect\n";

return false;

}

//load the mesh

mesh = new Mesh();

D3DXMatrixInverse( &wit, 0, &mesh->getMatrix() );

D3DXMatrixTranspose( &wit, &wit );

effect->setParam( "WorldInverseTranspose", wit );

if (camera) delete camera;

if (mesh) delete mesh;

Trang 21

if (effect) delete effect;

switch(evt->keycode){

case DIK_ESCAPE: g_engine->Shutdown(); break;

}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;

}}}

Textured Specular Reflection

Now, comparing the material-based specular shader with the textured version (see below), we can see that very little change is needed: just the addition of the texture sampler, one new property in the input and output structs Figure 10.3

Trang 22

shows the textured version The source code for the textured specular demo is

unchanged from the non-textured version, so we ’ll forego a duplication of the

code here and just present the textured specular reflection shader.

Trang 23

float4 DiffuseColor = float4(1, 1, 1, 1);

float4 Position : POSITION0;

float4 Normal : NORMAL0;

float2 TextureCoordinate : TEXCOORD0;

};

struct VertexShaderOutput

{

float4 Position : POSITION0;

float4 Color : COLOR0;

float3 Normal : TEXCOORD0;

float2 TextureCoordinate : TEXCOORD1;

};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)

{

VertexShaderOutput output;

float4 worldPosition = mul(input.Position, World);

float4 viewPosition = mul(worldPosition, View);

output.Position = mul(viewPosition, Projection);

float4 normal = normalize(mul(input.Normal, WorldInverseTranspose));

Trang 24

float lightIntensity = dot(normal, DiffuseLightDirection);

output.Color = saturate(DiffuseColor * DiffuseIntensity * lightIntensity);

float3 light = normalize(DiffuseLightDirection);

float3 normal = normalize(input.Normal);

float3 r = normalize(2 * dot(light, normal) * normal - light);

float3 v = normalize(mul(normalize(ViewVector), World));

float dotProduct = abs(dot(r, v));

float4 specular = max(pow(dotProduct, Shininess), 0) *

length(input.Color) * SpecularIntensity * SpecularColor;

float4 textureColor = tex2D(textureSampler, input.TextureCoordinate);

textureColor.a = 1;

return saturate(textureColor * (input.Color) +

AmbientColor * AmbientIntensity + specular);

VertexShader = compile vs_2_0 VertexShaderFunction();

PixelShader = compile ps_2_0 PixelShaderFunction();

}

}

Summary

Lighting is a monumental challenge when we ’re considering the features for a

game engine ’s rendering system, as you have seen in the pages of this chapter!

While the concepts behind lighting are not complex, implementing a directional

Trang 25

light, spotlight, and point light in GPU code can be complicated What often surprises many engine or renderer programmers is how unique (and uniquely demanding) each game ’s shader requirements are While there are some concepts that do see re-use, such as the usual diffuse/directional light shader, most techniques will change to meet the needs of each scene in a game, because

an innovative designer does not want his or her game to look like all the rest, and everyone knows that whiz-bang glowing fireballs alone do not sell! (On the contrary, such is now assumed as a baseline.)

Trang 26

Wrapping the Sky in a Box

The environment of a game can vary widely from one game genre to the next, from

an outer space environment (like in the phenomenally uber-classic Homeworld), which is usually just a large sky sphere with a space scene texture and various asteroids and planets in the vicinity, to the typical outdoor game world comprised

of heightmap terrain (like the world in World of Warcraft), to a common indoor theme for first-person shooters (like Doom III) In this chapter, we will see how to create a skybox and how to apply it to an outer space scene, while relegating the indoor and outdoor environment demos for upcoming chapters.

This chapter covers the following topics:

n Skybox or skysphere?

n Creating a custom skybox

n Skybox class

n Skybox shader

n Mountain skybox demo

n Space skybox demo

Building a Skybox

The first step toward creating an environment that grabs the player with a strong suspension of disbelief (where one forgets he or she is actually playing a game and becomes engrossed in the story, much like the experience while reading a

chapter 11

305

Trang 27

great novel) is to add a skybox A skybox is a cube mesh (or a sphere in the case

of a sky sphere) that surrounds the camera at all times But, rather than rendering a skybox within the scene, it wraps around the entire scene Therefore, the surface normals for a skybox must be directed inward from the inside of the cube, rather than pointing outward on the outer faces of the cube as is normally done to light a normal mesh A skybox moves with the camera to create the illusion of distance This is crucial! To fool the player ’s eyes into believing they are really in a larger environment surrounded by stars, or mountains (as are typical for most games), the skybox must move with the camera, giving the impression that it does not move at all.

Skybox or Skysphere?

A d v i c e

Although it may seem that a sphere map would produce better results due to its higher number offaces, a cube map is actually preferred because it works better with lower-resolution textures andrenders a higher quality surface when using algorithmically generated textures

The preferred way to professionally render a skybox or skysphere is with a cube texture, a self-contained texture file that must be generated with a custom tool such as the DirectX Texture Tool (look in the DirectX SDK in your Start Menu) This is one of the least user-friendly utilities ever created, so don ’t expect to get much practical use out of it Think of a cube texture as a paper cube with the sides unfolded to make a cross shape, like the one in Figure 11.1.

The reason why I dislike the cube texture approach to rendering a skybox is because I have no control over the cube texture (or at least not without much effort), while a simpler mesh of a cube with six texture files is more easily modifiable, giving us more control over exactly which mesh is being rendered on which side After loading the mesh and the six textures, we can also modify each individual texture in memory if needed—or replace the textures on the fly One nice effect is to adjust the ambient light intensity when rendering the skybox to reflect daytime or nighttime in the scene.

One thing to note about a skybox: it will never encompass the entire scene That ’s right; the skybox does not need to be larger than all of the geometry in the scene! But, won ’t the geometry intersect with the skybox unless it is really large?

Trang 28

Yes, quite simply The trick is not to make the skybox really huge, but instead to

screw with the Z-buffer Strangely enough, we can just turn off the Z-buffer for

the skybox and turn it back on for everything else Therefore, even if you have a

scene that stretches from virtual horizon to virtual horizon, encompassing

thousands of units in 3D space, while the skybox is only 10  10  10 units, it

will still appear to be a vast distance away.

A d v i c e

Due to the advanced render states needed to render a skybox or skysphere with a shader, our

skybox will render around the origin with only trivial geometry in the scene The skybox developed

in this chapter can be transformed to move with the camera When rendering a small skybox

“around” a normal scene in a game, be sure to disable z-buffering before rendering the skybox,

and then re-enable z-buffering again afterward

Another way to create a skybox is with a mesh already modeled with the

normals correctly set on the inside of the faces and the texture filenames

specified inside the X file This is certainly the easiest type of skybox to create —

just load the mesh, increase its scale, and render with any fixed function or

Figure 11.1

A cube texture is a single texture that wraps a cube with a different image on each of the six sides

Trang 29

programmable pipeline code Figure 11.2 shows a sample skybox mesh rendered

by the DirectX Viewer.

There is a third approach to creating a skybox: generating our own vertex buffer for a cube mesh and applying textures manually This is the most educational way to create a skybox, but certainly not the easiest or even necessarily the best method Doing something from scratch does afford a learning experience, but often at the expense of performance and quality In this case, there’s no harm in generating your own vertex buffer for a skybox.

Creating a Custom Skybox

Skybox meshes are fairly easy to come by, and that is the approach you may want to take with your own engine —by just loading a mesh with the internal normals and textures already built in However, we don ’t want to rely entirely on someone else ’s skybox mesh, so we’ll also see how to create a skybox vertex buffer with texture coordinates in the FVF so we can generate a mesh with

Figure 11.2

Note how the inverse normals cause the faces to reflect light frominsidethe skybox

Trang 30

desired dimensions as needed Why? Because I just like to torture myself with

more work than is actually necessary, with the goal of achieving awesomeness.

(Oh, gee, I made a cube!)

Our generated cube mesh will have four vertices per side, arranged as shown in

Figure 11.3 We will need six sides for the cube, each comprised of four vertices

containing position and texture coordinate values The upper-left corner of a

side will have a UV texture coordinate of (0,0), while the lower-right corner will

have a UV of (1,1), as shown in Figure 11.4.

A d v i c e

This chapter’s resource files can be downloaded from www.jharbour.com/forum or www.courseptr

com/downloads Please note that not every line of code will be in print due to space considerations:

only the most important sections of code are covered in each chapter

Figure 11.3

Each side of the skybox cube is made of a quad with two faces and four vertices in this

counter-clockwise order

Ngày đăng: 13/08/2014, 22:21

TỪ KHÓA LIÊN QUAN