OpenGL 4.3:在顶点和片段着色器中使用一个SSBO对象

oogrdqng  于 2022-11-04  发布在  其他
关注(0)|答案(1)|浏览(278)

我一直在尝试使用着色器存储缓冲区对象(SSBO)与opengl 4.3核心一段时间,但甚至不能让我的着色器程序链接
下面是我的顶点着色器的代码


# version 430 core

in vec3 vertex;
uniform mat4
perspectiveMatrix,
viewMatrix,
modelMatrix;

in vec3 normal;
out vec3 lightVectors[3];
out vec3 vertexNormal;
out vec3 cameraVector;

layout(std430,binding=1)buffer Lights
{
  vec3 positions[3];
  vec3 attenuations[3];
  vec3 colors[3];
}buf1;

void main()
{
 vec4 worldVertex=modelMatrix*vec4(vertex,1.0);
 gl_Position=perspectiveMatrix*viewMatrix*worldVertex;

 vertexNormal=(modelMatrix*vec4(normal,0)).xyz;
 for(int i=0;i<3;i++){
  lightVectors[i]=buf1.positions[i]-worldVertex.xyz;
 }
 cameraVector=(inverse(viewMatrix)*vec4(0,0,0,1)).xyz-worldVertex.xyz;

}

这是我的片段着色器的代码


# version 430 core

in vec3 vertexNormal;
in vec3 cameraVector;
in vec3 lightVectors[3];

out vec4 pixelColor;

layout(std430,binding=1)buffer Lights
{
  vec3 positions[3];
  vec3 attenuations[3];
  vec3 colors[3];
}buf2;

uniform Material
{
 vec3 diffuseMat;
 vec3 specularMat;
 float reflectivity;
 float shininess;
};

float getAtten(int i)
{
 float l=length(lightVectors[i]); 
 float atten=(buf2.attenuations[i].x*l)
 +((buf2.attenuations[i].y)*(l*l))
 +((buf2.attenuations[i].z)*(l*l*l));
 return atten;
}

vec3 computeLightColor()
{
 vec3 unitNormal=normalize(vertexNormal);
 vec3 unitCam=normalize(cameraVector);

 vec3 diffuse,specular,lightColor;
 for(int i=0;i<3;i++)
 {
 vec3 unitLight=normalize(lightVectors[i]);
 float atten=getAtten(i);

 float nDiffuseDot=dot(unitLight,unitNormal);
 float diffuseIntencity=max(0,nDiffuseDot); 
 diffuse+=(buf2.colors[i]*diffuseMat*diffuseIntencity)/atten;

 vec3 reflectedLight=reflect(-unitLight,unitNormal); 
 float nSpecularDot=dot(reflectedLight,unitCam);
 float specularIntencity=pow(max(0,nSpecularDot),reflectivity)*shininess;
 specular+=(buf2.colors[i]*specularMat*specularIntencity)/atten;
 }
 lightColor=diffuse+specular;

 return lightColor;
}

void main()
{
 pixelColor=vec4(computeLightColor(),1)*0.7;
}

这两个着色器的通用代码是

layout(std430,binding=1)buffer Lights
{
  vec3 positions[3];
  vec3 attenuations[3];
  vec3 colors[3];
};

这是我用于照明计算的SSBO
我需要在顶点着色器和片段着色器中使用这一个缓冲区,因为在我的顶点着色器中,这部分代码

lightVectors[i]=buf1.positions[i]-worldVertex.xyz;

使用SSBO中定义的灯光位置
在片段着色器中,

float getAtten(i) and
vec3 computeLight()

方法使用缓冲区颜色[3]和衰减[3]“阵列”来计算漫反射和镜面反射分量
但我无法使用上述SSBO定义链接顶点和碎片着色器,着色器信息日志为空,因此我也不知道错误
有没有办法在顶点着色器和碎片着色器中使用上面定义的SSBO,而不创建2个单独的SSBO,即一个用于顶点着色器,一个用于碎片着色器?
这是我的着色器类。我的所有着色器都扩展到此类以实现

public abstract class StaticShader extends Shader3D
{
 private int      
 vertexShaderID=-1,
 fragmentShaderID=-1;

 private boolean alive=false;
 private boolean isActive=false;

 public StaticShader(Object vertexShader,Object fragmentShader)
 {
   programID=GL20.glCreateProgram();  
   vertexShaderID=loadShader(vertexShader,GL20.GL_VERTEX_SHADER);
   fragmentShaderID=loadShader(fragmentShader,GL20.GL_FRAGMENT_SHADER);

   GL20.glAttachShader(programID,vertexShaderID);
   GL20.glAttachShader(programID,fragmentShaderID);
   bindAttributes();

   activateShader();
  }

 private int loadShader(Object src,int shaderType)
 {
     StringBuilder source=super.loadSource(src);

     int shaderID=GL20.glCreateShader(shaderType);
     GL20.glShaderSource(shaderID,source);
     GL20.glCompileShader(shaderID);

     if(GL20.glGetShaderi(shaderID,GL20.GL_COMPILE_STATUS)==GL11.GL_FALSE)
     {
       infoLogSize=GL20.glGetShaderi(shaderID,GL20.GL_INFO_LOG_LENGTH);
       System.err.println(GL20.glGetShaderInfoLog(shaderID,infoLogSize));
       System.err.println("COULD NOT COMPILE SHADER");
       System.exit(-1);
     }    

     return shaderID;
 }

protected void activateShader()
 {   
  GL20.glLinkProgram(programID);
  if(GL20.glGetProgrami(programID,GL20.GL_LINK_STATUS)==GL11.GL_FALSE)
  {  
    infoLogSize=GL20.glGetProgrami(programID,GL20.GL_INFO_LOG_LENGTH);
    System.err.println(GL20.glGetProgramInfoLog(programID,infoLogSize));
    System.err.println("COULD NOT LINK SHADER");
    System.exit(-1);
  } 

  GL20.glValidateProgram(programID); 
  if(GL20.glGetProgrami(programID,GL20.GL_VALIDATE_STATUS)==GL11.GL_FALSE)
  {
    infoLogSize=GL20.glGetProgrami(programID,GL20.GL_INFO_LOG_LENGTH);  
    System.err.println(GL20.glGetProgramInfoLog(programID,infoLogSize));
    System.err.println("COULD NOT VALIDATE SHADER");
    System.exit(-1);
  } 
 }

 public void dispose()
 {   
    GL20.glUseProgram(0);

    GL20.glDetachShader(programID,vertexShaderID);
    GL20.glDetachShader(programID,fragmentShaderID);

    GL20.glDeleteShader(vertexShaderID);
    GL20.glDeleteShader(fragmentShaderID);

    GL20.glDeleteProgram(programID);
 }        
}

我使用的是LWJGL 2.9.3 Java OpenGL版本
程序编译正常,但glLinkprogram()返回false且着色器信息日志为空
我甚至还没有创建任何类型的缓冲对象,我现在只是在学习语法
任何帮助都将不胜感激提前感谢你和那些在评论中帮助过我的人,但我现在非常沮丧

cgvd09ve

cgvd09ve1#

在您的代码中,我得到了链接器错误:
错误:SSBO(名为灯光)的着色器之间的绑定不匹配
对于不同着色器阶段中的相同命名缓冲区对象,必须使用相同的绑定点。
在顶点着色器中:

layout(std430, binding=1) buffer Lights
{
  vec3 positions[3];
  vec3 attenuations[3];
  vec3 colors[3];
} buf1;

Lights是缓冲区的外部可见名称,buf1是着色器内的块的名称。
这意味着您必须在片段着色器中为缓冲区对象Lights使用相同的绑定点:

layout(std430,binding=1) buffer Lights // <---- binding=1 instead of binding=2
{
    vec3 positions[3];
    vec3 attenuations[3];
    vec3 colors[3];
}buf2;

另请参阅:

缓冲区限定符用于声明全局变量,这些变量的值存储在通过OpenGL API绑定的缓冲区对象的数据存储中。

// use buffer to create a buffer block (shader storage block)
 buffer BufferName { // externally visible name of buffer
     int count; // typed, shared memory...
     ... // ...
     vec4 v[]; // last member may be an array that is not sized
               // until after link time (dynamically sized)
 } Name; // name of block within the shader

相关问题