主要是参考了youtube系列教程,b站有链接:https://www.bilibili.com/video/av22607806

一个外国小哥讲的,这里对一些重点知识和代码做下笔记,也当做新手讲解了。

-------------------------------------------------------------------------------------------------------------------------------------------------

记录:In Graphics Programming, you'll have two small programs called the vertex shader and the fragment shader.(在图形学编程中,常见到顶点着色器和片段着色器的编程。)

UnityShader--01_intro to Shaders

笔记:什么是着色器编程呢?就是通过编程来改变渲染行为。以前的固定功能图形管道只负责把数据交给GPU,GPU接管所有渲染工作,开发者无法控制渲染过程。但是后来出现了可编程管道,我们在可编程图形管道中编写的小程序被称为着色器(Shaders)。着色器就分为顶点着色器和片段着色器。

注意:着色器程序和普通程序之间最重要的区别是,着色器程序只是GPU中执行。

工作流程:(https://www.cnblogs.com/AaronBlogs/p/6964503.html)

当 你要渲染一个几何图形时,你会用一个VertexBuffer来定义构成几何图形的三角形,VertextBuffer中又包含一系列的顶点数据。来自 VertextBuffer中的顶点数据作为输入传递给着色器,在着色器中可以处理这些数据。GPU将顶点着色器的输出数据组装为三角形,然后这些三角形 被适当的剪裁以适应用户视域(viewport),接下来在光栅化单元被处理成一种新的格式:由片段(Fragments)组成的数据格式,片段是一种简单的数据格式,每一个片段包含一个三角形在屏幕上能显示的所有像素。

片段中的数据内容通常由顶点着色器决定。事实上,顶点着色器可以将顶点属性参数作为自己的输出。光栅化负责将着色器输出的顶点数据在三角形上进行颜色插值(interpolate),使片段上的每个像素都得到正确的属性值。

例如,有一个Vertex Buffer指定了顶点的颜色作为顶点属性,其中三角形的两个顶点被分别被指定为黑色和白色。顶点着色器会将这些顶点颜色数据作为输出,传递给管道中的下 一个处理单元。然后,片段的相对中间部位的某处,会被置为灰色,也就是黑色顶点和白色顶点的中间色。片段中接近白色顶点的像素颜色会亮一些,相反,接近黑 色顶点的像素会暗一些。

接下来,这些插值后未经处理的片段被传输给片段着色器,它利用这些数据来完成最终像素颜色的建立。

顶点着色器原理

顶点着色器是在GPU上运行的小程序。顾名思义,顶点着色器是用来处理顶点数据的。一个顶点着色器就是一个处理顶点的小程序(老外说话真的很啰嗦!)

一 般来说,可以将几何图形顶点数据放在VertexBuffer中,然后将其上传至GPU。然后,可以用一种着色器语言:例如AGAL来编写一个顶点着色 器。顶点着色器程序将处理VertextBuffer中的每一个顶点,这就好像在着色器周围使用了一个for循环,但实际上你根本看不到这个for循环, 如下:

for (var i:int = 0; i <vertexBuffer.length; i++)
{
    executeVertexShader(vertexBuffer);
}

所以,VertexBuffer中的所有顶点都会被处理。

你还可以将常量以常量寄存器的形式传递给顶点着色器,每次运行着色器(每次调用Context3D::drawTriangles方法,渲染一个网格)时,都可以传入一个不同的值,着色器可以根据常量的值来调节它的算法和输出。

顶 点着色器的输入是一个或多个顶点属性(Vertex Attribute)组成的VertexBuffer。VertexBuffer中的顶点应至少指出了顶点的位置属性,这些位置属性通常指的是每个3D模 型(每个模型都有其自身的原点)本身的坐标。顶点着色器将这些位置信息转换为屏幕位置,以便可以正确的显示。VertexBuffer中可能还包括一些其 它顶点属性,例如,顶点颜色或纹理UV坐标等。顶点着色器将这些作为输出(最终经过处理的),以便其可在光栅化单元进行插值,然后作为输入传递给片段着色 器。

顶点着色器常常用来对场景中几何图形坐标进行矩阵变换。顶点的坐标作为一个矩阵输入到顶点着色器中,它会将VertexBuffer中的所有顶点进行矩阵变换。由于使用了硬件加速,这个过程非常高效,大大快于自己用ActionScript编写的代码。

让 人感兴趣的时,顶点着色器是完全可编程的,你可以以任何你想要的方式修改几何图形。例如,一个典型的骨骼顶点修改的程序:你定义了一组骨骼也就是骨架和其 上的皮肤(网格)。当骨骼旋转时,由于骨骼和皮肤连在一起,所以皮肤的形状会跟着变化。那我们如何来实现呢?最好的办法是将骨骼旋转(变换)数据传递给一 个顶点着色器,让它来适当的修改皮肤的动画和变形。

还有一些会用到顶点着色器的应用场景:模拟柔软纺织品或者可变形对象的表面。用顶点着色器来让一个网格根据参数的变化从一个形状变为另一个形状。

片段着色器原理

 就像顶点着色器一样,片段着色器也是运行在GPU上的小程序。顾名思义,用它来处理片段。它们负责输出每个三角形像素的最终颜色。

基本上来说,它是这样运行的:片段着色器将顶点着色器输出的片段作为输入,片段的顶点属性已被光栅化单元进行了插值处理。

片段着色器执行的流程基本上也很像一个循环,如果你能把未经处理的片段想象成某种数据流,就叫片段流吧,片段着色器的处理就像代码中描述的一样:

for (var i:int = 0; i <fragmentStream.length; i++)
{
    executeFragmentShader(fragmentStream);
}

片段流之所以称之为未处理过的,是因为片段着色器还没有处理它,并计算出在屏幕上显示的像素的颜色。

片段着色器是可编程管道中的最最核心的部分。其普遍的作用就是计算各种各样的三角形像素颜色,从为着色顶点图形(vertex-colored geometries)计算的顶点属性颜色,和为纹理图形为计算的纹理及相关的UV纹理坐标。

但 是顶点着色器的功能远非制造这些简单的效果。实际上,现代3D游戏中令人惊叹的3D特效都是用片段着色器来生成的。例如,动态光源效果通常都是由片段着色 器完成。思考一下就会明白,动态光源意味着根据场景中已有的光源计算像素颜色,这与几何图形的位置、材料都有很大的关系,所以片段着色器是制作动态光源效 果的不二之选。

像水体环境映射之类的反射特效也都是由片段着色器完成的。片段着色器能生成世界上几乎所有的光影特效,以上提及的只不过是它的冰山一角。

最后要提一下的是,片段着色器决定了你在屏幕上能看到什么,所以,片段着色器才是影响渲染的核心代码。

--------------------------------------------------------------------------------------------------------------------------------------------------

记录:来一段shader编程

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Custom/Basic"
{
  
	SubShader
	{
		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			#include "UnityCG.cginc"

			//defines what information we are getting from each vertex on the mesh
			struct appdata
			{
				float4 vertex:POSITION;

			};

			//what information we are passing into the fragment function 
			struct v2f
			{
				float4 vertex:SV_POSITION;

			};

			/*initialize a v2f called o and it sets it for a text variable using this special function
			  -matrix multiplication on the local vertex to take it from a point relative to the object and transform it into a point on the screen
			*/
			v2f vert(appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				return o;
			}

			//returns a color in the form of a float for variable,turns potential colors on the screen
			float4 frag(v2f i):SV_Target
			{
				return float4(1,1,1,1);
			}
			ENDCG
		}
	}
}

然后在Unity面板上创建一个Quad,刚开始创建是这样的:

UnityShader--01_intro to Shaders

然后创建一个new material,把该material的shader改成自己编写的shader,然后这个material就从默认的灰色变成了白色:

UnityShader--01_intro to Shaders 

接下来把该材质拖拽到Quad上,Quad就变成了纯白色:

UnityShader--01_intro to Shaders

 

仅仅变换纯色似乎有点无聊,于是小哥决定bring more data from the mesh and do something more interesting...

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Custom/Basic"
{
  
	SubShader
	{
		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			#include "UnityCG.cginc"

			//defines what information we are getting from each vertex on the mesh
			struct appdata
			{
				float4 vertex:POSITION;
				float2 uv:TEXCOORD0;

			};

			//what information we are passing into the fragment function 
			struct v2f
			{
				float4 vertex:SV_POSITION;
				float2 uv:TEXCOORD0;

			};

			/*initialize a v2f called o and it sets it for a text variable using this special function
			  -matrix multiplication on the local vertex to take it from a point relative to the object and transform it into a point on the screen
			*/
			v2f vert(appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.uv = v.uv;
				return o;
			}

			//returns a color in the form of a float for variable,turns potential colors on the screen
			float4 frag(v2f i):SV_Target
			{
				return float4(i.uv.r,i.uv.g,0,1);
			}
			ENDCG
		}
	}
}

 结果如下:

UnityShader--01_intro to Shaders

笔记:在这里对程序做个简单的解释。Shader并不是一个统一的标准,不同的图形接口的Shader并不相同。OpenGL的着色语言是GLSL, NVidia开发了Cg,而微软的Direct3D使用高级着色器语言(HLSL)。而Unity的Shader 是将传统的图形接口的Shader(由 Cg / HLSL编写)嵌入到独有的描述性结构中而形成的一种代码生成框架,最终会自动生成各硬件平台自己的Shader,从而实现跨平台。

----------------------------------------------------------------------------------------------------------------------------------------------

记录:小哥自问自答,but Dan you asked ,a triangle has but three vertices if our photo vertex shader only executes three times how long are we getting such a splendid display of colors ?

UnityShader--01_intro to ShadersUnityShader--01_intro to ShadersUnityShader--01_intro to Shaders

 笔记:其实这个就是插值的问题。Even though a vert shader only run three times it can still generate hundreds of fragments. It also linearly interpolates Sitz values over those generated framents so even though our virtue aider really only passes along four unique UV values we end up getting every value in between .

UnityShader--01_intro to ShadersUnityShader--01_intro to ShadersUnityShader--01_intro to Shaders

-------------------------------------------------------------------------------------------------------------------------------------------------

上面的例子都是计算机自带的色彩,那么怎么用一个texture(图片)来创建shader呢?

记录:和上面代码的区别,define a set of properties for our shader before the sub shader region , this is the syntax for including a texture as a property and a default value of white for one node texture is assigned , as soon as you have done that the texture picker will appear in the inspector when you select the material in the editor. in our frag funciton, we'll use the text2d function to get the color value from the main text at the provided UV value, we also need to define main text in the scope of our CD program as a sampler2D otherwise our shader will compile``

代码如下:

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Custom/Basic"
{
    Properties
	{
		_MainTex("Texture",2D) = "white"
	}
	SubShader
	{
		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			#include "UnityCG.cginc"

			//defines what information we are getting from each vertex on the mesh
			struct appdata
			{
				float4 vertex:POSITION;
				float2 uv:TEXCOORD0;

			};

			//what information we are passing into the fragment function 
			struct v2f
			{
				float4 vertex:SV_POSITION;
				float2 uv:TEXCOORD0;

			};

			/*initialize a v2f called o and it sets it for a text variable using this special function
			  -matrix multiplication on the local vertex to take it from a point relative to the object and transform it into a point on the screen
			*/
			v2f vert(appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.uv = v.uv;
				return o;
			}

			sampler2D _MainTex;
			//returns a color in the form of a float for variable,turns potential colors on the screen
			float4 frag(v2f i):SV_Target
			{
				float4 color = tex2D(_MainTex,i.uv);
				return color;
			}
			ENDCG
		}
	}
}

 然后在Unity内把Material在Inspector面板上的Texture选上我的图像

UnityShader--01_intro to Shaders

然后场景中的Quad就变成了有图片纹理的

UnityShader--01_intro to Shaders

 但是我们想要透明不想要人物背景怎么办?--- 就是Transparency in your shader is how each pixel will blend with the pixel beneath it on the screen .关于blend方法在Unity的官方手册里有,作者这里用的是alpha blend。

UnityShader--01_intro to Shaders

UnityShader--01_intro to Shaders

但是我不知道为什么,一直透明不了,代码是这样的:

 Properties
	{
		_MainTex("Texture",2D) = "white" {}
	}
	SubShader
	{
		Tags
		{
			"Queue" = "Transparent"
			
		}
		

		Pass
		{
			Blend SrcAlpha OneMinusSrcAlpha
			
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			#include "UnityCG.cginc"
····

 如果有人知道为什么,欢迎在下面留言,给出改正。

-------------------------------------------------------------------------------------------------------------------

作者给出了一些其他的炫酷效果,但是我也都同样不起作用。。。。目前还不知道是为什么。

UnityShader--01_intro to Shaders

 恩,暂时到这里。

 

相关文章:

  • 2022-12-23
  • 2022-02-27
  • 2021-08-29
  • 2022-01-17
  • 2021-06-10
  • 2021-06-22
  • 2021-04-27
猜你喜欢
  • 2022-12-23
  • 2021-06-12
  • 2021-04-26
  • 2021-05-09
  • 2022-12-23
  • 2022-12-23
  • 2021-09-27
相关资源
相似解决方案