Emscripten 无法编译着色器

Posted

技术标签:

【中文标题】Emscripten 无法编译着色器【英文标题】:Emscripten fails to compile shader 【发布时间】:2021-12-31 21:18:25 【问题描述】:

我正在使用带有 C++ 17 和 WebGL 1.0 的 emscripten 来尝试在 OpenGL 中绘制一些基本的东西。但我似乎无法超越着色器编译。我尝试了许多不同类型的着色器来消除着色器成为问题的可能性。

我的假设是它是着色器文本的编码,但我似乎无法弄清楚。也许有人已经面临这个问题并且可以提供解决方案。

编译:

-s ENVIRONMENT=web
-s TOTAL_MEMORY=2147483648
-s MODULARIZE=1
-s EXPORT_ES6=1
-s DEMANGLE_SUPPORT=1
-s USE_PTHREADS=0
-s GL_ASSERTIONS=1
-s GL_DEBUG=1
--preload-file ./assets@/

如果您尝试构建一个最小程序,assets 中的文件名是standard.vertstandard.frag

着色器

顶点着色器:

precision mediump float;

attribute vec2 vertPosition;
attribute vec3 vertColor;

varying vec3 fragColor;

void main() 
    fragColor = vertColor;
    gl_Position = vec4(vertPosition, 0.0, 1.0);

片段着色器:

precision mediump float;

varying vec3 fragColor;

void main() 
    gl_FragColor = vec4(fragColor, 1.0);

加载器

readFile

std::string readFile( FILE* file )

    fseek( file, 0L, SEEK_END );
    long buffSize = ftell( file );
    rewind( file );

    std::string buffer( buffSize, '\0' );

    fread( (void*)buffer.c_str(), 1, buffSize, file );

    return buffer;

GLenum ErrorCheckValue  = glGetError();
GLint  gl_shader_result = GL_FALSE;
int    InfoLogLength;

std::string vertex_src;
std::string frag_src;
FILE*       fp = nullptr;

fp = fopen( "/standard.vert", "r" );
if ( !fp )

    emscripten_console_error( "No file found for vertex shader" );
    return;


vertex_src = readFile( fp );
emscripten_console_logf( "Vertex Shader:\n%s", vertex_src.c_str() );
fclose( fp );

fp = fopen( "/standard.frag", "r" );
if ( !fp )

    emscripten_console_error( "No file found for fragment shader" );
    return;


frag_src = readFile( fp );
emscripten_console_logf( "Fragment Shader:\n%s", frag_src.c_str() );
fclose( fp );

const char* vertexCode = vertex_src.c_str();
const char* fragCode   = frag_src.c_str();

u32 vertexShaderId = glCreateShader( GL_VERTEX_SHADER );
glShaderSource( vertexShaderId, 1, (const GLchar* const*)vertexCode, NULL );
glCompileShader( vertexShaderId );

// check for vertex shader errors
glGetShaderiv( vertexShaderId, GL_COMPILE_STATUS, &gl_shader_result );
glGetShaderiv( vertexShaderId, GL_INFO_LOG_LENGTH, &InfoLogLength );

if ( InfoLogLength > 0 )

    std::string msg( InfoLogLength + 1, '\0' );

    glGetShaderInfoLog( vertexShaderId, InfoLogLength, NULL, (GLchar*)msg.c_str() );

    emscripten_console_error( ( "WASM:: Vertex shader error: " + msg ).c_str() );

    return;


u32 fragmentShaderId = glCreateShader( GL_FRAGMENT_SHADER );
glShaderSource( fragmentShaderId, 1, (const GLchar* const*)fragCode, NULL );
glCompileShader( fragmentShaderId );

// check for vertex shader errors
glGetShaderiv( fragmentShaderId, GL_COMPILE_STATUS, &gl_shader_result );
glGetShaderiv( fragmentShaderId, GL_INFO_LOG_LENGTH, &InfoLogLength );

if ( InfoLogLength > 0 )

    std::string msg( InfoLogLength + 1, '\0' );

    glGetShaderInfoLog( fragmentShaderId, InfoLogLength, NULL, (GLchar*)msg.c_str() );

    emscripten_console_error( ( "WASM:: Fragment shader error: " + msg ).c_str() );

    return;


u32 shaderProgramId = glCreateProgram();
glAttachShader( shaderProgramId, vertexShaderId );
glAttachShader( shaderProgramId, fragmentShaderId );
glLinkProgram( shaderProgramId );

// Check the program
glGetProgramiv( shaderProgramId, GL_LINK_STATUS, &gl_shader_result );
glGetProgramiv( shaderProgramId, GL_INFO_LOG_LENGTH, &InfoLogLength );
if ( InfoLogLength > 0 )

    std::string msg( InfoLogLength + 1, '\0' );

    glGetProgramInfoLog( shaderProgramId, InfoLogLength, NULL, (GLchar*)msg.c_str() );

    emscripten_console_error( ( "WASM:: Shader compilation error: " + msg ).c_str() );

    return;


emscripten_console_log( "WASM:: Compiled shaders" );

glDetachShader( shaderProgramId, vertexShaderId );
glDetachShader( shaderProgramId, fragmentShaderId );

glDeleteShader( vertexShaderId );
glDeleteShader( fragmentShaderId );

当然还有错误:glCompileShader: ERROR: 1:1: '' : syntax error

感谢您耐心阅读所有内容。任何意见、建议或解决方案总是更好,所以谢谢。

【问题讨论】:

readFile 是做什么的?您的着色器文件是否可能有 BOM?以十六进制打印它们的前 3 个字节。 我无法正确显示十六进制。我用这行代码来打印它。 emscripten_console_logf( "Vert: %.2x, %.2x, %.2x", vertex_src[0], vertex_src[1], vertex_src[2] ); 输出为:70, 72, 65 70h, 72h, 65h 是'pre' 这是precision mediump float;的一部分所以没错。 【参考方案1】:

我不确定这是否是因为 WebGL 1.0/2.0 是 OpenGL ES2/ES3,但为了让 WebGL 正确读取着色器代码,它需要指向包含着色器代码的 char[] 指针的指针。

对顶点和片段着色器的修正是:

glShaderSource( vertexShaderId, 1, (const GLchar**)&vertexCode, NULL );

glShaderSource( fragmentShaderId, 1, (const GLchar**)&fragCode, NULL );

【讨论】:

以上是关于Emscripten 无法编译着色器的主要内容,如果未能解决你的问题,请参考以下文章

为啥我在 emscripten 使用“#version 300 es”得到“不支持的着色器版本”?

如何通过 Emscripten 激活抗锯齿

OpenGL 着色器无法编译

OpenGL 着色器无法编译但没有给出错误信息

OpenGL着色器无法编译

无法在 Maya 插件中编译顶点着色器