• Home
  • About
    • 게임 개발자 유정룡 photo

      게임 개발자 유정룡

      포트폴리오

    • Learn More
    • Email
    • Github
    • Bitbucket
  • Projects
    • All Projects
    • All Tags

Direct3D11 공부 35일차(Light - Point Light)

20 Jul 2021

Reading time ~3 minutes

Point Light

이런 식으로 전구에 불을 키면 사방에 빛이 퍼지는것 처럼 퍼진다.

Shader

00_Light.fx

void ComputePointLight(inout MaterialDesc output, float3 normal, float3 wPosition)
{
    output = MakeMaterial();
    MaterialDesc result = MakeMaterial();
    
    // Light 갯수만큼 for문을 돌아준다.(현재 최대 256개)
    // [unroll(MAX_POINT_LIGHTS)] -> 실행속도는 빨라지지만, 컴파일 속도는 느려진다.
    for (uint i = 0; i < PointLightCount; i++)
    {
        // wPosition : 레스터라이징이 되어 있는 정점의 위치
        // PointLight의 위치에서 정점 위치까지의 거리를 구하기
        float3 light = PointLights[i].Position - wPosition;
        float dist = length(light);
        
        // 거리거 PointLight의 범위를 넘어선다면 제외
        [flatten]
        if (dist > PointLights[i].Range)
        { continue; }
        
        light /= dist; // Normalize
        
        // Ambient는 자신이 갖고있는 Ambient와 빛의 Ambient를 곱해주면 된다.
        result.Ambient = PointLights[i].Ambient * Material.Ambient;
        
        // 이미 전역광에 대한 음영을 계산했지만, PointLight빛에 의해
        // 음영은 진해지기도 학도 빛에 의해 어두워 지는 부분 땜누에 PointLight에 대한 음영을 계산해준다. (빛은 누적됨)
        float NdotL = dot(light, normalize(normal));
        float3 E = normalize(ViewPosition() - wPosition); // 카메라가 바라보는 벡터
    
        // 조명각이 벗어났나 확인
        [flatten]
        if (NdotL > 0.0f)
        {
            result.Diffuse = Material.Diffuse * NdotL * PointLights[i].Diffuse;
        
        // 강도가 0 이하라면 연산 할 필요가 없기 때문
            [flatten]
            if (Material.Specular.a > 0.0f)
            {
            // 반사식 중요
                // 전역광이 아닌 Light에 대한 반사 계산 (Specular 계산)
                float3 R = normalize(reflect(-light, normal));
                float RdotE = saturate(dot(R, E));

                float specular = pow(RdotE, Material.Specular.a);
                result.Specular = Material.Specular * specular * PointLights[i].Specular;
            }
        }
    
        [flatten]
        if (Material.Emissive.a > 0.0f)
        {
            float NdotE = dot(E, normalize(normal));
            float emissive = smoothstep(1.0f - Material.Emissive.a, 1.0f, 1.0f - saturate(NdotE));
        
            result.Emissive = Material.Emissive * emissive * PointLights[i].Emissive;
        }
        
        // 조명이 들어갈곳, 안들어갈 곳 감쇠를 하기
        // Range에 대한 Dist의 비율을 구한 후 역수로 뒤집어줌 (계산을 편하게 해줌)
        float temp = 1.0f / saturate(dist / PointLights[i].Range);
        float att = temp * temp * PointLights[i].Intensity;

        // 빛 거리에 따른 감쇠(att)후 합산(빛은 합산할수록 밝아짐)
        output.Ambient += result.Ambient * temp;
        output.Diffuse += result.Diffuse * att;
        output.Specular += result.Specular * att;
        output.Emissive += result.Emissive * att;
    }
}

PointLight

#include "00_Global.fx"
#include "00_Light.fx"
#include "00_Render.fx"

float4 PS(MeshOutput input) : SV_Target
{
    Texture(Material.Diffuse, DiffuseMap, input.Uv);
    Texture(Material.Specular, SpecularMap, input.Uv);
    
    MaterialDesc output = MakeMaterial();
    MaterialDesc result = MakeMaterial();
    
    ComputeLight(output, input.Normal, input.wPosition);
    AddMaterial(result, output);
    
    ComputePointLight(output, input.Normal, input.wPosition);
    AddMaterial(result, output);
    
    return float4(MaterialToColor(result), 1.0f);
}

technique11 T0
{
    P_VP(P0, VS_Mesh, PS)
    P_VP(P1, VS_Model, PS)
    P_VP(P2, VS_Animation, PS)
}

이렇게 실행시켜주고,

Light

모든 라이트를 관리해줄 클래스를 싱들톤으로 만들어준다.

#pragma once

#define MAX_POINT_LIGHTS 256
struct PointLight
{
	Color Ambient;
	// 주 빛의 색
	Color Diffuse;
	Color Specular;
	Color Emissive;

	Vector3 Position;
	float Range;

	float Intensity;
	Vector3 Padding;
};

class Lighting
{
public:
	static Lighting* Get();
	static void Create();
	static void Delete();

public:
	UINT PointLightCount() { return pointLightCount; }
	UINT PointLights(OUT PointLight* lights);
	void AddPointLight(PointLight& light);
	PointLight& GetPointLight(UINT index);

private:
	Lighting();
	~Lighting();

private:
	static Lighting* instance;

private:
	UINT pointLightCount = 0;
	PointLight pointLights[MAX_POINT_LIGHTS];
};
#include "Framework.h"
#include "Lighting.h"

Lighting* Lighting::instance = NULL;

Lighting * Lighting::Get()
{
	assert(instance != NULL);

	return instance;
}

void Lighting::Create()
{
	assert(instance == NULL);

	instance = new Lighting();
}

void Lighting::Delete()
{
	SafeDelete(instance);
}

Lighting::Lighting()
{

}

Lighting::~Lighting()
{

}

UINT Lighting::PointLights(OUT PointLight * lights)
{
	memcpy(lights, pointLights, sizeof(PointLight) * pointLightCount);

	return pointLightCount;
}

void Lighting::AddPointLight(PointLight & light)
{
	pointLights[pointLightCount] = light;
	pointLightCount++;
}

PointLight & Lighting::GetPointLight(UINT index)
{
	return pointLights[index];
}

PerFrame

struct LightDesc
{
	Color Ambient;
	Color Specular;
	Vector3 Direction;
	float Padding;

	Vector3 Position;
	float Padding2;
} lightDesc;

struct PointLightDesc
{
	UINT Count = 0;
	float Padding[3];

	PointLight Lights[MAX_POINT_LIGHTS];
} pointLightDesc;

ConstantBuffer* pointLightBuffer;
ID3DX11EffectConstantBuffer* sPointLightBuffer;

그리고 PerFrame클래스에서 사용해준다.

PointLightDemo

이제 이 빛들을 모두 만들어 넣어주면

void PointLightingDemo::PointLighting()
{
	PointLight light;
	light =
	{
		Color(0.0f, 0.0f, 0.0f, 1.0f), //Ambient
		Color(0.0f, 0.0f, 1.0f, 1.0f), //Diffuse
		Color(0.0f, 0.0f, 0.7f, 1.0f), //Specular
		Color(0.0f, 0.0f, 0.7f, 1.0f), //Emissive
		Vector3(-30, 10, -30), 5.0f, 0.9f
	};
	Lighting::Get()->AddPointLight(light);

	light =
	{
		Color(0.0f, 0.0f, 0.0f, 1.0f),
		Color(1.0f, 0.0f, 0.0f, 1.0f),
		Color(0.6f, 0.2f, 0.0f, 1.0f),
		Color(0.6f, 0.3f, 0.0f, 1.0f),
		Vector3(15, 10, -30), 10.0f, 0.3f
	};
	Lighting::Get()->AddPointLight(light);

	light =
	{
		Color(0.0f, 0.0f, 0.0f, 1.0f), //Ambient
		Color(0.0f, 1.0f, 0.0f, 1.0f), //Diffuse
		Color(0.0f, 0.7f, 0.0f, 1.0f), //Specular
		Color(0.0f, 0.7f, 0.0f, 1.0f), //Emissive
		Vector3(-5, 1, -17.5f), 5.0f, 0.9f
	};
	Lighting::Get()->AddPointLight(light);

	light =
	{
		Color(0.0f, 0.0f, 0.0f, 1.0f),
		Color(0.0f, 0.0f, 1.0f, 1.0f),
		Color(0.0f, 0.0f, 0.7f, 1.0f),
		Color(0.0f, 0.0f, 0.7f, 1.0f),
		Vector3(-10, 1, -17.5f), 5.0f, 0.9f
	};
	Lighting::Get()->AddPointLight(light);
}

각각 색이 어떻게 나오는지 체크 했다.



DirectX Share Tweet +1