ФЭНДОМ


ВведениеПравить

В предыдущих уроках связанных с освещением, мы выводили только один источник света. В данном уроке мы сделаем 4 источника света.

Пишем кодПравить

main.cppПравить

#include "MyRender.h"

int main()
{
	Framework framework;

	MyRender *render = new MyRender();

	FrameworkDesc desc;
	desc.render = render;

	framework.Init(desc);
	framework.Run();
	framework.Close();
	
	return 0;
}

Light.hПравить

#pragma once

#include "D3D11_Framework.h"

using namespace D3D11Framework;

class Light
{
public:
	void SetDiffuseColor(float, float, float, float);
	void SetPosition(float, float, float);

	XMFLOAT4 GetDiffuseColor();
	XMFLOAT4 GetPosition();

private:
	XMFLOAT4 m_diffuseColor;
	XMFLOAT4 m_position;
};

Light.cppПравить

#include "Light.h"

void Light::SetDiffuseColor(float red, float green, float blue, float alpha)
{
	m_diffuseColor = XMFLOAT4(red, green, blue, alpha);
}

void Light::SetPosition(float x, float y, float z)
{
	m_position = XMFLOAT4(x, y, z, 1.0f);
}

XMFLOAT4 Light::GetDiffuseColor()
{
	return m_diffuseColor;
}

XMFLOAT4 Light::GetPosition()
{
	return m_position;
}

MyRender.hПравить

#pragma once

#include "D3D11_Framework.h"
#include "Light.h"
#include "PlaneModel.h"

using namespace D3D11Framework;

class MyRender : public Render
{
public:
	MyRender();
	bool Init();
	bool Draw();
	void Close();
	
private:
	friend PlaneModel;
	PlaneModel m_model;
	
	Camera m_cam;
	Light m_Light1, m_Light2, m_Light3, m_Light4;
};

MyRender.cppПравить

#include "MyRender.h"
#include "PlaneModel.h"

MyRender::MyRender()
{
}

bool MyRender::Init()
{
	// настраиваем камеру
	m_cam.SetPos(0.0f, 2.8f, -11.0f);

	// инициализируем модель
	m_model.Init(this);

	// настраиваем свет
	m_Light1.SetDiffuseColor(1.0f, 0.0f, 0.0f, 1.0f);
	m_Light1.SetPosition(-3.0f, 1.0f, 3.0f);

	m_Light2.SetDiffuseColor(0.0f, 1.0f, 0.0f, 1.0f);
	m_Light2.SetPosition(3.0f, 1.0f, 3.0f);

	m_Light3.SetDiffuseColor(0.0f, 0.0f, 1.0f, 1.0f);
	m_Light3.SetPosition(-3.0f, 1.0f, -3.0f);

	m_Light4.SetDiffuseColor(1.0f, 1.0f, 1.0f, 1.0f);
	m_Light4.SetPosition(3.0f, 1.0f, -3.0f);
	
	return true;
}

bool MyRender::Draw()
{		
	m_cam.Render();

	XMMATRIX camView = m_cam.GetViewMatrix();

	XMFLOAT4 diffuseColor[4];
	XMFLOAT4 lightPosition[4];
	diffuseColor[0] = m_Light1.GetDiffuseColor();
	diffuseColor[1] = m_Light2.GetDiffuseColor();
	diffuseColor[2] = m_Light3.GetDiffuseColor();
	diffuseColor[3] = m_Light4.GetDiffuseColor();
	lightPosition[0] = m_Light1.GetPosition();
	lightPosition[1] = m_Light2.GetPosition();
	lightPosition[2] = m_Light3.GetPosition();
	lightPosition[3] = m_Light4.GetPosition();
		
	m_model.Render(camView, m_Projection, diffuseColor, lightPosition);
	
	return true;
}

void MyRender::Close()
{
	m_model.Close();
}

PlaneModel.hПравить

#pragma once

#include "D3D11_Framework.h"
using namespace D3D11Framework;

class MyRender;

class PlaneModel
{
	struct ModelType
	{
		float x, y, z;
		float tu, tv;
		float nx, ny, nz;
	};
public:
	PlaneModel();

	bool Init(MyRender *render);
	void Close();
	void Render(CXMMATRIX view, CXMMATRIX proj, XMFLOAT4 diffuseColor[], XMFLOAT4 lightPosition[]);

private:
	MyRender *m_render;
	bool InitializeBuffers();	
	bool LoadModel(char*);

	ID3D11Buffer *m_vertexBuffer, *m_indexBuffer;
	int m_vertexCount, m_indexCount;	
	ModelType* m_model;
	
	ID3D11Buffer *m_constMatrixBuffer;
	ID3D11Buffer* m_lightColorBuffer;
	ID3D11Buffer* m_lightPositionBuffer;

	Shader *m_shader;
};

PlaneModel.cppПравить

#include "PlaneModel.h"
#include <fstream>
#include "MyRender.h"
using namespace std;

const int NUM_LIGHTS = 4;

struct VertexType
{
	XMFLOAT3 position;
	XMFLOAT2 texture;
	XMFLOAT3 normal;
};

struct MatrixBufferType
{
	XMMATRIX world;
	XMMATRIX view;
	XMMATRIX projection;
};

struct LightColorBufferType
{
	XMFLOAT4 diffuseColor[NUM_LIGHTS];
};

struct LightPositionBufferType
{
	XMFLOAT4 lightPosition[NUM_LIGHTS];
};

PlaneModel::PlaneModel()
{
	m_vertexBuffer = 0;
	m_indexBuffer = 0;
	m_model = 0;
}

bool PlaneModel::Init(MyRender *render)
{
	m_render = render;

	if(!LoadModel("plane01.txt"))
		return false;

	if(!InitializeBuffers())
		return false;

	// инициализируем шейдер и входной формат
	m_shader = new Shader(m_render);
	m_shader->AddInputElementDesc("POSITION", DXGI_FORMAT_R32G32B32_FLOAT);
	m_shader->AddInputElementDesc("TEXCOORD", DXGI_FORMAT_R32G32_FLOAT);
	m_shader->AddInputElementDesc("NORMAL", DXGI_FORMAT_R32G32B32_FLOAT);
	if ( !m_shader->CreateShader(L"shader.vs", L"shader.ps") )
		return false;
	if ( !m_shader->AddTexture(L"stone01.png") )
		return false;

	// создаем константный буфер
	m_constMatrixBuffer = Buffer::CreateConstantBuffer(m_render->m_pd3dDevice, sizeof(MatrixBufferType), false);
	m_lightColorBuffer = Buffer::CreateConstantBuffer(m_render->m_pd3dDevice, sizeof(LightColorBufferType), false);
	m_lightPositionBuffer = Buffer::CreateConstantBuffer(m_render->m_pd3dDevice, sizeof(LightPositionBufferType), false);
		
	return true;
}
bool PlaneModel::LoadModel(char* filename)
{
	ifstream fin;
	char input;

	fin.open(filename);
	if(fin.fail())
		return false;

	fin.get(input);
	while(input != ':')
		fin.get(input);

	fin >> m_vertexCount;

	m_indexCount = m_vertexCount;

	m_model = new ModelType[m_vertexCount];
	if(!m_model)
		return false;

	fin.get(input);
	while(input != ':')
		fin.get(input);

	fin.get(input);
	fin.get(input);

	for(int i=0; i<m_vertexCount; i++)
	{
		fin >> m_model[i].x >> m_model[i].y >> m_model[i].z;
		fin >> m_model[i].tu >> m_model[i].tv;
		fin >> m_model[i].nx >> m_model[i].ny >> m_model[i].nz;
	}

	fin.close();

	return true;
}

В данном классе мы будем грузить модель из файла

bool PlaneModel::InitializeBuffers()
{
	VertexType *vertices = new VertexType[m_vertexCount];
	if(!vertices)
		return false;

	unsigned long *indices = new unsigned long[m_indexCount];
	if(!indices)
		return false;

	for(int i=0; i<m_vertexCount; i++)
	{
		vertices[i].position = XMFLOAT3(m_model[i].x, m_model[i].y, m_model[i].z);
		vertices[i].texture = XMFLOAT2(m_model[i].tu, m_model[i].tv);
		vertices[i].normal = XMFLOAT3(m_model[i].nx, m_model[i].ny, m_model[i].nz);

		indices[i] = i;
	}

	m_vertexBuffer = Buffer::CreateVertexBuffer(m_render->m_pd3dDevice, sizeof(VertexType)*m_vertexCount, false, vertices);
	m_indexBuffer = Buffer::CreateIndexBuffer(m_render->m_pd3dDevice, sizeof(unsigned long)*m_indexCount, false, indices);

	_DELETE_ARRAY(vertices);
	_DELETE_ARRAY(indices);

	return true;
}

Инициализируем вершинный и индексный буферы.

void PlaneModel::Close()
{
	_DELETE_ARRAY(m_model);
	_RELEASE(m_vertexBuffer);
	_RELEASE(m_indexBuffer);
	_RELEASE(m_constMatrixBuffer);
	_RELEASE(m_lightColorBuffer);
	_RELEASE(m_lightPositionBuffer);
	_CLOSE(m_shader);
}

void PlaneModel::Render(CXMMATRIX view, CXMMATRIX proj, XMFLOAT4 diffuseColor[], XMFLOAT4 lightPosition[])
{
	MatrixBufferType cb;

	cb.world = XMMatrixTranspose(XMMatrixIdentity());
	cb.view = XMMatrixTranspose(view);
	cb.projection = XMMatrixTranspose(proj);
	m_render->m_pImmediateContext->UpdateSubresource(m_constMatrixBuffer, 0, NULL, &cb, 0, 0);
	m_render->m_pImmediateContext->VSSetConstantBuffers(0, 1, &m_constMatrixBuffer);

	LightPositionBufferType lpb;
	lpb.lightPosition[0] = lightPosition[0];
	lpb.lightPosition[1] = lightPosition[1];
	lpb.lightPosition[2] = lightPosition[2];
	lpb.lightPosition[3] = lightPosition[3];
	m_render->m_pImmediateContext->UpdateSubresource(m_lightPositionBuffer, 0, NULL, &lpb, 0, 0);
	m_render->m_pImmediateContext->VSSetConstantBuffers(1, 1, &m_lightPositionBuffer);

	LightColorBufferType lcb;
	lcb.diffuseColor[0] = diffuseColor[0];
	lcb.diffuseColor[1] = diffuseColor[1];
	lcb.diffuseColor[2] = diffuseColor[2];
	lcb.diffuseColor[3] = diffuseColor[3];
	m_render->m_pImmediateContext->UpdateSubresource(m_lightColorBuffer, 0, NULL, &lcb, 0, 0);
	m_render->m_pImmediateContext->PSSetConstantBuffers(0, 1, &m_lightColorBuffer);
	
	unsigned int stride = sizeof(VertexType); 
	unsigned int offset = 0;
	m_render->m_pImmediateContext->IASetVertexBuffers(0, 1, &m_vertexBuffer, &stride, &offset);
	m_render->m_pImmediateContext->IASetIndexBuffer(m_indexBuffer, DXGI_FORMAT_R32_UINT, 0);
	m_render->m_pImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
	m_shader->Draw();	
	m_render->m_pImmediateContext->DrawIndexed(m_indexCount, 0, 0);
}

Ну и выводим на экран.

shader.vsПравить

#define NUM_LIGHTS 4

cbuffer MatrixBuffer
{
	matrix worldMatrix;
	matrix viewMatrix;
	matrix projectionMatrix;
};

cbuffer LightPositionBuffer
{
	float4 lightPosition[NUM_LIGHTS];
};

struct VertexInputType
{
	float4 position : POSITION;
	float2 tex : TEXCOORD0;
	float3 normal : NORMAL;
};

struct PixelInputType
{
	float4 position : SV_POSITION;
	float2 tex : TEXCOORD0;
	float3 normal : NORMAL;
	float3 lightPos1 : TEXCOORD1;
	float3 lightPos2 : TEXCOORD2;
	float3 lightPos3 : TEXCOORD3;
	float3 lightPos4 : TEXCOORD4;
};

PixelInputType VS(VertexInputType input)
{
	PixelInputType output;
	float4 worldPosition;
	input.position.w = 1.0f;

	output.position = mul(input.position, worldMatrix);
	output.position = mul(output.position, viewMatrix);
	output.position = mul(output.position, projectionMatrix);
    
	output.tex = input.tex;
    
	output.normal = mul(input.normal, (float3x3)worldMatrix);
	output.normal = normalize(output.normal);
	
	worldPosition = mul(input.position, worldMatrix);

	// Определение позиции света на основе позиции света и позиции вершины в мире
	output.lightPos1.xyz = lightPosition[0].xyz - worldPosition.xyz;
	output.lightPos2.xyz = lightPosition[1].xyz - worldPosition.xyz;
	output.lightPos3.xyz = lightPosition[2].xyz - worldPosition.xyz;
	output.lightPos4.xyz = lightPosition[3].xyz - worldPosition.xyz;

	// Нормализация позиции света
	output.lightPos1 = normalize(output.lightPos1);
	output.lightPos2 = normalize(output.lightPos2);
	output.lightPos3 = normalize(output.lightPos3);
	output.lightPos4 = normalize(output.lightPos4);

	return output;
}

shader.psПравить

#define NUM_LIGHTS 4

Texture2D shaderTexture;
SamplerState SampleType;

cbuffer LightColorBuffer
{
	float4 diffuseColor[NUM_LIGHTS];
};

struct PixelInputType
{
	float4 position : SV_POSITION;
	float2 tex : TEXCOORD0;
	float3 normal : NORMAL;
	float3 lightPos1 : TEXCOORD1;
	float3 lightPos2 : TEXCOORD2;
	float3 lightPos3 : TEXCOORD3;
	float3 lightPos4 : TEXCOORD4;
};

float4 PS(PixelInputType input) : SV_TARGET
{
	float4 textureColor = shaderTexture.Sample(SampleType, input.tex);
	
	// Вычисление количества света на данном пикселе в зависимости от позиции света
	float lightIntensity1 = saturate(dot(input.normal, input.lightPos1));
	float lightIntensity2 = saturate(dot(input.normal, input.lightPos2));
	float lightIntensity3 = saturate(dot(input.normal, input.lightPos3));
	float lightIntensity4 = saturate(dot(input.normal, input.lightPos4));
	
	// Вычисление рассеяного цвета для каждого из 4 источников света
	float4 color1 = diffuseColor[0] * lightIntensity1;
	float4 color2 = diffuseColor[1] * lightIntensity2;
	float4 color3 = diffuseColor[2] * lightIntensity3;
	float4 color4 = diffuseColor[3] * lightIntensity4;

	// перемножение пикселя из текстуры с 4 цветами света
	float4 color = saturate(color1 + color2 + color3 + color4) * textureColor;
	
	return color;
}

ЗавершениеПравить

скачать

Lesson 2013-04-27 16-39-41-95
Материалы сообщества доступны в соответствии с условиями лицензии CC-BY-SA , если не указано иное.