您的位置:首页 > 其它

shader 着色器

2017-05-16 23:34 127 查看

shader 着色器

着色器是运行在GPU上面的小程序,这些小程序为图形渲染的某个特定部份而运行,从基本意义上来说,着色器只一种把输入转换为输出的程序。

着色器的开头声明版本,接着输入和输出变量,uniform和main函数。

一个典型的着色器有下面的结构

#version version_number

in type in_variable_name;
in type in_variable_name;

out type out_variable_name;

uniform type uniform_name;

int main()
{
// 处理输入并进行一些图形操作
...
// 输出处理过的结果到输出变量
out_variable_name = weird_stuff_we_processed;
}


顶点着色器的输入变量也叫顶点属性(Vertex Attribute),它由硬件来决定,OpenGL确保至少有16个包含4分量的顶点属性可以用,可以用GL_MAX_VERTEX_ATTRIBS来查询

GLint nrAttributes;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes);
std::cout << "Maximum nr of vertex attributes supported: " << nrAttributes << std::endl;


数据类型

GLSL中包含C等其它语言大部份的默认的数据类型,如
int
,
float
,
double
,
uint
,
bool
.GLSL也有两种容器类型,矩阵(Matrix),向量(Vector

向量

类型说明
vecn包含n个float分量的的默认向量
bvecn包含n个bool分量的向量
ivecn包含n个int分量的向量
uvecn包含n个unsigned int 分量的向量
dvecn包含n个double分量的向量

输入与输出

顶点着色器接收的是一种特殊行式的输入,顶点着色器的输入特殊在,它从顶点数据中直接接收输入。为了定义顶点数据该如何管理,我们使用location这一元数据指定输入变量,这样我们才可以在CPU上配置顶点属性。我们已经在前面的教程看过这个了,layout (location = 0)。顶点着色器需要为它的输入提供一个额外的layout标识,这样我们才能把它链接到顶点数据。

另一个例外是片段着色器,它需要一个vec4颜色输出变量,因为片段着色器需要生成一个最终输出的颜色。如果你在片段着色器没有定义输出颜色,OpenGL会把你的物体渲染为黑色(或白色)。

所以,如果我们打算从一个着色器向另一个着色器发送数据,我们必须在发送方着色器中声明一个输出,在接收方着色器中声明一个类似的输入。当类型和名字都一样的时候,OpenGL就会把两个变量链接到一起,它们之间就能发送数据了(这是在链接程序对象时完成的)。

//
// main.cpp
// shaders0
//
// Created by xufan on 2017/5/16.
// Copyright © 2017年 xufan. All rights reserved.
//

#include <iostream>
#include <math.h>

#define GLEW_STATIC
#include <GL/glew.h>

#include <GLFW/glfw3.h>

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
void display();

// Shaders

const GLchar *vertexShaderSource = " \n \
#version 330 core \n \
layout (location = 0) in vec3 position; // position变量的属性位置值为0 \n \
layout (location = 1) in vec3 color; // 颜色变量的属性位置值为1 \n \
\n \
out vec3 ourColor; // 为片段着色器输出一个颜色输出\n \
\n \
void main() \n \
{ \n \
gl_Position = vec4(position, 1.0); // 注意我们如何把一个vec3作为vec4的构造器的参数\n \
ourColor = color; //将ourColor设置为我们从顶点数据那里得到的输入颜色\n \
}\n";

const GLchar* fragmentShaderSource = "\n \
#version 330 core \n \
in vec3 ourColor; // 从顶点着色器传来的输入变量(名称相同、类型相同)\n \
\n \
out vec4 color; // 片段着色器输出的变量名可以任意命名,类型必须是vec4\n \
//uniform vec4 ourColor; //在OpenGL程序代码中设定这个变量\n \
\n \
void main() \n \
{ \n \
color = vec4(ourColor, 1.0f); \n \
//color = ourColor; \n \
}\n";

int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);

GLFWwindow *window = glfwCreateWindow(800, 600, "learnOpenGL", nullptr, nullptr);
glfwMakeContextCurrent(window);

glfwSetKeyCallback(window, key_callback);

glewExperimental = GL_TRUE;
glewInit();

printf("%s\n",vertexShaderSource);
printf("%s\n",fragmentShaderSource);
GLint nrAttributes; glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes); std::cout << "Maximum nr of vertex attributes supported: " << nrAttributes << std::endl;
int width,height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);

//vertex shader
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);

//check
GLint success;
GLchar infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout<<"vertex shader compilation failed"<<std::endl;
}

//fragmeng shader
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource,NULL);
glCompileShader(fragmentShader);

glGetShaderiv(fragmentShader,GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cout<<"fragment shader compilation failed"<<std::endl;
}

//create a program
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);

//check
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cout<<"shaderPorgram failed"<<std::endl;
}

glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);

// GLfloat vertices[] = {
// -0.5f, -0.5f, 0.0f, // Left
// 0.5f, -0.5f, 0.0f, // Right
// 0.0f, 0.5f, 0.0f // Top
// };
// GLfloat vertices[] = {
//
//
//
// // 第一个三角形
// 0.5f, 0.5f, 0.0f, // 右上角
// 0.5f, -0.5f, 0.0f, // 右下角
// -0.5f, 0.5f, 0.0f, // 左上角
// // 第二个三角形
// 0.5f, -0.5f, 0.0f, // 右下角
// -0.5f, -0.5f, 0.0f, // 左下角
// -0.5f, 0.5f, 0.0f // 左上角
//
// };

GLfloat vertices[] = {
// 位置 // 颜色
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // 右下
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // 左下
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // 顶部

};

GLuint VBO; // vertex buffer object,顶点缓冲对象
GLuint VAO; // vertex array object ,顶点数组对象

glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);

//绑定
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);

//复制
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

//设置顶点属性指针,位置属性
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT) * 6, (GLvoid*)(0));
//启动顶点属性,位置是0
glEnableVertexAttribArray(0);

//设置颜色属性,启动
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, (GLvoid *)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);

//解绑
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);

//线框
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
//GL_FILL 填充

while (!glfwWindowShouldClose(window)) {

glfwPollEvents();

display();

//激活着色器
glUseProgram(shaderProgram);

// GLfloat timeValue = glfwGetTime();
// GLfloat greenValue = (sin(timeValue) / 2) + 0.5;
// GLint vertextColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
// glUniform4f(vertextColorLocation, 0.0f, greenValue, 0.0f, 1.0f);
//
//绘制这个三角形
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, sizeof(vertices)/ (3 * sizeof(vertices[0])));
glBindVertexArray(0);

glfwSwapBuffers(window);
}

glDeleteVertexArrays(1,&VAO);
glDeleteBuffers(1, &VBO);

glfwTerminate();

return 0;
}

void display()
{
//缓冲颜色
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
//清空颜色缓冲
glClear(GL_COLOR_BUFFER_BIT);
}

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {

std::cout<<"enter escape";
glfwSetWindowShouldClose(window, GL_TRUE);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: