当前位置: 首页 > 知识库问答 >
问题:

片段着色器莫名其妙的行为

蒋芷阳
2023-03-14

我已经写了一个C程序,在这里我画了一个茶壶并应用了照明。它本身很简单,但我也使用着色器。简单我是GLSL新手我刚刚尝试了一个简单的片段着色器,但是屏幕输出令人费解。

在这个文件中,我在init方法中初始化了glew,在这里我还编译了顶点和片段着色器。它们位于“顶点着色器”和“片段着色器”文件中。

你可能不认识什么是Light和材质。它们只是一些包含有关灯的所有信息的结构。我已经测试了这些结构,所以我确信工作符合预期。当我声明材质=BlackPlastic时,我只是将其设置为使用定义指令定义的默认值。如果您认为问题存在,我也可以发布此代码。

#include <GL/glew.h>
#include <GL/glut.h>
#include <iostream>
#include <fstream>
#include <vector>
#include "utility.hpp"

#define MAX_DIM 1000

GLfloat width=600, height=800;
GLuint vertex_shader, fragment_shader;
GLuint program;
const char* vertex_shader_filename= "vertex_shader";
const char* fragment_shader_filename= "fragment_shader";
Light light;
Material material;

void init()
{    
    // Inizializzazione di GLEW
    glewInit();
    if(GLEW_ARB_vertex_shader && GLEW_ARB_fragment_shader)
    {
    cout << "Supporto GLSL" << endl;
    }

    // Lettura e compilazione del vertex shader
    GLchar* buffer= new GLchar[MAX_DIM];
    ifstream stream;
    streamsize count;
    stream.open(vertex_shader_filename);
    stream.read(buffer,MAX_DIM);
    count= stream.gcount();
    stream.close();
    vertex_shader= glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertex_shader, 1, (const GLchar**)&buffer, &count);
    glCompileShader(vertex_shader);

    // Lettura, inizializzazione ed esecuzione del fragment shader
    stream.open(fragment_shader_filename);
    stream.read(buffer,MAX_DIM);
    count= stream.gcount();
    stream.close();
    fragment_shader= glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragment_shader, 1, (const GLchar**)&buffer, &count);
    glCompileShader(fragment_shader);
    delete[] buffer;

    // Creazione del programma

    program= glCreateProgram();
    glAttachShader(program, vertex_shader);
    glAttachShader(program, fragment_shader);
    glLinkProgram(program);
    glUseProgram(program);

    // Inizializzazione materiale e luce
    material= BlackPlastic;
    light= {vector<GLfloat>{-2,2,2,1} ,vector<GLfloat>{1,1,1,1},vector<GLfloat>{1,1,1,1},vector<GLfloat>{1,1,1,1} };
}

void display()
{
    glEnable(GL_DEPTH_TEST);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45,width/height,1,1000);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0,0,-100,0,0,0,0,1,0);

    // Illuminazione
    glShadeModel(GL_SMOOTH);
    material.apply(); // This just causes glMaterialfv to be called for the ambient, diffuse, specular and shininess values.
    light.apply(); // This just causes glLightfv to be called for the ambient, diffuse and specular values
    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHTING);

    // Rendering
    glClearColor(0.8,0.8,0.8,1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glutSolidTeapot(10);
    glutSwapBuffers();
}

void reshape(int w, int h)
{
    width=w;
    height=h;
    glutPostRedisplay();
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
    glutInitWindowPosition(100,100);
    glutInitWindowSize(500,500);
    glutCreateWindow("test");
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    init();
    glutMainLoop();
    return 0;
}

我不认为顶点着色器会造成任何问题,它只是正确地分配颜色和计算位置。此外,片段着色器显然是正确的,这是唯一执行的指令:

gl_FragColor = gl_Color;

如果我这样做,我只会看到一个白色的茶壶。如果改为将此值更改为任意颜色:

gl_FragColor = vec4{0,0,1,1};

我得到了颜色合适的茶壶:黑色塑料。我不知道为什么,我不在这里使用照明,我应该计算一下。

我精确地说,我执行了相同的程序,但没有应用着色器,我让茶壶有正确的颜色。

共有1个答案

庞意智
2023-03-14

首先,你把固定的函数管道和“更新的东西”混合在一起。这是一个非常糟糕的做法,因为它可能会引发很多问题,因为你并不真正知道后台发生了什么。

如果要使用漫反射着色器进行真实照明,则必须自行计算漫反射颜色。很久以前,我上次使用ffp,所以我搜索了一些使用它的着色器:

顶点着色器

varying vec3 normal;
varying vec3 v;
varying vec3 lightvec;
void main(void)
{
    normal      = normalize(gl_NormalMatrix * gl_Normal);
    v           = vec3(gl_ModelViewMatrix * gl_Vertex);
    lightvec    = normalize(gl_LightSource[0].position.xyz - v);
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

片段着色器

varying vec3 normal;
varying vec3 v;
varying vec3 lightvec;

void main(void)
{
   vec3 Eye          = normalize(-v);
   vec3 Reflected    = normalize( reflect( -lightvec, normal )); 
   vec4 IAmbient     = gl_LightSource[0].ambient * gl_FrontMaterial.ambient;
   vec4 IDiffuse     = gl_LightSource[0].diffuse * gl_FrontMaterial.diffuse * max(dot(normal, lightvec), 0.0);
   vec4 ISpecular    = gl_LightSource[0].specular * gl_FrontMaterial.specular * pow(max(dot(Reflected, Eye), 0.0), gl_FrontMaterial.shininess);
   gl_FragColor      = gl_FrontLightModelProduct.sceneColor + IAmbient + IDiffuse + ISpecular;
}
 类似资料:
  • 今天午刚睡醒就接到面试电话,用友java一面(因为海投,所以刚开始不知道面试的公司,面试官介绍他是哪个公司的时候,我也没听清楚,后面加了微信,问了一下才知道),开始就是自我介绍,然后开始挖项目,就是一通吹,然后自圆其说,然后java的基本类型有哪些?基本类型和引用类型的区别?mysql的索引,索引的底层数据结构,索引失效的场景?Spring boot的IOC aop,自动装配?环形链表?然后面到这

  • 片段着色器调用每个需要渲染的像素。我们将开发一个红色透镜,它将会增加图片的红色通道的值。 配置场景(Setting up the scene) 首先我们配置我们的场景,在区域中央使用一个网格显示我们的源图片(source image)。 import QtQuick 2.0 Rectangle { width: 480; height: 240 color: '#1e1e1e'

  • 如何使用片段着色器绘制一条线或一条曲线? 我有一个程序,根据用户指定的一组顶点计算贝塞尔曲线。在早期,我非常简单,只需在应用程序端处理每个顶点,就可以根据三次贝塞尔曲线方程生成一组插值点: ... 然后将所有处理过的顶点存储到GL_VERTEX_数组中,以便使用glDrawArrays(GL_LINE_STRIP,0,myArraySize)绘制。虽然解决方案很简单,但此实现的时间复杂度为O(n^

  • 我需要一个着色程序,然后我需要一个着色程序。一旦我从我的着色器中获得和后,是否可以将它们作为采样器发送到着色器中,以便在屏幕上渲染到四元体上? 我需要将颜色附件发送到第二个着色器的原因是,我正在不同的监视器上渲染和将出现在一个屏幕上,而将出现在另一个屏幕上。。。 我正在做测试视力的心理实验。我的第一个着色器处理我的原始纹理集,但由于两个输出纹理所需的大部分处理是相同的,所以如果不需要,我基本上不想

  • WebGL的着色器代码分为顶点着色器代码和片元着色器代码两部分,顶点着色器代码会在GPU的顶点着色器单元执行,片元着色器代码会在GPU的片元着色器单元执行,在WebGL渲染管线流程中,或者说GPU的渲染流程中,顶点着色器代码先执行处理顶点,得到一系列片元,然后再执行片元着色器代码处理片元。 main()函数 顶点着色器和片元着色器代码都有一个唯一的主函数main(),attribute、varyi