怎样查看网站建设时间,做文献的ppt模板下载网站,怎样做网站推广啊,公司互联网站全面改版上一篇#xff1a;纹理系统 | 下一篇#xff1a;几何体系统 | 返回目录 #x1f4da; 快速导航 #x1f4cb; 目录
引言学习目标材质系统概念材质数据结构材质配置文件材质系统架构材质加载流程配置文件解析字符串工具扩展渲染器集成使用示例常见问题练习与挑战下一步 纹理系统 | 下一篇几何体系统 | 返回目录 快速导航 目录引言学习目标材质系统概念材质数据结构材质配置文件材质系统架构材质加载流程配置文件解析字符串工具扩展渲染器集成使用示例常见问题练习与挑战下一步 引言在上一个教程中我们实现了纹理系统能够高效地管理纹理资源。但是在真实的3D渲染中物体的外观不仅仅由纹理决定还包括颜色、光泽度、金属度等多种属性。这些属性的集合称为材质Material。目前我们的渲染代码直接使用纹理和颜色这导致硬编码问题- 颜色和纹理在代码中写死无法复用- 相同外观的物体需要重复设置难以调整- 修改外观需要重新编译缺乏组织- 大量属性散落在各处材质系统解决了这些问题。它允许我们在配置文件中定义材质复用材质到多个对象运行时加载和切换材质统一管理渲染属性 学习目标目标描述 理解材质概念掌握材质在渲染管线中的作用 设计配置格式创建可读的材质配置文件 实现材质系统使用与纹理系统相同的模式 解析配置文件从文本文件加载材质属性 集成到渲染器将材质连接到着色器材质系统概念什么是材质材质定义了物体表面的视觉属性材质 颜色 纹理 光照属性 ... 示例1木头材质 - 漫反射颜色: (0.6, 0.4, 0.2) - 漫反射贴图: wood_diffuse.png - 法线贴图: wood_normal.png - 粗糙度: 0.8 - 金属度: 0.0 示例2金属材质 - 漫反射颜色: (0.9, 0.9, 0.9) - 金属度: 1.0 - 粗糙度: 0.2材质 vs 纹理纹理Texture ┌───────────┐ │ 图像数据 │ 单纯的像素信息 │ 512x512 │ └───────────┘ 材质Material ┌─────────────────────────┐ │ 漫反射颜色: vec4(1,1,1,1) │ │ 漫反射贴图: Texture* │ 属性的集合 │ 法线贴图: Texture* │ │ 金属度: 0.5 │ └─────────────────────────┘材质系统流程acquire材质查找哈希表是否release材质游戏代码材质系统已加载?增加引用计数读取.kmt文件解析配置获取纹理创建材质返回材质指针渲染对象减少引用计数材质数据结构纹理用途枚举首先定义纹理在材质中的用途engine/src/resources/resource_types.h/** * brief 纹理在材质中的用途 */typedefenumtexture_use{TEXTURE_USE_UNKNOWN0x00,// 未知用途TEXTURE_USE_MAP_DIFFUSE0x01// 漫反射贴图// 未来可扩展:// TEXTURE_USE_MAP_NORMAL 0x02// TEXTURE_USE_MAP_SPECULAR 0x04// TEXTURE_USE_MAP_ROUGHNESS 0x08}texture_use;纹理映射结构/** * brief 纹理映射将纹理与用途关联 */typedefstructtexture_map{texture*texture;// 纹理指针texture_use use;// 用途标志}texture_map;材质结构#defineMATERIAL_NAME_MAX_LENGTH256/** * brief 材质定义物体表面的视觉属性 */typedefstructmaterial{u32 id;// 材质IDu32 generation;// 版本号用于热重载u32 internal_id;// 渲染器内部IDcharname[MATERIAL_NAME_MAX_LENGTH];// 材质名称vec4 diffuse_colour;// 漫反射颜色texture_map diffuse_map;// 漫反射贴图// TODO: 未来扩展// texture_map normal_map;// texture_map specular_map;// f32 shininess;// f32 metalness;}material;纹理结构更新为纹理添加名称字段方便材质系统引用#defineTEXTURE_NAME_MAX_LENGTH512typedefstructtexture{u32 id;u32 width;u32 height;u8 channel_count;b8 has_transparency;u32 generation;charname[TEXTURE_NAME_MAX_LENGTH];// 新增纹理名称void*internal_data;}texture;数据结构关系material test_material ├─ diffuse_colour: (1.0, 1.0, 1.0, 1.0) └─ diffuse_map ├─ use: TEXTURE_USE_MAP_DIFFUSE └─ texture → texture paving ├─ width: 1024 ├─ height: 1024 ├─ name: paving └─ internal_data → vulkan_texture_data 材质配置文件材质配置使用.kmt(Kohi Material) 格式。文件格式# 这是注释 version0.1 name材质名称 diffuse_colourR G B A diffuse_map_name纹理名称示例配置文件assets/materials/test_material.kmt#material file version0.1 nametest_material diffuse_colour1.0 1.0 1.0 1.0 diffuse_map_namepaving配置字段说明字段类型说明示例version字符串配置文件版本0.1name字符串材质唯一名称test_materialdiffuse_colourvec4漫反射颜色(RGBA)1.0 1.0 1.0 1.0diffuse_map_name字符串漫反射贴图名称paving配置文件示例木头材质# assets/materials/wood.kmt version0.1 namewood diffuse_colour0.6 0.4 0.2 1.0 diffuse_map_namewood_diffuse金属材质# assets/materials/metal.kmt version0.1 namemetal diffuse_colour0.8 0.8 0.8 1.0 diffuse_map_namemetal_diffuse无纹理材质纯色# assets/materials/red.kmt version0.1 namered diffuse_colour1.0 0.0 0.0 1.0 # diffuse_map_name留空使用默认纹理材质系统架构材质系统的设计几乎完全复用了纹理系统的模式。系统状态engine/src/systems/material_system.c/** * brief 材质引用信息 */typedefstructmaterial_reference{u64 reference_count;// 引用计数u32 handle;// 材质数组中的索引b8 auto_release;// 是否自动释放}material_reference;/** * brief 材质系统状态 */typedefstructmaterial_system_state{material_system_config config;// 配置material default_material;// 默认材质// 已注册材质数组material*registered_materials;// 哈希表用于快速查找hashtable registered_material_table;}material_system_state;staticmaterial_system_state*state_ptr0;配置结构engine/src/systems/material_system.h#pragmaonce#includedefines.h#includeresources/resource_types.h#defineDEFAULT_MATERIAL_NAMEdefault/** * brief 材质系统配置 */typedefstructmaterial_system_config{u32 max_material_count;// 最大材质数量}material_system_config;/** * brief 材质配置从文件加载 */typedefstructmaterial_config{charname[MATERIAL_NAME_MAX_LENGTH];b8 auto_release;vec4 diffuse_colour;chardiffuse_map_name[TEXTURE_NAME_MAX_LENGTH];}material_config;// 系统函数b8material_system_initialize(u64*memory_requirement,void*state,material_system_config config);voidmaterial_system_shutdown(void*state);// 材质操作material*material_system_acquire(constchar*name);material*material_system_acquire_from_config(material_config config);voidmaterial_system_release(constchar*name);系统内存布局Material System内存布局 ┌────────────────────────────────────────┐ │ material_system_state (结构体) │ ├────────────────────────────────────────┤ │ registered_materials[4096] (数组) │ │ - material 0 │ │ - material 1 │ │ - ... │ │ - material 4095 │ ├────────────────────────────────────────┤ │ hashtable memory (哈希表数据) │ │ - material_reference[4096] │ └────────────────────────────────────────┘材质加载流程系统初始化b8material_system_initialize(u64*memory_requirement,void*state,material_system_config config){if(config.max_material_count0){KFATAL(material_system_initialize - config.max_material_count must be 0.);returnfalse;}// 计算内存需求u64 struct_requirementsizeof(material_system_state);u64 array_requirementsizeof(material)*config.max_material_count;u64 hashtable_requirementsizeof(material_reference)*config.max_material_count;*memory_requirementstruct_requirementarray_requirementhashtable_requirement;if(!state){returntrue;// 第一次调用返回内存需求}state_ptrstate;state_ptr-configconfig;// 设置数组指针void*array_blockstatestruct_requirement;state_ptr-registered_materialsarray_block;// 设置哈希表内存void*hashtable_blockarray_blockarray_requirement;// 创建哈希表hashtable_create(sizeof(material_reference),config.max_material_count,hashtable_block,false,state_ptr-registered_material_table);// 填充无效引用material_reference invalid_ref;invalid_ref.auto_releasefalse;invalid_ref.handleINVALID_ID;invalid_ref.reference_count0;hashtable_fill(state_ptr-registered_material_table,invalid_ref);// 初始化所有材质为无效u32 countstate_ptr-config.max_material_count;for(u32 i0;icount;i){state_ptr-registered_materials[i].idINVALID_ID;state_ptr-registered_materials[i].generationINVALID_ID;state_ptr-registered_materials[i].internal_idINVALID_ID;}// 创建默认材质if(!create_default_material(state_ptr)){KFATAL(Failed to create default material.);returnfalse;}returntrue;}材质获取从文件名/** * brief 从文件名获取材质 * param name 材质名称不含扩展名 * return 材质指针失败返回NULL */material*material_system_acquire(constchar*name){// 加载配置文件material_config config;char*format_strassets/materials/%s.%s;charfull_file_path[512];// TODO: 尝试不同扩展名string_format(full_file_path,format_str,name,kmt);if(!load_configuration_file(full_file_path,config)){KERROR(Failed to load material file: %s.,full_file_path);return0;}// 从配置获取材质returnmaterial_system_acquire_from_config(config);}材质获取从配置/** * brief 从配置获取材质 * param config 材质配置 * return 材质指针失败返回NULL */material*material_system_acquire_from_config(material_config config){// 特殊处理默认材质if(strings_equali(config.name,DEFAULT_MATERIAL_NAME)){returnstate_ptr-default_material;}material_reference ref;if(state_ptrhashtable_get(state_ptr-registered_material_table,config.name,ref)){// 首次加载时设置auto_releaseif(ref.reference_count0){ref.auto_releaseconfig.auto_release;}ref.reference_count;if(ref.handleINVALID_ID){// 材质不存在需要创建// 1. 查找空闲槽位u32 countstate_ptr-config.max_material_count;material*m0;for(u32 i0;icount;i){if(state_ptr-registered_materials[i].idINVALID_ID){ref.handlei;mstate_ptr-registered_materials[i];break;}}// 2. 确保找到空闲槽位if(!m||ref.handleINVALID_ID){KFATAL(material_system_acquire - No more material slots.);return0;}// 3. 加载材质if(!load_material(config,m)){KERROR(Failed to load material %s.,config.name);return0;}// 4. 设置generationif(m-generationINVALID_ID){m-generation0;}else{m-generation;}// 5. 设置IDm-idref.handle;KTRACE(Material %s created, ref_count%i.,config.name,ref.reference_count);}else{KTRACE(Material %s already exists, ref_count%i.,config.name,ref.reference_count);}// 更新哈希表hashtable_set(state_ptr-registered_material_table,config.name,ref);returnstate_ptr-registered_materials[ref.handle];}KERROR(material_system_acquire_from_config failed for %s.,config.name);return0;}材质释放/** * brief 释放材质 * param name 材质名称 */voidmaterial_system_release(constchar*name){// 忽略默认材质if(strings_equali(name,DEFAULT_MATERIAL_NAME)){return;}material_reference ref;if(state_ptrhashtable_get(state_ptr-registered_material_table,name,ref)){if(ref.reference_count0){KWARN(Tried to release non-existent material: %s,name);return;}ref.reference_count--;if(ref.reference_count0ref.auto_release){material*mstate_ptr-registered_materials[ref.handle];// 销毁材质destroy_material(m);// 重置引用ref.handleINVALID_ID;ref.auto_releasefalse;KTRACE(Released material %s. Unloaded (ref_count0, auto_releasetrue).,name);}else{KTRACE(Released material %s, ref_count%i (auto_release%s).,name,ref.reference_count,ref.auto_release?true:false);}// 更新哈希表hashtable_set(state_ptr-registered_material_table,name,ref);}else{KERROR(material_system_release failed for %s.,name);}}材质加载与销毁/** * brief 加载材质数据 */b8load_material(material_config config,material*m){kzero_memory(m,sizeof(material));// 复制名称string_ncopy(m-name,config.name,MATERIAL_NAME_MAX_LENGTH);// 设置漫反射颜色m-diffuse_colourconfig.diffuse_colour;// 加载漫反射贴图if(string_length(config.diffuse_map_name)0){m-diffuse_map.useTEXTURE_USE_MAP_DIFFUSE;m-diffuse_map.texturetexture_system_acquire(config.diffuse_map_name,true);if(!m-diffuse_map.texture){KWARN(Unable to load texture %s for material %s, using default.,config.diffuse_map_name,m-name);m-diffuse_map.texturetexture_system_get_default_texture();}}else{m-diffuse_map.useTEXTURE_USE_UNKNOWN;m-diffuse_map.texture0;}// TODO: 其他贴图法线、高光等// 请求渲染器资源if(!renderer_create_material(m)){KERROR(Failed to acquire renderer resources for material %s.,m-name);returnfalse;}returntrue;}/** * brief 销毁材质 */voiddestroy_material(material*m){KTRACE(Destroying material %s...,m-name);// 释放纹理引用if(m-diffuse_map.texture){texture_system_release(m-diffuse_map.texture-name);}// 释放渲染器资源renderer_destroy_material(m);// 清零并无效化kzero_memory(m,sizeof(material));m-idINVALID_ID;m-generationINVALID_ID;m-internal_idINVALID_ID;}默认材质b8create_default_material(material_system_state*state){kzero_memory(state-default_material,sizeof(material));state-default_material.idINVALID_ID;state-default_material.generationINVALID_ID;string_ncopy(state-default_material.name,DEFAULT_MATERIAL_NAME,MATERIAL_NAME_MAX_LENGTH);// 白色材质使用默认纹理state-default_material.diffuse_colourvec4_one();state-default_material.diffuse_map.useTEXTURE_USE_MAP_DIFFUSE;state-default_material.diffuse_map.texturetexture_system_get_default_texture();if(!renderer_create_material(state-default_material)){KFATAL(Failed to create default material.);returnfalse;}returntrue;}配置文件解析配置文件解析是材质系统的关键部分。解析流程是否是否否是打开文件读取一行文件结束?关闭文件去除空白空行或注释?查找符号找到?警告并跳过分割变量名和值去除两侧空白解析变量实现代码b8load_configuration_file(constchar*path,material_config*out_config){file_handle f;if(!filesystem_open(path,FILE_MODE_READ,false,f)){KERROR(Unable to open material file: %s.,path);returnfalse;}// 逐行读取charline_buf[512];char*pline_buf[0];u64 line_length0;u32 line_number1;while(filesystem_read_line(f,511,p,line_length)){// 去除空白char*trimmedstring_trim(line_buf);line_lengthstring_length(trimmed);// 跳过空行和注释if(line_length1||trimmed[0]#){line_number;continue;}// 查找 符号i32 equal_indexstring_index_of(trimmed,);if(equal_index-1){KWARN(Formatting issue in file %s line %ui: not found.,path,line_number);line_number;continue;}// 提取变量名最多64字符charraw_var_name[64];kzero_memory(raw_var_name,sizeof(char)*64);string_mid(raw_var_name,trimmed,0,equal_index);char*trimmed_var_namestring_trim(raw_var_name);// 提取值最多446字符charraw_value[446];kzero_memory(raw_value,sizeof(char)*446);string_mid(raw_value,trimmed,equal_index1,-1);// 读取剩余部分char*trimmed_valuestring_trim(raw_value);// 解析变量if(strings_equali(trimmed_var_name,version)){// TODO: 版本检查}elseif(strings_equali(trimmed_var_name,name)){string_ncopy(out_config-name,trimmed_value,MATERIAL_NAME_MAX_LENGTH);}elseif(strings_equali(trimmed_var_name,diffuse_map_name)){string_ncopy(out_config-diffuse_map_name,trimmed_value,TEXTURE_NAME_MAX_LENGTH);}elseif(strings_equali(trimmed_var_name,diffuse_colour)){// 解析颜色if(!string_to_vec4(trimmed_value,out_config-diffuse_colour)){KWARN(Error parsing diffuse_colour in %s. Using white.,path);out_config-diffuse_colourvec4_one();}}// TODO: 更多字段// 清空行缓冲区kzero_memory(line_buf,sizeof(char)*512);line_number;}filesystem_close(f);returntrue;}解析示例输入文件内容 nametest_material diffuse_colour1.0 1.0 1.0 1.0 解析过程 1. 读取 nametest_material - trimmed nametest_material - equal_index 4 - var_name name - value test_material - config.name test_material 2. 读取 diffuse_colour1.0 1.0 1.0 1.0 - var_name diffuse_colour - value 1.0 1.0 1.0 1.0 - string_to_vec4(1.0 1.0 1.0 1.0) - config.diffuse_colour vec4(1, 1, 1, 1)字符串工具扩展材质系统需要一些新的字符串操作函数。string_to_vec4engine/src/core/kstring.h/** * brief 将字符串解析为vec4 * param str 格式x y z w * param out_vector 输出向量 * return 成功返回true */KAPI b8string_to_vec4(constchar*str,vec4*out_vector);engine/src/core/kstring.cb8string_to_vec4(constchar*str,vec4*out_vector){if(!str||!out_vector){returnfalse;}kzero_memory(out_vector,sizeof(vec4));// 使用sscanf解析i32 resultsscanf(str,%f %f %f %f,out_vector-x,out_vector-y,out_vector-z,out_vector-w);returnresult4;}其他字符串函数// 获取子字符串KAPIvoidstring_mid(char*dest,constchar*source,i32 start,i32 length);// 字符串去除空白KAPIchar*string_trim(char*str);// 查找字符位置KAPI i32string_index_of(constchar*str,charc);这些函数的实现细节请参考源代码。 渲染器集成渲染器接口更新engine/src/renderer/renderer_frontend.h// 材质操作b8renderer_create_material(structmaterial*material);voidrenderer_destroy_material(structmaterial*material);engine/src/renderer/renderer_frontend.cb8renderer_create_material(structmaterial*material){returnstate_ptr-backend.create_material(material);}voidrenderer_destroy_material(structmaterial*material){state_ptr-backend.destroy_material(material);}Vulkan后端实现材质的internal_id用于索引Vulkan着色器的对象状态engine/src/renderer/vulkan/vulkan_backend.cb8vulkan_renderer_create_material(material*material){// 为材质获取着色器资源u32 object_id0;if(!vulkan_material_shader_acquire_resources(context,context.material_shader,object_id)){KERROR(Failed to acquire shader resources for material %s.,material-name);returnfalse;}material-internal_idobject_id;returntrue;}voidvulkan_renderer_destroy_material(material*material){// 释放着色器资源if(material-internal_id!INVALID_ID){vulkan_material_shader_release_resources(context,context.material_shader,material-internal_id);material-internal_idINVALID_ID;}}使用材质渲染更新渲染调用以使用材质// 旧代码直接使用纹理geometry_render_data data{};data.object_id0;data.textures[0]some_texture;// 新代码使用材质geometry_render_data data{};data.materialmy_material;data.modeltransform_matrix;材质着色器会从材质中提取颜色和纹理voidvulkan_material_shader_use(...){// 从材质获取颜色vec4 diffusematerial-diffuse_colour;// 从材质获取纹理texture*diffuse_texmaterial-diffuse_map.texture;// 更新uniform和描述符...}使用示例示例1加载并使用材质voidsetup_scene(){// 获取材质material*wood_matmaterial_system_acquire(wood);material*metal_matmaterial_system_acquire(metal);// 创建使用材质的对象create_cube(wood_mat);create_sphere(metal_mat);}voidrender_object(object*obj){geometry_render_data data{};data.materialobj-material;data.modelobj-transform;renderer_draw_geometry(data);}voidcleanup_scene(){// 释放材质material_system_release(wood);material_system_release(metal);}示例2程序化创建材质voidcreate_custom_material(){material_config config{};string_ncopy(config.name,custom_red,MATERIAL_NAME_MAX_LENGTH);config.auto_releasetrue;config.diffuse_colourvec4_create(1.0f,0.0f,0.0f,1.0f);// 不设置diffuse_map_name使用默认纹理material*red_matmaterial_system_acquire_from_config(config);// 使用材质...material_system_release(custom_red);}示例3材质库typedefstructmaterial_library{material*wood;material*metal;material*stone;material*grass;}material_library;voidload_material_library(material_library*lib){lib-woodmaterial_system_acquire(wood);lib-metalmaterial_system_acquire(metal);lib-stonematerial_system_acquire(stone);lib-grassmaterial_system_acquire(grass);}voidunload_material_library(material_library*lib){material_system_release(wood);material_system_release(metal);material_system_release(stone);material_system_release(grass);}❓ 常见问题❓ 材质和纹理有什么区别纹理是原始的图像数据就像一张照片。材质是如何使用这些纹理和其他属性的集合纹理 数据 wood_diffuse.png (512x512图像) 材质 属性集合 - 颜色: (0.6, 0.4, 0.2) - 漫反射贴图: wood_diffuse.png - 法线贴图: wood_normal.png - 粗糙度: 0.8一个纹理可以被多个材质使用metal_diffuse.png 被使用于 - shiny_metal 材质 (粗糙度0.1) - rusty_metal 材质 (粗糙度0.7)❓ 为什么材质需要internal_idinternal_id是材质在渲染器中的资源IDmaterial{id5// 材质系统中的索引internal_id12// Vulkan着色器中的object_id}当材质被创建时renderer_create_material(material)→vulkan_material_shader_acquire_resources(...,object_id)→ material-internal_idobject_id渲染时使用internal_idrender(material)→vulkan_shader_use(material-internal_id)→ 使用descriptor_sets[internal_id]这样材质系统和渲染器可以独立管理各自的资源。❓ diffuse_map.use字段有什么用use字段标记纹理的用途为未来扩展预留material{diffuse_map.useTEXTURE_USE_MAP_DIFFUSE normal_map.useTEXTURE_USE_MAP_NORMAL specular_map.useTEXTURE_USE_MAP_SPECULAR}着色器可以根据use字段决定如何采样if(map.useTEXTURE_USE_MAP_DIFFUSE){// 漫反射采样colortexture(diffuse_sampler,uv);}elseif(map.useTEXTURE_USE_MAP_NORMAL){// 法线采样normaltexture(normal_sampler,uv).rgb*2.0-1.0;}❓ 如何支持多个漫反射贴图当前实现只支持一个漫反射贴图。要支持多个需要修改材质结构typedefstructmaterial{// ...texture_map diffuse_maps[4];// 数组u32 diffuse_map_count;}material;修改配置格式diffuse_map_name_0texture1 diffuse_map_name_1texture2修改着色器layout(set 1, binding 1) uniform sampler2D diffuse_samplers[4]; void main() { vec4 color vec4(0); for (int i 0; i diffuse_map_count; i) { color texture(diffuse_samplers[i], uv); } color / diffuse_map_count; }❓ .kmt格式可以扩展吗完全可以添加新属性很简单在material结构中添加字段typedefstructmaterial{// ...f32 metalness;f32 roughness;}material;在material_config中添加typedefstructmaterial_config{// ...f32 metalness;f32 roughness;}material_config;在解析器中处理elseif(strings_equali(var_name,metalness)){config-metalnessstring_to_f32(value);}更新配置文件metalness0.8 roughness0.2 练习与挑战练习1添加法线贴图支持扩展材质系统以支持法线贴图typedefstructmaterial{// ... 现有字段 ...texture_map normal_map;}material;配置文件normal_map_namewood_normal查看提示在material结构中添加texture_map normal_map在material_config中添加char normal_map_name[...]在load_configuration_file中解析normal_map_name在load_material中获取法线纹理更新着色器绑定法线贴图采样器练习2实现材质继承允许材质继承另一个材质的属性# metal_rusty.kmt basemetal diffuse_colour0.7 0.5 0.3 1.0查看提示在配置中添加base字段如果存在base先加载基础材质复制基础材质的所有属性到新材质用配置文件中的属性覆盖if(config.base_name[0]!\0){material*basematerial_system_acquire(config.base_name);*m*base;// 复制所有属性material_system_release(config.base_name);}// 然后应用配置覆盖m-diffuse_colourconfig.diffuse_colour;练习3材质编辑器创建一个简单的材质编辑器运行时修改材质voidmaterial_editor_update(material*mat,f32 delta_time){if(input_is_key_down(KEY_R))mat-diffuse_colour.rdelta_time;if(input_is_key_down(KEY_G))mat-diffuse_colour.gdelta_time;if(input_is_key_down(KEY_B))mat-diffuse_colour.bdelta_time;// 保存到文件if(input_was_key_pressed(KEY_S)){save_material_to_file(mat,modified.kmt);}}查看提示实现save_material_to_filevoidsave_material_to_file(material*mat,constchar*path){file_handle f;filesystem_open(path,FILE_MODE_WRITE,false,f);filesystem_write_line(f,version0.1\n);charline[512];string_format(line,name%s\n,mat-name);filesystem_write_line(f,line);string_format(line,diffuse_colour%f %f %f %f\n,mat-diffuse_colour.r,mat-diffuse_colour.g,mat-diffuse_colour.b,mat-diffuse_colour.a);filesystem_write_line(f,line);filesystem_close(f);} 下一步在本教程中我们实现了完整的材质系统✅ 材质数据结构颜色纹理映射✅ .kmt配置文件格式✅ 材质系统引用计数哈希表✅ 配置文件解析器✅ 与纹理系统和渲染器集成材质系统是渲染管线的核心组件。下一步我们可以几何体系统- 管理网格和顶点数据资源系统- 统一管理所有资源类型场景系统- 组织场景中的对象实体组件系统ECS- 更灵活的游戏对象架构结语恭喜你完成了本教程材质系统让我们可以用数据驱动的方式定义物体外观。通过复用纹理系统的设计模式我们快速实现了一个功能完整的材质系统。从简单的配置文件到复杂的引用计数每个部分都协同工作为游戏提供了灵活的材质管理能力。关键要点回顾材质是纹理和属性的集合.kmt格式提供了可读的配置方式引用计数自动管理材质生命周期材质系统与纹理系统紧密协作统一的接口简化了材质使用随着引擎的发展材质系统可以扩展支持PBR材质、程序化材质、材质动画等高级特性。如果你有任何问题或建议欢迎在GitHub上提出issue。关注公众号获取更多引擎开发资讯觉得有帮助请作者喝杯咖啡 作者: 上手实验室 项目地址: https://github.com/travisvroman/kohi上一篇纹理系统 | 下一篇几何体系统