[GEiv]第七章:着色器 高效GPU渲染方案

第七章:着色器

高效GPU渲染方案

本章介绍着色器的基本知识以及Geiv下对其提供的支持接口。并以“渐变高斯模糊”为线索进行实例的演示解说。

[背景信息]

[计算机中央处理器的局限性]

在大学的“数字图像处理”课程中,老师解说了高斯模糊的基本算法。并使用C#进行了基本实现。高斯模糊。简单地说,就是使用高斯权重模板对图像的每个像素进行再计算、填充,以达到模糊的效果。

在课程中。对于给定的模板与模糊度系数,对一副800X600的图像进行模糊处理。须要计算48万个像素点,虽然当时机房已经普及了酷睿系列CPU。但这个过程依然耗时2~3秒。

于是有这种一个问题:在游戏中,我们常常看到画面进行模糊到清晰的动态转变。即使是次世代的GBA\SFC等游戏主机依旧有这种效果实现。而论硬件性能,我们的PC应该远远高于这些次世代游戏机,而2、3秒的运算结果已经明白告诉我,想要进行更为高效的模糊计算,显示地挨个计算像素点是不可能达到预期效率的,想要一秒钟完毕60幅不同模糊度的图像计算,还要另寻他路。

为什么计算性能普遍较低的游戏机却能实现高性能CPU都无法流畅做到的运算呢?笔者觉得还是由于CPU的结构差异导致的,PC的任务种类多。过程复杂。须要复杂的指令集系统。但游戏机的CPU主要为图像而生。仅仅需使用针对图像的少数精简指令系统就可以。

总而言之,为了保证CPU在复杂任务下的通用性,计算机的CPU并不擅长进行图形运算。而且在一些场合下,图形运算的效率相当低下。

[图形处理器GPU]

为了弥补CPU处理图形的缺陷,GPU便诞生了。GPU是针对图形运算而生的处理器,现在的主流游戏PC都会有一个高性能的GPU。详细的概念笔者就不在这里提了,相信搞计算机的都会对其了解一二。

[在编程中使用GPU运算资源]

在大多数开发场合下,不管是C还是Java。我们敲的代码都无疑地执行在CPU之上。那我们如何才干显示地调用GPU的资源呢?在OPENGL中,除了经常使用的固定管线式编程外,还提供了更为灵活的功能。它同意开发人员使用着色语言(GLSL,一种类C语言)编写名为“着色器”的程序,经编译执行于GPU之上并接管一部分GPU内置功能。

[Opengl着色器简述]

介于笔者履历有限,这里仅仅做简介,具体概念能够參考《Opengl着色语言》一书,它对着色器和GLSL有着很具体的介绍。

一个Opengl着色器(下简称着色器)由一个顶点着色器与片段着色器构成。它们负责的工作大部分是不同的,仅有少部分交集。

Opengl为着色器的校验、编译、连接和设置參数提供了完整的API,仅仅要显卡支持,在Opengl上下文中就可以由源文件得到着色器程序,无需其它环境。

编写着色器的目的。是为了实现诸如模糊、雾化、发光等固定管线不易叙述的功能,进而丰富图像的表现能力。非常多游戏引擎将Opengl中与着色器相关的API包装到了上层,我在设计时也採用了这样的方案。

[内置着色器]

在GEiv中,内置了5个系统着色器,它们是在设计之初进行着色器測试时所保留下来的。并非因为“经常使用”(笔者感觉着色器的编写往往非常有针对性,一般非常难有经常使用一说)。

依次介绍:

SD_ANTICOLOR:将目标色改为反色

SD_EMBOSS_MODE9:浮雕效果,后面的MODE9表示它使用的是3X3的模板,能够适应一般的需求,若要提高准确度,能够将模板扩充至4X4\5X5等。

SD_GAUSSIAN_MODE9:高斯模糊

SD_LAPLACIAN_MODE9:锐化

SD_MEAN_MODE9:均值化

[为图元设置着色器]

在GEiv中。使用着色器的对象是图元,使用其setShaderProgram方法将着色器绑顶到相应图元上。如:

Obj T =UES.creatObj(UESI.BGIndex);
T.addGLImage(0,0, "./mdls.jpg");
T.setShaderProgram(SysShader.SD_GAUSSIAN_MODE9);//将系统着色器绑定到图元T上

[设置Uniform參数]

Uniform修饰词(不是数据类型)指明一个GLSL中的变量是外部传入的。而且在整个着色器运行过程中不会改变(差别于attribute),比如对于实现模糊变化来讲,“模糊度”这个变量属于Uniform型无疑。

在GLSL中。数组有非常多存在形式,float[]能够表示一维线性浮点数组。vect2则表示了一个点对,而vec2[]则表示了一维线性浮点“数对”组,类似的还有vect3\4等等这样在java中没有现成的相应结构的数据。也就是说,设置Uniform參数时必须给定我们的数据源(一维线性数组)和映射到GLSL中变量的方式。

在GEiv的图元类中。setShaderUniform(String uniformName, Object value, intTPFLAG)方法能够设置该图元上绑定的着色器參数,这种方法的參数依次是:

uniformName是着色器中对于的变量名称。

value是数据源,眼下仅仅支持float[]、Float[]或单个的Float型。

TPFLAG 是指定的映射方式。你能够直接从ShaderController的静态值部分直接引用。

它能够是下列值之中的一个:

AFLOAT与FLOATS分别相应单个float值与一维float数组。

VERTXS表示由X个点对组成的数组,即该数组每一个元素包括一个X维度向量。所给数据源必须是一个X整数倍大小的一维线性数组,该数组会依照顺序依次填充这些X维度向量。比如使用TP_VERT2S时,数据源一维数组的前两个元素构成了着色器向量数组的第一个向量元素。

VERTEX表示一个X维度向量。要求给定的一维数据源数组大小必须为X。

[自己定义用户着色器]

除了使用SysShader中现成的着色器外,还能够使用用户自己定义的着色器程序。

在引擎的句柄UESI中,包装并简化的Opengl产生着色器的API:

UESI.createShaderProgram(String spName,String vpPath, String fpPath);

參数介绍:

spName是用户为着色器起的名字。

vpPath是顶点着色器的源文件路径,如”./vp.txt”。

fpPath是片段着色器源文件路径。

之后我们仅仅须要使用设置着色器的API对图元绑定spName即可了。与之前介绍的字库同样。spName也具有全局效应,能够为其他上下文的图元绑定。

[实例-渐变高斯模糊]

您能够在[GitHub]Sample\Sample-Shader下找到这个样例及使用的资源。

Main.java

package com.geiv.test;

import geivcore.R;
import geivcore.UESI;

public class Main{
	public static void main(String[] args) {
		UESI UES = new R();
		new Guassion(UES);
	}
}

Guassion.java

package com.geiv.test;

import geivcore.SerialTask;
import geivcore.UESI;
import geivcore.engineSys.shadercontroller.ShaderController;
import geivcore.engineSys.shadercontroller.SysShader;
import geivcore.enginedata.canonical.CANExPos;
import geivcore.enginedata.obj.Obj;

import java.awt.event.KeyEvent;
import java.util.Arrays;

public class Guassion implements SerialTask{
	UESI UES;
	float[] g_aryVerticalOffset;
	float[] vertstatic;
	float bur = 600f;//bur作为模糊度因子,使用静态偏移量(vertstatic)除以模糊度因子得到不同的偏移量參数(g_aryVerticalOffset)。因为GLSL上下文是使用的OPENGL坐标式,与GEiv有所不同,因此初始因子经计算转换后定为600f

	Obj T;
	public Guassion(UESI UES) {
		this.UES = UES;

		T = UES.creatObj(UESI.BGIndex);
		T.addGLImage(0, 0, "./mdls.jpg");

		T.setShaderProgram(SysShader.SD_GAUSSIAN_MODE9);//设置着色器
		T.setShaderUniform(SysShader.NA_WEIGHTARGS,SysShader.BR_GAUSSIAN_MODE9, ShaderController.TP_FLOATS);//设置Unfiorm參数,当中规格化后的权重模板及其在GLSL上下文中的名称已经给定。它们能够由SysShader直接引用。

		vertstatic = new float[]{-1,-1, 0,-1, 1,-1
				  -1, 0, 0, 0, 1, 0
				  -1, 1, 0, 1, 1, 1};//偏移量模板。看不懂的话能够參考以下的图

		g_aryVerticalOffset = Arrays.copyOf(vertstatic, vertstatic.length);

		for(int i = 0;i < g_aryVerticalOffset.length;i++)
		{
			g_aryVerticalOffset[i] = vertstatic[i]/bur;
		}

		T.setShaderUniform(SysShader.NA_OFFSETARGS, g_aryVerticalOffset,ShaderController.TP_VERT2S);//设置Uniform偏移量
		T.setPosition(CANExPos.POS_CENTER);
		T.show();

		UES.addSerialTask(this);
	}

	@Override
	public void Serial(int clock) {//挂载一个扫描式的键盘输入,当Z键按下时bur添加。重置偏移量并重设Uniform。

当X键按下时则相反。
		if(UES.getKeyStatus(KeyEvent.VK_Z))
		{
			T.setShaderUniform(SysShader.NA_OFFSETARGS,g_aryVerticalOffset,ShaderController.TP_VERT2S);
			bur+=4f;
			for(int i = 0;i < g_aryVerticalOffset.length;i++)
			{
				g_aryVerticalOffset[i] = vertstatic[i]/bur;
			}
		}
		else if(UES.getKeyStatus(KeyEvent.VK_X))
		{
			T.setShaderUniform(SysShader.NA_OFFSETARGS,g_aryVerticalOffset,ShaderController.TP_VERT2S);
			bur-=4f;
			for(int i = 0;i < g_aryVerticalOffset.length;i++)
			{
				g_aryVerticalOffset[i] = vertstatic[i]/bur;
			}
		}
	}
}

关于偏移量模板的映射,实际上是这种↓:

除此之外,还有高斯模糊着色器的两部分源码

顶点着色器:

attribute float sys_pIndex;
void main(void)
{
	gl_TexCoord[0] = gl_MultiTexCoord0;
	gl_Position = ftransform();
}

↑这个顶点着色器没有写不论什么实质性的功能,它被非常多片段着色器共用。

高斯-片段着色器:

const int g_iWeightNumber = 9;//权重模板大小
uniform sampler2D g_FilterTexture;//我们的纹理
uniform float g_aryWeight[g_iWeightNumber];//权重数组
uniform vec2 g_aryOffset[g_iWeightNumber];//偏移量-即使使用9个格子,也没有规定必须是相邻的格子;偏移量叙述着权重模板格子间的实际像素距离,取值越高,模糊度越高。

void main(void)
{
	vec4 vec4Sum = vec4(0.0);
	for(int i = 0; i < g_iWeightNumber; ++i)
	{
		vec4Sum += texture2D(g_FilterTexture, gl_TexCoord[0].st + g_aryOffset[i])*g_aryWeight[i];//这里进行实质的计算过程。也就是替换原先我们让CPU挨个计算像素点的部分。

gl_TexCoord[0]是绑定的0号纹理(Opengl中图形是能够绑定多个纹理的)。它的st就是位置,一个vec2类型量;位置与偏移量进行加和,得到偏移位置。之后依据纹理和偏移位置取出相应的rgba四维向量,它是一个vec4类型。进一步,将我们的vec4乘以规格化后的权重。并加和到vec4Sum上。因为是规格化后的权重,因此RGBA都不会越界。

}
	gl_FragColor = vec4Sum;// 最后,我们将这个计算完成的RGBA结果填入纹理中。

}

最后,运行结果(按住X键时):

↑能够观察到由清晰到模糊的动态过程。

[总结]

本章介绍了着色器的使用场合以及GEiv下相应的API。

使用着色器是为了实现固定管线难以叙述的效果。

着色器执行于GPU,在对图像渲染时效率比直接使用CPU运算高出非常多。

版权声明:本文博客原创文章。博客,未经同意,不得转载。

时间: 07-09

[GEiv]第七章:着色器 高效GPU渲染方案的相关文章

[GEiv]第七章:着色器 高效的GPU渲染方案

第七章:着色器 高效的GPU渲染方案 本章介绍着色器的基本知识以及Geiv下对其提供的支持接口,并以"渐变高斯模糊"为线索进行实例的演示讲解. [背景信息] [计算机中央处理器的局限性] 在大学的"数字图像处理"课程中,老师讲解了高斯模糊的基本算法,并使用C#进行了基本实现.高斯模糊,简单地说,就是使用高斯权重模板对图像的每一个像素进行再计算.填充,以达到模糊的效果. 在课程中,对于给定的模板与模糊度系数,对一副800X600的图像进行模糊处理,需要计算48万个像素

【OPENGL】第三章 着色器基础(一)

在这一章,我们会学习什么是着色器(Shader),什么是着色器语言(OpenGL Shading Language-GLSL),以及着色器怎么和OpenGL程序交互. 首先我们先来看看什么叫着色器. Shader(着色器)是用来实现图像渲染的,用来替代固定渲染管线的可编程程序. 着色器替代了传统的固定渲染管线,可以实现3D图形学计算中的相关计算,由于其可编程性,可以实现各种各样的图像效果而不用受显卡的固定渲染管线限制.这极大的提高了图像的画质. 在上一篇文章( http://www.cnblog

第4章:缓冲区、着色器、GLSL

原文链接: http://www.rastertek.com/gl40tut04.html Tutorial 4: Buffers, Shaders, and GLSL This tutorial will be the introduction to writing vertex and pixel shaders in OpenGL 4.0. It will also be the introduction to using vertex and index buffers in OpenG

GPU渲染管线与可编程着色器

本文由@浅墨_毛星云 出品,转载请注明出处.   文章链接:http://blog.csdn.net/poem_qianmo/article/details/71978861 这篇文章是解析计算机图形学界"九阴真经总纲"一般存在的<Real-Time Rendering 3rd>系列文章的第三篇.将带来RTR3第三章内容"Chapter 3 The Graphics Processing Unit 图形处理器"的总结.概括与提炼. 这章的主要内容是介绍G

顶点着色器和片断着色器

顶点和片段着色器 必备知识 熟悉Stage3D API.最好之前使用过VertexBuffer.在继续这个教程之前一定要先阅读本系列的第一个教程(Stage3D原理).    所需软件 Flash Builder 4.5 Premium (Download trial) Flash Professional CS5.5 (Download trial) 在本章中,你将对着色器(Shaders)有一个大概的了解.着色器是Stage3D渲染管道的核心.你将学到顶点和片段着色器是个什么东东,它们在3D

OpenGL管线(用经典管线代说着色器内部)

图形管线(graphics pipeline)向来以复杂为特点,这归结为图形任务的复杂性和挑战性.OpenGL作为图形硬件标准,是最通用的图形管线版本.本文用自顶向下的思路来简单总结OpenGL图形管线,即从最高层开始,然后逐步细化到管线图中的每个框,再进一步细化到OpenGL具体函数.注意,这里用经典管线代说着色器内部,也就是OpenGL固定管线功能(Fixed-Function,相对于programmable也即可编程着色器),也会涉及着色器,但差不多仅限于“这些固定管线功能对应xx着色器”

Directx 中HLSL高级着色器语言 脑补一下吧

HLSL初级教程 作者:trcj 目录 前言 1.HLSL入门 1.1什么是着色器 1.2什么是HLSL 1.3怎么写HLSL着色器 1.4怎么用HLSL着色器 2.顶点着色器 2.1可编程数据流模型 2.2顶点声明 2.3用顶点着色器实现渐变动画 3.像素着色器 3.1多纹理化 3.2多纹理效果的像素着色器 3.3应用程序 4.HLSL Effect(效果框架) 4.1Effect代码结构 4.2用Effect实现多纹理化效果 结语 参考资料 前言 本教程针对HLSL(High Level S

Android学习笔记&mdash;&mdash;OpenGL ES的基本用法、绘制流程与着色器编译

首先声明下,本文为笔者学习<OpenGL ES应用开发实践指南(Android卷)>的笔记,涉及的代码均出自原书,如有需要,请到原书指定源码地址下载. 在Android.iOS等移动平台上,开发者可以使用跨平台应用编程接口创建二维或者三维图形,或进行图像处理和计算机视觉应用,结合两者将能构建丰富有趣的交互体验.前者称为OpenGL,后者称为OpenCV,不过本文主要介绍前者,OpenCV在后续文章中涉及.OpenGL应用于桌面系统的历史已经很长了,但考虑到移动平台的特点(计算能力.性能等),将

Shader开发之三大着色器

固定功能管线着色器Fixed Function Shaders 固定功能管线着色器的关键代码一般都在Pass的材质设置Material{}和纹理设置SetTexture{}部分. Shader "Custom/VertexList" { Properties { _Color("Main Color",Color) = (0,1,1,0.5) _SpecColor("Spec Color",Color) = (1,1,1,1) _Emission