顶点属性的插值
Interpolation of a vertex attribute
我正在尝试将距离作为顶点属性从我的 C++ 代码传递到在两个顶点之间绘制一条线的着色器中。
当前一行的距离为 0(开始),另一行的距离为 1.0。我希望这个值像颜色一样被插值,但它似乎不起作用。因此,我希望线的一半是红色,另一半是绿色,但整条线都是绿色的。
下面的片段着色器代码,其中顶点着色器中的 dist 来自 float in_dist 中的布局(位置 = 2),并作为 out float dist(未执行任何操作)传递出去。
in float dist;
Fragment getFragment()
{
Fragment frag;
frag.depth = vs_positionScreenSpace.w;
frag.gPosition = vs_gPosition;
if(dist > 0.5){
frag.color = vec4(1.0,0.0,0.0,1.0);
}else{
frag.color = vec4(0.0,1.0,0.0,1.0);
}
frag.gNormal = vec4(0.0, 0.0, 1.0, 0.0);
return frag;
}
顶点着色器
layout(location = 0) in vec3 in_point_position;
layout(location = 1) in vec4 in_color;
layout(location = 2) in float in_dist;
out float dist;
void main() {
//somestuff....
dist = in_dist;
}
在这里工作很好:
MCVE:
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <vector>
#include <iostream>
#include <cstdarg>
struct Program
{
static GLuint Load( const char* shader, ... )
{
GLuint prog = glCreateProgram();
va_list args;
va_start( args, shader );
while( shader )
{
const GLenum type = va_arg( args, GLenum );
AttachShader( prog, type, shader );
shader = va_arg( args, const char* );
}
va_end( args );
glLinkProgram( prog );
CheckStatus( prog );
return prog;
}
private:
static void CheckStatus( GLuint obj )
{
GLint status = GL_FALSE;
if( glIsShader(obj) ) glGetShaderiv( obj, GL_COMPILE_STATUS, &status );
if( glIsProgram(obj) ) glGetProgramiv( obj, GL_LINK_STATUS, &status );
if( status == GL_TRUE ) return;
GLchar log[ 1 << 15 ] = { 0 };
if( glIsShader(obj) ) glGetShaderInfoLog( obj, sizeof(log), NULL, log );
if( glIsProgram(obj) ) glGetProgramInfoLog( obj, sizeof(log), NULL, log );
std::cerr << log << std::endl;
std::exit( EXIT_FAILURE );
}
static void AttachShader( GLuint program, GLenum type, const char* src )
{
GLuint shader = glCreateShader( type );
glShaderSource( shader, 1, &src, NULL );
glCompileShader( shader );
CheckStatus( shader );
glAttachShader( program, shader );
glDeleteShader( shader );
}
};
const char* vert = R"GLSL(
#version 330 core
layout( location = 0 ) in vec4 inPos;
layout( location = 1 ) in float inDist;
out float dist;
void main()
{
dist = inDist;
gl_Position = inPos;
}
)GLSL";
const char* frag = R"GLSL(
#version 330 core
in float dist;
out vec4 outColor;
void main()
{
if( dist > 0.5 )
{
outColor = vec4( 1.0, 0.0, 0.0, 1.0 );
}
else
{
outColor = vec4( 0.0, 1.0, 0.0, 1.0 );
}
}
)GLSL";
int main( int argc, char** argv )
{
glfwInit();
glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 );
glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 3 );
glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE );
GLFWwindow* window = glfwCreateWindow( 640, 480, "GLFW", NULL, NULL );
glfwMakeContextCurrent( window );
glewInit();
glfwSwapInterval( 1 );
GLuint prog = Program::Load( vert, GL_VERTEX_SHADER, frag, GL_FRAGMENT_SHADER, NULL );
glUseProgram( prog );
GLuint vao = 0;
glGenVertexArrays( 1, &vao );
glBindVertexArray( vao );
GLuint vbo0 = 0;
glGenBuffers( 1, &vbo0 );
glBindBuffer( GL_ARRAY_BUFFER, vbo0 );
std::vector<float> data0 =
{
-0.5f, -0.5f,
0.5f, 0.5f,
};
glBufferData( GL_ARRAY_BUFFER, data0.size() * sizeof( std::vector<float>::value_type ), data0.data(), GL_STATIC_DRAW );
glVertexAttribPointer( 0 , 2, GL_FLOAT, GL_FALSE, 0, 0 );
glEnableVertexAttribArray( 0 );
GLuint vbo1 = 0;
glGenBuffers( 1, &vbo1 );
glBindBuffer( GL_ARRAY_BUFFER, vbo1 );
std::vector<float> data1 =
{
0.0f, 1.0f,
};
glBufferData( GL_ARRAY_BUFFER, data1.size() * sizeof( std::vector<float>::value_type ), data1.data(), GL_STATIC_DRAW );
glVertexAttribPointer( 1 , 1, GL_FLOAT, GL_FALSE, 0, 0 );
glEnableVertexAttribArray( 1 );
while( !glfwWindowShouldClose( window ) )
{
glfwPollEvents();
int w, h;
glfwGetFramebufferSize( window, &w, &h );
glViewport( 0, 0, w, h );
glClear( GL_COLOR_BUFFER_BIT );
glUseProgram( prog );
glBindVertexArray( vao );
glDrawArrays( GL_LINES, 0, 2 );
glfwSwapBuffers( window );
}
glfwDestroyWindow( window );
glfwTerminate();
}
已解决;结果证明问题不在着色器代码中,而是在如何定义顶点属性 att glVertexAttributePointer。
我正在尝试将距离作为顶点属性从我的 C++ 代码传递到在两个顶点之间绘制一条线的着色器中。
当前一行的距离为 0(开始),另一行的距离为 1.0。我希望这个值像颜色一样被插值,但它似乎不起作用。因此,我希望线的一半是红色,另一半是绿色,但整条线都是绿色的。
下面的片段着色器代码,其中顶点着色器中的 dist 来自 float in_dist 中的布局(位置 = 2),并作为 out float dist(未执行任何操作)传递出去。
in float dist;
Fragment getFragment()
{
Fragment frag;
frag.depth = vs_positionScreenSpace.w;
frag.gPosition = vs_gPosition;
if(dist > 0.5){
frag.color = vec4(1.0,0.0,0.0,1.0);
}else{
frag.color = vec4(0.0,1.0,0.0,1.0);
}
frag.gNormal = vec4(0.0, 0.0, 1.0, 0.0);
return frag;
}
顶点着色器
layout(location = 0) in vec3 in_point_position;
layout(location = 1) in vec4 in_color;
layout(location = 2) in float in_dist;
out float dist;
void main() {
//somestuff....
dist = in_dist;
}
在这里工作很好:
MCVE:
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <vector>
#include <iostream>
#include <cstdarg>
struct Program
{
static GLuint Load( const char* shader, ... )
{
GLuint prog = glCreateProgram();
va_list args;
va_start( args, shader );
while( shader )
{
const GLenum type = va_arg( args, GLenum );
AttachShader( prog, type, shader );
shader = va_arg( args, const char* );
}
va_end( args );
glLinkProgram( prog );
CheckStatus( prog );
return prog;
}
private:
static void CheckStatus( GLuint obj )
{
GLint status = GL_FALSE;
if( glIsShader(obj) ) glGetShaderiv( obj, GL_COMPILE_STATUS, &status );
if( glIsProgram(obj) ) glGetProgramiv( obj, GL_LINK_STATUS, &status );
if( status == GL_TRUE ) return;
GLchar log[ 1 << 15 ] = { 0 };
if( glIsShader(obj) ) glGetShaderInfoLog( obj, sizeof(log), NULL, log );
if( glIsProgram(obj) ) glGetProgramInfoLog( obj, sizeof(log), NULL, log );
std::cerr << log << std::endl;
std::exit( EXIT_FAILURE );
}
static void AttachShader( GLuint program, GLenum type, const char* src )
{
GLuint shader = glCreateShader( type );
glShaderSource( shader, 1, &src, NULL );
glCompileShader( shader );
CheckStatus( shader );
glAttachShader( program, shader );
glDeleteShader( shader );
}
};
const char* vert = R"GLSL(
#version 330 core
layout( location = 0 ) in vec4 inPos;
layout( location = 1 ) in float inDist;
out float dist;
void main()
{
dist = inDist;
gl_Position = inPos;
}
)GLSL";
const char* frag = R"GLSL(
#version 330 core
in float dist;
out vec4 outColor;
void main()
{
if( dist > 0.5 )
{
outColor = vec4( 1.0, 0.0, 0.0, 1.0 );
}
else
{
outColor = vec4( 0.0, 1.0, 0.0, 1.0 );
}
}
)GLSL";
int main( int argc, char** argv )
{
glfwInit();
glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 );
glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 3 );
glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE );
GLFWwindow* window = glfwCreateWindow( 640, 480, "GLFW", NULL, NULL );
glfwMakeContextCurrent( window );
glewInit();
glfwSwapInterval( 1 );
GLuint prog = Program::Load( vert, GL_VERTEX_SHADER, frag, GL_FRAGMENT_SHADER, NULL );
glUseProgram( prog );
GLuint vao = 0;
glGenVertexArrays( 1, &vao );
glBindVertexArray( vao );
GLuint vbo0 = 0;
glGenBuffers( 1, &vbo0 );
glBindBuffer( GL_ARRAY_BUFFER, vbo0 );
std::vector<float> data0 =
{
-0.5f, -0.5f,
0.5f, 0.5f,
};
glBufferData( GL_ARRAY_BUFFER, data0.size() * sizeof( std::vector<float>::value_type ), data0.data(), GL_STATIC_DRAW );
glVertexAttribPointer( 0 , 2, GL_FLOAT, GL_FALSE, 0, 0 );
glEnableVertexAttribArray( 0 );
GLuint vbo1 = 0;
glGenBuffers( 1, &vbo1 );
glBindBuffer( GL_ARRAY_BUFFER, vbo1 );
std::vector<float> data1 =
{
0.0f, 1.0f,
};
glBufferData( GL_ARRAY_BUFFER, data1.size() * sizeof( std::vector<float>::value_type ), data1.data(), GL_STATIC_DRAW );
glVertexAttribPointer( 1 , 1, GL_FLOAT, GL_FALSE, 0, 0 );
glEnableVertexAttribArray( 1 );
while( !glfwWindowShouldClose( window ) )
{
glfwPollEvents();
int w, h;
glfwGetFramebufferSize( window, &w, &h );
glViewport( 0, 0, w, h );
glClear( GL_COLOR_BUFFER_BIT );
glUseProgram( prog );
glBindVertexArray( vao );
glDrawArrays( GL_LINES, 0, 2 );
glfwSwapBuffers( window );
}
glfwDestroyWindow( window );
glfwTerminate();
}
已解决;结果证明问题不在着色器代码中,而是在如何定义顶点属性 att glVertexAttributePointer。