导航:首页 > 净水问答 > glsl顶点过滤

glsl顶点过滤

发布时间:2021-11-12 16:20:09

『壹』 WebGL的顶点着色器编译失败,问题,怎么解决

WebGL里有顶点着色器和片段着色器两种着色器。无论哪一种都可以使用GLSL来编写。顶点着色器和片段着色器是相互依赖的,缺一不可,并且首先被调用的是顶点着色器。

『贰』 GLSL初学求助着色器不起作用橙宝书的程序

OpenGL着色语言(GLSL―OpenGLShadingLanguage)是用来在OpenGL中着色编程的语言,也即开发人员写的短小的自定义程序,他们是在图形卡的GPU(GraphicProcessorUnit图形处理单元)上执行的,代替了固定的渲染管线的一部分,使渲染管线中不同层次具有可编程型。比如:视图转换、投影转换等。GLSL(GLShadingLanguage)的着色器代码分成2个部分:VertexShader(顶点着色器)和Fragment(片断着色器),有时还会有GeometryShader(几何着色器)。负责运行顶点着色的是顶点着色器。它可以得到当前OpenGL中的状态,GLSL内置变量进行传递。GLSL其使用C语言作为基础高阶着色语言,避免了使用汇编语言或硬件规格语言的复杂性。

『叁』 glsl语言和c语言的区别·也就是不同的地方有哪些,明确点。谢谢喽

变量

GLSL的变量命名方式与C语言类似。变量的名称可以使用字母,数字以及下划线,但变量名不能以数字开头,还有变量名不能以gl_作为前缀,这个是GLSL保留的前缀,用于GLSL的内部变量。当然还有一些GLSL保留的名称是不能够作为变量的名称的。

基本类型

除了布尔型,整型,浮点型基本类型外,GLSL还引入了一些在着色器中经常用到的类型作为基本类型。这些基本类型都可以作为结构体内部的类型。如下表:

类型 描述
void 跟C语言的void类似,表示空类型。作为函数的返回类型,表示这个函数不返回值。
bool 布尔类型,可以是true 和false,以及可以产生布尔型的表达式。
int 整型 代表至少包含16位的有符号的整数。可以是十进制的,十六进制的,八进制的。
float 浮点型
bvec2 包含2个布尔成分的向量
bvec3 包含3个布尔成分的向量
bvec4 包含4个布尔成分的向量
ivec2 包含2个整型成分的向量
ivec3 包含3个整型成分的向量
ivec4 包含4个整型成分的向量
mat2 或者 mat2x2 2×2的浮点数矩阵类型
mat3或者mat3x3 3×3的浮点数矩阵类型
mat4x4 4×4的浮点矩阵
mat2x3 2列3行的浮点矩阵(OpenGL的矩阵是列主顺序的)
mat2x4 2列4行的浮点矩阵
mat3x2 3列2行的浮点矩阵
mat3x4 3列4行的浮点矩阵
mat4x2 4列2行的浮点矩阵
mat4x3 4列3行的浮点矩阵
sampler1D 用于内建的纹理函数中引用指定的1D纹理的句柄。只可以作为一致变量或者函数参数使用
sampler2D 二维纹理句柄
sampler3D 三维纹理句柄
samplerCube cube map纹理句柄
sampler1DShadow 一维深度纹理句柄
sampler2DShadow 二维深度纹理句柄

结构体

结构体

结构体可以组合基本类型和数组来形成用户自定义的类型。在定义一个结构体的同时,你可以定义一个结构体实例。或者后面再定义。
struct surface {float indexOfRefraction;

vec3 color;float turbulence;

} mySurface;

surface secondeSurface;

你可以通过=为结构体赋值,或者使用 ==,!=来判断两个结构体是否相等。

mySurface = secondSurface;

mySurface == secondSurface;

只有结构体中的每个成分都相等,那么这两个结构体才是相等的。访问结构体的内部成员使用. 来访问。

vec3 color = mySurface.color + secondSurface.color;

结构体至少包含一个成员。固定大小的数组也可以被包含在结构体中。GLSL的结构体不支持嵌套定义。只有预先声明的结构体可以嵌套其中。
struct myStruct {

vec3 points[3]; //固定大小的数组是合法的

surface surf; //可以,之前已经定义了

struct velocity { //不合法float speed;

vec3 direction;

} velo;

subSurface sub; //不合法,没有预先声明;};struct subSurface { int id;
};

数组

GLSL中只可以使用一维的数组。数组的类型可以是一切基本类型或者结构体。下面的几种数组声明是合法的:
surface mySurfaces[];
vec4 lightPositions[8];
vec4 lightPos[] = light www.hnne.com Positions;const int numSurfaces = 5;
surface myFiveSurfaces[numSurfaces];float[5] values;

指定显示大小的数组可以作为函数的参数或者使返回值,也可以作为结构体的成员.数组类型内建了一个length()函数,可以返回数组的长度。

lightPositions.length() //返回数组的大小 8

最后,你不能定义数组的数组。

修饰符

变量的声明可以使用如下的修饰符。

修饰符 描述
const 常量值必须在声明是初始化。它是只读的不可修改的。
attribute 表示只读的顶点数据,只用在顶点着色器中。数据来自当前的顶点状态或者顶点数组。它必须是全局范围声明的,不能再函数内部。一个attribute可以是浮点数类型的标量,向量,或者矩阵。不可以是数组或则结构体
uniform 一致变量。在着色器执行期间一致变量的值是不变的。与const常量不同的是,这个值在编译时期是未知的是由着色器外部初始化的。一致变量在顶点着色器和片段着色器之间是共享的。它也只能在全局范围进行声明。
varying 顶点着色器的输出。例如颜色或者纹理坐标,(插值后的数据)作为片段着色器的只读输入数据。必须是全局范围声明的全局变量。可以是浮点数类型的标量,向量,矩阵。不能是数组或者结构体。
centorid varying 在没有多重采样的情况下,与varying是一样的意思。在多重采样时,centorid varying在光栅化的图形内部进行求值而不是在片段中心的固定位置求值。
invariant (不变量)用于表示顶点着色器的输出和任何匹配片段着色器的输入,在不同的着色器中计算产生的值必须是一致的。所有的数据流和控制流,写入一个invariant变量的是一致的。编译器为了保证结果是完全一致的,需要放弃那些可能会导致不一致值的潜在的优化。除非必要,不要使用这个修饰符。在多通道渲染中避免z-fighting可能会使用到。
in 用在函数的参数中,表示这个参数是输入的,在函数中改变这个值,并不会影响对调用的函数产生副作用。(相当于C语言的传值),这个是函数参数默认的修饰符
out 用在函数的参数中,表示该参数是输出参数,值是会改变的。
inout 用在函数的参数,表示这个参数即是输入参数也是输出参数。

内置变量

内置变量可以与固定函数功能进行交互。在使用前不需要声明。顶点着色器可用的内置变量如下表:

名称 类型 描述
gl_Color vec4 输入属性-表示顶点的主颜色
gl_SecondaryColor vec4 输入属性-表示顶点的辅助颜色
gl_Normal vec3 输入属性-表示顶点的法线值
gl_Vertex vec4 输入属性-表示物体空间的顶点位置
gl_MultiTexCoordn vec4 输入属性-表示顶点的第n个纹理的坐标
gl_FogCoord float 输入属性-表示顶点的雾坐标
gl_Position vec4 输出属性-变换后的顶点的位置,用于后面的固定的裁剪等操作。所有的顶点着色器都必须写这个值。
gl_ClipVertex vec4 输出坐标,用于用户裁剪平面的裁剪
gl_PointSize float 点的大小
gl_FrontColor vec4 正面的主颜色的varying输出
gl_BackColor vec4 背面主颜色的varying输出
gl_FrontSecondaryColor vec4 正面的辅助颜色的varying输出
gl_BackSecondaryColor vec4 背面的辅助颜色的varying输出
gl_TexCoord[] vec4 纹理坐标的数组varying输出
gl_FogFragCoord float 雾坐标的varying输出

片段着色器的内置变量如下表:

名称 类型 描述
gl_Color vec4 包含主颜色的插值只读输入
gl_SecondaryColor vec4 包含辅助颜色的插值只读输入
gl_TexCoord[] vec4 包含纹理坐标数组的插值只读输入
gl_FogFragCoord float 包含雾坐标的插值只读输入
gl_FragCoord vec4 只读输入,窗口的x,y,z和1/w
gl_FrontFacing bool 只读输入,如果是窗口正面图元的一部分,则这个值为true
gl_PointCoord vec2 点精灵的二维空间坐标范围在(0.0, 0.0)到(1.0, 1.0)之间,仅用于点图元和点精灵开启的情况下。
gl_FragData[] vec4 使用glDrawBuffers输出的数据数组。不能与gl_FragColor结合使用。
gl_FragColor vec4 输出的颜色用于随后的像素操作
gl_FragDepth float 输出的深度用于随后的像素操作,如果这个值没有被写,则使用固定功能管线的深度值代替

表达式

操作符

GLSL语言的操作符与C语言相似。如下表(操作符的优先级从高到低排列)

操作符 描述
() 用于表达式组合,函数调用,构造
[] 数组下标,向量或矩阵的选择器
. 结构体和向量的成员选择
++ – 前缀或后缀的自增自减操作符
+ – ! 一元操作符,表示正 负 逻辑非
* / 乘 除操作符
+ - 二元操作符 表示加 减操作
<> <= >= == != 小于,大于,小于等于, 大于等于,等于,不等于 判断符
&& || ^^ 逻辑与 ,或, 异或
?: 条件判断符
= += –= *= /= 赋值操作符
, 表示序列

像 求地址的& 和 解引用的 * 操作符不再GLSL中出现,因为GLSL不能直接操作地址。类型转换操作也是不允许的。 位操作符(&,|,^,~, <<, >> ,&=, |=, ^=, <<=, >>=)是GLSL保留的操作符,将来可能会被使用。还有求模操作(%,%=)也是保留的。

数组访问

数组的下标从0开始。合理的范围是[0, size - 1]。跟C语言一样。如果数组访问越界了,那行为是未定义的。如果着色器的编译器在编译时知道数组访问越界了,就会提示编译失败。

vec4 myColor, ambient, diffuse[6], specular[6];

myColor = ambient + diffuse[4] + specular[4];

构造函数

构造函数可以用于初始化包含多个成员的变量,包括数组和结构体。构造函数也可以用在表达式中。调用方式如下:

vec3 myNormal = vec3(1.0, 1.0, 1.0);

greenTint = myColor + vec3(0.0, 1.0, 0.0);

ivec4 myColor = ivec4(255);

还可以使用混合标量和向量的方式来构造,只要你的元素足以填满该向量。

vec4 color = vec4(1.0, vec2(0.0, 1.0), 1.0);

vec3 v = vec3(1.0, 10.0, 1.0);

vec3 v1 = vec3(v);

『肆』 glsl 顶点着色器 能实现波浪吗

设置OpenGL ES环境
创建GLSurfaceView
显示OpenGL图形需要使用GLSurfaceView类像其任何View类意义添加Activity或Fragment通布局xml文件定义或者代码创建实例
本教程我使用GLSurfaceView作唯View我Activity简便我代码创建GLSurfaceView实例并其传入setContentView填充整手机屏幕ActivityonCreate:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); GLSurfaceView view = new GLSurfaceView(this); setContentView(view);}
媒体效框架仅仅支持OpenGL ES2.0及版本所setEGLContextClientVersion 传入2;
view.setEGLContextClientVersion(2);
确保GLSurfaceView仅仅必要候进行渲染我setRenderMode 进行设置:
view.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
创建Renderer
Renderer负责渲染GLSurfaceView内容
创建类实现接口GLSurfaceView.Renderer我打算类命名EffectsRenderer添加构造函数并覆写接口抽象:
public class EffectsRenderer implements GLSurfaceView.Renderer { public EffectsRenderer(Context context){ super(); } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { } @Override public void onDrawFrame(GL10 gl) { }}
Activity调用setRenderer让GLSurfaceView使用我创建Renderer:
view.setRenderer(new EffectsRenderer(this));
编写Manifest文件
想要发布App谷歌商店AndroidManifest.xml文件添加语句:

确保app能安装支持OpenGL ES2.0设备现OpenGL环境准备完毕
创建OpenGL平面
定义顶点
GLSurfaceView能直接显示张照片照片首先应该转化纹理应用OpenGL square本教程我创建2D平面并且具4顶点简单我使用形现创建新类Square用代表形状
public class Square {}
默认OpenGL系统坐标系原点4角坐标表示:
左角: (-1, -1) 右角:(1, -1) 右角:(1, 1) 左角:(-1, 1)
我使用OpenGL绘制所物体都应该由三角形决定画形我需要两具条公共边三角形意味着些三角形坐标应该:
triangle 1: (-1, -1) (1, -1) (-1, 1) triangle 2: (1, -1) (-1, 1) (1, 1)
创建float数组代表些顶点:
private float vertices[] = { -1f, -1f, 1f, -1f, -1f, 1f, 1f, 1f,};
square定位纹理需要确定纹理顶点坐标创建另数组表示纹理顶点坐标:
private float textureVertices[] = { 0f,1f, 1f,1f, 0f,0f, 1f,0f};
创建缓冲区
些坐标数组应该转变缓冲字符(byte buffer)OpenGL使用前接进行定义:
private FloatBuffer verticesBuffer;private FloatBuffer textureBuffer;
initializeBuffers初始化些缓冲区:使用ByteBuffer.allocateDirect创建缓冲区float4字节我需要byte数组度应该float4倍
面使用ByteBuffer.nativeOrder定义底层本平台byte顺序使用asFloatBufferByteBuffer转化FloatBufferFloatBuffer创建我调用putfloat数组放入缓冲区调用position保证我由缓冲区进行读取
private void initializeBuffers(){ ByteBuffer buff = ByteBuffer.allocateDirect(vertices.length * 4); buff.order(ByteOrder.nativeOrder()); verticesBuffer = buff.asFloatBuffer(); verticesBuffer.put(vertices); verticesBuffer.position(0); buff = ByteBuffer.allocateDirect(textureVertices.length * 4); buff.order(ByteOrder.nativeOrder()); textureBuffer = buff.asFloatBuffer(); textureBuffer.put(textureVertices); textureBuffer.position(0);}
创建着色器
着色器简单运行GPU每单独顶点C程序本教程我使用两种着色器:顶点着色器片段着色器
顶点着色器代码:
attribute vec4 aPosition; attribute vec2 aTexPosition; varying vec2 vTexPosition; void main() { gl_Position = aPosition; vTexPosition = aTexPosition; };
片段着色器代码
precision mediump float; uniform. sampler2D uTexture; varying vec2 vTexPosition; void main() { gl_FragColor = texture2D(uTexture, vTexPosition); };
解OpenGL段代码说熟悉能理解段代码参考OpenGL documentation
-

『伍』 glsl 怎么打印FBO的内容

什么叫“打印”FBO?

FBO是frame buffer object,是一堆数据,你要打印这个?

不管怎么样,shader只管吃进顶点,然后计算,算出来的结果返回给rendertarget。其他的是在API(openGL)里做。你要打印什么东西的话,就要去C++里调打印机。和shader完全没有关系。

『陆』 如何调试GLSL Fragment shader

要断点调试的话有些麻烦,要专门的插件我也没用过
我一般是用颜色值来观察的,把一些数值赋给顶点颜色,就能知道大概情况了

『柒』 opengl es的着色器语言 vec3(顶点)+vec3(向量)是什么意思是每个分量相加吗有什么意义

是每个分量相加。就跟代数里通常的向量加法一样,表示平移。需要注意的是着色器语言里向量乘法跟代数里的定义不一样,也是各个分量单独相乘。

『捌』 如何向GLSL中传入多个纹理

设置OpenGL ES环境
创建GLSurfaceView
为了显示OpenGL的图形,你需要使用GLSurfaceView类,就像其他任何的View子类意义,你可以将它添加到你的Activity或Fragment之上,通过在布局xml文件中定义或者在代码中创建实例。
在本次的教程中,我们使用GLSurfaceView作为唯一的View在我们的Activity中,因此,为了简便,我们在代码中创建GLSurfaceView的实例并将其传入setContentView中,这样它将会填充你的整个手机屏幕。Activity中的onCreate方法如下:
<code class=“hljs” java=“”>protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); GLSurfaceView view = new GLSurfaceView(this); setContentView(view);}</code>
因为媒体效果的框架仅仅支持OpenGL ES2.0及以上的版本,所以在setEGLContextClientVersion 方法中传入2;
<code avrasm=“” class=“hljs”>view.setEGLContextClientVersion(2);</code>
为了确保GLSurfaceView仅仅在必要的时候进行渲染,我们在setRenderMode 方法中进行设置:
<code avrasm=“” class=“hljs”>view.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);</code>
创建Renderer
Renderer负责渲染GLSurfaceView中的内容。
创建类实现接口GLSurfaceView.Renderer,在这里我们打算将这个类命名为EffectsRenderer,添加构造函数并覆写接口中的抽象方法,如下:
<code class=“hljs” java=“”>public class EffectsRenderer implements GLSurfaceView.Renderer { public EffectsRenderer(Context context){ super(); } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { } @Override public void onDrawFrame(GL10 gl) { }}</code>
回到Activity中调用setRenderer方法,让GLSurfaceView使用我们创建的Renderer:
<code class=“hljs” cs=“”>view.setRenderer(new EffectsRenderer(this));</code>
编写Manifest文件
如果你想要发布你的App到谷歌商店,在AndroidManifest.xml文件中添加如下语句:
<code class=“hljs” xml=“”><uses-feature android:glesversion=“0x00020000” android:required=“true”></uses-feature></code>
这会确保你的app只能被安装在支持OpenGL ES2.0的设备之上。现在OpenGL环境准备完毕。
创建一个OpenGL平面
定义顶点
GLSurfaceView是不能直接显示一张照片的,照片首先应该被转化为纹理,应用在OpenGL square之上。在本次教程中,我将创建一个2D平面,并且具有4个顶点。为了简单,我将使用一个长方形,现在,创建一个新的类Square,用它来代表形状。
<code class=“hljs” cs=“”>public class Square {}</code>
默认的OpenGL系统的坐标系中的原点是在中心,因此4个角的坐标可以表示为:
左下角: (-1, -1) 右下角:(1, -1) 右上角:(1, 1) 左上角:(-1, 1)
我们使用OpenGL绘制的所有的物体都应该是由三角形决定的,为了画一个方形,我们需要两个具有一条公共边的三角形,那意味着这些三角形的坐标应该是:
triangle 1: (-1, -1), (1, -1), 和 (-1, 1) triangle 2: (1, -1), (-1, 1), 和 (1, 1)
创建一个float数组来代表这些顶点:
<code class=“hljs” cpp=“”>private float vertices[] = { -1f, -1f, 1f, -1f, -1f, 1f, 1f, 1f,};</code>
为了在square上定位纹理,需要确定纹理的顶点坐标,创建另一个数组来表示纹理顶点的坐标:
<code class=“hljs” cpp=“”>private float textureVertices[] = { 0f,1f, 1f,1f, 0f,0f, 1f,0f};</code>
创建缓冲区
这些坐标数组应该被转变为缓冲字符(byte buffer)在OpenGL可以使用之前,接下来进行定义:
<code class=“hljs” cs=“”>private FloatBuffer verticesBuffer;private FloatBuffer textureBuffer;</code>
在initializeBuffers方法中去初始化这些缓冲区:使用ByteBuffer.allocateDirect来创建缓冲区,因为float是4个字节,那么我们需要的byte数组的长度应该为float的4倍。
下面使用ByteBuffer.nativeOrder方法来定义在底层的本地平台上的byte的顺序。使用asFloatBuffer方法将ByteBuffer转化为FloatBuffer,在FloatBuffer被创建后,我们调用put方法来将float数组放入缓冲区,最后,调用position方法来保证我们是由缓冲区的开头进行读取。
<code avrasm=“” class=“hljs”>private void initializeBuffers(){ ByteBuffer buff = ByteBuffer.allocateDirect(vertices.length * 4); buff.order(ByteOrder.nativeOrder()); verticesBuffer = buff.asFloatBuffer(); verticesBuffer.put(vertices); verticesBuffer.position(0); buff = ByteBuffer.allocateDirect(textureVertices.length * 4); buff.order(ByteOrder.nativeOrder()); textureBuffer = buff.asFloatBuffer(); textureBuffer.put(textureVertices); textureBuffer.position(0);}</code>
创建着色器
着色器只不过是简单的运行在GPU中的每个单独的顶点的C程序,在本次教程中,我们使用两种着色器:顶点着色器和片段着色器。
顶点着色器的代码:
<code class=“hljs” glsl=“”>attribute vec4 aPosition; attribute vec2 aTexPosition; varying vec2 vTexPosition; void main() { gl_Position = aPosition; vTexPosition = aTexPosition; };</code>
片段着色器的代码
<code class=“hljs” glsl=“”>precision mediump float; uniform. sampler2D uTexture; varying vec2 vTexPosition; void main() { gl_FragColor = texture2D(uTexture, vTexPosition); };</code>
如果你了解OpenGL,那么这段代码对你来说是熟悉的,如果你不能理解这段代码,你可以参考OpenGL documentation。

『玖』 顶点和片段着色器 和 表面着色器的区别

对显卡的性能影响很大,是显卡的主要参数之一。

什么是顶点着色器?
1 顶点着色器是一组指令代码,这组指令代码在顶点被渲染时执行。
2 同一时间内,只能激活一个顶点着色器。
3 每个源顶点着色器最多拥有128条指令(DirextX8.1),而在DirectX9,则可以达到256条。

为什么大家要使用顶点着色器?
1 顶点着色器可以提高渲染场景速度。
2 用顶点着色器你可以做布类仿真,高级别动画,实时修改透视效果(比如水底效果),高级光亮(需要像素着色器支持)

顶点着色器如何运作?
简单说来,运作方式如下:当渲染一个顶点时,API会执行你在顶点着色器中所写的指令。依靠这种方法,你可以自己控制每个顶点,包括渲染,确定位置,是否显示在屏幕上。

如何创建一个顶点着色器?
用一个文本编辑器就可以了!我建议你们使用notepad或者vs开发环境来创建和修改着色器。另外,必须拥有一个支持可编程着色器的显卡。写完着色器后,保存他。API就可以调用他了(Direct3D或OpenGL)。API通过一些函数来调用这些代码指令到硬件中。

什么是像素着色器?
1 像素着色器也是一组指令,这组指令在顶点中像素被渲染时执行。在每个执行时间,都会有很多像素被渲染。(像素的数目依靠屏幕的分辨率决定)
2像素着色器的指令和顶点着色器的指令非常接近。像素着色器不能像顶点着色器那样,单独存在。他们在运行的时候,必须有一个顶点着色器被激活。

为什么大家要使用像素着色器?
1 像素着色器过去是一种高级图形技术,专门用来提高渲染速度。
2 和顶点着色器一样,使用像素着色器,程序员能自定义渲染每个像素。

像素着色器如何运作?
一个像素着色器操作顶点上单独的像素。和顶点着色器一样,像素着色器源代码也是通过一些API加载到硬件的。

如何创建一个像素着色器?
也和顶点着色器一样,你只需要一个文本编辑器和支持着色器编程的显卡即可。同样,API(Direct3D OpenGL)加载像素着色器代码指令到硬件中。

『拾』 谁用过GLSL的Attribute类型

导入模型时,就把Tangent和Binormal计算并记录了下来,然后用多重纹理传至vs。
传下代码:
1.求三角面三个顶点各自的T和B
//计算切线
void CModel::calculateTangent()
{
vector<CTangentCoord> tangentCoordList;
vector<CBinormalCoord> binormalCoordList;
CTangentCoord newTangentCoord;
CBinormalCoord newBinormalCoord;
CVertexCoord v[3], P, Q;
CTextureCoord uv[3];
float s1, t1;
float s2, t2;
float tmp;
int i, j, k, p;

//计算切线
for (i=1;i<numOfFace;i++)
{
for (j=0;j<3;j++)
{
//提取到对应位置
for (p=j;p<3+j;p++)
{
k = pFaceList[i].vertexCoordIndex[p%3];
v[p%3].x = pVertexCoordList[k].x;
v[p%3].y = pVertexCoordList[k].y;
v[p%3].z = pVertexCoordList[k].z;

k = pFaceList[i].textureCoordIndex[p%3];
uv[p%3].x = pTextureCoordList[k].x;
uv[p%3].y = pTextureCoordList[k].y;
}

P.x = v[1].x - v[0].x;
P.y = v[1].y - v[0].y;
P.z = v[1].z - v[0].z;

Q.x = v[2].x - v[0].x;
Q.y = v[2].y - v[0].y;
Q.z = v[2].z - v[0].z;

s1 = uv[1].x - uv[0].x;
t1 = uv[1].y - uv[0].y;

s2 = uv[2].x - uv[0].x;
t2 = uv[2].y - uv[0].y;

if (fabs(s1*t2 - s2*t1) == 0.0)
{
tmp = 1.0;
}
else
{
tmp = 1.0 / (s1*t2 - s2*t1);
}

newTangentCoord.x = (t2*P.x - t1*Q.x) * tmp;
newTangentCoord.y = (t2*P.y - t1*Q.y) * tmp;
newTangentCoord.z = (t2*P.z - t1*Q.z) * tmp;

newBinormalCoord.x = (s1*Q.x - s2*P.x) * tmp;
newBinormalCoord.y = (s1*Q.y - s2*P.y) * tmp;
newBinormalCoord.z = (s1*Q.z - s2*P.z) * tmp;

tangentCoordList.push_back(newTangentCoord);
binormalCoordList.push_back(newBinormalCoord);
}
}

//拷贝
pTangentCoordList = new CTangentCoord[numOfFace * 3];
pBinormalCoordList = new CBinormalCoord[numOfFace * 3];
for (i=0;i<numOfFace*3;i++)
{
pTangentCoordList[i].x = tangentCoordList[i].x;
pTangentCoordList[i].y = tangentCoordList[i].y;
pTangentCoordList[i].z = tangentCoordList[i].z;

pBinormalCoordList[i].x = binormalCoordList[i].x;
pBinormalCoordList[i].y = binormalCoordList[i].y;
pBinormalCoordList[i].z = binormalCoordList[i].z;
}
}

2.导入shader
//给出法向量
k = normalIndex;
glNormal3f(pModel->pNormalCoordList[k].x, pModel->pNormalCoordList[k].y, pModel->pNormalCoordList[k].z);

//纹理坐标
k = textureIndex;
glMultiTexCoord2fARB(GL_TEXTURE0_ARB, pModel->pTextureCoordList[k].x, pModel->pTextureCoordList[k].y);

//顶点坐标
k = vertexIndex;
glVertex3f(pModel->pVertexCoordList[k].x, pModel->pVertexCoordList[k].y, pModel->pVertexCoordList[k].z);

//切线(用多重纹理)
glMultiTexCoord3fARB(GL_TEXTURE1_ARB, pModel->pTangentCoordList[i+j].x,
pModel->pTangentCoordList[i+j].y,
pModel->pTangentCoordList[i+j].z);

//次法线
glMultiTexCoord3fARB(GL_TEXTURE2_ARB, pModel->pBinormalCoordList[i+j].x,
pModel->pBinormalCoordList[i+j].y,
pModel->pBinormalCoordList[i+j].z);

3.vs代码
#version 120

varying mat3 toObjectLocal;
varying vec4 textureCoord;
varying mat3 normalMatrix;

varying vec3 positionData;
varying vec3 normalData;
varying vec4 colorData;
varying vec4 specularData;

void main()
{
//位置
vec4 position = gl_ModelViewMatrix * gl_Vertex;
positionData = vec3(position) / position.w;

//漫射颜色
colorData = gl_FrontMaterial.diffuse;

//镜面反射
specularData = gl_FrontMaterial.specular;

//法线
normalData = normalize(gl_NormalMatrix * gl_Normal);

textureCoord = gl_MultiTexCoord0;
normalMatrix = gl_NormalMatrix;
gl_Position = ftransform();

//切线空间变换矩阵
vec3 tangent = gl_MultiTexCoord1.stp;
vec3 binormal = gl_MultiTexCoord2.stp;

vec3 T = normalize(tangent);
vec3 B = normalize(binormal);
vec3 N = normalize(gl_Normal);

toObjectLocal = mat3(
T.x, B.x, N.x,
T.y, B.y, N.y,
T.z, B.z, N.z);

toObjectLocal = transpose(toObjectLocal);//转置原因见fs代码
}

4.fs代码(我用的是延时渲染)
#version 330

uniform sampler2D mapKd;
uniform sampler2D mapKs;
uniform sampler2D mapNormal;
uniform int shadeModelType;

layout (location = 0) out vec3 PositionData;
layout (location = 1) out vec3 NormalData;
layout (location = 2) out vec4 ColorData;

varying mat3 toObjectLocal;
varying vec4 textureCoord;
varying mat3 normalMatrix;

varying vec3 positionData;
varying vec3 normalData;
varying vec4 colorData;
varying vec4 specularData;

void main()
{
int useTexture[3];
int p = shadeModelType, i = 0;

//是否使用三种纹理
while (i < 3)
{
useTexture[i] = p % 2;
p = p / 2;
i++;
}

PositionData = positionData;

if (useTexture[0] == 1)
ColorData = texture2D(mapKd, textureCoord.xy);
else
ColorData = colorData;

if (useTexture[1] == 1)
{
vec4 specular = texture2D(mapKs, textureCoord.xy);
ColorData.w = 0.27 * specular.x + 0.67 * specular.y + 0.06 * specular.z;
}
else
ColorData.w = 0.27 * specularData.x + 0.67 * specularData.y + 0.06 * specularData.z;

if (useTexture[2] == 1)
{
vec3 objectNormal = texture2D(mapNormal, textureCoord.xy).stp;
objectNormal = (objectNormal - 0.5) * 2.0;
NormalData = normalize(normalMatrix * toObjectLocal * objectNormal);//转置的TBN矩阵和法线贴图中的法线相乘,得出物体坐标系下的法线,再乘以gl_NormalMatrix转至视图空间
}
else
NormalData = normalData;
}

阅读全文

与glsl顶点过滤相关的资料

热点内容
d500树脂 浏览:260
测总氮含量的蒸馏装置 浏览:300
水怎样蒸馏 浏览:35
建设农村污水处理站的必要性 浏览:396
饮水机怎么放热水出来 浏览:980
机油滤芯质量不好会有什么影响 浏览:362
软水大师和怡口净水哪个性价比高 浏览:937
中性土壤阳离子交换量数据 浏览:450
迈锐宝空调滤芯什么样 浏览:381
动脉管路血液过滤器 浏览:549
地下室不用污水泵 浏览:260
吉林污水处理的费用怎么计算 浏览:862
驻极式静电除尘过滤网 浏览:900
纯水内毒素是高怎么处理 浏览:892
脱盐水处理工艺离子交换工艺 浏览:707
梦见污水把自己困住了 浏览:833
多联过滤器 浏览:653
苯乙烯树脂可以装食物吗 浏览:330
金属污水如何处理 浏览:938
压铸脱模废水处理 浏览:708