openGL着色器 (shader)

2023-11-06

着色器 (shader)

着色器(Shader)就是运行在GPU上的小程序。这些小程序在图形渲染管线的某个特定部分而运行。从基本意义上来说,着色器只是一种把输入转化为输出的程序。着色器也是一种非常独立的程序,因为它们之间不能相互通信;它们之间唯一的沟通只有通过输入和输出。

图形渲染管线

在讲着色器之前,不得不先理清楚openGL的图像渲染管线。在OpenGL中,任何事物都在3D空间中,而我们的屏幕和窗口却是2D像素数组,所以OpenGL的大部分工作都是关于把3D坐标转变为适应你屏幕的2D像素。3D坐标转为2D坐标的处理过程是由OpenGL的图形渲染管线(Graphics Pipeline)管理的。图形渲染管线可以被划分为两个主要部分:第一部分把3D坐标转换为2D坐标,第二部分是把2D坐标转变为实际的有颜色的像素。

下图是图形渲染管线的每个阶段的抽象展示

  • 首先,我们以数组的形式传递3个3D坐标作为图形渲染管线的输入,用来表示一个三角形,这个数组叫做顶点数据(Vertex Data);顶点数据是一系列顶点的集合。

  • 图形渲染管线的第一个部分是顶点着色器(Vertex Shader),它把一个单独的顶点作为输入。顶点着色器主要的目的是把3D坐标转为另一种3D坐标,同时顶点着色器允许我们对顶点属性进行一些基本处理。

  • 图元装配(Primitive Assembly)阶段将顶点着色器输出的所有顶点作为输入(如果是GL_POINTS,那么就是一个顶点),并所有的点装配成指定图元的形状。

  • 下一个阶段是几何着色器(Geometry Shader),图元装配阶段的输出会传递给几何着色器。几何着色器以图元形式的一系列顶点的集合为输入,通过产生新顶点构造出新的图元来生成其他形状。例子中,它生成了另一个三角形。

  • 下个阶段是光栅化阶段(Rasterization Stage),这里它会把图元映射为最终屏幕上相应的像素,生成供片段着色器(Fragment Shader)使用的片段(Fragment)(一个片段是OpenGL渲染一个像素所需的所有数据)。在片段着色器运行之前会执行裁切(Clipping)。裁切会丢弃超出视图以外的所有像素,用来提升执行效率

  • 下个阶段就是片段着色器(Fragment Shader),主要是计算一个像素的最终颜色,这也是所有OpenGL高级效果产生的地方。通常,片段着色器包含3D场景的数据(比如光照、阴影、光的颜色等等),这些数据可以被用来计算最终像素的颜色。

  • 最后,在所有对应颜色值确定以后,最终的对象将会被传到**Alpha测试和混合(Blending)**阶段。这个阶段检测片段的对应的深度值,用它们来判断这个像素在其它物体的前面还是后面,决定是否应该被丢弃(如果被其他物体挡住,此像素就可以丢弃不渲染)。这个阶段也会检查alpha值(透明度)并对物体进行混合(Blend),注意混合和深度检测之间的合作。

    原则上,OpenGL允许程序员对每个阶段进行装配,给予程序员最大自由度,但对于大多数场合,我们只需要配置顶点和片段着色器就行了。而且在现代OpenGL中,我们必须定义至少一个顶点着色器和一个片段着色器(因为GPU中没有默认的顶点/片段着色器)。出于这个原因,刚开始学习现代OpenGL的时候可能会非常困难,要了解VAO,VBO以及shader等一大堆知识,此处我推荐learnopengl网站进行相关内容的学习。本文主要是基于使用~~glut工具库(已废弃)~~的OpenGL的一些介绍,虽然glut不再更新,但架不住它可以简单画一些三角形,圆,以及在我作业里要求的茶壶。

GLSL语言

着色器是使用一种叫GLSL的类C语言写成的。GLSL是为图形计算量身定制的,它包含一些针对向量和矩阵操作的有用特性。

若要细说GLSL语言,还是有很多内容的,可以看看Addison.Wesley写的OpenGL.Shading.Language.3rd这本书,我反正没看下去,使用的时候再查也行

版本

OpenGL和GLSL语言发展至今,有很多版本,每个版本之间都有些许差异:

  • 2.0:从OpenGL 2.0开始,OpenGL 发生了重大的改变,其中最大的改变莫过于有了自己的着色语言,版本为1.00,毕竟之前使用的是固定管线,这也导致两个实现方式并存的局面。

  • 3.0:从OpenGL 3开始,编程模式被分为3种:

    • 兼容模式:传统模式。
    • 核心模式:完全新的纯可编程流水线模式,但是兼容废弃特性。(API不再兼容旧的)
    • 核心向前兼容模式:完全不兼容废弃特性,其它和核心模式相同。
  • 3.2::这个版本,最大的变化就是支持了几何着色器。

  • 3.3:这个版本就是learnopengl里面使用的,这个版本不再需要查询输入变量(attribute)的location的方式,可以使用layout去指定位置,还有片元着色器中的内建变量也弃用了,取而代之的是自定义的in和out变量。

  • 4.0:这个版本增加细分曲面着色器(Tessellation Shader),还有使用最新的Shader Language 4.00的subroutine提供了在运行时刻不需要切换着色器或者是重新编译或者使用if判断选择不同功能的方法,降低了切换着色器程序所带来的巨大开销。其中,细分曲面着色器同样在顶点着色器之后执行,但是细分曲面着色器和几何着色器谁先谁后呢?如下图:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f8Mu5aDv-1621502738664)(C:\Users\Chobit\Downloads\RenderingPipeline.png)]

  • 4.3:这个版本则是增加了可以用于并行计算的computer shader,避免在CPU中进行大量复杂的计算,可以减轻CPU的负担;同时在uniform也可以使用layout进行指定了。

OpenGL和glsl的版本比较

OpenGL Version GLSL Version
2.0 110
2.1 120
3.0 130
3.1 140
3.2 150
3.3 330
4.0 400
4.1 410
4.2 420
4.3 430

所以在使用时要注意OpenGL和GLSL的版本.

内置变量(大部分在GLSL120后弃用)

GLSL语言内置的变量,包括内置的顶点属性(attribute)、一致变量(uniform)等

  • 顶点属性:指顶点的信息,OpenGL据此绘制各个图元,对于传统的顶点属性包括坐标、纹理坐标、颜色等GLSL都会设置一个内置变量与之对应,以便在需要时可以在 顶点或片元着色器中直接引用,但在glsl120之后就已废弃。GLSL中内置的顶点属性包括以下几个:
// 顶点属性
attribute vec4 gl_Color;       // 顶点颜色
attribute vec4 gl_SecondaryColor;   // 辅助顶点颜色
attribute vec3 gl_Normal;       // 顶点法线
attribute vec4 gl_Vertex;       // 顶点物体空间坐标(未变换)
attribute vec4 gl_MultiTexCoord[0-N]; // 顶点纹理坐标(N = gl_MaxTextureCoords)
attribute float gl_FogCoord;     // 顶点雾坐标
  • 一致变量:就是常说的Uniform,这是用户向GLSL传递自己数据的最常用方法,比如光源位置等等。之所以称为一致变量,是为了与易变变量相区别。不同于顶点属性在每个顶点有其自己的值,也不同于易变变量由顶点程序向片元程序插值传递,一致变量在一个图元的绘制过程中是不会改变的,而且可以在顶点shader和 片元shader间共享。GLSL内置的一致变量包括:
// 矩阵状态
uniform mat4 gl_ModelViewMatrix;        // 模型视图变换矩阵
uniform mat4 gl_ProjectMatrix;         // 投影矩阵
uniform mat4 gl_ModelViewProjectMatrix;     // 模型视图投影变换矩阵(ftransform())
uniform mat3 gl_NormalMatrix;          // 法向量变换到视空间矩阵
uniform mat4 gl_TextureMatrix[gl_MatTextureCoords];   // 各纹理变换矩阵

// 普通缩放因子
uniform float gl_NormalScale;

// 窗口坐标深度范围
struct gl_DepthRangeParameters
{
  float near;
  float far;
  float diff; // far-near
};
uniform gl_DepthRangeParameters gl_DepthRange;

// 裁剪平面
uniform vec4 gl_ClipPlane[gl_MaxClipPlanes];

// 点属性
struct gl_PointParameters
{
  float size;
  float sizeMin;
  float sizeMax;
  float fadeThresholdSize;
  float distanceConstantAttenuation;
  float distanceLinearAttenuation;
  float distanceQuadraticAttenuation;
};
uniform gl_PointParameters gl_Point;

// 材质
struct gl_MaterialParameters
{
  vec4 emission;    // 自身光照Ecm
  vec4 ambient;    // 环境光吸收系数Acm
  vec4 diffuse;    // 漫反射吸收系数Dcm
  vec4 specular;    // 镜面反射吸收系数Scm
  float shininess;   // Srm
};
uniform gl_MaterialParameters gl_FrontMaterial;    // 正面材质
uniform gl_MaterialParameters gl_BackMaterial;    // 反面材质

// 光源性质
struct gl_LightSourceParameters
{
  vec4 ambient;        // Acii
  vec4 diffuse;        // Dcii
  vec4 specular;        // Scii
  vec4 position;        // Ppii
  vec4 halfVector;       // Hi
  vec3 spotDirection;     // Sdli
  float spotExponent;     // Srli
  float spotCutoff;      // Crli
  float spotCosCutoff;     // cos(Crli)
  float constantAttenuation;  // K0
  float linearAttenuation;   // K1
  float quadraticAttenuation; // K2
};
uniform gl_LightSourceParameters gl_LightSource[gl_MaxLights];
struct gl_LightModelParameters
{
  vec4 ambient;  // Acs
};
uniform gl_LightModelParameters gl_LightModel;

// 光照和材质的派生状态
struct gl_LightModelProducts
{
  vec4 sceneColor;    // Ecm+Acm*Acs
};
uniform gl_LightModelProducts gl_FrontLightModelProduct;
uniform gl_LightModelProducts gl_BackLightModelProduct;
struct gl_LightProducts
{
  vec4 ambient;   // Acm * Acli
  vec4 diffuse;   // Dcm * Dcli
  vec4 specular;   // Scm * Scli
};
uniform gl_LightProducts gl_FrontLightProduct[gl_MaxLights];
uniform gl_LightProducts gl_BackLightProduct[gl_MaxLights];


// 纹理环境和生成
unifrom vec4 gl_TextureEnvColor[gl_MaxTextureImageUnits];
unifrom vec4 gl_EyePlaneS[gl_MaxTextureCoords];
unifrom vec4 gl_EyePlaneT[gl_MaxTextureCoords];
unifrom vec4 gl_EyePlaneR[gl_MaxTextureCoords];
unifrom vec4 gl_EyePlaneQ[gl_MaxTextureCoords];
unifrom vec4 gl_ObjectPlaneS[gl_MaxTextureCoords];
unifrom vec4 gl_ObjectPlaneT[gl_MaxTextureCoords];
unifrom vec4 gl_ObjectPlaneR[gl_MaxTextureCoords];
unifrom vec4 gl_ObjectPlaneQ[gl_MaxTextureCoords];

// 雾参数
struct gl_FogParameters
{
  vec4 color;
  float density;
  float start;
  float end;
  float scale; // 1/(end-start)
};
uniform gl_FogParameters gl_Fog;

注:除了 gl_DepthRange 外的所有uniform都已在glsl 1.30 中废弃.

顶点着色器

顶点着色器(Vertex Shader)是几个可编程着色器中的一个。首先用着色器语言GLSL编写顶点着色器,然后编译这个着色器,这样我们就可以在程序中使用它了。下面你会看到一个非常基础的GLSL顶点着色器的源代码:

#version 330 core //版本申明,并申明使用核心模式
layout (location = 0) in vec3 aPos; //in关键字表示该变量是输入的数据,layout (location = 0)`设定了输入变量的位置值(Location)

void main()
{
    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}

当前这个顶点着色器可能是我们能想到的最简单的顶点着色器了,因为我们对输入数据什么都没有处理就把它传到着色器的输出了。在真实的程序里输入数据通常都不是标准化设备坐标,所以我们首先必须先把它们转换至OpenGL的可视区域内。

片段着色器

片段着色器(Fragment Shader)所做的是计算像素最后的颜色输出。以下例子中的片段着色器将会一直输出橘黄色。在计算机图形中颜色被表示为有4个元素的数组:红色、绿色、蓝色和alpha(透明度)分量,通常缩写为RGBA。

#version 330 core
out vec4 FragColor;

void main()
{
    FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);//完全不透明的橘黄色
} 

片段着色器只需要一个输出变量FragColor,表示最终的输出颜色,我们应该自己将其计算出来。声明输出变量可以使用out关键字。

编译着色器

现在,我们暂时将顶点(片段)着色器的源代码硬编码在代码文件顶部的C风格字符串中:例如

const char *vertexShaderSource = "#version 330 core\n"
    "layout (location = 0) in vec3 aPos;\n"
    "void main()\n"
    "{\n"
    "   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
    "}\0";

为了能够让OpenGL我们写的着色器,必须在运行时动态编译它的源代码。

  • 首先要做的是创建一个着色器对象:
unsigned int shader;
shader = glCreateShader(GL_VERTEX_SHADER);//glCreateShader(GL_FRAGMENT_SHADER);

我们把需要创建的着色器类型以参数形式提供给glCreateShaderGL_VERTEX_SHADER表示创建顶点着色器,GL_FRAGMENT_SHADER片段着色器。

  • 下一步把这个着色器源码附加到着色器对象上,然后编译它:
glShaderSource(shader, 1, &shaderSource, NULL);//绑定
glCompileShader(shader);//编译

glShaderSource函数把要编译的着色器对象作为第一个参数,第二参数指定了传递的源码字符串数量,这里只有一个。第三个参数是顶点着色器真正的源码,第四个参数我们先设置为NULL

  • 检测编译时错误可以通过以下代码来实现:
int  success;
char infoLog[512];
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);

首先我们定义一个整型变量来表示是否成功编译,还定义了一个储存错误消息的容器。然后我们用glGetShaderiv检查是否编译成功。如果编译失败,我们会用glGetShaderInfoLog获取错误消息,然后打印它。

if(!success)
{
    glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
    std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}

如果编译的时候没有检测到任何错误,顶点着色器就被编译成功了。

着色器程序

着色器程序对象(Shader Program Object)是多个着色器合并之后并最终链接完成的版本。如果要使用刚才编译的着色器我们必须把它们链接(Link)为一个着色器程序对象,然后在渲染对象的时候激活这个着色器程序。已激活着色器程序的着色器将在我们发送渲染调用的时候被使用。

当链接着色器至一个程序的时候,它会把每个着色器的输出链接到下个着色器的输入。当输出和输入不匹配的时候,你会得到一个连接错误。

  • 首先创建一个着色器程序对象:
unsigned int shaderProgram;
shaderProgram = glCreateProgram();

glCreateProgram函数创建一个程序,并返回新创建程序对象的ID引用。

  • 然后把之前编译的着色器附加到程序对象上,然后用glLinkProgram链接它们:
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
  • 就像着色器的编译一样,我们也可以检测链接着色器程序是否失败:
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if(!success) {
    glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
}
  • 最后,在使用前调用glUseProgram函数,用刚创建的程序对象作为它的参数,以激活这个程序对象:
glUseProgram(shaderProgram);
  • 在把着色器对象链接到程序对象以后,记得删除着色器对象,我们不再需要它们了:
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);

现在,我们已经指示了GPU如何在顶点和片段着色器中处理我们的物体。

示例

绘制两个茶壶,一个采用固定管线的Per-Vertex shading,另一个使用Per-Pixel Shading.

现实世界的光照是极其复杂的,而且会受到诸多因素的影响,这是我们有限的计算能力所无法模拟的。因此OpenGL的光照使用的是简化的模型,其中一个模型被称为冯氏光照模型(Phong Lighting Model)。冯氏光照模型的主要结构由3个分量组成:环境(Ambient)、漫反射(Diffuse)和镜面(Specular)光照。

  • 环境光照(Ambient Lighting):即使在黑暗的情况下,世界上通常也仍然有一些光亮(月亮、远处的光),所以物体几乎永远不会是完全黑暗的。为了模拟这个,我们会使用一个环境光照常量,它永远会给物体一些颜色。
  • 漫反射光照(Diffuse Lighting):模拟光源对物体的方向性影响(Directional Impact)。它是冯氏光照模型中视觉上最显著的分量。物体的某一部分越是正对着光源,它就会越亮。
  • 镜面光照(Specular Lighting):模拟有光泽物体上面出现的亮点。镜面光照的颜色相比于物体的颜色会更倾向于光的颜色。
Per-Vertex shading 逐顶点着色

针对每个顶点计算,而后对每个顶点的结果颜色进行线性插值得到片元的颜色。

  • 如上述GLSL语言内置的变量提供了很多对OpenGL状态的访问,其中包含了灯光设置的数据以及材质属性的设置,既包括单个光的参数,也包括全局光源的参数:
uniform gl_LightSourceParameters gl_LightSource[gl_MaxLights];//单个光源
uniform gl_LightModelParameters gl_LightModel;//全局光源

uniform gl_MaterialParameters gl_FrontMaterial;//前面材质
uniform gl_MaterialParameters gl_BackMaterial;//后面材质
  • 我们从漫反射这一项开始, OpenGL中的漫射照明假设: 无论观察者的位置如何,光线都以相同的强度被感知。它的强度与光的漫反射强度和材料的漫反射系数成正比, “朗伯余弦定律”还指出,漫反射平面的亮度还与光的入射方向和表面法线之间的角度的余弦值成正比。 公式如下:
    在这里插入图片描述

    I表示反射强度, Ld表示光的漫反射颜色(gl_LightSource[0].diffuse), Md是材质的漫反射颜色(gl_FrontMaterial.diffuse)。

    在顶点着色器中使用这个公式,将要使用到光源的位置属性和漫反射强度.同时还有材质的漫反射强度.因此,要使用这个着色器,只需像往常一样在OpenGL中设置灯光。 但是请注意,因为我们不使用固定的功能,所以不需要启用灯光(不用写glEnable(GL_LIGHTING);glEnable(GL_LIGHT0)等代码)。

    因为我们需要计算余弦,首先要确保法向量和光方向向量(gl_LightSource[0].position)是标准化的,然后我们将使用点乘来得到余弦。OpenGL在视觉空间坐标中存储光的方向; 因此,我们需要将法线转换到视觉空间来计算点乘。 为了将法线转换到视觉空间,使用预定义的统一变量gl_NormalMatrix。 这个矩阵是模型视图矩阵3×3左上子矩阵的逆的转置。

  • 接下来是全局光ambient, 公式如下:
    在这里插入图片描述

  • 最后就是镜面反射的部分,镜面光照也是依据光的方向向量和物体的法向量来决定的,但是它也依赖于观察方向,例如玩家是从什么方向看着这个片段的。镜面光照是基于光的反射特性。如果我们想象物体表面像一面镜子一样,那么,无论我们从哪里去看那个表面所反射的光,镜面光照都会达到最大化。
    根据Phong模型,镜面反射正比于光反射矢量和视线矢量夹角的余弦值。 如下图:
    在这里插入图片描述
    L是从光照到被着色顶点的向量。 N是法向量,Eye是从顶点到眼睛或相机的向量。 R是镜面反射光。 如果眼睛向量与反射向量重合,那么我们就得到了最大的镜面强度。 当偏离反射矢量时,镜面强度衰减。 衰减速率由一个亮度因子控制。 亮度因子越高,衰减越快。 这意味着高亮度的高光斑比低亮度的高光斑要小。 简单地说,亮度shiness(OpenGL中的值在0到128之间)控制着亮点的大小(在代码中用glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 128)设置)。

    反射矢量的计算公式:
    在这里插入图片描述

    Phong模型的镜面反射公式:
    在这里插入图片描述
    s指数为亮度值,Ls为光的反射强度,Ms为材料的反射系数。

    Blinn提出了一个更简单、更快的模型,基于半矢量的Blinn- phong模型。 半矢量是一个方向介于视线矢量和光矢量之间的矢量,镜面反射的强度基于半矢量和法线之间夹角的余弦。
    在这里插入图片描述
    半矢量的计算公式:
    在这里插入图片描述
    Blinn-Phong模型的镜面反射公式:
    在这里插入图片描述

    GLSL120为我们计算了半向量!

  • GLSL代码:

//顶点着色器
    void main()
    {
    	vec3 normal, lightDir, viewVector, halfVector;
    	vec4 diffuse, ambient, globalAmbient, specular = vec4(0.0);
    	float NdotL,NdotHV;
    
    	normal = normalize(gl_NormalMatrix * gl_Normal);
    
    	lightDir = normalize(vec3(gl_LightSource[0].position));
    
    	NdotL = max(dot(normal, lightDir), 0.0);
    	
    	diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
    	ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;
    	globalAmbient = gl_LightModel.ambient * gl_FrontMaterial.ambient;
    
    	if (NdotL > 0.0) {
    
    		NdotHV = max(dot(normal, normalize(gl_LightSource[0].halfVector.xyz)),0.0);
    		specular = gl_FrontMaterial.specular * gl_LightSource[0].specular * pow(NdotHV,gl_FrontMaterial.shininess);
    	}
    	
    	gl_FrontColor = globalAmbient + NdotL * diffuse + ambient + specular;
    
    	gl_Position = ftransform();
    	
    } 
    //片段着色器
    void main()
    {
    	gl_FragColor = gl_Color;
    }

效果图
在这里插入图片描述

Per-Pixel shading

对每个片元进行着色计算
每个顶点会有两个信息: 法线和半向量 。我们将法线转换为视觉空间,并将其标准化。 这个归一化向量将被插值,然后发送到片段着色器,所以我们需要声明可变变量来保持法线。 我们也可以在顶点着色器中结合灯光设置和材质进行一些计算,从而帮助在顶点着色器和碎片着色器之间分配负载。

//顶点着色器
varying vec4 diffuse,ambient;
varying vec3 normal,halfVector;
 
void main()
{
    /* first transform the normal into eye space and
    normalize the result */
    normal = normalize(gl_NormalMatrix * gl_Normal);
 
    /* pass the halfVector to the fragment shader */
    halfVector = gl_LightSource[0].halfVector.xyz;
 
    /* Compute the diffuse, ambient and globalAmbient terms */
    diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
    ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;
    ambient += gl_LightModel.ambient * gl_FrontMaterial.ambient;
    gl_Position = ftransform();
 
}

在片段着色器中, 必须声明相同的变量。 法线已经被插值计算过,所以还是需要正则化。 然后计算法线和光向之间的点乘。 如果点积NdotL大于零,那么我们必须计算漫反射以及镜面反射,从顶点着色器接收到的漫反射强度乘以点乘。再对从顶点着色器接收到的半矢量进行归一化,并计算归一化半矢量和法线之间的点乘。 根据镜面反射公式计算镜面反射的强度。

//片段着色器
varying vec4 diffuse,ambient;  
varying vec3 normal,lightDir,halfVector;  
 
void main()  
{  
 
    vec3 n,halfV;  
    float NdotL,NdotHV;  
    vec4 color = ambient;  
    n = normalize(normal);  
 
    NdotL = max(dot(n,lightDir),0.0);  
    if (NdotL > 0.0)  {  
       color += diffuse * NdotL;  
       halfV = normalize(halfVector);  
       NdotHV = max(dot(n,halfV),0.0);  
       color += gl_FrontMaterial.specular * gl_LightSource[0].specular * pow(NdotHV, gl_FrontMaterial.shininess);  
     }  
     gl_FragColor = color;  
}

效果图
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

openGL着色器 (shader) 的相关文章

  • 更改 GLUT 调用以与 MFC/C++ 一起使用

    我有一个使用 GLUT 进行 OpenGL 渲染的程序 现在我需要它位于 MFC 项目内部 以便它可以与另一个程序组件一起使用 我已经按照这个教程进行操作 http www codeguru com cpp g m opengl openf
  • 致命错误 gl.h 包含在 glew.h 之前

    include
  • 在windows + opengl中选择图形设备

    我知道如何使用 openGL 打开窗口 使用 Win32 或其他工具包 但是当系统有2块显卡时 如何选择要渲染的图形设备 我的编程语言是 C 我专注于 Windows 但任何示例都将受到欢迎 编辑 也许更好地解释我的问题是个好主意 以便添加
  • 有没有好的 GLSL 哈希函数?

    所以我对这个问题的古老评论仍然得到了支持 GLSL rand 这一行代码的起源是什么 https stackoverflow com questions 12964279 whats the origin of this glsl rand
  • 如何在不使用 Kinect SDK 函数的情况下将深度空间中的点转换为 Kinect 中的颜色空间?

    我正在做一个增强现实应用程序 将 3D 对象叠加在用户的彩色视频之上 使用 Kinect 1 7 版本 虚拟对象的渲染在 OpenGL 中完成 我已经成功地在深度视频上叠加了 3D 对象 只需使用 NuiSensor h 标头中深度相机的固
  • OpenGL:顶点越多,性能越慢

    我正在开发一个程序的一部分 其中给定 xyz 坐标集合 制作 3D 模型 我已经完成了这张图片所需的所有功能 即平移 旋转 缩放 但是给出的 xyz 坐标越多 程序运行速度就越慢 我的程序在处理 29 000 个坐标时运行得非常流畅 但当我
  • 如何使用现代 OpenGL 在透视投影中绘制对象的正交轴? [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我有带有透视投影的 3D 场景 我还可以选择场景中的一个对象 我需要为选定的对象绘制轴 问题是轴不会在透视投影中保存其大小 如果物体远离眼睛
  • 在 QML 中控制纹理 3D 对象的不透明度

    我对 QML 中的 Qt 3D 有点陌生 我正在尝试控制 Qt 3D 的不透明度textured3D 对象 我正在使用简单qml3d https github com tripolskypetr simpleqml3d测试项目来做到这一点
  • glColor4f() - alpha 值的效果

    我正在使用 glColor4f 令人惊讶的是 更改 alpha 即第四个参数 不会导致透明度发生任何变化 代码段是 const GLfloat squareVertices 0 5 0 5 0 0 0 5 0 5 0 0 0 5 0 5 0
  • Opengl 视频纹理

    我正在使用 Visual Studio 10 在 Windows 上用 C 开发 opengl 应用程序 目前我在立方体上使用静态纹理 但我想集成视频纹理 你知道我可以使用哪个库来打开和解密视频吗 查看 ffmpeg libavformat
  • glm 中矩阵值的顺序不正确?

    我开始使用GLM http glm g truc net通过 OpenGL 3 和 GLSL 进行数学运算的库 我需要正交投影来绘制 2D 图形 所以我编写了这个简单的代码 glm mat4 projection 1 0 projectio
  • 在 OpenGL 中渲染纹理 1 到 1

    所以我想做的是使用 OpenGL 和 C 将纹理渲染到平面上 作为显示图像的一种方式 但是我需要确保在渲染纹理时没有对纹理进行任何处理 抗锯齿 插值 平滑 模糊等 这是 OpenGL 处理渲染纹理的默认方式吗 或者是否需要设置一些标志才能禁
  • 延迟阴影映射 GLSL

    我目前正在实施延迟渲染管道 但我仍坚持使用阴影贴图 我已经成功地将其实施到前向管道中 我所做的步骤是 获取灯光视图中的位置 转换为光视图剪辑空间 使用 0 5 0 5 获取阴影纹理坐标 检查深度 编辑 使用新结果图像更新代码 float c
  • 创建并使用我自己的纹理图集的 mipmap

    我目前正在使用自动 mipmap 生成 C OpenTK GL GenerateMipmap GenerateMipmapTarget Texture2D 我使用的纹理平铺为 16px 的块 所以我的问题是 是否可以使用不会缩小至 1x1
  • Qt 5.5 QOpenGLWidget 链接错误未链接任何 openGL 调用

    我尝试使用 Qt 5 5 1 构建一个简单的 OpenGL 应用程序 一切都很好 直到我尝试使用 glClearColor 等 openGL 本机函数调用 该小部件实际上编译并产生黑屏 但在我尝试使用任何 openGL 本机函数后 它甚至不
  • GPU-android opengl es 3.0中的亮度直方图计算

    用于亮度直方图计算 我使用了 Brad Larson 的 GPU image ios 项目中的代码 他使用混合进行直方图计算 连接顶点和片段着色器 顶点着色器 version 300 es in vec4 position out vec3
  • 在着色器中旋转法线

    我有一个场景 其中有多个具有各自位置和旋转的模型 给定法线 着色器对每个像素应用简单的双向照明 那是我的顶点着色器 version 150 in vec3 position in vec3 normal in vec2 texcoord o
  • 带有 std::vector 的 VBO

    我用 C 和 OpenGL 编写了一个模型加载器 我用过std vectors 来存储我的顶点数据 但现在我想将其传递给glBufferData 但是数据类型却截然不同 我想知道是否有办法可以相互转换std vector至已记录的const
  • OpenSceneGraph 将相机设置在初始位置

    我是第一次使用 OpenSceneGraph 我有点迷失 因为文档确实不太清楚 所以 我有这段代码加载一个带有房子的 obj 文件 并且我在我想要的 人 所在的地方淹没了一个小盒子 所以现在 我不想把那个盒子放在那里 而是想把相机放在那里
  • Windows 上的 OpenGL SDK

    我正在尝试编写一个 OpenGL 应用程序 因此我安装了 Windows 7 SDK 然而 它似乎是OpenGL 1 1 define GL VERSION 1 1 1 如何找到我安装的 OpenGL 版本 dll 以及在哪里可以找到较新的

随机推荐