Link

์ด์ œ MaterialInstance๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ , ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•  GLTF ์…ฐ์ด๋”์— ํ•„์š”ํ•œ ๊ตฌ์กฐ์ฒด๋“ค์„ ์ •์˜ํ•˜๋Š” ์ž‘์—…๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ๊ตฌ์กฐ์ฒด๋“ค์„ vk_types.h์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

enum class MaterialPass :uint8_t {
    MainColor,
    Transparent,
    Other
};
struct MaterialPipeline {
	VkPipeline pipeline;
	VkPipelineLayout layout;
};

struct MaterialInstance {
    MaterialPipeline* pipeline;
    VkDescriptorSet materialSet;
    MaterialPass passType;
};

์ด ๊ตฌ์กฐ์ฒด๋“ค์€ ๋จธํ…Œ๋ฆฌ์–ผ ๋ฐ์ดํ„ฐ์— ํ•„์š”ํ•œ ๊ตฌ์กฐ์ฒด๋“ค์ž…๋‹ˆ๋‹ค. MaterialInstance๋Š” ์‹ค์ œ ํŒŒ์ดํ”„๋ผ์ธ์„ ๋‹ด๋Š” MaterialPipeline์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ๋ฅผ ๋‹ด์Šต๋‹ˆ๋‹ค(์†Œ์œ ํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค). ๋˜ํ•œ, ๋””์Šคํฌ๋ฆฝํ„ฐ ์…‹๋„ ํ•จ๊ป˜ ๋‹ด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๊ฐ์ฒด๋“ค์„ ์ƒ์„ฑํ•˜๋Š” ๋กœ์ง์€ VulkanEngine์ด ์ ์  ์ปค์ง€๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ณ„๋„์˜ ๊ตฌ์กฐ์ฒด๋กœ ๊ฐ์‹ธ์„œ ๋ถ„๋ฆฌํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. ๋‚˜์ค‘์—๋Š” ๋‹ค์–‘ํ•œ ๋จธํ…Œ๋ฆฌ์–ผ๋“ค์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๋‹ค์Œ์„ vk_engine.h์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

struct GLTFMetallic_Roughness {
	MaterialPipeline opaquePipeline;
	MaterialPipeline transparentPipeline;

	VkDescriptorSetLayout materialLayout;

	struct MaterialConstants {
		glm::vec4 colorFactors;
		glm::vec4 metal_rough_factors;
		//padding, we need it anyway for uniform buffers
		glm::vec4 extra[14];
	};

	struct MaterialResources {
		AllocatedImage colorImage;
		VkSampler colorSampler;
		AllocatedImage metalRoughImage;
		VkSampler metalRoughSampler;
		VkBuffer dataBuffer;
		uint32_t dataBufferOffset;
	};

	DescriptorWriter writer;

	void build_pipelines(VulkanEngine* engine);
	void clear_resources(VkDevice device);

	MaterialInstance write_material(VkDevice device, MaterialPass pass, const MaterialResources& resources, DescriptorAllocatorGrowable& descriptorAllocator);
};

ํ˜„์žฌ๋กœ์„œ๋Š” ๋‘ ํŒŒ์ดํ”„๋ผ์ธ์„ ๋ณด์œ ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ํ•˜๋‚˜๋Š” ํˆฌ๋ช…ํ•œ ๊ฐ์ฒด๋ฅผ ๊ทธ๋ฆด ๋•Œ, ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” ๋ถˆํˆฌ๋ช…ํ•œ ๊ฐ์ฒด์™€ ์•ŒํŒŒ๋งˆ์Šคํ‚น๋œ ๊ฐ์ฒด๋ฅผ ๊ทธ๋ฆด ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋จธํ…Œ๋ฆฌ์–ผ์„ ์œ„ํ•œ ๋””์Šคํฌ๋ฆฝํ„ฐ ์…‹ ๋ ˆ์ด์•„์›ƒ๋„ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

๋จธํ…Œ๋ฆฌ์–ผ ์ƒ์ˆ˜๋ฅผ ์œ„ํ•œ ๊ตฌ์กฐ์ฒด๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ตฌ์กฐ์ฒด๋Š” ๋‚˜์ค‘์— ์œ ๋‹ˆํผ ๋ฒ„ํผ์— ์“ฐ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ง€๊ธˆ ํ•„์š”ํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • colorFactors๋Š” ์ƒ‰์ƒ ํ…์Šค์ณ์— ๊ณฑํ•ด์งˆ ์ƒ‰์ƒ ๊ฐ’์ž…๋‹ˆ๋‹ค.
  • metal_rough_factors๋Š” metallic๊ณผ roughness ๊ฐ’์„ ๊ฐ๊ฐ r๊ณผ b์ปดํฌ๋„ŒํŠธ์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
  • ๊ทธ ์™ธ์—๋„ ๋‹ค๋ฅธ ์šฉ๋„๋กœ ์‚ฌ์šฉ๋˜๋Š” ๋‘ ๊ฐ€์ง€ ์ถ”๊ฐ€ ๊ฐ’์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

์ด์™ธ์—๋„ ์—ฌ๋Ÿฌ vec4๋“ค์ด ์ถ”๊ฐ€๋˜์–ด ์žˆ๋Š”๋ฐ, ์ด๋Š” ํŒจ๋”ฉ(padding)์„ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. Vulkan์—์„œ๋Š” ์œ ๋‹ˆํผ ๋ฒ„ํผ๋ฅผ ๋ฐ”์ธ๋”ฉํ•  ๋•Œ๋Š” ์ตœ์†Œ ์ •๋ ฌ ๊ทœ์น™์„ ๋งŒ์กฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ณดํ†ต 256๋ฐ”์ดํŠธ ์ •๋ ฌ์„ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•˜๋ฉฐ, ์šฐ๋ฆฌ๊ฐ€ ๋ชฉํ‘œ๋กœ ํ•˜๋Š” ๋ชจ๋“  GPU์—์„œ ์ด๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด ๊ตฌ์กฐ์ฒด์˜ ํฌ๊ธฐ๋ฅผ 2566๋ฐ”์ดํŠธ๋กœ ๋งž์ถ”๊ธฐ ์œ„ํ•ด vec4๋“ค์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

๋””์Šคํฌ๋ฆฝํ„ฐ ์…‹์„ ์ƒ์„ฑํ•  ๋•Œ๋Š” ๋ช‡ ๊ฐ€์ง€ ํ…์Šค์ณ์™€ ํ•จ๊ป˜, ์•ž์„œ ์–ธ๊ธ‰ํ•œ colorFactors ๋ฐ ๊ธฐํƒ€ ์†์„ฑ์„ ๋‹ด๊ณ  ์žˆ๋Š” ์œ ๋‹ˆํผ ๋ฒ„ํผ๋ฅผ ๋ฐ”์ธ๋”ฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ž์›๋“ค์„ MaterialResources ๊ตฌ์กฐ์ฒด์— ๋‹ด์•„ write_material ํ•จ์ˆ˜์— ์ „๋‹ฌํ•˜๊ธฐ ์‰ฝ๊ฒŒ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.

build_pipelines ํ•จ์ˆ˜๋Š” ํŒŒ์ดํ”„๋ผ์ธ์„ ์ปดํŒŒ์ผ ํ•ฉ๋‹ˆ๋‹ค. clear_resources๋Š” ๊ด€๋ จ๋œ ๋ชจ๋“  ์ž์›์„ ์ •๋ฆฌํ•˜๊ณ , write_material์€ ๋””์Šคํฌ๋ฆฝํ„ฐ ์…‹์„ ์ƒ์„ฑํ•˜๊ณ  ๋ Œ๋”๋ง ์‹œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์™„์ „ํ•œ MaterialInstance ๊ตฌ์กฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ด์ œ ์ด ํ•จ์ˆ˜๋“ค์˜ ๊ตฌํ˜„๋ถ€๋ฅผ ์‚ดํŽด๋ด…์‹œ๋‹ค.

void GLTFMetallic_Roughness::build_pipelines(VulkanEngine* engine)
{
	VkShaderModule meshFragShader;
	if (!vkutil::load_shader_module("../../shaders/mesh.frag.spv", engine->_device, &meshFragShader)) {
		fmt::println("Error when building the triangle fragment shader module");
	}

	VkShaderModule meshVertexShader;
	if (!vkutil::load_shader_module("../../shaders/mesh.vert.spv", engine->_device, &meshVertexShader)) {
		fmt::println("Error when building the triangle vertex shader module");
	}

	VkPushConstantRange matrixRange{};
	matrixRange.offset = 0;
	matrixRange.size = sizeof(GPUDrawPushConstants);
	matrixRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;

    DescriptorLayoutBuilder layoutBuilder;
    layoutBuilder.add_binding(0,VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
    layoutBuilder.add_binding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
	layoutBuilder.add_binding(2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);

    materialLayout = layoutBuilder.build(engine->_device, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);

	VkDescriptorSetLayout layouts[] = { engine->_gpuSceneDataDescriptorLayout,
        materialLayout };

	VkPipelineLayoutCreateInfo mesh_layout_info = vkinit::pipeline_layout_create_info();
	mesh_layout_info.setLayoutCount = 2;
	mesh_layout_info.pSetLayouts = layouts;
	mesh_layout_info.pPushConstantRanges = &matrixRange;
	mesh_layout_info.pushConstantRangeCount = 1;

	VkPipelineLayout newLayout;
	VK_CHECK(vkCreatePipelineLayout(engine->_device, &mesh_layout_info, nullptr, &newLayout));

    opaquePipeline.layout = newLayout;
    transparentPipeline.layout = newLayout;

	// build the stage-create-info for both vertex and fragment stages. This lets
	// the pipeline know the shader modules per stage
	PipelineBuilder pipelineBuilder;
	pipelineBuilder.set_shaders(meshVertexShader, meshFragShader);
	pipelineBuilder.set_input_topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
	pipelineBuilder.set_polygon_mode(VK_POLYGON_MODE_FILL);
	pipelineBuilder.set_cull_mode(VK_CULL_MODE_NONE, VK_FRONT_FACE_CLOCKWISE);
	pipelineBuilder.set_multisampling_none();
	pipelineBuilder.disable_blending();
	pipelineBuilder.enable_depthtest(true, VK_COMPARE_OP_GREATER_OR_EQUAL);

	//render format
	pipelineBuilder.set_color_attachment_format(engine->_drawImage.imageFormat);
	pipelineBuilder.set_depth_format(engine->_depthImage.imageFormat);

	// use the triangle layout we created
	pipelineBuilder._pipelineLayout = newLayout;

	// finally build the pipeline
    opaquePipeline.pipeline = pipelineBuilder.build_pipeline(engine->_device);

	// create the transparent variant
	pipelineBuilder.enable_blending_additive();

	pipelineBuilder.enable_depthtest(false, VK_COMPARE_OP_GREATER_OR_EQUAL);

	transparentPipeline.pipeline = pipelineBuilder.build_pipeline(engine->_device);
	
	vkDestroyShaderModule(engine->_device, meshFragShader, nullptr);
	vkDestroyShaderModule(engine->_device, meshVertexShader, nullptr);
}

build_pipelines๋Š” VulkanEngine์—์„œ์˜ init_pipelines ํ•จ์ˆ˜์™€ ์œ ์‚ฌํ•œ ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. ํ”„๋ž˜๊ทธ๋จผํŠธ์™€ ์ •์  ์…ฐ์ด๋”๋ฅผ ๋ถˆ๋Ÿฌ์™€ ํŒŒ์ดํ”„๋ผ์ธ์œผ๋กœ ์ปดํŒŒ์ผํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์—์„œ ํŒŒ์ดํ”„๋ผ์ธ ๋ ˆ์ด์•„์›ƒ๋„ ์ƒ์„ฑํ•˜๋ฉฐ, ๋™์ผํ•œ PipelineBuilder๋ฅผ ์‚ฌ์šฉํ•ด 2๊ฐœ์˜ ํŒŒ์ดํ”„๋ผ์ธ์„ ์ƒ์„ฑํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋จผ์ € ๋ถˆํˆฌ๋ช… ๋ Œ๋”๋ง์„ ์œ„ํ•œ ํŒŒ์ดํ”„๋ผ์ธ์„ ์ƒ์„ฑํ•˜๊ณ , ๊ทธํ›„ ๋ธ”๋ Œ๋”ฉ์„ ํ™œ์„ฑํ™”ํ•˜์—ฌ ํˆฌ๋ช… ๋ Œ๋”๋ง์„ ์œ„ํ•œ ํŒŒ์ดํ”„๋ผ์ธ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ํŒŒ์ดํ”„๋ผ์ธ์„ ๋ชจ๋‘ ์ƒ์„ฑํ•œ ํ›„์—๋Š” ์…ฐ์ด๋” ๋ชจ๋“ˆ์„ ํŒŒ๊ดดํ•ด๋„ ๋ฌธ์ œ์—†์Šต๋‹ˆ๋‹ค.

2๊ฐœ์˜ ์ƒˆ๋กœ์šด ์…ฐ์ด๋”๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์— ํ•ด๋‹น ์…ฐ์ด๋”๋“ค์˜ ์ฝ”๋“œ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ๋ถ€ํ„ฐ๋Š” ๋จธํ…Œ๋ฆฌ์–ผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ Œ๋”๋ง์„ ์ˆ˜ํ–‰ํ•  ๊ฒƒ์ด๋ฏ€๋กœ, ๊ธฐ์กด ์…ฐ์ด๋” ๋Œ€์‹  ์™„์ „ํžˆ ์ƒˆ๋กœ์šด ์…ฐ์ด๋”๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ ์ด๋ฒˆ์—๋Š” ์…ฐ์ด๋” ์ฝ”๋“œ์— #include ์ง€์‹œ๋ฌธ์„ ์‚ฌ์šฉํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. ๋™์ผํ•œ ์ž…๋ ฅ ๊ตฌ์กฐ๊ฐ€ ์ •์  ์…ฐ์ด๋”์™€ ํ”„๋ž˜๊ทธ๋จผํŠธ ์…ฐ์ด๋” ์–‘์ชฝ ๋ชจ๋‘์—์„œ ์‚ฌ์šฉ๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

input_structures.glsl์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

layout(set = 0, binding = 0) uniform  SceneData{   

	mat4 view;
	mat4 proj;
	mat4 viewproj;
	vec4 ambientColor;
	vec4 sunlightDirection; //w for sun power
	vec4 sunlightColor;
} sceneData;

layout(set = 1, binding = 0) uniform GLTFMaterialData{   

	vec4 colorFactors;
	vec4 metal_rough_factors;
	
} materialData;

layout(set = 1, binding = 1) uniform sampler2D colorTex;
layout(set = 1, binding = 2) uniform sampler2D metalRoughTex;

์”ฌ ๋ฐ์ดํ„ฐ์šฉ ์œ ๋‹ˆํผ์ด ํ•˜๋‚˜ ์žˆ์œผ๋ฉฐ, ๋ทฐ ํ–‰๋ ฌ๊ณผ ๋ช‡ ๊ฐ€์ง€ ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ์ด ์œ ๋‹ˆํผ์€ ์ „์—ญ ๋””์Šคํฌ๋ฆฝํ„ฐ ์…‹์œผ๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

๊ทธํ›„ ๋จธํ…Œ๋ฆฌ์–ผ์„ ์œ„ํ•œ ๋””์Šคํฌ๋ฆฝํ„ฐ ์…‹(set 1)์—๋Š” ์ด 3๊ฐœ์˜ ๋ฐ”์ธ๋”ฉ์ด ์žˆ์œผ๋ฉฐ, ๊ฐ๊ฐ ๋จธํ…Œ๋ฆฌ์–ผ ์ƒ์ˆ˜๋ฅผ ์œ„ํ•œ ์œ ๋‹ˆํผ ํ•˜๋‚˜์™€ ํ…์Šค์ณ ๋‘ ๊ฐœ๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค.

mesh.vert๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

#version 450

#extension GL_GOOGLE_include_directive : require
#extension GL_EXT_buffer_reference : require

#include "input_structures.glsl"

layout (location = 0) out vec3 outNormal;
layout (location = 1) out vec3 outColor;
layout (location = 2) out vec2 outUV;

struct Vertex {

	vec3 position;
	float uv_x;
	vec3 normal;
	float uv_y;
	vec4 color;
}; 

layout(buffer_reference, std430) readonly buffer VertexBuffer{ 
	Vertex vertices[];
};

//push constants block
layout( push_constant ) uniform constants
{
	mat4 render_matrix;
	VertexBuffer vertexBuffer;
} PushConstants;

void main() 
{
	Vertex v = PushConstants.vertexBuffer.vertices[gl_VertexIndex];
	
	vec4 position = vec4(v.position, 1.0f);

	gl_Position =  sceneData.viewproj * PushConstants.render_matrix *position;

	outNormal = (PushConstants.render_matrix * vec4(v.normal, 0.f)).xyz;
	outColor = v.color.xyz * materialData.colorFactors.xyz;	
	outUV.x = v.uv_x;
	outUV.y = v.uv_y;
}

์ด์ „๊ณผ ๋™์ผํ•œ ์ •์  ์ฒ˜๋ฆฌ ๋กœ์ง์„ ์‚ฌ์šฉํ•˜์ง€๋งŒ, ์ด๋ฒˆ์—๋Š” ์œ„์น˜๋ฅผ ๊ณ„์‚ฐํ•  ๋•Œ ํ–‰๋ ฌ์„ ๊ณฑํ•ด์ค๋‹ˆ๋‹ค. ๋˜ํ•œ ์ •์  ์ƒ‰์ƒ๊ณผ UV๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฒ•์„ ์˜ ๊ฒฝ์šฐ ์นด๋ฉ”๋ผ ํ–‰๋ ฌ์€ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  render_matrix๋งŒ ๊ณฑํ•ฉ๋‹ˆ๋‹ค.

mesh.frag๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

#version 450

#extension GL_GOOGLE_include_directive : require
#include "input_structures.glsl"

layout (location = 0) in vec3 inNormal;
layout (location = 1) in vec3 inColor;
layout (location = 2) in vec2 inUV;

layout (location = 0) out vec4 outFragColor;

void main() 
{
	float lightValue = max(dot(inNormal, sceneData.sunlightDirection.xyz), 0.1f);

	vec3 color = inColor * texture(colorTex,inUV).xyz;
	vec3 ambient = color *  sceneData.ambientColor.xyz;

	outFragColor = vec4(color * lightValue *  sceneData.sunlightColor.w + ambient ,1.0f);
}

์—ฌ๊ธฐ์„œ ๋งค์šฐ ๊ธฐ๋ณธ์ ์ธ ์กฐ๋ช… ์…ฐ์ด๋”๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ฉ”์‹œ๋ฅผ ์กฐ๊ธˆ ๋” ๋‚˜์€ ๋ฐฉ์‹์œผ๋กœ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ •์  ์ƒ‰์ƒ๊ณผ ํ…์Šค์ณ๋ฅผ ๊ณฑํ•ด ํ‘œ๋ฉด ์ƒ‰์„ ๊ณ„์‚ฐํ•œ ๋’ค, ํ•˜๋‚˜์˜ ํƒœ์–‘๊ด‘๊ณผ ํ™˜๊ฒฝ๊ด‘๋งŒ์„ ์‚ฌ์šฉํ•˜๋Š” ๋‹จ์ˆœํ•œ ์กฐ๋ช… ๋ชจ๋ธ์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ด ๋ฐฉ์‹์€ ์˜ค๋ž˜๋œ ๊ฒŒ์ž„์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋Š” ์ข…๋ฅ˜์˜ ์กฐ๋ช… ๋ชจ๋ธ๋กœ, ํ•˜๋‚˜์˜ ํ•˜๋“œ์ฝ”๋”ฉ๋œ ์กฐ๋ช…๊ณผ ์•„์ฃผ ๋‹จ์ˆœํ•œ ๊ณฑ์…ˆ ๊ธฐ๋ฐ˜ ์กฐ๋ช… ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋‚˜์ค‘์— ๊ฐœ์„ ํ•  ์˜ˆ์ •์ด์ง€๋งŒ, ํ˜„์žฌ๋Š” ๋จธํ…Œ๋ฆฌ์–ผ์„ ์ข€ ๋” ์ž˜ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•œ ์ตœ์†Œํ•œ์˜ ์กฐ๋ช… ๊ณ„์‚ฐ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์ด์ œ GLTFMetallic_Roughness๋กœ ๋Œ์•„๊ฐ€ ๋””์Šคํฌ๋ฆฝํ„ฐ ์…‹์„ ์ƒ์„ฑํ•˜๊ณ  ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์„ค์ •ํ•˜๋Š” write_material ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•ด๋ด…์‹œ๋‹ค.

MaterialInstance GLTFMetallic_Roughness::write_material(VkDevice device, MaterialPass pass, const MaterialResources& resources, DescriptorAllocatorGrowable& descriptorAllocator)
{
	MaterialInstance matData;
	matData.passType = pass;
	if (pass == MaterialPass::Transparent) {
		matData.pipeline = &transparentPipeline;
	}
	else {
		matData.pipeline = &opaquePipeline;
	}

	matData.materialSet = descriptorAllocator.allocate(device, materialLayout);


	writer.clear();
	writer.write_buffer(0, resources.dataBuffer, sizeof(MaterialConstants), resources.dataBufferOffset, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
	writer.write_image(1, resources.colorImage.imageView, resources.colorSampler, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
	writer.write_image(2, resources.metalRoughImage.imageView, resources.metalRoughSampler, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);

	writer.update_set(device, matData.materialSet);

	return matData;
}

materaiPass์— ๋”ฐ๋ผ ํˆฌ๋ช…๊ณผ ๋ถˆํˆฌ๋ช… ํŒŒ์ดํ”„๋ผ์ธ ์ค‘ ์„ ํƒํ•œ ํ›„, ๋””์Šคํฌ๋ฆฝํ„ฐ ์…‹์„ ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค. ์ดํ›„ MaterialResource์— ์žˆ๋Š” ์ด๋ฏธ์ง€์™€ ๋ฒ„ํผ๋ฅผ ์‚ฌ์šฉํ•ด ๋””์Šคํฌ๋ฆฝํ„ฐ ์…‹์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

์ด์ œ ์—”์ง„์˜ ๋กœ๋”ฉ ์‹œํ€€์Šค๋ฅผ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋ณธ ๋จธํ…Œ๋ฆฌ์–ผ์„ ์ƒ์„ฑํ•ฉ์‹œ๋‹ค.

๋จผ์ € VulkanEngine์— ๋จธํ…Œ๋ฆฌ์–ผ ๊ตฌ์กฐ์ฒด๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•  MaterialInstance ๊ตฌ์กฐ์ฒด๋„ ์ •์˜ํ•ฉ์‹œ๋‹ค.

MaterialInstance defaultData;
GLTFMetallic_Roughness metalRoughMaterial;

init_pipelines() ํ•จ์ˆ˜์˜ ๋งˆ์ง€๋ง‰์—์„œ ๋จธํ…Œ๋ฆฌ์–ผ ๊ตฌ์กฐ์ฒด์— ๋Œ€ํ•ด build_pipelinesํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํŒŒ์ดํ”„๋ผ์ธ์„ ์ปดํŒŒ์ผํ•ฉ๋‹ˆ๋‹ค.

void VulkanEngine::init_pipelines()
{
	//rest of initializing functions

    metalRoughMaterial.build_pipelines(this);
}

์ด์ œ init_default_data()ํ•จ์ˆ˜์˜ ๋งˆ์ง€๋ง‰์—์„œ, ์•ž์„œ ๋งŒ๋“  ๊ธฐ๋ณธ ํ…์Šค์ณ๋“ค์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ธฐ๋ณธ MaterialInstance ๊ตฌ์กฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์”ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์œ„ํ•œ ์ž„์‹œ ๋ฒ„ํผ์—์„œ ํ–ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ, ๋ฒ„ํผ๋ฅผ ํ• ๋‹นํ•œ ํ›„ ์‚ญ์ œ ํ์— ๋“ฑ๋กํ•  ๊ฒƒ์ธ๋ฐ, ์ด๋ฒˆ์—๋Š” ์ „์—ญ ์‚ญ์ œ ํ์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ๋จธํ…Œ๋ฆฌ์–ผ ์ƒ์ˆ˜ ๋ฒ„ํผ๋Š” ์ƒ์„ฑ ์ดํ›„์—๋Š” ๋” ์ด์ƒ ์ ‘๊ทผํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

	GLTFMetallic_Roughness::MaterialResources materialResources;
	//default the material textures
	materialResources.colorImage = _whiteImage;
	materialResources.colorSampler = _defaultSamplerLinear;
	materialResources.metalRoughImage = _whiteImage;
	materialResources.metalRoughSampler = _defaultSamplerLinear;

	//set the uniform buffer for the material data
	AllocatedBuffer materialConstants = create_buffer(sizeof(GLTFMetallic_Roughness::MaterialConstants), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU);

	//write the buffer
	GLTFMetallic_Roughness::MaterialConstants* sceneUniformData = (GLTFMetallic_Roughness::MaterialConstants*)materialConstants.allocation->GetMappedData();
	sceneUniformData->colorFactors = glm::vec4{1,1,1,1};
	sceneUniformData->metal_rough_factors = glm::vec4{1,0.5,0,0};

	_mainDeletionQueue.push_function([=, this]() {
		destroy_buffer(materialConstants);
	});

	materialResources.dataBuffer = materialConstants.buffer;
	materialResources.dataBufferOffset = 0;

	defaultData = metalRoughMaterial.write_material(_device,MaterialPass::MainColor,materialResources, globalDescriptorAllocator);

MaterialResources์— ์žˆ๋Š” ๋จธํ…Œ๋ฆฌ์–ผ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๊ธฐ๋ณธ ํฐ์ƒ‰ ์ด๋ฏธ์ง€๋กœ ์ฑ„์šธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ดํ›„ ๋จธํ…Œ๋ฆฌ์–ผ ์ƒ‰์ƒ์„ ์ €์žฅํ•  ๋ฒ„ํผ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์‚ญ์ œ ํ์— ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ write_material ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋””์Šคํฌ๋ฆฝํ„ฐ ์…‹์„ ์ƒ์„ฑํ•˜๊ณ , ๊ธฐ๋ณธ ๋จธํ…Œ๋ฆฌ์–ผ์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.

Next: Meshes and Camera