Visual Studio 2012 和 2010 中基于 Opengl Sierpinski Shader 的 C 代码

Posted

技术标签:

【中文标题】Visual Studio 2012 和 2010 中基于 Opengl Sierpinski Shader 的 C 代码【英文标题】:Opengl Sierpinski Shader based C code in Visual Studio2012 & 2010 【发布时间】:2013-12-03 05:25:01 【问题描述】:

我正在 OpenGL 着色器基础编程和计算机图形学方面迈出第一步。我正在尝试以下示例,但是当我尝试编译项目时出现以下错误:

片段着色器链接失败。顶点着色器无法链接。 错误:并非所有着色器都有有效的对象代码

我尝试在 Visual Studio 2012 和 2010 中运行该程序。glut 库版本是 3.7,glew 库版本是 1.10.0。问题是什么?

.cpp 程序

#include <stdio.h>
#include <stdlib.h>
#include <glew.h>
#include <glut.h>
#include <gl.h>


#pragma comment(lib,"glew32.lib")
#define NoP 50000

GLuint InitShader(char *, char *);
void mydisplay();


struct points
   GLfloat x,y,z;
;
void init();
void Sierpinski(points Num[]);

int main(int argc, char** argv)
    
    glutInit(&argc,  argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE|GLUT_DEPTH);
    glutInitWindowSize(600, 600);
    glutInitWindowPosition(0,0);
    glutCreateWindow("Sierpinski 3D");
    glewInit();
    init();
    glEnable(GL_DEPTH_TEST);
    glutDisplayFunc(mydisplay);
    glutMainLoop();


void init()

    points  Num[NoP];
    Sierpinski(Num);

    glClearColor(1.0f, 1.0f, 1.0f, 0.0f);//set the color for clearing the display
    glPointSize(2); // set the point size
    // Creating a program object containing shader files
    GLuint program;
    program = InitShader("vshader.glsl","fshader.glsl");
    glUseProgram(program);

    //Creating a buffer object containing Sirepinski verteces data
    GLuint buffer;
    glGenBuffers(1, &buffer);
    glBindBuffer(GL_ARRAY_BUFFER, buffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Num), Num, GL_STATIC_DRAW);

    //Make a conncetion between data in object buffer and "vPosition in vertex shader
    GLuint location = glGetAttribLocation(program, "vPosition");
    glEnableVertexAttribArray ( location );
    glVertexAttribPointer( location, 3, GL_FLOAT, GL_FALSE,0, 0);//BUFFER_OFFSET(0));

void mydisplay()

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //the clear call will affect the color buffer
    glDrawArrays(GL_POINTS,0,NoP);//Rendering verteces data
    glFlush();  //Empty all commands buffer, causing all issued commands to be executed as quickly as they are accepted by the actual rendering engine


static char * ReadShaderSource(char * ShaderFile)

    FILE *fp;
    fp = fopen(ShaderFile,"rt");
    if (!fp) return NULL;
    long size=0;
    while (!feof(fp))
    
      fgetc (fp);
      size++;
    
    size--;//EOF should not be counted
    fseek(fp, 0, SEEK_SET);
    char * buf= new char[size + 1];
    fread(buf, 1, size,fp);
    buf[size]=0;// string is NULL terminated
    fclose(fp);
    return buf;

GLuint InitShader(char * vShaderFile, char * fShaderFile)
 
    char * svs, * sfs; 
    GLuint program, VertexShader, FragmentShader;
    program = glCreateProgram();
    VertexShader =  glCreateShader(GL_VERTEX_SHADER);
    svs=ReadShaderSource(vShaderFile);
    glShaderSource(VertexShader,1,(const GLchar **)&svs,NULL);
    glCompileShader(VertexShader);

    // reading GLSL compiler error messages for vertex shader
    GLint compiled;
    glGetShaderiv(VertexShader, GL_COMPILE_STATUS, &compiled);
    if(!compiled)
       printf("/n failed to compile");
        GLint logSize;
        glGetShaderiv(VertexShader, GL_INFO_LOG_LENGTH,&logSize);
        char * logMsg = new char[logSize];
        glGetShaderInfoLog(VertexShader, logSize, NULL, logMsg);
        printf("\n  %s",logMsg);
        delete [] logMsg;
        getchar();
        exit(EXIT_FAILURE);
    

    FragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    sfs = ReadShaderSource(fShaderFile);
    glShaderSource(FragmentShader, 1, (const GLchar **)&sfs, NULL);
    glCompileShader(FragmentShader);

    // reading GLSL compiler error messages for fragment shader
    glGetShaderiv(FragmentShader, GL_COMPILE_STATUS, &compiled);
    if(!compiled) 
       printf("\n failed to compile");
        GLint logSize2;
        glGetShaderiv(FragmentShader, GL_INFO_LOG_LENGTH,&logSize2);
        char * logMsg2 = new char[logSize2];
        glGetShaderInfoLog(FragmentShader, logSize2, NULL, logMsg2);
        printf("\n  %s",logMsg2);
        delete [] logMsg2;
        getchar();
        exit(EXIT_FAILURE);
    
    glAttachShader(program,VertexShader);
    glAttachShader(program, FragmentShader);
    glLinkProgram(program);
    // reading GLSL linker error messages for program object
    GLint linked;
    glGetProgramiv(program, GL_LINK_STATUS, &linked);
    if(!linked)
       printf("/n failed to link");
        GLint logSize;
        glGetProgramiv(program, GL_INFO_LOG_LENGTH,&logSize);
        char * logMsg = new char[logSize];
        glGetProgramInfoLog(program, logSize, NULL, logMsg);
        printf("\n  %s",logMsg);
        delete [] logMsg;
        getchar();
        exit(EXIT_FAILURE);
    

    glUseProgram(program);
    return program;

void Sierpinski(points Num[])

    int j;
    points  Vertices[4]=-1.0,-1.0, -1.0,1.0,-1.0,-1.0,0.0,1.0,-1.0,0.0,0.0,1.0;
    Num[0].x = 0;
    Num[0].y = 0;
    Num[0].z = 0;
    for(int i=1;i<NoP;i++)
    
        j = rand()  % 4;
        Num[i].x = (Vertices[j].x + Num[i - 1].x)/2;
        Num[i].y = (Vertices[j].y + Num[i - 1].y)/2;
        Num[i].z = (Vertices[j].z + Num[i - 1].z)/2;
    


vshader.glsl

#version 130
in vec4 vPosition;
out vec4 color;
void main()
  

    gl_Position = vPosition;
    color = vPosition;

fshader.glsl

#version 130
in vec4 color;
void main()

    gl_FragColor = vec4((1.0 + color.xyz)/2.0,1.0);

【问题讨论】:

您知道有更简单的方法可以获取着色器的文件大小,对吧? fseek (fp, 0, SEEK_END), ftell (fp), frewind (fp)... 因为着色器文件的长度不太可能超过 4 GiB,所以这样做非常安全:P 通常你会考虑 ftello (...) (Linux/OSX/BSD)/@ 987654328@(Windows)或fstat (...)(远不那么便携,因为它是POSIX而不是std.C)如果你有更大的文件来获取文件大小。但是在任何情况下,您实际上都不需要像现在这样遍历文件,这是非常低效的。 @AndonM.Coleman:或者更好,使用fstat() @kusma:这样更好吗?这会降低可移植性,并且着色器永远不会大于 4 GiB。 因为在 Windows 上,它只查询文件系统的目录项,而不是更大、更昂贵的文件项。实际上,它不会以任何方式影响可移植性,因为它在 POSIX 和 Windows 中都是如此。 【参考方案1】:

似乎工作正常:

#include <GL/glew.h>
#include <GL/glut.h>
#include <iostream>

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 << 17 ] =  0 ;
    if( glIsShader(obj) ) glGetShaderInfoLog( obj, sizeof(log), NULL, log );
    if( glIsProgram(obj) ) glGetProgramInfoLog( obj, sizeof(log), NULL, log );
    std::cerr << log << std::endl;
    exit( -1 );


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


GLuint LoadProgram( const char* vert, const char* geom, const char* frag )

    GLuint prog = glCreateProgram();
    if( vert ) AttachShader( prog, GL_VERTEX_SHADER, vert );
    if( geom ) AttachShader( prog, GL_GEOMETRY_SHADER, geom );
    if( frag ) AttachShader( prog, GL_FRAGMENT_SHADER, frag );
    glLinkProgram( prog );
    CheckStatus( prog );
    return prog;


#define GLSL(version, shader) "#version " #version "\n" #shader

const char* vert = GLSL
(
    130,
    in vec4 vPosition;
    out vec4 color;
    void main()
      
        gl_Position = vPosition;
        color = vPosition;
    
);

const char* frag = GLSL
(
    130,
    precision mediump float;
    in vec4 color;
    void main()
    
        gl_FragColor = vec4((1.0 + color.xyz)/2.0,1.0);
    
);


#define NoP 50000

struct points
   
    GLfloat x,y,z;
;

void Sierpinski(points Num[])

    int j;
    points  Vertices[4]=-1.0,-1.0, -1.0,1.0,-1.0,-1.0,0.0,1.0,-1.0,0.0,0.0,1.0;
    Num[0].x = 0;
    Num[0].y = 0;
    Num[0].z = 0;
    for(int i=1;i<NoP;i++)
    
        j = rand()  % 4;
        Num[i].x = (Vertices[j].x + Num[i - 1].x)/2;
        Num[i].y = (Vertices[j].y + Num[i - 1].y)/2;
        Num[i].z = (Vertices[j].z + Num[i - 1].z)/2;
    


void init()

    points  Num[NoP];
    Sierpinski(Num);

    GLuint program = LoadProgram( vert, NULL, frag );
    glUseProgram(program);

    //Creating a buffer object containing Sirepinski verteces data
    GLuint buffer;
    glGenBuffers(1, &buffer);
    glBindBuffer(GL_ARRAY_BUFFER, buffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Num), Num, GL_STATIC_DRAW);

    //Make a conncetion between data in object buffer and "vPosition in vertex shader
    GLuint location = glGetAttribLocation(program, "vPosition");
    glEnableVertexAttribArray ( location );
    glVertexAttribPointer( location, 3, GL_FLOAT, GL_FALSE,0, 0);//BUFFER_OFFSET(0));


void mydisplay()

    glClearColor(1.0f, 1.0f, 1.0f, 0.0f);//set the color for clearing the display
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //the clear call will affect the color buffer

    glPointSize(2); // set the point size
    glDrawArrays(GL_POINTS,0,NoP);//Rendering verteces data

    glutSwapBuffers();


int main(int argc, char** argv)

    glutInit(&argc,  argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE|GLUT_DEPTH);
    glutInitWindowSize(600, 600);
    glutInitWindowPosition(0,0);
    glutCreateWindow("Sierpinski 3D");
    glewInit();
    init();
    glEnable(GL_DEPTH_TEST);
    glutDisplayFunc(mydisplay);
    glutMainLoop();

确保你使用FreeGLUT,Nate's GLUT 太老了。

【讨论】:

谢谢。我尝试运行您的代码,还下载了您提到的 FreeGlut 版本并使用了它。但我遇到了几个错误,例如:error LNK2001: unresolved external symbol __imp____glewAttachShader 你链接到glew32.lib了吗? 谢谢。我链接了它,错误消失了。但是现在当我运行项目时,我在 cmd 处收到此消息并退出:Fragment Shader 无法编译并出现以下错误:声明必须包含精度限定符,或者必须事先声明默认精度。 你的GL_VERSIONGL_SHADING_LANGUAGE_VERSIONGL_VENDOR 是什么? 打印出glGetString(GL_VERSION)glGetString(GL_VENDOR)等在glewInit()之后的值。

以上是关于Visual Studio 2012 和 2010 中基于 Opengl Sierpinski Shader 的 C 代码的主要内容,如果未能解决你的问题,请参考以下文章

在 Visual Studio 2010 和 Visual Studio 2012 中,带有 col、colgroup、tbody 和 thead 的 HTML 表格标记引发编译错误

Visual Studio 2012 与 Visual Studio 2010 (delta) [关闭]

Visual Studio 2010 和 2012 和 2013 连接到 Team Server Foundation 2008

我可以使用 Visual Studio 2012 安装 Visual Studio 2010 SP1 SDK 吗?

用于区分 Visual Studio 2012 和 2010 的 C# 预处理器指令或条件?

我需要用于 .NET 4.5 的 Visual Studio 2012 还是 Visual Studio 2010 适合 4.5?