You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用shaderc与SPIRV-Cross转换HLSL至GLSL时如何保持出入变量名一致?

HLSL转GLSL时顶点/片段着色器变量名不匹配的解决方法

问题背景

使用shaderc将HLSL编译为SPIR-V,再通过SPIRV-Cross转换为GLSL后,顶点着色器的输出变量名(如_entryPointOutput_texcoord)与片段着色器的输入变量名(如input_texcoord)不一致,导致OpenGL编译报错。

相关代码

C++转换代码

const shaderc::Compiler scompiler;

shaderc::CompileOptions soptions;
soptions.SetSourceLanguage(shaderc_source_language_hlsl);
soptions.SetOptimizationLevel(shaderc_optimization_level_performance);
soptions.SetIncluder(std::make_unique<MyIncluder>(includer));
soptions.SetAutoSampledTextures(true);
soptions.SetGenerateDebugInfo();


const shaderc::SpvCompilationResult vertex_result = scompiler.CompileGlslToSpv(
        source, shaderc_vertex_shader, name, vert_entry, soptions);


const shaderc::SpvCompilationResult fragment_result = scompiler.CompileGlslToSpv(
        source, shaderc_fragment_shader, name, frag_entry, soptions);

const std::vector<uint32_t> spirv_vert(vertex_result.cbegin(), vertex_result.cend());
const std::vector<uint32_t> spirv_frag(fragment_result.cbegin(), fragment_result.cend());

// 原代码错误:用HLSL源码而非SPIR-V字节码初始化编译器
spirv_cross::CompilerGLSL gcompiler(source);

spirv_cross::CompilerGLSL::Options goptions;
goptions.version = 330;
goptions.enable_row_major_load_workaround = false;
goptions.emit_uniform_buffer_as_plain_uniforms = true;
gcompiler.set_common_options(goptions);

std::cout << gcompiler.compile();

原始HLSL代码

struct VertexInput {
    float4 position : POSITION;
    float2 texcoord : TEXCOORD0;
};

struct VertexOutput {
    float4 position : SV_POSITION;
    float2 texcoord : TEXCOORD0;
};

Texture2D mainTexture;
SamplerState mainTextureSampler;

VertexOutput vertShader(VertexInput input) {
    VertexOutput output;
    output.position = input.position;
    output.texcoord = input.texcoord;
    return output;
};

float4 fragShader(VertexOutput input) : SV_TARGET {
    return mainTexture.Sample(mainTextureSampler, input.texcoord);
};

转换后错误的GLSL

顶点着色器:

#version 330
#ifdef GL_ARB_shading_language_420pack
#extension GL_ARB_shading_language_420pack : require
#endif

layout(location = 0) in vec4 input_position;
layout(location = 1) in vec2 input_texcoord;
out vec2 _entryPointOutput_texcoord;

void main()
{
    gl_Position = input_position;
    _entryPointOutput_texcoord = input_texcoord;
}

片段着色器:

#version 330
#ifdef GL_ARB_shading_language_420pack
#extension GL_ARB_shading_language_420pack : require
#endif

layout(binding = 0) uniform sampler2D mainTexture;

in vec2 input_texcoord;
layout(location = 0) out vec4 _entryPointOutput;

void main()
{
    _entryPointOutput = texture(mainTexture, input_texcoord);
}

解决方法

核心思路是基于HLSL的语义标记(如TEXCOORD0)统一顶点输出与片段输入的变量名,通过SPIRV-Cross读取SPIR-V中的HLSL语义装饰来实现。

1. 修复SPIRV-Cross初始化错误

原代码错误地用HLSL源码而非编译后的SPIR-V字节码初始化编译器,需分别为顶点和片段着色器创建独立的编译器实例:

// 顶点着色器处理
spirv_cross::CompilerGLSL vert_compiler(spirv_vert);
// 片段着色器处理
spirv_cross::CompilerGLSL frag_compiler(spirv_frag);

2. 基于HLSL语义统一变量名

遍历SPIR-V中的资源,读取HLSL语义标记,将顶点输出和片段输入的变量名设置为语义名称,确保二者一致:

// 通用GLSL转换配置
spirv_cross::CompilerGLSL::Options goptions;
goptions.version = 330;
goptions.enable_row_major_load_workaround = false;
goptions.emit_uniform_buffer_as_plain_uniforms = true;

// 处理顶点着色器:将输出变量名改为HLSL语义
auto& vert_resources = vert_compiler.get_shader_resources();
for (auto& output : vert_resources.stage_outputs) {
    // 获取HLSL语义(如TEXCOORD0)
    std::string semantic = vert_compiler.get_decoration_string(output.id, spv::DecorationHlslSemanticGOOGLE);
    // 设置变量名为语义名称
    vert_compiler.set_name(output.id, semantic);
}
vert_compiler.set_common_options(goptions);
std::string vert_glsl = vert_compiler.compile();

// 处理片段着色器:将输入变量名改为HLSL语义
auto& frag_resources = frag_compiler.get_shader_resources();
for (auto& input : frag_resources.stage_inputs) {
    std::string semantic = frag_compiler.get_decoration_string(input.id, spv::DecorationHlslSemanticGOOGLE);
    frag_compiler.set_name(input.id, semantic);
}
frag_compiler.set_common_options(goptions);
std::string frag_glsl = frag_compiler.compile();

3. 验证shaderc编译选项

已设置的SetGenerateDebugInfo()会保留HLSL语义所需的装饰数据,无需额外修改编译选项。

转换后正确的GLSL示例

顶点着色器输出与片段着色器输入将统一使用语义名称:
顶点着色器:

#version 330
#ifdef GL_ARB_shading_language_420pack
#extension GL_ARB_shading_language_420pack : require
#endif

layout(location = 0) in vec4 input_position;
layout(location = 1) in vec2 input_texcoord;
out vec2 TEXCOORD0;

void main()
{
    gl_Position = input_position;
    TEXCOORD0 = input_texcoord;
}

片段着色器:

#version 330
#ifdef GL_ARB_shading_language_420pack
#extension GL_ARB_shading_language_420pack : require
#endif

layout(binding = 0) uniform sampler2D mainTexture;

in vec2 TEXCOORD0;
layout(location = 0) out vec4 _entryPointOutput;

void main()
{
    _entryPointOutput = texture(mainTexture, TEXCOORD0);
}

内容的提问来源于stack exchange,提问作者Sarathi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 23:10:57