Unity 几何着色器
Unity 几何着色器
Unity 几何着色器
如果学习不能带来价值,那将毫无意义
简介
在顶点和片段着色器之间有一个可选的着色器,叫做几何着色器(Geometry Shader)。几何着色器以一个或多个表示为一个单独基本图形(primitive)即图元的顶点作为输入,比如可以是一个点或者三角形。几何着色器在将这些顶点发送到下一个着色阶段之前,可以将这些顶点转变为它认为合适的内容。几何着色器有意思的地方在于它可以把(一个或多个)顶点转变为完全不同的基本图形(primitive),从而生成比原来多得多的顶点。
输入
几何着色器阶段可将整个图元作为输入,并能够在输出上生成顶点。
必须首先指定单次调用几何着色器输出的顶点的最大数量(每个图元调用几何着色器)。这可以通过使用以下属性语法在着色器定义之前设置最大顶点数:
[maxvertexcount(N)]
其中N是几何着色器为单个调用输出的顶点的最大数量。几何着色器可以在每次调用时输出的顶点数量是可变的,但不能超过定义的最大值。出于性能考虑,最大顶点数应尽可能小; [NVIDIA08]指出,当GS输出在1到20个标量之间时,可以实现GS的性能峰值,如果GS输出在27-40个标量之间,则性能下降50%。每次调用的标量输出数是最大顶点输出数和输出顶点类型结构中的标量数的乘积。
| 基本图形 | 描述 |
|---|---|
| point | 绘制GL_POINTS基本图形的时候(1) |
| line | 当绘制GL_LINES或GL_LINE_STRIP(2)时 |
| lineadj | 输入图元具有邻接线段(4) |
| triangle | GL_TRIANGLES, GL_TRIANGLE_STRIP或GL_TRIANGLE_FAN(3) |
| triangleadj | 输入图元具有邻接三角形(6) |
输出
几何着色器通过将顶点附加到输出流对象来一次输出一个顶点。 流的拓扑由固定声明确定,选择 TriangleStream、LineStream 和 PointStream 作为 GS 阶段的输出。
声明
- [maxvertexcount(3)]
- void geometry_shader(point VS_OUTPUT IN[1], inout TriangleStream<GS_
- OUTPUT> triStream) { /*shader body*/ }
示例
不做处理
几何着色器位于顶点着色器和片元着色器之间,下面示例中几何着色器没做多余的效果,仅仅相当于默认的数据传递。
- Shader "ShaderCookbook/几何着色器/SimplePoint"
- {
- Properties
- {
- _MainTex ("Texture", 2D) = "white" {}
- }
- SubShader
- {
- Tags { "RenderType"="Opaque" }
- LOD 100
- Pass
- {
- CGPROGRAM
- #pragma vertex vert
- //-------声明几何着色器
- #pragma geometry geom
- #pragma fragment frag
- #include "UnityCG.cginc"
- struct appdata
- {
- float4 vertex : POSITION;
- float2 uv : TEXCOORD0;
- };
- //-------顶点向几何阶段传递数据
- struct v2g{
- float4 vertex:SV_POSITION;
- float2 uv:TEXCOORD0;
- };
- //-------几何阶段向片元阶段传递数据
- struct g2f
- {
- float2 uv : TEXCOORD0;
- float4 vertex : SV_POSITION;
- };
- sampler2D _MainTex;
- float4 _MainTex_ST;
- v2g vert (appdata v)
- {
- v2g o;
- o.vertex = UnityObjectToClipPos(v.vertex);
- o.uv = TRANSFORM_TEX(v.uv, _MainTex);
- return o;
- }
- //-------静态制定单个调用的最大顶点个数
- [maxvertexcount(3)]
- void geom(triangle v2g input[3],inout TriangleStream<g2f> outStream){
- for(int i=0;i<3;i++){
- g2f o=(g2f)0;
- o.vertex=input[i].vertex;
- o.uv=input[i].uv;
- //-----将一个顶点添加到输出流列表
- outStream.Append(o);
- }
- //-------restart strip可以模拟一个primitives list
- outStream.RestartStrip();
- }
- fixed4 frag (g2f i) : SV_Target
- {
- // sample the texture
- fixed4 col = tex2D(_MainTex, i.uv);
- return col;
- }
- ENDCG
- }
- }
- }
点
示例一:单纯的点
- Shader "ShaderCookbook/几何着色器/OnlyPoint"
- {
- Properties
- {
- _MainTex ("Texture", 2D) = "white" {}
- }
- SubShader
- {
- Tags { "RenderType"="Opaque" }
- LOD 100
- Pass
- {
- CGPROGRAM
- #pragma vertex vert
- //-------声明几何着色器
- #pragma geometry geom
- #pragma fragment frag
- #include "UnityCG.cginc"
- struct appdata
- {
- float4 vertex : POSITION;
- float2 uv : TEXCOORD0;
- };
- //-------顶点向几何阶段传递数据
- struct v2g{
- float4 vertex:SV_POSITION;
- float2 uv:TEXCOORD0;
- };
- //-------几何阶段向片元阶段传递数据
- struct g2f
- {
- float2 uv : TEXCOORD0;
- float4 vertex : SV_POSITION;
- };
- sampler2D _MainTex;
- float4 _MainTex_ST;
- v2g vert (appdata v)
- {
- v2g o;
- o.vertex = UnityObjectToClipPos(v.vertex);
- o.uv = TRANSFORM_TEX(v.uv, _MainTex);
- return o;
- }
- //-------静态制定单个调用的最大顶点个数
- [maxvertexcount(4)]
- void geom(point v2g input[1],inout PointStream<g2f> outStream){
- g2f o=(g2f)0;
- o.vertex=input[0].vertex;
- o.uv=input[0].uv;
- outStream.Append(o);
- }
- fixed4 frag (g2f i) : SV_Target
- {
- // sample the texture
- fixed4 col = tex2D(_MainTex, i.uv);
- return col;
- }
- ENDCG
- }
- }
- }
示例二:散裂
这里需要注意的是我们通过以v[0]为原点构建两个向量,通过这两个向量我们可以自定义点。
- Shader "ShaderCookbook/GeometryShader/分解" {
- Properties {
- _MainTex("Texture", 2 D) = "white" {}
- _Height("Length", float) = 0.5
- _Offset("Offset", float) = 0.1
- _StripColor("StripColor", Color) = (1, 1, 1, 1)
- _OutColor("OutColor", Color) = (1, 1, 1, 1)
- _InColor("InColor", Color) = (1, 1, 1, 1)
- }
- SubShader {
- Cull off
- Pass {
- Tags {
- "RenderType" = "Opaque"
- }
- CGPROGRAM# pragma vertex vert# pragma fragment frag#include "UnityCG.cginc"
- struct appdata {
- float4 vertex: POSITION;
- float2 uv: TEXCOORD0;
- };
- struct v2f {
- float4 vertex: SV_POSITION;
- float4 objPos: TEXCOORD1;
- float2 uv: TEXCOORD0;
- };
- sampler2D _MainTex;
- float4 _MainTex_ST;
- float _Height;
- float _Offset;
- fixed4 _StripColor;
- v2f vert(appdata v) {
- v2f o;
- o.vertex = UnityObjectToClipPos(v.vertex);
- o.objPos = v.vertex;
- o.uv = v.uv;
- return o;
- }
- fixed4 frag(v2f i): SV_Target {
- fixed4 col = tex2D(_MainTex, i.uv);
- clip(_Height + _Offset - i.objPos.y);
- if (i.objPos.y > _Height)
- col = _StripColor;
- return col;
- }
- ENDCG
- }
- pass {
- Tags {
- "RenderType" = "Opaque"
- }
- CGPROGRAM# pragma vertex vert# pragma geometry geome# pragma fragment frag#include "UnityCG.cginc"
- fixed4 _OutColor;
- fixed4 _InColor;
- float _Height;
- float _Offset;
- struct appdata {
- float4 vertex: POSITION;
- float2 uv: TEXCOORD0;
- float3 normal: NORMAL;
- };
- struct v2g {
- float4 objPos: TEXCOORD0;
- float3 normal: NORMAL;
- };
- struct g2f {
- float4 vertex: SV_POSITION;
- fixed4 col: TEXCOORD0;
- };
- void ADD_VERT(float4 v, g2f o, inout PointStream < g2f > outstream) {
- o.vertex = v;
- outstream.Append(o);
- }
- v2g vert(appdata v) {
- v2g o;
- o.objPos = v.vertex;
- o.normal = v.normal;
- return o;
- }
- [maxvertexcount(6)]
- void geome(triangle v2g input[3], inout PointStream < g2f > outStream) {
- g2f o;
- //--------将一个三角面三个顶点的平均位置作为均值
- float4 vertex = (input[0].objPos + input[1].objPos + input[2].objPos) / 3.0;
- float3 normal = (input[0].normal + input[1].normal + input[2].normal) / 3.0;
- if (vertex.y < _Height + _Offset)
- return;
- //-------以v[0]为原点构建两个向量,用来在后续过程中通过这两个向量来构建三角面中自定义的点
- float4 s = input[1].objPos - input[0].objPos;
- float4 t = input[2].objPos - input[0].objPos;
- o.col = _OutColor * 2;
- for (int i = 0; i < 3; i++) {
- input[i].objPos.xyz += input[i].normal * (vertex.y - _Height);
- input[i].objPos = UnityObjectToClipPos(input[i].objPos);
- ADD_VERT(input[i].objPos, o, outStream);
- }
- o.col = _InColor * 2;
- //-------通过s,t两个向量构建自定义点
- float4 v[3];
- v[0] = 0.2 * s + 0.2 * t;
- v[1] = 0.4 * s + 0.6 * t;
- v[2] = 0.6 * s + 0.4 * t;
- for (int i = 0; i < 3; i++) {
- v[i].xyz += normal * (vertex.y - _Height);
- v[i] = UnityObjectToClipPos(v[i]);
- ADD_VERT(v[i], o, outStream);
- }
- }
- fixed4 frag(g2f i): SV_Target {
- fixed4 col = i.col;
- return col;
- }
- ENDCG
- }
- }
- }
线
示例:wire frame
- Shader "ShaderCookbook/几何着色器/TriangleLine"
- {
- Properties
- {
- _MainTex ("Texture", 2D) = "white" {}
- }
- SubShader
- {
- Tags { "RenderType"="Opaque" }
- LOD 100
- Pass
- {
- CGPROGRAM
- #pragma vertex vert
- //-------声明几何着色器
- #pragma geometry geom
- #pragma fragment frag
- #include "UnityCG.cginc"
- struct appdata
- {
- float4 vertex : POSITION;
- float2 uv : TEXCOORD0;
- };
- //-------顶点向几何阶段传递数据
- struct v2g{
- float4 vertex:SV_POSITION;
- float2 uv:TEXCOORD0;
- };
- //-------几何阶段向片元阶段传递数据
- struct g2f
- {
- float2 uv : TEXCOORD0;
- float4 vertex : SV_POSITION;
- };
- sampler2D _MainTex;
- float4 _MainTex_ST;
- v2g vert (appdata v)
- {
- v2g o;
- o.vertex = UnityObjectToClipPos(v.vertex);
- o.uv = TRANSFORM_TEX(v.uv, _MainTex);
- return o;
- }
- //-------静态制定单个调用的最大顶点个数
- [maxvertexcount(3)]
- //使用三角面作为输入,线段作为输出我们得到完整的线框
- void geom(triangle v2g input[3],inout LineStream<g2f> outStream){
- g2f o=(g2f)0;
- o.vertex=input[0].vertex;
- o.uv=input[0].uv;
- outStream.Append(o);
- o.vertex=input[1].vertex;
- o.uv=input[1].uv;
- outStream.Append(o);
- o.vertex=input[2].vertex;
- o.uv=input[2].uv;
- outStream.Append(o);
- }
- fixed4 frag (g2f i) : SV_Target
- {
- // sample the texture
- fixed4 col = tex2D(_MainTex, i.uv);
- return col;
- }
- ENDCG
- }
- }
- }
面
示例:尖刺
- Shader "ShaderCookbook/GeometryShader/尖刺" {
- Properties {
- _MainTex("Texture", 2D) = "white" {}
- _Length("Length", float) = 0.5
- }
- SubShader {
- Tags {
- "RenderType" = "Opaque"
- }
- LOD 100
- Pass {
- CGPROGRAM
- #pragma vertex vert
- #pragma geometry geom
- #pragma fragment frag
- // make fog work
- #pragma multi_compile_fog
- #include "UnityCG.cginc"
- struct appdata {
- float4 vertex: POSITION;
- float2 uv: TEXCOORD0;
- };
- struct v2g {
- float4 pos: SV_POSITION;
- float2 uv: TEXCOORD0;
- };
- struct g2f {
- float2 uv: TEXCOORD0;
- float4 vertex: SV_POSITION;
- };
- sampler2D _MainTex;
- float4 _MainTex_ST;
- float _Length;
- void ADD_VERT(float3 v, g2f o, inout TriangleStream < g2f > tristream) {
- o.vertex = UnityObjectToClipPos(v);
- tristream.Append(o);
- }
- void ADD_TRI(float3 p0, float3 p1, float3 p2, g2f o, inout TriangleStream < g2f > tristream) {
- ADD_VERT(p0, o, tristream);
- ADD_VERT(p1, o, tristream);
- ADD_VERT(p2, o, tristream);
- tristream.RestartStrip();
- }
- v2g vert(appdata v) {
- v2g o = (v2g) 0;
- o.pos = v.vertex;
- o.uv = TRANSFORM_TEX(v.uv, _MainTex);
- return o;
- }
- [maxvertexcount(9)]
- void geom(triangle v2g input[3], inout TriangleStream < g2f > outStream) {
- g2f o;
- //-----------这里通过三角面的两个边叉乘来获得垂直于三角面的法线方向
- float3 s = (input[1].pos - input[0].pos).xyz;
- float3 t = (input[2].pos - input[0].pos).xyz;
- float3 normal = normalize(cross(s, t));
- float3 centerPos = (input[0].pos.xyz + input[1].pos.xyz + input[2].pos.xyz) / 3.0;
- float2 centerUv = (input[0].uv + input[1].uv + input[2].uv) / 3.0;
- o.uv = centerUv;
- centerPos += normal * _Length * abs(sin(_Time.y * 5));
- ADD_TRI(input[0].pos, centerPos, input[2].pos, o, outStream);
- ADD_TRI(input[2].pos, centerPos, input[1].pos, o, outStream);
- ADD_TRI(input[1].pos, centerPos, input[0].pos, o, outStream);
- }
- fixed4 frag(g2f i): SV_Target {
- fixed4 col = tex2D(_MainTex, i.uv);
- return col;
- }
- ENDCG
- }
- }
- }
Other
项目工程:链接: https://pan.baidu.com/s/1eGk6GHIfWzIFcAX6pxTGRA 提取码: fv75
解压密码:https://fgk.pw/i/eqm2Bj23236
这里推荐一款可视化shader编程工具,对美术同学非常友好,就像建模工具中的材质编辑器一样
Unity 几何着色器的更多相关文章
- DirectX11 With Windows SDK--15 几何着色器初探
前言 从这一部分开始,感觉就像是踏入了无人深空一样,在之前初学DX11的时候,这部分内容都是基本上跳过的,现在打算重新认真地把它给拾回来. DirectX11 With Windows SDK完整目录 ...
- DirectX11 With Windows SDK--17 利用几何着色器实现公告板效果
前言 上一章我们知道了如何使用几何着色器将顶点通过流输出阶段输出到绑定的顶点缓冲区.接下来我们继续利用它来实现一些新的效果,在这一章,你将了解: 实现公告板效果 Alpha-To-Coverage 对 ...
- 翻译:探索GLSL-用几何着色器(着色器库)实现法线可视化
翻译:探索GLSL-用几何着色器(着色器库)实现法线可视化 翻译自: Exploring GLSL – Normal Visualizer with Geometry Shaders (Shader ...
- Unity Shader着色器优化
https://mp.weixin.qq.com/s?__biz=MzU5MjQ1NTEwOA==&mid=2247493518&idx=1&sn=c51b92e9300bcf ...
- Unity 5着色器系统代码介绍(上)
http://forum.china.unity3d.com/thread-25724-1-10.html Unity 5着色器系统代码介绍(上) Unity在着色器开发方面提供了很大的灵活性.有些工 ...
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十二章:几何着色器(The Geometry Shader)
原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十二章:几何着色器(The Geometry Shader) 代码工 ...
- [Unity] Shader(着色器)输入输出和语义
在Unity5.x后, 已经支持了基于物理的光照模型,也就是常说的次时代引擎所必须具备的功能. 如果在Properties使用2D,CG里要用sampler2D,代表使用的是2维纹理 如果在Prope ...
- Unity 5着色器系统代码介绍(下)
http://forum.china.unity3d.com/thread-25738-1-10.html 上一篇对着色器系统的工作原理做了介绍,现在我们将继续深入,将目光聚焦在标准着色器的光照函数. ...
- [Unity] Shader(着色器)之纹理贴图
在Shader中,我们除了可以设定各种光线处理外,还可以增加纹理贴图. 使用 settexture 命令可以为着色器指定纹理. 示例代码: Shader "Sbin/ff2" { ...
随机推荐
- spark搭建部署
基础环境准备 安装JDK1.8+,并设置环境变量 搭建zookeeper集群 搭建Hadoop集群 Spark local模式 上传编译完成的spark安装程序到服务器上,并解压到指定目录 [root ...
- 【译文】MySQL InnoDB 事物模型
InnoDB事物模型 事物的隔离级别 自动提交,提交和回滚 一致的非锁定读 锁定读 在InnoDB事物模型中,目标是为了多版本数据库和传统的俩段锁协议的最佳实践(多版本并发控制).InnoDB在行级别 ...
- angular 生命周期钩子 ngOnInit() 和 ngAfterViewInit() 的区别
angular 生命周期钩子的详细介绍在 https://angular.cn/guide/lifecycle-hooks 文档中做了介绍. ngOnInit() 在 Angular 第一次显示数据 ...
- 利用mpvue开发微信小程序
最近公司部门负责人提出需求需要开发一款微信小程序,由于本人之前是做前端开发的,对于小程序开发一窍不通,但是很多时候我们都是把不会做变成我会学.于是便在网上寻找小程序开发教程,相比于相生的小程序开发,本 ...
- [USACO09MAR]Moon Mooing
嘟嘟嘟 某谷的翻译挺迷的,简单来说就是给一个初值c,然后有两个函数f1 = a1 * x / d1 + b1, f2 = a2 * x / d2 + b2.把c分别带进去,所得的结果也递归带进去,这样 ...
- HBase学习之路 (三)HBase集群Shell操作
进入HBase命令行 在你安装的随意台服务器节点上,执行命令:hbase shell,会进入到你的 hbase shell 客 户端 [hadoop@hadoop1 ~]$ hbase shell S ...
- Codeforces 1133 F2. Spanning Tree with One Fixed Degree 并查集+生成树
好久没更新博客了,一直懒得动,这次更新一下. 题意大概是:给出一个图,求它的一个一号节点的度数恰好为D的生成树的方案. 一开始随便水了个乱搞贪心,不出意外并没有过. 仔细思考之后,对于这个问题我们可以 ...
- [luogu3941] 入阵曲
题面 话说题目前面的那首诗还挺有意境的啊哈哈. 可能今天要把中文的标点都换成英文的了, 先熟悉一下吧... 好了, 进入正题, 求一个矩阵内有多少个子矩阵满足这个子矩阵的和模k为零.看到矩 ...
- 初识Qt基于http协议网页浏览
1.新建一个Qt Gui应用,项目名称为http,基类选择为QMainWindow,类名设置为MainWindow. 2.在http.pro文件中的QT += core gui后添加\ networ ...
- tcpdump 和 wireshark 的实用例子
tcpdump: 1.用 tcpdump 截取本机 ip 10.2.1.2 10050 端口的包 tcpdump -nnv -i eth0 host 10.2.1.2 and port 10050 ...