Как преобразовать шейдеры GLSL в GLSL ES - PullRequest
0 голосов
/ 07 мая 2020

Я портирую приложение openGL на веб-сборку с помощью Emscripten. Я написал кучу шейдеров на GLSL (330) для нативной версии. Однако для веб-версии мне нужны шейдеры, написанные на GLSL ES (300 es). Как мне go преобразовать свои шейдеры из GLSL в GLSL ES?

Возможности, которые я рассмотрел до сих пор:

  • GLSL -> SPIR-V -> GLSL ES,
  • с набором #ifdef операторов в коде GLSL, чтобы блоки кода выполнялись только для GLSL ES или GLSL,
  • написание специального кода C ++, который динамически создает код GLSL / GLSL ES в зависимости от того, что вам нужно
  • просто наличие двух почти идентичных копий всех шейдеров, одна в GLSL, а другая в GLSL ES

Пример вершинного шейдера GLSL:


    #version 330 core
    #define NR_LIGHTS 10

    layout (location = 0) in vec3 position;
    layout (location = 1) in vec3 normal;

    out vec3 normalViewSpace;
    out vec3 posViewSpace;
    out vec2 textureCoords;
    out vec4 positionsLightSpace[NR_LIGHTS];

    uniform mat4 modelMatrix;
    uniform mat4 viewMatrix;
    uniform mat4 projectionMatrix;
    uniform mat3 normalMatrix;
    uniform mat4 lightMatrices[NR_LIGHTS];


    void main()
    {
        vec4 posViewSpaceV4;
        posViewSpaceV4 = viewMatrix * modelMatrix * vec4(position, 1.0);
        posViewSpace = posViewSpaceV4.xyz;
        gl_Position = projectionMatrix * posViewSpaceV4;
        normalViewSpace = mat3(viewMatrix) * normalMatrix * normal;
        for( int i = 0; i 

Пример фрагментного шейдера GLSL:


    #version 330 core
    #define NR_LIGHTS 10
    struct Material {
        vec3 ambient;
        vec3 diffuse;
        vec3 specular;
        float shininess;
        float alpha;
    };

    struct Light {
     vec3 posViewSpace;
     vec3 ambient;
     vec3 diffuse;
     vec3 specular;

     float constant;
     float linear;
     float quadratic;

     vec3 directionViewSpace;
     float cutOff;
     float outerCutOff;

     sampler2D shadowMap;
    };

    out vec4 FragColor;
    in vec3 normalViewSpace;
    in vec3 posViewSpace;
    in vec4 positionsLightSpace[NR_LIGHTS];

    uniform Material material;
    uniform Light lights[NR_LIGHTS];

    float shadowCalculation(vec4 posLightSpace, sampler2D shadowMap, Light light)
    {
        // perform perspective divide
        vec3 projCoords = posLightSpace.xyz / posLightSpace.w; // range [-1, 1]

        // transform range [0, 1]
        projCoords = projCoords * 0.5 + 0.5;
        float closestDepth = texture(shadowMap, projCoords.xy).r;
        float currentDepth = projCoords.z;
        vec3 lightDir = normalize(light.posViewSpace - posViewSpace);
        float bias = max(0.00005 * (1.0 - dot(normalViewSpace, lightDir)), 0.000005); // solves shadow acne
        float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0;
        return shadow;
    }

    vec3 calcSpotLight( Light light, vec3 normal, vec3 position, float shadow) // normal and position in view space, although this function should not care about which space it's in
    {
      vec3 result = vec3(0.0, 0.0, 0.0);
      vec3 lightDir = normalize(light.posViewSpace - position);
      float theta = dot(lightDir, normalize(-light.directionViewSpace));
      float epsilon = light.cutOff - light.outerCutOff;
      float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0); // interpolate between inner and outer cutOff and clamp to 0 and 1
      if( intensity > 0 ) // if inside spot radius
      {
        // attenuation
        float distance = length(light.posViewSpace - position);
        float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
        if( attenuation > 0.001 )
        {
          // ambient
          vec3 ambient = material.ambient * light.ambient;

          // diffuse
          vec3 norm = normalize(normalViewSpace);
          float diff = max(dot(norm, lightDir), 0.0);
          vec3 diffuse = diff * material.diffuse * light.diffuse;

          // specular
          vec3 viewDir = normalize(-position); // in view space the camera is at (0, 0, 0)
          vec3 reflectDir = reflect(-lightDir, norm); // reflect function expect vector FROM light source TO position
          float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
          vec3 specular = material.specular * spec * light.specular;

          // result
          result = intensity * attenuation * (ambient + (1.0 - shadow) * (diffuse + specular));
        }
      }

      return result;
    }

    void main()
    {
      vec3 result = material.ambient * 0.08;
      for( int i = 0; i 
...