由于 gl_Position,opengl 纹理坐标未正确插值

opengl texture coordinates not interpolated correctly due to gl_Position

我正在使用 LWJGL 制作 opengl 联合动画 java。我所有的关节和顶点都按预期正确转换,但是当我使用纹理

渲染我的模型时,奇怪的事情开始发生

顶点着色器代码

# version 430 core

uniform mat4
projection,
view,
model;
in vec3 vertex;
uniform mat4 rotate;

in vec2 texCoord;
out vec2 vertexTexCoord;

uniform mat4 joints[16];
in ivec4 jointIndices;
in vec4  weights;

in vec3 normal;
const vec3 directions[3]={vec3(0,-1,0),vec3(0,1,0),vec3(0,0,-1)};
out vec3 vertexNormal;
out vec3 lighting[3];


void main()
{
 mat4 modelRotate=(model*rotate);
 vec4 finalVertex=vec4(0.0);
 vec4 finalNormal=vec4(0.0);

 for(int i=0;i<4;i++)
 {
   mat4 jointTransform=joints[jointIndices[i]];  

   vec4 modelVertex=vec4(vertex,1.0);
   vec4 posVertex=jointTransform*modelVertex;
   finalVertex+=posVertex*weights[i];

   vec4 modelNormal=vec4(normal,0.0);
   vec4 poseNormal=jointTransform*modelNormal;
   finalNormal+=poseNormal*weights[i];
 }
 gl_Position=projection*view*modelRotate*vec4(vertex,1.0);

 vertexNormal=(modelRotate*finalNormal).xyz;
 for(int i=0;i<3;i++){lighting[i]=directions[i]*-1;}

 vertexTexCoord=texCoord;
}

片段着色器代码

#version 430 core

in vec3 vertexNormal;
in vec3 lighting[3];

in vec2 vertexTexCoord;
uniform sampler2D tex;

out vec4 pixelColor;

void main()
{
 vec3 nNormal=normalize(vertexNormal); 

 vec3 lightColor=vec3(0.0);
 for(int i=0;i<3;i++)
 {
  vec3 nLight=normalize(lighting[i]);  
  float nDot=max(0.0,dot(nNormal,nLight));
  lightColor+=vec3(1,1,1)*nDot;
 }

 pixelColor=vec4(vertexTexCoord.x,vertexTexCoord.y,0,0);
}

我没有在我的模型中使用光照,因为它已经过测试并且工作正常,但我的纹理坐标不正确,所以我在我的着色器中将它们作为红色、绿色组合输出以进行调试

我的每个着色器中有两行代码需要注意

VertexShader:   gl_Position
FragmentShader: pixelColor

gl_Position=projection*view*modelRotate*vec4(vertex,1.0);
pixelColor=vec4(vertexTexCoord.x,vertexTexCoord.y,0,0);

那是我的模型使用原始输入顶点而不是转换后的 finalVertex

输出

如您所见,每个表面的纹理坐标都不同,应该是正确的。

因此,当我通过将 pixelColor 更改为

使用具有这些纹理坐标的正确纹理渲染我的模型时
pixelColor=texture(tex,vertexTexCoord);

输出

我的模型在正确的位置正确渲染了纹理。

现在事情从这一点开始变得很奇怪 将我的着色器代码更改为

gl_Position=projection*view*modelRotate*finalVertex;
pixelColor=vec4(vertexTexCoord.x,vertexTexCoord.y,0,0);

现在我的模型使用每个关节的最终变换顶点,我的片段着色器输出纹理坐标。 输出应该与上面的文字相同,没有任何改变,但后来我得到了这个

输出

现在纹理坐标在整个模型中完全相同,根本不进行插值。全程统一!!!

现在,当我通过将片段着色器代码更改为

使用这些错误的纹理坐标进行采样时
pixelColor=texture(tex,vertexTexCoord);

输出符合预期,不是我预期的:(

输出:

如果对我有帮助,这是我的模型纹理。我从教程下载的

纹理坐标似乎停留在图像的左上角,这可能解释了为什么我的模型是全黑的,因为左上角有很多黑色区域

所以总结通过改变我的顶点着色器中的一行代码从

gl_Position=projection*view*modelRotate*vec4(vertex,1.0);
                    TO
gl_Position=projection*view*modelRotate*finalVertex;

它改变了我的生活

致此:(

任何来自任何地方的建议,无论是重塑我的角色或我的纹理,还是创建一个新的渲染引擎,我们都将不胜感激。

编写加载模型的代码以及联合变换和层次结构花了我 4 天的时间

2 周过去了,我仍然无法弄清楚我的着色器有什么问题。 谢谢

我这里有一个简单的静态着色器,可以加载统一矩阵

public abstract class StaticShader
{
 private int
 programID=0,
 vertexShaderID=0,
 fragmentShaderID=0,
 infoLogSize=0;

 private final FloatBuffer mat4fBuffer=BufferUtils.createFloatBuffer(16);

 protected 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();   



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

 protected void bindAttribute(int attribno,String variable){GL20.glBindAttribLocation(programID,attribno,variable);}
 abstract void bindAttributes();

 private int loadShader(Object src,int shaderType)
 {
     StringBuilder source=Utils.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;
 }

 public void start(){GL20.glUseProgram(programID);}
 public void stop(){GL20.glUseProgram(0);}
 public void release()
 {
   GL20.glUseProgram(0);

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

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

 public void loadMatrix(String name,Matrix4f mat)
 {
  start(); 
  mat.store(mat4fBuffer);
  mat4fBuffer.flip();
  GL20.glUniformMatrix4(GL20.glGetUniformLocation(programID,name),false,mat4fBuffer);
  stop();
 }
}

我从这个着色器继承了 MyShader class

public class MyShader extends StaticShader
{
  private static final String
  VERTEX_SHADER="/main/animate.VS",
  FRAGMENT_SHADER="/main/animate.FS";

  private Texture tex;

  public MyShader()
  {
    super(VERTEX_SHADER,FRAGMENT_SHADER);
    Matrix4f mat=new Matrix4f();

     try
     {
      InputStream is=MyShader.class.getResourceAsStream("Character Texture.png");
      tex=TextureLoader.getTexture(".png",is,true);
      is.close();
     }
     catch(Exception ex){ex.printStackTrace();}


     float aspectRatio=(float)Display.getWidth()/(float)Display.getHeight();
     Utils.perspective(50,0.1f,1000,aspectRatio,mat);
     super.loadMatrix("projection",mat);/*PERSPECTIVE MATRIX*/

     Vector3f location=new Vector3f(0,4,12);
     Vector3f lookAt=new Vector3f(0,4,0);
     Vector3f up=new Vector3f(0,1,0);
     Utils.lookAt(location,lookAt,up,mat);
     super.loadMatrix("view",mat);        /*VIEW MATRIX*/

     mat.setIdentity();
     mat.scale(new Vector3f(1.2f,1,1));
     super.loadMatrix("model",mat);       /*MODEL MATRIX*/

     mat.setIdentity();
     mat.rotate((float)Math.toRadians(90),new Vector3f(-1,0,0));
     super.loadMatrix("rotate",mat);     /*FLIP MODEL BY 90 DEGRESS*/

     for(int i=0;i<16;i++)
     {
      mat.setIdentity();/*LOAD ALL JOINT TRANSFORM'S AS IDENTITY*/ 
      super.loadMatrix("joints["+String.valueOf(i)+"]",mat);
     }
  }

  public void bindAttributes()
  {
   super.bindAttribute(0,"vertex");
   super.bindAttribute(1,"normal");
   super.bindAttribute(2,"texCoord");
   super.bindAttribute(3,"jointIndices");
   super.bindAttribute(4,"weights");   
  }

  public void start()
  {
   super.start();
   GL13.glActiveTexture(GL13.GL_TEXTURE0);
   GL11.glBindTexture(GL11.GL_TEXTURE_2D,tex.getTextureID());
  }

  public void release()
  {
   tex.release();
   super.release();
  }
}

接下来我们有一个几何渲染器,它从二进制文件加载模型并将其渲染到屏幕上。

public class MeshRender
{
 private final int vao;
 private final ArrayList<Integer> vbos=new ArrayList<Integer>();
 private final ArrayList<Integer> indexLocations=new ArrayList<Integer>();
 private final int vertexCount;

 public MeshRender(int vertices)
 {
  vao=GL30.glGenVertexArrays();
  GL30.glBindVertexArray(vao);
  vertexCount=vertices;
 }

 public void createAttribute(int index,int vectype,FloatBuffer buffer)
 {
  int vbo=GL15.glGenBuffers();
  GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER,vbo);
  GL15.glBufferData(GL15.GL_ARRAY_BUFFER,buffer,GL15.GL_DYNAMIC_DRAW);
  GL20.glVertexAttribPointer(index,vectype,GL11.GL_FLOAT,false,0,0);
  GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER,0);

  indexLocations.add(index);
  vbos.add(vbo);
 }

 public void createAttribute(int index,int vectype,IntBuffer buffer)
 {
  int vbo=GL15.glGenBuffers();
  GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER,vbo);
  GL15.glBufferData(GL15.GL_ARRAY_BUFFER,buffer,GL15.GL_DYNAMIC_DRAW);
  GL20.glVertexAttribPointer(index,vectype,GL11.GL_INT,false,0,0);
  GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER,0);

  indexLocations.add(index);
  vbos.add(vbo);   
 }

 public void unBind(){GL30.glBindVertexArray(0);}

 public void render()
 {
  GL30.glBindVertexArray(vao);
  for(int index: indexLocations){GL20.glEnableVertexAttribArray(index);}
  GL11.glDrawArrays(GL11.GL_TRIANGLES,0,vertexCount);
  for(int index: indexLocations){GL20.glDisableVertexAttribArray(index);}
  GL30.glBindVertexArray(0);
 }

 public void release()
 {
  for(int vbo: vbos){GL15.glDeleteBuffers(vbo);}
  GL30.glDeleteVertexArrays(vao);
 } 

 public static MeshRender createMesh()
 {
  MeshRender mesh=null;
  try
  {
   Model model=Model.readFromFile("/main/Model.data");
   FloatBuffer fBuffer;
   IntBuffer iBuffer;

   fBuffer=model.toFBuffer(0);

   mesh=new MeshRender(fBuffer.capacity()/3);
   mesh.createAttribute(0,3,fBuffer);/*VERTICES'      INDEX=0  FLOAT'S=3*/

   fBuffer=model.toFBuffer(1);
   mesh.createAttribute(1,3,fBuffer);/*NORMAL'S       INDEX=1  FLOAT'S=3*/

   fBuffer=model.toFBuffer(2);
   mesh.createAttribute(2,2,fBuffer);/*TEX COORD'S    INDEX=2  FLOAT'S=2*/

   iBuffer=model.toIBuffer(3);
   mesh.createAttribute(3,4,iBuffer);/*JOINT INDICES  INDEX=3  INT'S=4*/

   fBuffer=model.toFBuffer(4);
   mesh.createAttribute(4,4,fBuffer);/*WEIGHT'S       INDEX=4  FLOAT'S=4*/

   mesh.unBind();        
  }
  catch(Exception ex){ex.printStackTrace();}
  return mesh;
 }
}

Class 模型是从工作文件加载的实际数据 fine.But 你可以在这里加载你想要的任何信息。

最后我的着色器和几何体一起用于我的主要 class

public class Main
{
 /*DISPLAY ATTRIBUTES*/   
private static ContextAttribs createDisplayAttributes()
 {
   ContextAttribs attribs=new ContextAttribs(4,2)
   .withForwardCompatible(true)
   .withProfileCore(true);

   return attribs;
 }

 private static void initDisplay(String title)
 {
  try
  {
   Display.create(new PixelFormat(),createDisplayAttributes());

   Display.setTitle(title);

   Display.setDisplayMode(new DisplayMode(1500,705));

   Display.setLocation(0,-2);

   Display.setResizable(false);
  }
  catch(Exception e)
  {
   e.printStackTrace();
  }    
 }
 /*DISPLAY ATTRIBUTES*/

 private static void startFrame()
 {
  GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
  GL11.glEnable(GL11.GL_DEPTH_TEST);
  GL11.glClearColor(0,0,1,0);
 }

 public static void main(String args[])
 {
  initDisplay("ANIMATION TEST");

  MeshRender mesh=MeshRender.createMesh();
  MyShader myShader=new MyShader();

  while(!Display.isCloseRequested())
  {
   startFrame();

   myShader.start();
   mesh.render();
   myShader.stop();

   updateDisplay();
  }

  mesh.release();
  myShader.release();

  mesh.release();
  releaseOpenGL();
 }

 private static void updateDisplay()
 {
  Display.update();
  Display.sync(60);
 }

 private static void releaseOpenGL()
 {
   try
   {    
    Mouse.destroy();
    Keyboard.destroy();
    Display.releaseContext();
    Display.destroy();
   }
   catch(Exception ex){ex.printStackTrace();}
 }

我的悬架正在将一个矩阵加载到一组制服中,但我不确定。谢谢你

好吧,我发现问题不在于我的着色器或我的模型,而是在 linking 数据时我的 MeshRenderer。

如果你必须 link 整数数据到你的着色器[linking jointId's] 你必须使用

GL30.glVertexAttribIPointer(index,vecType,GL11.GL_INT,0,0)
                      And not
GL20.glVertexAttribPointer(index,vectype,GL11.GL_INT,false,0,0);

不知道为什么他们为 linking 整数制作了一个单独的方法,但这使我的纹理完美工作。结案