这一节在渲染中加入了光照影响。由于引入了光照,所以所以框架会继续扩展,要加入一个光照类。目前的框架大概可以粗略画成这样:
另外光照的渲染与多边形以及顶点的法线方向关系密切,所以顶点格式也要发生变化:添加一个法线向量。这样调用shader的类中顶点layout、模型类中顶点各成员的赋值也要随之修改。
加入光照后的shader:
加入光照后,shader中的顶点结构改变,增加了法向量,vertex shader和pixel shader的代码都要发生变化,此外光的属性(方向、颜色)是在LightClass对象中设定的,在shader渲染的时候需要知道这两个属性,所以要在shader中添加两个对应的全局变量,technique保持不变:
// Filename: light.fx
/
// GLOBALS //
/
matrix worldMatrix;
matrix viewMatrix;
matrix projectionMatrix;
Texture2D shaderTexture;
float4 diffuseColor;
float3 lightDirection;
///
// SAMPLE STATES //
///
SamplerState SampleType
{
Filter = MIN_MAG_MIP_LINEAR;
AddressU = Wrap;
AddressV = Wrap;
};
//
// TYPEDEFS //
//
struct VertexInputType
{
float4 position : POSITION;
float2 tex : TEXCOORD0;
float3 normal : NORMAL;
};
struct PixelInputType
{
float4 position : SV_POSITION;
float2 tex : TEXCOORD0;
float3 normal : NORMAL;
};
// Vertex Shader
PixelInputType LightVertexShader(VertexInputType input)
{
PixelInputType output;
// Change the position vector to be 4 units for proper matrix calculations.
input.position.w = 1.0f;
// Calculate the position of the vertex against the world, view, and projection matrices.
output.position = mul(input.position, worldMatrix);
output.position = mul(output.position, viewMatrix);
output.position = mul(output.position, projectionMatrix);
// Store the texture coordinates for the pixel shader.
output.tex = input.tex;
// Calculate the normal vector against the world matrix only.
output.normal = mul(input.normal, (float3x3)worldMatrix);
// Normalize the normal vector.
output.normal = normalize(output.normal);
return output;
}
// Pixel Shader
float4 LightPixelShader(PixelInputType input) : SV_Target
{
float4 textureColor;
float3 lightDir;
float lightIntensity;
float4 color;
// Sample the pixel color from the texture using the sampler at this texture coordinate location.
textureColor = shaderTexture.Sample(SampleType, input.tex);
// Invert the light direction for calculations.
lightDir = -lightDirection;
// Calculate the amount of light on this pixel.
lightIntensity = saturate(dot(input.normal, lightDir));
// Determine the final amount of diffuse color based on the diffuse color combined with the light intensity.
color = saturate(diffuseColor * lightIntensity);
// Multiply the texture pixel and the final diffuse color to get the final pixel color result.
color = color * textureColor;
return color;
}
负责加载shader的LightShaderClass:
调用shader的类(上一篇笔记中的TextureShaderClass)没有发生太多变化,由于shader中增加了描述光照的两个全局变量,所以在该类中需要添加两个指针成员,用来指向那两个成员变量:
ID3D10EffectVectorVariable* m_lightDirectionPtr;
ID3D10EffectVectorVariable* m_diffuseColorPtr;
由于顶点格式发生了变化(增加了法向量),所以在该类的初始化函数中,需要对layout进行相应的调整:
polygonLayout[2].SemanticName = "NORMAL";
polygonLayout[2].SemanticIndex = 0;
polygonLayout[2].Format = DXGI_FORMAT_R32G32B32_FLOAT;
polygonLayout[2].InputSlot = 0;
polygonLayout[2].AlignedByteOffset = D3D10_APPEND_ALIGNED_ELEMENT;
polygonLayout[2].InputSlotClass = D3D10_INPUT_PER_VERTEX_DATA;
polygonLayout[2].InstanceDataStepRate = 0;
此外在初始化的时候还需要获得shader中分别代表光的颜色和方向的全局变量的指针:
m_lightDirectionPtr = m_effect->GetVariableByName("lightDirection")->AsVector();
m_diffuseColorPtr = m_effect->GetVariableByName("diffuseColor")->AsVector();
同样,SetShaderParameters函数也要考虑这两个新加入的变量,该函数又增加了两个参数,以及相应的set代码:
void LightShaderClass::SetShaderParameters(D3DXMATRIX worldMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix,
ID3D10ShaderResourceView* texture, D3DXVECTOR3 lightDirection, D3DXVECTOR4 diffuseColor)
{
// Set the world matrix variable inside the shader.
m_worldMatrixPtr->SetMatrix((float*)&worldMatrix);
// Set the view matrix variable inside the shader.
m_viewMatrixPtr->SetMatrix((float*)&viewMatrix);
// Set the projection matrix variable inside the shader.
m_projectionMatrixPtr->SetMatrix((float*)&projectionMatrix);
// Bind the texture.
m_texturePtr->SetResource(texture);
// Set the direction of the light inside the shader.
m_lightDirectionPtr->SetFloatVector((float*)&lightDirection);
// Set the diffuse color of the light inside the shader.
m_diffuseColorPtr->SetFloatVector((float*)&diffuseColor);
return;
}
ModelClass的变化:
顶点格式:
struct VertexType
{
D3DXVECTOR3 position;
D3DXVECTOR2 texture;
D3DXVECTOR3 normal;
};
设置vertex array现在也要考虑到法向量:
// Load the vertex array with data.
vertices[0].position = D3DXVECTOR3(-1.0f, -1.0f, 0.0f); // Bottom left.
vertices[0].texture = D3DXVECTOR2(0.0f, 1.0f);
vertices[0].normal = D3DXVECTOR3(0.0f, 0.0f, -1.0f);
vertices[1].position = D3DXVECTOR3(0.0f, 1.0f, 0.0f); // Top middle.
vertices[1].texture = D3DXVECTOR2(0.5f, 0.0f);
vertices[1].normal = D3DXVECTOR3(0.0f, 0.0f, -1.0f);
vertices[2].position = D3DXVECTOR3(1.0f, -1.0f, 0.0f); // Bottom right.
vertices[2].texture = D3DXVECTOR2(1.0f, 1.0f);
vertices[2].normal = D3DXVECTOR3(0.0f, 0.0f, -1.0f);
新增加的光照类:
目前只考虑光照的颜色和方向,所以这个类比较简单:
// Filename: lightclass.h
#ifndef _LIGHTCLASS_H_
#define _LIGHTCLASS_H_
//
// INCLUDES //
//
#include
// Class name: LightClass
class LightClass
{
public:
LightClass();
LightClass(const LightClass&);
~LightClass();
void SetDiffuseColor(float, float, float, float);
void SetDirection(float, float, float);
D3DXVECTOR4 GetDiffuseColor();
D3DXVECTOR3 GetDirection();
private:
D3DXVECTOR4 m_diffuseColor;
D3DXVECTOR3 m_direction;
};
#endif
// Filename: lightclass.cpp
#include "lightclass.h"
LightClass::LightClass()
{
}
LightClass::LightClass(const LightClass& other)
{
}
LightClass::~LightClass()
{
}
void LightClass::SetDiffuseColor(float red, float green, float blue, float alpha)
{
m_diffuseColor = D3DXVECTOR4(red, green, blue, alpha);
return;
}
void LightClass::SetDirection(float x, float y, float z)
{
m_direction = D3DXVECTOR3(x, y, z);
return;
}
D3DXVECTOR4 LightClass::GetDiffuseColor()
{
return m_diffuseColor;
}
D3DXVECTOR3 LightClass::GetDirection()
{
return m_direction;
}
视图类的变化:
在视图类中添加了LightClass指针成员,用于设置光照:
LightClass* m_Light;
在InitializeShader中创建光照对象,并设置颜色和照明方向:
// Create the light object.
m_Light = new LightClass;
if(!m_Light)
{
return false;
}
// Initialize the light object.
m_Light->SetDiffuseColor(1.0f, 0.0f, 1.0f, 1.0f);
m_Light->SetDirection(0.0f, 0.0f, 1.0f);
最后,OnPaint函数中调用LightShaderClass的Render函数进行绘制:
m_LightShader->Render(m_device, pmesh->GetIndexCount(), worldMatrix, viewMatrix, projectionMatrix, pmesh->GetTexture(),
m_Light->GetDirection(), m_Light->GetDiffuseColor());