使用CMake重构VS2022项目时无法读取.glsl文件求助
解决CMake项目中GLSL着色器文件找不到的问题
问题根源在于:程序运行时会从当前工作目录查找vShader.glsl和fShader.glsl,但这些文件实际存放在EngineLibray/Graphics/Shader目录下,编译过程中不会自动拷贝到可执行文件的输出目录,导致运行时找不到文件。以下是三种可行的解决方案:
方案1:将GLSL文件自动复制到可执行文件输出目录
修改Shader模块的CMakeLists.txt,添加文件拷贝逻辑,编译时自动将着色器文件同步到可执行文件的输出目录:
# 定义着色器文件路径 set(SHADER_FILES "${CMAKE_CURRENT_SOURCE_DIR}/vShader.glsl" "${CMAKE_CURRENT_SOURCE_DIR}/fShader.glsl" ) # 将着色器文件复制到可执行文件输出目录 foreach(SHADER ${SHADER_FILES}) get_filename_component(SHADER_NAME ${SHADER} NAME) configure_file(${SHADER} "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${SHADER_NAME}" COPYONLY) endforeach() # 原有Shader库定义代码保持不变 set(LIBRARY_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/include/Shader.h") set(LIBRARY_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/src/Shader.cpp") add_library(Shader STATIC ${LIBRARY_HEADER} ${LIBRARY_SOURCE} ) target_include_directories(Shader PUBLIC include/ PRIVATE src/ ) target_link_libraries(Shader PRIVATE ExternalLibs)
这种方式适合需要随时修改着色器文件、无需重新编译程序的场景。
方案2:通过CMake传递绝对路径加载着色器
直接在代码中使用着色器文件的绝对路径,避免文件拷贝操作:
- 修改
Shader模块的CMakeLists.txt,通过编译宏传递文件绝对路径:
set(LIBRARY_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/include/Shader.h") set(LIBRARY_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/src/Shader.cpp") add_library(Shader STATIC ${LIBRARY_HEADER} ${LIBRARY_SOURCE} ) # 传递着色器文件的绝对路径给代码 target_compile_definitions(Shader PRIVATE VSHADER_PATH="${CMAKE_CURRENT_SOURCE_DIR}/vShader.glsl" FSHADER_PATH="${CMAKE_CURRENT_SOURCE_DIR}/fShader.glsl" ) target_include_directories(Shader PUBLIC include/ PRIVATE src/ ) target_link_libraries(Shader PRIVATE ExternalLibs)
- 修改
Renderer.cpp中的代码,使用编译宏定义的路径:
const char* Render::VertShader() { return VSHADER_PATH; } const char* Render::FragShader() { return FSHADER_PATH; } void Render::CreateShader() { pShader = new Shader(); pShader->CreateFromFile(VertShader(), FragShader()); ShaderList.push_back(pShader); }
这种方式无需拷贝文件,直接引用源文件路径,适合不需要动态修改着色器的场景。
方案3:将GLSL文件嵌入到二进制文件中
把着色器内容编译为C++字符串,直接嵌入到静态库/可执行文件中,消除外部文件依赖:
- 修改
Shader模块的CMakeLists.txt,添加自定义命令生成包含着色器内容的头文件:
# 自定义函数:将GLSL文件转换为C++字符串头文件 function(compile_shader SHADER_FILE OUTPUT_VAR) file(READ ${SHADER_FILE} SHADER_CONTENTS) # 转义字符串中的特殊字符 string(REPLACE "\"" "\\\"" SHADER_CONTENTS "${SHADER_CONTENTS}") string(REPLACE "\n" "\\n\"\n\"" SHADER_CONTENTS "${SHADER_CONTENTS}") # 生成头文件内容 set(SHADER_HEADER "static const char* ${OUTPUT_VAR} = \"${SHADER_CONTENTS}\";") file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_VAR}.h" "${SHADER_HEADER}") endfunction() # 生成两个着色器的头文件 compile_shader("${CMAKE_CURRENT_SOURCE_DIR}/vShader.glsl" VERT_SHADER_SRC) compile_shader("${CMAKE_CURRENT_SOURCE_DIR}/fShader.glsl" FRAG_SHADER_SRC) # 原有Shader库定义代码 set(LIBRARY_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/include/Shader.h") set(LIBRARY_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/src/Shader.cpp") add_library(Shader STATIC ${LIBRARY_HEADER} ${LIBRARY_SOURCE} ) # 添加生成头文件的目录到包含路径 target_include_directories(Shader PUBLIC include/ PRIVATE src/ ${CMAKE_CURRENT_BINARY_DIR} ) target_link_libraries(Shader PRIVATE ExternalLibs)
- 修改
Renderer.cpp,直接使用生成的字符串(需同步修改Shader类的接口,新增接受字符串的创建方法,比如CreateFromString):
#include "VERT_SHADER_SRC.h" #include "FRAG_SHADER_SRC.h" const char* Render::VertShaderSource() { return VERT_SHADER_SRC; } const char* Render::FragShaderSource() { return FRAG_SHADER_SRC; } void Render::CreateShader() { pShader = new Shader(); pShader->CreateFromString(VertShaderSource(), FragShaderSource()); ShaderList.push_back(pShader); }
这种方式适合需要完全消除外部文件依赖的场景,程序发布时无需携带着色器文件。
内容的提问来源于stack exchange,提问作者GloriousDemonFist
相关产品推荐
相关产品推荐

