Opengl GLSL水着色器在光线经过时法线变形?

Opengl GLSL水着色器在光线经过时法线变形?,opengl,graphics,glsl,processing,shader,Opengl,Graphics,Glsl,Processing,Shader,我决定使用sines之和方法编写一个基本的GLSL水着色器。我试图在Processing 5中实现它,我在PShape中创建了一个顶点场,以创建一个要处理的网格。然后,我用自己的顶点和片段着色器重写了默认着色器,并放置了平行光,以便可以实际看到法线。我确保平行光也是可移动的,这样我就可以看到法线是否从各个角度工作 我得到了正确的波浪高度,我有一些形式的法线,但是法线的相互作用非常奇怪。当光线穿过水平面的中心轴时,法线似乎会在不同的波之间变形,并根据光线角度而变化。我捕获的gif太大,无法在线发布

我决定使用sines之和方法编写一个基本的GLSL水着色器。我试图在Processing 5中实现它,我在PShape中创建了一个顶点场,以创建一个要处理的网格。然后,我用自己的顶点和片段着色器重写了默认着色器,并放置了平行光,以便可以实际看到法线。我确保平行光也是可移动的,这样我就可以看到法线是否从各个角度工作

我得到了正确的波浪高度,我有一些形式的法线,但是法线的相互作用非常奇怪。当光线穿过水平面的中心轴时,法线似乎会在不同的波之间变形,并根据光线角度而变化。我捕获的gif太大,无法在线发布,因此我确信看到它会比我的文字更好地解释:

您应该最大化链接以查看整个图片。请注意,当灯光从左向右平移时,波的法线似乎在两组之间变形?这一点在穿过中心时尤为明显。这就像法线根据对象的照明方向不一致一样

中间的球体是使用标准处理着色器的普通球体。我把它放在那里作为参考,以查看海浪,并确认我的照明在哪里,它工作正常

知道我做错了什么吗?我知道我在什么地方算错了

编辑:建议我添加(冗长的)源代码[我从一开始就应该这样做]。 顶点着色器:

#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;
}

您应该添加相关代码(MCVE)。。。也许是你描述的bug的截图(用彩色圆圈或箭头或用油漆编辑的东西或其他东西来强调),这样我们就知道该找什么了。编辑文章,至少包含相关代码。它的效果很难突出显示或圈出,所以我认为gif的场景将有助于可视化。谢谢你的建议。是的,动画很好,但我通常也会拍摄一个屏幕截图,并在一个圆圈框或箭头中编辑,显示要查看的确切区域或特征。在你的情况下,问题并不明显。。。因为阴影的连接可能只是由于波浪动画的几何体属性,而不是bug。我会尝试将水冻结在预定义的状态(通过滚动条或手动键进行动画处理)然后用移动光的方向检查阴影,就像你现在看到的那样,这将决定它是否真的是一个照明错误,在这种情况下,或者仅仅是我们的想象,它是不正确的。我说的涡流是指这样的东西,光是点光还是无限方向的(第二个球意味着点光)?在这两种情况下,它看起来都不对。对于点光源,光的耗散应该是圆形的,而在另一个非点光源中,则是半平面。所以检查你的法线和光照方程。我通常会像这样目视检查法线:
#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;
}