Direct3D lighting

composition of light

Ambient light: This type of light reaches the surface of the object after being reflected from other surfaces and illuminates the entire scene. If you want to roughly simulate this type of reflected light at a low cost, ambient light is a good choice.

Diffuse light: This type of light travels in a specific direction. When it reaches a certain surface, it will be reflected uniformly in all directions. No matter which direction it is viewed from, the surface brightness will be the same. Therefore, there is no need to consider the position of the observer when using this model. In this way, only light propagation needs to be considered in the diffuse light equation. The direction and surface orientation of the light emitted from a light source are generally of this type.

Specular light: This type of light travels in a specific direction. When such light reaches a surface, it will be reflected strictly in another direction, resulting in a high-brightness illumination that can only be observed within a certain angle range, so In the specular illumination equation, not only the incident direction of the light and the surface orientation of the primitive need to be considered, but also the position of the observation point needs to be considered. Specular lights can be used to simulate highlights on an object, such as those caused when light hits a polished surface.

Specular light requires more calculations than other types of light, so Direct3D provides a switch option. By default, Direct does not perform specular reflection calculations. If you want to enable specular light, you must call the interface to set it.

Device->SetRenderState(D3DRS_SPECULARENABLE, true);

Each type of light can be represented by the structure D3DCOLORVALUE or D3DXCOLOR. When describing the color of the light, the Alpha value in the D3DXCOLOR class will be ignored.

D3DXCOLOR redAmbient(1.0f, 0.0f, 0.0f, 1.0f);
D3DXCOLOR blueDiffuse(0.0f, 0.0f, 1.0f, 1.0f);
D3DXCOLOR whiteSpecular(1.0f, 1.0f, 1.0f, 1.0f);

Material

In the real world, the color of an object we observe is determined by the color of the light reflected by the object. For example, a pure red sphere reflects all red incident light and absorbs all non-red light, so it appears is red. When an object absorbs all light, it appears black. If an object can reflect 100% of red, green, and blue light, it will appear white. Direct3D simulates the same phenomenon by defining the material of the object. The material allows us to define the reflection ratio of various colors of light on the surface of the object . The material is represented by the structure D3DMATERIAL9.

typedef struct D3DMATERIAL9 {
    D3DCOLORVALUE   Diffuse;  
    D3DCOLORVALUE   Ambient;  
    D3DCOLORVALUE   Specular; 
    D3DCOLORVALUE   Emissive; 
    float           Power;    
} D3DMATERIAL9;

Diffuse : Specify the reflectivity of the material to diffuse light.
Ambient : Specify the reflectivity of the material to ambient light.
Specular : Specify the reflectivity of the material to specular light.
Emissive : This component is used to enhance the brightness of the object, making it look like it can emit light by itself.
Power : Specifies the sharpness of the specular highlight point. The larger the value, the greater the sharpness of the highlight point.

//只反射红色光
D3DMATERIAL9 red;
::ZeroMemory(&red, sizeof(red));
red.Diffuse = D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f);
red.Ambient= D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f);
red.Specular = D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f);
red.Emissive = D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f);
red.Power = 5.0f;

Set the material interface SetMaterial

D3DMATERIAL9 blueMaterial;
Device->SetMaterial(&blueMaterial);
//draw...

vertex normal

The vertex normal describes the normal of each vertex that makes up the polygon. Direct3D needs to know the normal direction of the vertex to determine the incident angle when the light reaches the surface. Since the lighting calculation is performed for each vertex, Direct3D needs to know the surface. The local orientation (normal direction) at each vertex. Describing a vertex normal requires modifying the vertex structure.

struct Vertex
{
	float _x, _y, _z;
	float _nx, _ny, _nz;
	static const DWORD FVF;
};
const DWORD Vertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL;

Calculating the normals of the three vertices of a triangle can be obtained by calculating the normal vector of the surface. First, calculate the two vectors located in the plane of the triangle.

void ComputeNormal(D3DXVECTOR3* p0, D3DXVECTOR3* p1, D3DXVECTOR3* p2, D3DXVECTOR3* out)
{
	D3DXVECTOR3 u = *p1 - *p0;
	D3DXVECTOR3 v = *p2 - *p0;
	D3DXVec3Cross(out, &u, &v);
	D3DXVec3Normalize(out, out);
}

When using triangular units to approximate a surface, using the patch normal vector as the vertex normal vector that constitutes the patch cannot produce a very smooth effect. A better way to find the vertex normal vector is to calculate the mean of the normal vectors. We You need to find the surface normal vectors of all triangles that share point v, then add these normal vectors and divide by the number to average.

During the transformation process, it is possible that the vertex normals are no longer canonical so the best way is to re-normalize by setting the draw state after the transformation is complete

Device->SetRenderState(D3DRS_NORMALIZENORMALS, true);

light source

Direct3D supports 3 types of light sources, namely point light source, directional light and spotlight.

Point light source : This light source has a fixed position in the world coordinate system and emits light in all directions (D3DLIGHT_POINT)
Directional light : This light source has no position information, and the emitted light rays propagate parallel to each other in a specific direction (D3DLIGHT_DIRECTIONAL)
Spotlight : This type of light source is similar to a flashlight. The light source has position information and the light it emits spreads in a cone shape along a specific direction (D3DLIGHT_SPOT)

typedef struct D3DLIGHT9 {
    D3DLIGHTTYPE    Type;        
    D3DCOLORVALUE   Diffuse;     
    D3DCOLORVALUE   Specular;    
    D3DCOLORVALUE   Ambient;     
    D3DVECTOR       Position;    
    D3DVECTOR       Direction;   
    float           Range;       
    float           Falloff;     
    float           Attenuation0;
    float           Attenuation1;
    float           Attenuation2;
    float           Theta;       
    float           Phi;         
} D3DLIGHT9;

Type : Define the type of light source created, which can take the following three enumeration values: D3DLIGHT_POINT , D3DLIGHT_SPOT , D3DLIGHT_DIRECTIONAL
Diffuse : The color of the diffuse light emitted by the light source
Specular : The color of the specular light emitted by the light source
Ambient : The color of the specular light emitted by the light source The color of ambient light.
Position : a vector used to describe the position of the light source in the world coordinate system. This parameter is meaningless for directional light.
Direction : a vector that describes the propagation direction of light in the world coordinate system. This parameter is meaningless for point light sources.
Range : The maximum optical path that the light can reach before "dying". The maximum value of this value is. \sqrt{FLT\_MAX}For directional light, this parameter is meaningless.
Falloff : This value is used for spotlights. This parameter defines the light intensity from the inner cone to the outer cone. The first version of this parameter is set to 1.0f. These attenuation variables
Attenuation0 , Attenuation1 , and Attenuation2 define the way the light intensity attenuates with distance. These variables are only used for point light sources and spotlights, and represent the constant, linear, and Quadratic distance attenuation coefficient, the attenuation formula is attenuation=\frac{1}{A_{0}+A_{1}\cdot D+A_{2}\cdot D^{2}}, where D is the distance from the light source to the vertex.
Theta : For spotlights only, specifies the cone angle of the inner cone in radians
Phi : For spotlights only, specifies the cone angle of the outer cone in radians

Similar to the initialization of the D3DMATERIAL9 structure, the initialization of the D3DLIGHT9 structure is also very cumbersome when a simple light source is required.

D3DLIGHT9 d3d::InitDirectionalLight(D3DXVECTOR3* direction, D3DXCOLOR* color)
{
	D3DLIGHT9 light;
	::ZeroMemory(&light, sizeof(light));
	light.Type = D3DLIGHT_DIRECTIONAL;
	light.Ambient = *color * 0.4f;
	light.Diffuse = *color;
	light.Specular = *color * 0.6f;
	light.Direction = *direction;
	return light;
}

D3DXVECTOR3 dir(1.0f, 0.0f, 0.0f);
D3DXCOLOR c = d3d::WHITE;
D3DLIGHT9 dirLight = d3d::InitDirectionalLight(&dir, &c);

After the D3DLIGHT9 instance is initialized, we need to register the light source to be used in an internal list of light sources maintained by Direct3D. After successful registration, we can control its on/off status.

Device->SetLight(0, &light);
Device->LightEnable(0, true);

Lighting routine

bool SetUpPyramid()
{
	//启用光照(默认是启用的)
	Device->SetRenderState(D3DRS_LIGHTING, true);

	Device->CreateVertexBuffer(12 * sizeof(PyramidVertex), D3DUSAGE_WRITEONLY, PyramidVertex::FVF, D3DPOOL_MANAGED, &Pyramid, 0);

	PyramidVertex* v;
	Pyramid->Lock(0, 0, (void**)&v, 0);

	v[0] = PyramidVertex(-1.0f, 0.0f, -1.0f, 0.0f, 0.707f, -0.707f);
	v[1] = PyramidVertex(0.0f, 1.0f, 0.0f, 0.0f, 0.707f, -0.707f);
	v[2] = PyramidVertex(1.0f, 0.0f, -1.0f, 0.0f, 0.707f, -0.707f);

	v[3] = PyramidVertex(-1.0f, 0.0f, 1.0f, -0.707f, 0.707f, 0.0f);
	v[4] = PyramidVertex(0.0f, 1.0f, 0.0f, -0.707f, 0.707f, 0.0f);
	v[5] = PyramidVertex(-1.0f, 0.0f, -1.0f, -0.707f, 0.707f, 0.0f);

	v[6] = PyramidVertex(1.0f, 0.0f, -1.0f, 0.707f, 0.707f, 0.0f);
	v[7] = PyramidVertex(0.0f, 1.0f, 0.0f, 0.707f, 0.707f, 0.0f);
	v[8] = PyramidVertex(1.0f, 0.0f, 1.0f, 0.707f, 0.707f, 0.0f);

	v[9] = PyramidVertex(1.0f, 0.0f, 1.0f, 0.0f, 0.707f, 0.707f);
	v[10] = PyramidVertex(0.0f, 1.0f, 0.0f, 0.0f, 0.707f, 0.707f);
	v[11] = PyramidVertex(-1.0f, 0.0f, 1.0f, 0.0f, 0.707f, 0.707f);
	Pyramid->Unlock();

	D3DMATERIAL9 mtrl;
	mtrl.Ambient = d3d::WHITE;
	mtrl.Diffuse = d3d::WHITE;
	mtrl.Specular= d3d::WHITE;
	mtrl.Emissive = d3d::BLACK;
	mtrl.Power = 5.0f;
	Device->SetMaterial(&mtrl);

	D3DLIGHT9 dir;
	::ZeroMemory(&dir, sizeof(dir));
	dir.Type = D3DLIGHT_DIRECTIONAL;
	dir.Diffuse = d3d::WHITE;
	dir.Specular = d3d::WHITE * 0.3f;
	dir.Ambient = d3d::WHITE * 0.6f;
	dir.Direction = D3DXVECTOR3(1.0f, 0.0f, 0.0f);
	Device->SetLight(0, &dir);
	Device->LightEnable(0, true);

	//规范化法向量
	Device->SetRenderState(D3DRS_NORMALIZENORMALS, true);
	//启用镜面高光
	Device->SetRenderState(D3DRS_SPECULARENABLE, true);

	//取景变换(观察者坐标系)
	D3DXVECTOR3 position(3.0f, 2.0f, -3.0f);
	D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
	D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
	D3DXMATRIX V;
	D3DXMatrixLookAtLH(&V, &position, &target, &up);
	Device->SetTransform(D3DTS_VIEW, &V);
	
	//投影变换
	D3DXMATRIX proj;
	D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI*0.5f, (float)Width / (float)Height, 1.0f, 1000.0f);
	Device->SetTransform(D3DTS_PROJECTION, &proj);
	return true;
}

Guess you like

Origin blog.csdn.net/SwordArcher/article/details/132720227