GLSL Водный шейдер нормализуется при прохождении света? - PullRequest
2 голосов
/ 26 апреля 2020

Я решил следовать руководству classi c для написания базовых c GLSL-шейдеров с использованием метода суммы синусов. Я попытался реализовать это внутри Обработки 5, где я создал поле вершин в PShape, чтобы заставить меня sh связываться. Затем я перезаписал шейдеры по умолчанию своими вершинными и фрагментными шейдерами, и я упал в направленном свете, чтобы я мог реально видеть нормали. Я удостоверился, что направленный свет также был подвижным, чтобы я мог видеть, работают ли нормали со всех сторон.

Я заставил волны правильно формировать высоту, и у меня была некоторая форма работы нормалей, но нормали взаимодействуют действительно странно. Когда мой свет проходит через центральную ось моей плоскости воды, нормали изменяются между различными волнами и изменяются в зависимости от угла света. Захваченный мною рисунок был слишком велик, чтобы разместить его в строке, поэтому я уверен, что он лучше объяснит, чем мои слова:

https://imgur.com/PCznL7U

Вы должны увеличить ссылка, чтобы увидеть всю картину. Заметьте, как при перемещении света слева направо нормали волн, кажется, изменяются между двумя наборами? Это особенно очевидно, поскольку оно пересекает центр. Это похоже на то, что нормали несовместимы в зависимости от направления освещения объекта.

Сфера в середине - это нормальная сфера, использующая стандартный шейдер Обработки. Я оставил его там для справки, чтобы увидеть волны, а также подтвердить, где было мое освещение и что оно работает нормально.

Есть идеи, что я сделал не так? Я знаю, что где-то неправильно вычислял математику.

РЕДАКТИРОВАТЬ: Было рекомендовано, что я добавил (длинный) исходный код [что я должен был сделать с самого начала]. Вершинный шейдер:

#define PROCESSING_LIGHT_SHADER
#define MAXWAVES 6

const float pi = 3.14159;

uniform mat4 transform;
uniform mat4 modelview;
uniform mat3 normalMatrix;

uniform float time; //Time since shader started

attribute vec4 position; //Position the vertex from Processing
attribute vec4 color; //Color of the vertex from Processing
attribute vec3 normal; //Normal of the vertex from Processing
attribute vec4 ambient;
attribute vec4 specular;
attribute vec4 emissive;
attribute float shininess;

varying vec4 vertColor; //Color passed on to fragment shader
varying vec4 backVertColor; //Color passed on to fragment shader

uniform float waveLength[MAXWAVES]; //Length of wave
uniform float speed[MAXWAVES]; //Cycle speed of wave
uniform float amplitude[MAXWAVES]; //Wave cycle height
uniform float xDirection[MAXWAVES];
uniform float yDirection[MAXWAVES]; //Flow vector of wave

uniform int lightCount;
uniform vec4 lightPosition[8];
uniform vec3 lightNormal[8];
uniform vec3 lightAmbient[8];
uniform vec3 lightDiffuse[8];
uniform vec3 lightSpecular[8];      
uniform vec3 lightFalloff[8];
uniform vec2 lightSpot[8];

varying vec3 Normal;
varying vec3 FragPos;
varying vec3 Vec;
varying vec3 lightDir;

//Some constants that the processing shader used
const float zero_float = 0.0;
const float one_float = 1.0;
const vec3 zero_vec3 = vec3(0);


float falloffFactor(vec3 lightPos, vec3 vertPos, vec3 coeff) {
  vec3 lpv = lightPos - vertPos;
  vec3 dist = vec3(one_float);
  dist.z = dot(lpv, lpv);
  dist.y = sqrt(dist.z);
  return one_float / dot(dist, coeff);
}

float spotFactor(vec3 lightPos, vec3 vertPos, vec3 lightNorm, float minCos, float spotExp) {
  vec3 lpv = normalize(lightPos - vertPos);
  vec3 nln = -one_float * lightNorm;
  float spotCos = dot(nln, lpv);
  return spotCos <= minCos ? zero_float : pow(spotCos, spotExp);
}

float lambertFactor(vec3 lightDir, vec3 vecNormal) {
  return max(zero_float, dot(lightDir, vecNormal));
}

float blinnPhongFactor(vec3 lightDir, vec3 vertPos, vec3 vecNormal, float shine) {
  vec3 np = normalize(vertPos);
  vec3 ldp = normalize(lightDir - np);
  return pow(max(zero_float, dot(ldp, vecNormal)), shine);
}


//Returns the height of a vertex given a single wave param
float WaveHeight(int waveNumber, float x, float y) {
    vec2 direction = (vec2(xDirection[waveNumber], yDirection[waveNumber]));
    float frequency = 2.0*pi/waveLength[waveNumber];
    float phase = speed[waveNumber] * frequency;
    float theta = dot(direction, vec2(x, y));
    return amplitude[waveNumber] * sin(theta * frequency + time * phase);
}

//Returns height of a vertex given all the active waves
// and its current x/y value
float WaveSum(float x, float y)
{
     float height = 0.0;
     for(int i = 0; i < MAXWAVES; i++)
     {
          height += WaveHeight(i, x, y);
     }
     return height;
} 


float getDy(int waveNumber, float x, float y) {
     vec2 direction = (vec2(xDirection[waveNumber], yDirection[waveNumber]));
    float frequency = 2.0*pi/waveLength[waveNumber];
    float phase = speed[waveNumber] * frequency;
    float theta = dot(direction, vec2(x, y));
    float A = amplitude[waveNumber] * direction.y * frequency;
    return A * cos(theta * frequency + time * phase);
}

float getDx(int waveNumber, float x, float y) {
     vec2 direction = (vec2(xDirection[waveNumber], yDirection[waveNumber]));
    float frequency = 2.0*pi/waveLength[waveNumber];
    float phase = speed[waveNumber] * frequency;
    float theta = dot(direction, vec2(x, y));
    float A = amplitude[waveNumber] * direction.x * frequency;
    return A * cos(theta * frequency + time * phase);
}

//Returns the normal vector for each vertex
vec3 getNormal(float x, float y) {
    float dx = 0.0;
    float dy = 0.0;

    //Sum for each wave
    for (int i = 0; i < MAXWAVES; i++) {
        dx += getDx(i, x, y);
        dy += getDy(i, x, y);
    }
    vec3 n = vec3(-dx, -dy, 1.0);
    return normalize(n);
}


void main() {
 vec4 pos = position; //Grab the position from Processing bc it's read only   
  pos.z = WaveSum(pos.x, pos.y);
  gl_Position  = transform * pos; //Get clipping matrix for view

  vec3 ecVertex = vec3(modelview * pos);

  // Normal vector in eye coordinates
  vec3 Normal = getNormal(pos.x, pos.y);
  vec3 ecNormal = normalize(normalMatrix * Normal);

  vec3 ecNormalInv = ecNormal * -one_float;

  // Light calculations
  vec3 totalAmbient = vec3(0, 0, 0);

  vec3 totalFrontDiffuse = vec3(0, 0, 0);
  vec3 totalFrontSpecular = vec3(0, 0, 0);

  vec3 totalBackDiffuse = vec3(0, 0, 0);
  vec3 totalBackSpecular = vec3(0, 0, 0);

  for (int i = 0; i < 8; i++) {
    if (lightCount == i) break;

    vec3 lightPos = lightPosition[i].xyz;
    bool isDir = lightPosition[i].w < one_float;
    float spotCos = lightSpot[i].x;
    float spotExp = lightSpot[i].y;

    vec3 lightDir;
    float falloff;    
    float spotf;

    if (isDir) {
      falloff = one_float;
      lightDir = -one_float * lightNormal[i];
    } else {
      falloff = falloffFactor(lightPos, ecVertex, lightFalloff[i]);  
      lightDir = normalize(lightPos - ecVertex);
    }

    spotf = spotExp > zero_float ? spotFactor(lightPos, ecVertex, lightNormal[i], 
                                              spotCos, spotExp) 
                                 : one_float;

    if (any(greaterThan(lightAmbient[i], zero_vec3))) {
      totalAmbient       += lightAmbient[i] * falloff;
    }

    if (any(greaterThan(lightDiffuse[i], zero_vec3))) {
      totalFrontDiffuse  += lightDiffuse[i] * falloff * spotf * 
                            lambertFactor(lightDir, ecNormal);
      totalBackDiffuse   += lightDiffuse[i] * falloff * spotf * 
                            lambertFactor(lightDir, ecNormalInv);
    }

    if (any(greaterThan(lightSpecular[i], zero_vec3))) {
      totalFrontSpecular += lightSpecular[i] * falloff * spotf * 
                            blinnPhongFactor(lightDir, ecVertex, ecNormal, shininess);
      totalBackSpecular  += lightSpecular[i] * falloff * spotf * 
                            blinnPhongFactor(lightDir, ecVertex, ecNormalInv, shininess);
    }    
  }    

  // Calculating final color as result of all lights (plus emissive term).
  // Transparency is determined exclusively by the diffuse component.
  vertColor =    
                  vec4(totalFrontDiffuse, 1) * color;

                  backVertColor = 
                  vec4(totalBackDiffuse, 1) * color;
}

Фрагментный шейдер:

#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif


varying vec4 vertColor; //Color from vertshader
varying vec4 backVertColor; //Color from vertshader


void main() {        
     gl_FragColor = gl_FrontFacing ? vertColor : backVertColor;
}
...