튀김족발
공부 끄적이는 공간
튀김족발
전체 방문자
오늘
어제
  • 분류 전체보기 (33)
    • C++ (10)
    • DirectX (12)
    • Unreal (11)
    • Unity (0)
    • EASTL (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
튀김족발

공부 끄적이는 공간

8. 주변광
DirectX

8. 주변광

2022. 12. 6. 11:44

주변광은 특정한 방향이 없이 주변을 덮고 있는 빛을 말합니다. 물론 광원은 있지만, 여러가지 요소들에 부딪히고 반사되어 점차 방향을 잃어버린 빛의 현태에 해당합니다. 따라서 이러한 조명은 물체의 어떤 면에나 비춰지며, 지금까지 살펴본 예제에서와 같이 어느쪽으로 회전하던간에 일정한 밝기와 색상으로 표현되는 경우가 바로 이 주변광의 영향을 받은 것입니다.

주변광을 흉내내기 위해서 간단한 방정식을 사용할 것입니다. 단지 픽셀 셰이더에서 맨처음 각 픽셀마다 일정 수준의 주변광에 해당하는 값을 줍니다. 드 귀에 이루어지는 모든 연산들은 단지 그 주변광 값에 계산된 값들을 더하는 것입니다. 이렇게 하여 아무리 어두운 곳이더라도 최소한 주변광 만큼의 색상을 가지게 할 수 있습니다.

 

LightPixelShader에 확산조명을 추가하고 LightVertexShader에는 코드 변경이 없으므로 생략하겠습니다.

 

LightPixel.hlsl

/////////////
// GLOBALS //
/////////////
Texture2D shaderTexture;
SamplerState sampleType;

cbuffer LightBuffer
{
    float4 ambientColor;
    float4 diffuseColor;
    float3 lightDirection;
    float padding;
};

//////////////
// TYPEDEFS //
//////////////
struct PixelInputType
{
    float4 position : SV_POSITION;
    float2 tex : TEXCOORD0;
    float3 normal : NORMAL;
};

////////////////////
// Pixel Shader //
////////////////////
float4 LightPixelShader(PixelInputType input) : SV_TARGET
{
    float4 textureColor;
    float3 lightDir;
    float lightIntensity;
    float4 color;
    
    // 이 텍스처 좌표 위치에서 샘플러를 사용하여 텍스처에서 픽셀 색상을 샘플링 합니다.
    textureColor = shaderTexture.Sample(sampleType, input.tex);
    
    // 모든 픽셀의 기본 출력 색상을 주변 광원 값으로 설정합니다.
    color = ambientColor;
    
    // 계산을 위해 빛 방향을 반전시킵니다.
    lightDir = -lightDirection;
    
    // 이 픽셀의 빛의 양을 계산합니다.
    lightIntensity = saturate(dot(input.normal, lightDir));
    
    if(lightIntensity > 0.0f)
    {
        // 확산 색과 광 강도의 양에 따라 최종 확산 색을 결정합니다.
        color += (diffuseColor * lightIntensity);
    }
    
    // 최종 빛의 색상을 채웁니다.
    color = saturate(color);
    
    // 텍스처 픽셀과 최종 확산 색을 곱하여 최종 픽셀 색상 결과를 얻습니다.
    color = color * textureColor;
    
    return color;
}

LightBuffer에 ambientColor를 추가합니다.

cbuffer LightBuffer
{
    float4 ambientColor;
    float4 diffuseColor;
    float3 lightDirection;
    float padding;
};

 

결과의 색상 값을 기본으로 주변광 값으로 맞춥니다. 이제 모든 픽셀들은 최소한 주변광 값을 가지게 됩니다.

    // Set the default output color to the ambient light value for all pixels.
    color = ambientColor;

    // Invert the light direction for calculations.
    lightDir = -lightDirection;

    // Calculate the amount of light on this pixel.
    lightIntensity = saturate(dot(input.normal, lightDir));

 

법선과 빛의 방향의 내적이 0보다 큰지 확인해 봅니다. 만약, 그렇다면 조명값을 주변광에 더하고, 그렇지 않다면 조명값을 더하지 않도록 해야 합니다. 드렇게 하는 이유는 간혹 음수로 계산되는 빛의 밝기 값이 주변광 값을 깎아먹는 경우가 생기기 때문입니다.

    if(lightIntensity > 0.0f)
    {
        // 확산 색과 광 강도의 양에 따라 최종 확산 색을 결정합니다.
        color += (diffuseColor * lightIntensity);
    }

 

주변광과 조명의 조합의 결과가 1이 넘을 수 있으므로 saturate함수로 최종 색상이 적절한 값이 되도록 잘라냅니다.

    // 최종 빛의 색상을 채웁니다.
    color = saturate(color);
    
    // 텍스처 픽셀과 최종 확산 색을 곱하여 최종 픽셀 색상 결과를 얻습니다.
    color = color * textureColor;
    
    return color;

 

LightShaderClass

LightShaderClass.h

#pragma once

class LightShaderClass : public AlignedAllocationPolicy<16>
{
private:
	struct MatrixBufferType
	{
		XMMATRIX world;
		XMMATRIX view;
		XMMATRIX projection;
	};

	struct LightBufferType
	{
		XMFLOAT4 ambientColor;
		XMFLOAT4 diffuseColor;
		XMFLOAT3 lightDirection;
		float padding;			// 구조체가 CreateBuffer 함수 요구 사항에 대해 16의 배수가 되도록 여분의 패딩을 추가
	};

public:
	LightShaderClass();
	LightShaderClass(const LightShaderClass& other);
	~LightShaderClass();

	bool Initialize(ID3D11Device* device, HWND hwnd);
	void ShutDown();
	bool Render(ID3D11DeviceContext* deviceContext, int indexCount, XMMATRIX worldMatrix, XMMATRIX viewMatrix, XMMATRIX projectionMatrix, ID3D11ShaderResourceView* texture, XMFLOAT3 lightDirection, XMFLOAT4 ambientColor, XMFLOAT4 diffuseColor);

private:
	bool InitializeShader(ID3D11Device* device, HWND hwnd, WCHAR* vsFileName, WCHAR* psFileName);
	void ShutdownShader();
	bool OutputShaderErrorMessage(ID3D10Blob* blob, HWND hwnd, WCHAR* shaderFileName);

	bool SetShaderParameters(ID3D11DeviceContext* deviceContext, XMMATRIX worldMatrix, XMMATRIX viewMatrix, XMMATRIX projectionMatrix, ID3D11ShaderResourceView* texture, XMFLOAT3 lightDirection, XMFLOAT4 ambientColor, XMFLOAT4 diffuseColor);
	void RenderShader(ID3D11DeviceContext* deviceContext, int indexCount);

private:
	ID3D11VertexShader* _vertexShader = nullptr;
	ID3D11PixelShader* _pixelShader = nullptr;
	ID3D11InputLayout* _layout = nullptr;
	ID3D11SamplerState* _sampleState = nullptr;
	ID3D11Buffer* _matrixBuffer = nullptr;
	ID3D11Buffer* _lightBuffer = nullptr;
};

 

LightBufferType이 주변광을 갖도록 수정했습니다.

그리고 원하는 주변광 값을 받을 수 있도록 함수 매개변수를 추가 했습니다.

	struct LightBufferType
	{
		XMFLOAT4 ambientColor;
		XMFLOAT4 diffuseColor;
		XMFLOAT3 lightDirection;
		float padding;			// 구조체가 CreateBuffer 함수 요구 사항에 대해 16의 배수가 되도록 여분의 패딩을 추가
	};
    
    bool Render(ID3D11DeviceContext* deviceContext, int indexCount, XMMATRIX worldMatrix, XMMATRIX viewMatrix, XMMATRIX projectionMatrix, ID3D11ShaderResourceView* texture, XMFLOAT3 lightDirection, XMFLOAT4 ambientColor, XMFLOAT4 diffuseColor);
    
    bool SetShaderParameters(ID3D11DeviceContext* deviceContext, XMMATRIX worldMatrix, XMMATRIX viewMatrix, XMMATRIX projectionMatrix, ID3D11ShaderResourceView* texture, XMFLOAT3 lightDirection, XMFLOAT4 ambientColor, XMFLOAT4 diffuseColor);

 

LightShaderClass.cpp

#include "stdafx.h"
#include "LightShaderClass.h"

LightShaderClass::LightShaderClass()
{
    _vertexShader = 0;
    _pixelShader = 0;
    _layout = 0;
    _sampleState = 0;
    _matrixBuffer = 0;
    _lightBuffer = 0;
}

LightShaderClass::LightShaderClass(const LightShaderClass& other)
{
}

LightShaderClass::~LightShaderClass()
{
}

bool LightShaderClass::Initialize(ID3D11Device* device, HWND hwnd)
{
    // 정점 및 픽셀 쉐이더를 초기화합니다.
    return InitializeShader(device, hwnd, L"Shader/LightVertex.hlsl", L"Shader/LightPixel.hlsl");
}

void LightShaderClass::ShutDown()
{
    // 버텍스 및 픽셀 쉐이더와 관련된 객체를 종료합니다.
    ShutdownShader();
}

bool LightShaderClass::Render(ID3D11DeviceContext* deviceContext, int indexCount, XMMATRIX worldMatrix, XMMATRIX viewMatrix, XMMATRIX projectionMatrix, ID3D11ShaderResourceView* texture, XMFLOAT3 lightDirection, XMFLOAT4 ambientColor, XMFLOAT4 diffuseColor)
{
    // 렌더링에 사용할 쉐이더 매개 변수를 설정합니다.
    if (!SetShaderParameters(deviceContext, worldMatrix, viewMatrix, projectionMatrix, texture, lightDirection, ambientColor, diffuseColor))
    {
        return false;
    }

    // 설정된 버퍼를 쉐이더로 렌더링합니다.
    RenderShader(deviceContext, indexCount);

    return true;
}

bool LightShaderClass::InitializeShader(ID3D11Device* device, HWND hwnd, WCHAR* vsFileName, WCHAR* psFileName)
{
    HRESULT result;
    ID3D10Blob* errorMessage = nullptr;

    // 버텍스 쉐이더 코드를 컴파일 합니다.
    ID3D10Blob* vertexShaderBuffer = nullptr;
    result = D3DCompileFromFile(vsFileName, NULL, NULL, "LightVertexShader", "vs_5_0", D3D10_SHADER_ENABLE_STRICTNESS, 0, &vertexShaderBuffer, &errorMessage);
    if (FAILED(result))
    {
        // 셰이더 컴파일 실패시 오류메시지를 출력합니다.
        if (errorMessage)
        {
            OutputShaderErrorMessage(errorMessage, hwnd, vsFileName);
        }
        // 컴파일 오류가 아니라면 셰이더 파일을 찾을 수 없는 경우입니다.
        else
        {
            MessageBox(hwnd, vsFileName, L"Missing Shader File", MB_OK);
        }

        return false;
    }

    // 픽셀 쉐이더 코드를 컴파일합니다.
    ID3D10Blob* pixelShaderBuffer = nullptr;
    result = D3DCompileFromFile(psFileName, NULL, NULL, "LightPixelShader", "ps_5_0", D3D10_SHADER_ENABLE_STRICTNESS, 0, &pixelShaderBuffer, &errorMessage);
    if (FAILED(result))
    {
        // 셰이더 컴파일 실패시 오류메시지를 출력합니다.
        if (errorMessage)
        {
            OutputShaderErrorMessage(errorMessage, hwnd, psFileName);
        }
        // 컴파일 오류가 아니라면 셰이더 파일을 찾을 수 없는 경우입니다.
        else
        {
            MessageBox(hwnd, psFileName, L"Missing Shader File", MB_OK);
        }

        return false;
    }

    // 버퍼에서 정점 쉐이더를 생성합니다.
    result = device->CreateVertexShader(vertexShaderBuffer->GetBufferPointer(), vertexShaderBuffer->GetBufferSize(), NULL, &_vertexShader);
    if (FAILED(result))
    {
        return false;
    }

    // 버퍼에서 픽셀 쉐이더를 생성합니다.
    result = device->CreatePixelShader(pixelShaderBuffer->GetBufferPointer(), pixelShaderBuffer->GetBufferSize(), NULL, &_pixelShader);
    if (FAILED(result))
    {
        return false;
    }

    // 정점 입력 레이아웃 구조체를 설정합니다.
    // 이 설정은 ModelCalss 와 쉐이더의 VertexType 구조와 일치해야 합니다.
    D3D11_INPUT_ELEMENT_DESC polygonLayout[3];
    polygonLayout[0].SemanticName = "POSITION";
    polygonLayout[0].SemanticIndex = 0;
    polygonLayout[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
    polygonLayout[0].InputSlot = 0;
    polygonLayout[0].AlignedByteOffset = 0;
    polygonLayout[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
    polygonLayout[0].InstanceDataStepRate = 0;

    polygonLayout[1].SemanticName = "TEXCOORD";
    polygonLayout[1].SemanticIndex = 0;
    polygonLayout[1].Format = DXGI_FORMAT_R32G32_FLOAT;
    polygonLayout[1].InputSlot = 0;
    polygonLayout[1].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
    polygonLayout[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
    polygonLayout[1].InstanceDataStepRate = 0;

    polygonLayout[2].SemanticName = "NORMAL";
    polygonLayout[2].SemanticIndex = 0;
    polygonLayout[2].Format = DXGI_FORMAT_R32G32B32_FLOAT;
    polygonLayout[2].InputSlot = 0;
    polygonLayout[2].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
    polygonLayout[2].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
    polygonLayout[2].InstanceDataStepRate = 0;

    // 레이아웃의 요소 수를 가져옵니다.
    UINT numElements = sizeof(polygonLayout) / sizeof(polygonLayout[0]);

    // 정점 입력 레이아웃을 만듭니다.
    result = device->CreateInputLayout(polygonLayout, numElements, vertexShaderBuffer->GetBufferPointer(), vertexShaderBuffer->GetBufferSize(), &_layout);
    if (FAILED(result))
    {
        return false;
    }

    // 더 이상 사용되지 않는 정점 쉐이더 버퍼와 픽셀 쉐이더 버퍼를 해제합니다.
    SAFE_RELEASE(vertexShaderBuffer);
    SAFE_RELEASE(pixelShaderBuffer);

    // 텍스처 샘플러 상태 구조체를 생성 및 설정합니다.
    D3D11_SAMPLER_DESC samplerDesc;
    samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
    samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
    samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
    samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
    samplerDesc.MipLODBias = 0.0f;
    samplerDesc.MaxAnisotropy = 1;
    samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
    samplerDesc.BorderColor[0] = 0;
    samplerDesc.BorderColor[1] = 0;
    samplerDesc.BorderColor[2] = 0;
    samplerDesc.BorderColor[3] = 0;
    samplerDesc.MinLOD = 0;
    samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;

    // 텍스처 샘플러 상태를 만듭니다.
    result = device->CreateSamplerState(&samplerDesc, &_sampleState);
    if (FAILED(result))
    {
        return false;
    }

    // 정점 쉐이더에 있는 행렬 상수 버퍼의 구조체를 작성합니다.
    D3D11_BUFFER_DESC matrixBufferDesc;
    matrixBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
    matrixBufferDesc.ByteWidth = sizeof(MatrixBufferType);
    matrixBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    matrixBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
    matrixBufferDesc.MiscFlags = 0;
    matrixBufferDesc.StructureByteStride = 0;

    // 상수 버퍼 포인터를 만들어 이 클래스에서 정점 쉐이더 상수 버퍼에 접근할 수 있게 합니다.
    result = device->CreateBuffer(&matrixBufferDesc, NULL, &_matrixBuffer);
    if (FAILED(result))
    {
        return false;
    }

    // 필셀 쉐이더에 있는 광원 동적 상수 버펑의 설명을 설정합니다.
    // D3D11_BIND_CONSTANT_BUFFER를 사용하면 ByteWidth가 항상 16배수 여야 하며 그렇지 않으면 CreateBuffer가 실패합니다.
    D3D11_BUFFER_DESC lightBufferDesc;
    lightBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
    lightBufferDesc.ByteWidth = sizeof(LightBufferType);
    lightBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    lightBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
    lightBufferDesc.MiscFlags = 0;
    lightBufferDesc.StructureByteStride = 0;

    // 이 클래스 내에서 정점 쉐이더 상수 버퍼에 액세스 할 수 있도록 상수 버퍼 포인터를 만듭니다.
    result = device->CreateBuffer(&lightBufferDesc, NULL, &_lightBuffer);
    if (FAILED(result))
    {
        return false;
    }

    return true;
}

void LightShaderClass::ShutdownShader()
{
    SAFE_RELEASE(_lightBuffer);
    SAFE_RELEASE(_matrixBuffer);
    SAFE_RELEASE(_sampleState);
    SAFE_RELEASE(_layout);
    SAFE_RELEASE(_pixelShader);
    SAFE_RELEASE(_vertexShader);
}

bool LightShaderClass::OutputShaderErrorMessage(ID3D10Blob* blob, HWND hwnd, WCHAR* shaderFileName)
{
    // 에러 메시지를 출력창에 표시합니다.
    OutputDebugStringA(reinterpret_cast<const char*>(blob->GetBufferPointer()));

    // 에러 메시지를 반환합니다.
    SAFE_RELEASE(blob);

    // 파일 에러가 있음을 팝업 메시지로 알려줍니다.
    MessageBox(hwnd, L"Error Compiling Shader.", shaderFileName, MB_OK);
    return false;
}

bool LightShaderClass::SetShaderParameters(ID3D11DeviceContext* deviceContext, XMMATRIX worldMatrix, XMMATRIX viewMatrix, XMMATRIX projectionMatrix, ID3D11ShaderResourceView* texture, XMFLOAT3 lightDirection, XMFLOAT4 ambientColor, XMFLOAT4 diffuseColor)
{
    // 행렬을 transpose하여 쉐이더에서 사용할 수 있게 합니다.
    worldMatrix = XMMatrixTranspose(worldMatrix);
    viewMatrix = XMMatrixTranspose(viewMatrix);
    projectionMatrix = XMMatrixTranspose(projectionMatrix);

    // 상수 버퍼의 내용을 쓸 수 있도록 잠급니다.
    D3D11_MAPPED_SUBRESOURCE mappedResource;
    if (FAILED(deviceContext->Map(_matrixBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource)))
    {
        return false;
    }

    // 상수 버퍼의 데이터에 대한 포인터를 가져옵니다.
    MatrixBufferType* dataPtr = (MatrixBufferType*)mappedResource.pData;

    // 상수 버퍼에 행렬을 복사합니다.
    dataPtr->world = worldMatrix;
    dataPtr->view = viewMatrix;
    dataPtr->projection = projectionMatrix;

    // 상수 버퍼의 점금을 풉니다.
    deviceContext->Unmap(_matrixBuffer, 0);

    // 정점 쉐이더에서의 상수 버퍼의 위치를 설정합니다.
    unsigned int bufferNumber = 0;

    // 마지막으로 정점 쉐이더의 상수 버퍼를 바뀐 값으로 바꿉니다.
    deviceContext->VSSetConstantBuffers(bufferNumber, 1, &_matrixBuffer);

    // 픽셀 셰이더에서 셰이더 텍스처 리소스를 설정합니다.
    deviceContext->PSSetShaderResources(0, 1, &texture);

    // light constant buffer를 잠글 수 있도록 기록한다.
    if (FAILED(deviceContext->Map(_lightBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource)))
    {
        return false;
    }

    // 상수 버퍼의 데이터에 대한 포인터를 가져옵니다.
    LightBufferType* dataPtr2 = (LightBufferType*)mappedResource.pData;

    // 조명 변수를 상수 버퍼에 복사합니다.
    dataPtr2->ambientColor = ambientColor;
    dataPtr2->diffuseColor = diffuseColor;
    dataPtr2->lightDirection = lightDirection;
    dataPtr2->padding = 0.0f;

    // 상수 버퍼의 잠금을 해제합니다.
    deviceContext->Unmap(_lightBuffer, 0);

    // 픽셀 쉐이더에서 광원 상수 버퍼의 위치를 설정합니다.
    bufferNumber = 0;

    // 마지막으로 업데이트 된 값으로 픽셀 쉐이더에서 광원 상수 버퍼를 설정합니다.
    deviceContext->PSSetConstantBuffers(bufferNumber, 1, &_lightBuffer);
    return true;
}

void LightShaderClass::RenderShader(ID3D11DeviceContext* deviceContext, int indexCount)
{
    // 정점 입력 레이아웃을 설정합니다.
    deviceContext->IASetInputLayout(_layout);

    // 삼각형을 그릴 정점 쉐이더와 픽셀 쉐이더를 설정합니다.
    deviceContext->VSSetShader(_vertexShader, NULL, 0);
    deviceContext->PSSetShader(_pixelShader, NULL, 0);

    // 픽셀 쉐이더에서 샘플러 상태를 설정합니다.
    deviceContext->PSSetSamplers(0, 1, &_sampleState);

    // 삼각형을 그립니다
    deviceContext->DrawIndexed(indexCount, 0, 0);
}

 

추가되는 부분은 LightBuffer에 값을 복사하는 부분 입니다.

    // 조명 변수를 상수 버퍼에 복사합니다.
    dataPtr2->ambientColor = ambientColor;
    dataPtr2->diffuseColor = diffuseColor;
    dataPtr2->lightDirection = lightDirection;
    dataPtr2->padding = 0.0f;

 

LightClass

LightClass.h

#pragma once
class LightClass
{
public:
	LightClass();
	LightClass(const LightClass& other);
	~LightClass();

	void SetAmbientColor(float red, float green, float blue, float alpha);
	void SetDiffuseColor(float red, float green, float blue, float alpha);
	void SetDirection(float x, float y, float z);

	XMFLOAT4 GetAmbient();
	XMFLOAT4 GetDiffuseColor();
	XMFLOAT3 GetDirection();

private:
	XMFLOAT4 _ambientColor;
	XMFLOAT4 _diffuseColor;
	XMFLOAT3 _direction;
};

주변광에 관한 변수, 함수가 추가됐습니다.

LightClass.cpp

#include "stdafx.h"
#include "LightClass.h"

LightClass::LightClass()
{
}

LightClass::LightClass(const LightClass& other)
{
}

LightClass::~LightClass()
{
}

void LightClass::SetAmbientColor(float red, float green, float blue, float alpha)
{
    _ambientColor = XMFLOAT4(red, green, blue, alpha);
}

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

void LightClass::SetDirection(float x, float y, float z)
{
    _direction = XMFLOAT3(x, y, z);
}

XMFLOAT4 LightClass::GetAmbient()
{
    return _ambientColor;
}

XMFLOAT4 LightClass::GetDiffuseColor()
{
    return _diffuseColor;
}

XMFLOAT3 LightClass::GetDirection()
{
    return _direction;
}

추가 됐습니다.

 

GraphicsClass

GraphcisClass.h

추가된 부분이나 변경된 부분이 없어 생략 하겠습니다.

GraphicsClass.cpp

#include "stdafx.h"
#include "d3dclass.h"
#include "CameraClass.h"
#include "ModelClass.h"
#include "LightShaderClass.h"
#include "LightClass.h"
#include "GraphicsClass.h"


GraphicsClass::GraphicsClass()
{
}


GraphicsClass::GraphicsClass(const GraphicsClass& other)
{
}


GraphicsClass::~GraphicsClass()
{
}


bool GraphicsClass::Initialize(int screenWidth, int screenHeight, HWND hwnd)
{
	// Direct3D 객체 생성
	//_direct3D = (D3DClass*) SAFE_ALIGNED_NEW(sizeof(D3DClass), 16);
	_direct3D = new D3DClass();
	if (!_direct3D)
	{
		return false;
	}

	// Direct3D 객체 초기화
	if (!_direct3D->Initialize(screenWidth, screenHeight, VSYNC_ENABLED, hwnd, FULL_SCREEN, SCREEN_DEPTH, SCREEN_NEAR))
	{
		MessageBox(hwnd, L"Could not initialze Direct3D", L"Error", MB_OK);
		return false;
	}

	// _camera 객체 생성
	_camera = new CameraClass();
	if (_camera == nullptr)
	{
		return false;
	}

	// 카메라 포지션 변경
	_camera->SetPosition(0.0f, 0.0f, -5.0f);

	// _model 객체 생성
	_model = new ModelClass();
	if (_model == nullptr)
	{
		return false;
	}

	// _model 객체 초기화
	if (!_model->Initialize(_direct3D->GetDevice(), "Data/Cube.txt", L"Data/seafloor.dds"))
	{
		MessageBox(hwnd, L"Could not initialize the model object.", L"Error", MB_OK);
		return false;
	}

	// _lightShader 생성
	_lightShader = new LightShaderClass();
	if (_lightShader == nullptr)
	{
		return false;
	}

	// _lightShader 객체 초기화
	if (!_lightShader->Initialize(_direct3D->GetDevice(), hwnd))
	{
		MessageBox(hwnd, L"Could not initialize the color shader object.", L"Error", MB_OK);
		return false;
	}

	// _light 객체 생성
	_light = new LightClass();
	if (_light == nullptr)
	{
		return false;
	}

	//_light->SetAmbientColor(0.01f, 0.01f, 0.01f, 1.0f);
	_light->SetAmbientColor(0.15f, 0.15f, 0.15f, 1.0f);
	_light->SetDiffuseColor(1.0f, 1.0f, 1.0f, 1.0f);
	_light->SetDirection(1.0f, 0.0f, 1.0f);

	return true;
}


void GraphicsClass::Shutdown()
{
	if (_lightShader)
	{
		_lightShader->ShutDown();
		SAFE_DELETE(_lightShader);
	}

	if (_light)
	{
		SAFE_DELETE(_light);
	}

	if (_model)
	{
		_model->ShutDown();
		SAFE_DELETE(_model);
	}

	// _camera 객체 반환
	SAFE_DELETE(_camera);

	// Direct3D 객체 반환
	if (_direct3D)
	{
		_direct3D->Shutdown();
		SAFE_DELETE(_direct3D);
	}
}


bool GraphicsClass::Frame()
{
	static float rotation = 0.0f;

	// 각 프레임의 rotation 변수를 업데이트 합니다.
	rotation += (float)XM_PI * 0.005f;
	if (rotation > 360.0f)
	{
		rotation -= 360.0f;
	}

	// 그래픽 랜더링 처리
	return Render(rotation);
}


bool GraphicsClass::Render(float rotation)
{  
	// 씬을 그리기 위해 버퍼를 지웁니다.
	_direct3D->BeginScene(0.0f, 0.0f, 0.0f, 1.0f);

	// 카메라의 위치에 따라 뷰 행렬을 생성합니다.
	_camera->Render();

	// 카메라 및 d3d 객체에서 월드, 뷰 및 투영 행렬을 가져옵니다.
	XMMATRIX worldMatrix, viewMatrix, projectionMatrix;
	_direct3D->GetWorldMatrix(worldMatrix);
	_camera->GetViewMatrix(viewMatrix);
	_direct3D->GetProjectionMatrix(projectionMatrix);

	// 삼각형이 회전 할 수 있도록 회전 값으로 월드 행렬을 회전합니다.
	worldMatrix = XMMatrixRotationY(rotation);

	// 모델 버텍스와 인덱스 버퍼를 그래픽 파이프 라인에 배치하여 드로잉을 준비합니다.
	_model->Render(_direct3D->GetDeviceContext());

	// 텍스처 쉐이더를 사용하여 모델을 렌더링 합니다.
	if (!_lightShader->Render(_direct3D->GetDeviceContext(), _model->GetIndexCount(), worldMatrix, viewMatrix, projectionMatrix, 
								_model->GetTexture(), _light->GetDirection(), _light->GetAmbient(), _light->GetDiffuseColor()))
	{
		return false;
	}
	
	// 버퍼의 내용을 화면에 출력합니다.
	_direct3D->EndScene();

	return true;
}

LightClass에 AmbientColor를 설정해주는 부분을 추가 합니다.

	_light->SetAmbientColor(0.15f, 0.15f, 0.15f, 1.0f);
	_light->SetDiffuseColor(1.0f, 1.0f, 1.0f, 1.0f);
	_light->SetDirection(1.0f, 0.0f, 1.0f);

마지막으로 렌더링 할때 주변광 변수를 같이 넣어줍니다.

bool GraphicsClass::Render(float rotation)
{  
	// 씬을 그리기 위해 버퍼를 지웁니다.
	_direct3D->BeginScene(0.0f, 0.0f, 0.0f, 1.0f);

	// 카메라의 위치에 따라 뷰 행렬을 생성합니다.
	_camera->Render();

	// 카메라 및 d3d 객체에서 월드, 뷰 및 투영 행렬을 가져옵니다.
	XMMATRIX worldMatrix, viewMatrix, projectionMatrix;
	_direct3D->GetWorldMatrix(worldMatrix);
	_camera->GetViewMatrix(viewMatrix);
	_direct3D->GetProjectionMatrix(projectionMatrix);

	// 삼각형이 회전 할 수 있도록 회전 값으로 월드 행렬을 회전합니다.
	worldMatrix = XMMatrixRotationY(rotation);

	// 모델 버텍스와 인덱스 버퍼를 그래픽 파이프 라인에 배치하여 드로잉을 준비합니다.
	_model->Render(_direct3D->GetDeviceContext());

	// 텍스처 쉐이더를 사용하여 모델을 렌더링 합니다.
	if (!_lightShader->Render(_direct3D->GetDeviceContext(), _model->GetIndexCount(), worldMatrix, viewMatrix, projectionMatrix, 
								_model->GetTexture(), _light->GetDirection(), _light->GetAmbient(), _light->GetDiffuseColor()))
	{
		return false;
	}
	
	// 버퍼의 내용을 화면에 출력합니다.
	_direct3D->EndScene();

	return true;
}


결과화면

어두운 면이 생겼다...

 

'DirectX' 카테고리의 다른 글

10. 2D 렌더링  (0) 2023.01.31
9. 정반사광  (0) 2022.12.13
7. Maya 2011 모델 불러오기  (2) 2022.12.05
6. 3D 모델 렌더링  (0) 2022.11.26
5. 조명  (0) 2022.11.21
    'DirectX' 카테고리의 다른 글
    • 10. 2D 렌더링
    • 9. 정반사광
    • 7. Maya 2011 모델 불러오기
    • 6. 3D 모델 렌더링
    튀김족발
    튀김족발

    티스토리툴바