曲面着色器初试--地面轨迹模拟(部分细节不完善)
曲面着色器初试(部分细节不完善)
文章目录
- 曲面着色器初试(部分细节不完善)
- 前言
- 一、曲面细分着色器基本概念
- 1.整体概念
- 二、曲面着色器小试牛刀
- 1.大致需求
- 1-1.实现效果
- 2.实现步骤
- 2-0.大体思路
- 2-1.场景组合
- 2-2.shader代码实现(使用Unlit)
- 2-3.shader代码实现(使用surf)
- 总结
前言
在图形管线基础(一)中我们介绍OpenGL渲染管线的基本流程以及基本概念。本次章节将对图形管线中的曲面细分着色器做一个小Demo,有不完善的地方,仅提供思路。也有一个问题尚未解决,如果你们有解决方案也请私聊我。
一、曲面细分着色器基本概念
1.整体概念
曲面细分着色流程位于顶点着色器之后,几何着色器之前。细分曲面是将高阶基元(opengl中成为贴片[patch])分解为许多更小,更简单的基元进行渲染的过程。例如拆分为多个三角形。Opengl包含一个固定功能的、可配置的细分曲面引擎。可将多个四边形、三角形和线分解为大量更小的点,线或三角形,这些点、线或三角形可有管线中常规光栅器硬件直接使用。从逻辑上讲,细分曲面阶段位于Opengl管线中顶点着阶段之后,主要由三部分组成:细分曲面控制器(Tessellaction Control Shader)、固定函数细分曲面引擎(Tessellation Primitive Gen)和细分曲面评估着色器(Tessellation Eval Shader),这三个部分具体概念之前的文章有讲过,这里不再赘述。
我们可以从图中可以看到,曲面着色器中,有两个模块是可以编辑模块,分别是曲面控制器以及曲面细分评估着色器。曲面细分引擎是固定函数不可编辑。在实际编写曲面着色器时,这并不像其他着色器添加一个其他程序那么简单。我们需要一个外壳程序和域程序。如下图所示:
‘不知道我的理解有没有错误,我认为Hull Program外壳函数就是我们渲染流程图中的细分曲面控制器,主要负责输出控制点以及细分因子。Tessellation就是我们的细分引擎,不可编辑。Domain Program作为我们的域函数就是我们的细分评估着色器,主要执行顶点赋值操作。介绍了大致概念,我们开始来做一个demo。
二、曲面着色器小试牛刀
1.大致需求
我们希望在地形上记录人物行走轨迹,使用曲面着色器细分地形,然后做一个地形下拉,完成人物轨迹的制作。在不使用曲面着色器的情况下,地形顶点较少,下拉后形状呈倒三角,过于平整,不好看。使用曲面细分后,顶点增加,随之面数也增加,下拉后形状趋于渐变,自然。本次demo会用使用两种着色器实现,一种是表面着色器,代码量少,几句话就能实现,一种Unlit着色器,需要手动实现曲面细分着色器,代码量多,但是效果是一样的。
1-1.实现效果
2.实现步骤
2-0.大体思路
整体思路很简单,用一个额外摄像机记录人物轨迹,摄像机数据不清除。将摄像机拍摄的内容放到我们的RT中,在shader中我们先使用细分曲面着色器根据线长度细分地形,增加更多的顶点以及面片,再采样RT,根据人物轨迹做y轴上的地形下拉,完成效果。
2-1.场景组合
场景构成如上,箭头标注1,2,3.
箭头标注1:是一个扁平化球体,他将挂在人物脚步位置,随着角色移动,将作为记录人物运动轨迹的标签。
箭头标注2:就是我们结合人物运动轨迹使用曲面细分着色器制作的地形下拉效果。
箭头标注3:将作为我们拍摄角色运动标签的摄像机,摄像机位于人物头顶上方,跟小地图制作方式差不多。使用正交投影,摄像机设置如下:关键参数已经标注。
我们可以切到网状视图下,看细分的效果
2-2.shader代码实现(使用Unlit)
Shader "Unlit/Tessellation"
{Properties{_Color ("Tint", Color) = (1, 1, 1, 1)_MainTex ("Albedo", 2D) = "white" {}_SnowTex("SnowTex", 2D) = "white" {}_SnowFactor("SnowFactor", float) = 1_SnowColor("SnowColor", Color) = (1,1,1,1)_TessellationEdgeLength ("Tessellation Edge Length", Range(5, 100)) = 50_Specular ("Specular", Color) = (1, 1, 1, 1)_Gloss ("Gloss", Range(1.0, 500)) = 20}CGINCLUDEENDCGSubShader{Tags { "RenderType"="Opaque" }LOD 100Pass {Tags {"LightMode" = "ForwardBase"}CGPROGRAM#pragma target 4.0#pragma vertex MyTessellationVertexProgram #pragma fragment frag#pragma hull MyHullProgram#pragma domain MyDomainProgram#include "UnityCG.cginc"#include "Lighting.cginc"float _TessellationEdgeLength;sampler2D _MainTex;float4 _MainTex_ST;float4 _SnowColor;sampler2D _SnowTex;float4 _SnowTex_ST;float _SnowFactor;fixed4 _Specular;float _Gloss;struct InterpolatorsVertex {float4 pos : SV_POSITION;float4 uv : TEXCOORD0;float3 normal : TEXCOORD1;float3 worldPos : TEXCOORD2;float3 worldNormal : TEXCOORD3 ;};struct VertexData {float4 vertex : POSITION;float3 normal : NORMAL;float2 uv : TEXCOORD0;};struct TessellationControlPoint {float4 vertex : INTERNALTESSPOS;float3 normal : NORMAL;float2 uv : TEXCOORD0;};struct TessellationFactors {float edge[3] : SV_TessFactor;float inside : SV_InsideTessFactor;};TessellationControlPoint MyTessellationVertexProgram (VertexData v) {TessellationControlPoint p;p.vertex = v.vertex;p.normal = v.normal;p.uv = v.uv;return p;}float TessellationEdgeFactor (float3 p0, float3 p1) {float edgeLength = distance(p0, p1);float3 edgeCenter = (p0 + p1) * 0.5;float viewDistance = distance(edgeCenter, _WorldSpaceCameraPos);return edgeLength * _ScreenParams.y /(_TessellationEdgeLength * viewDistance);}TessellationFactors MyPatchConstantFunction (InputPatch<TessellationControlPoint, 3> patch) {float3 p0 = mul(unity_ObjectToWorld, patch[0].vertex).xyz;float3 p1 = mul(unity_ObjectToWorld, patch[1].vertex).xyz;float3 p2 = mul(unity_ObjectToWorld, patch[2].vertex).xyz;TessellationFactors f;f.edge[0] = TessellationEdgeFactor(p1, p2);f.edge[1] = TessellationEdgeFactor(p2, p0);f.edge[2] = TessellationEdgeFactor(p0, p1);f.inside =(TessellationEdgeFactor(p1, p2) +TessellationEdgeFactor(p2, p0) +TessellationEdgeFactor(p0, p1)) * (1 / 3.0);return f;}[UNITY_domain("tri")][UNITY_outputcontrolpoints(3)][UNITY_outputtopology("triangle_cw")][UNITY_partitioning("fractional_odd")][UNITY_patchconstantfunc("MyPatchConstantFunction")]TessellationControlPoint MyHullProgram (InputPatch<TessellationControlPoint, 3> patch,uint id : SV_OutputControlPointID) {return patch[id];}InterpolatorsVertex MyVertexProgram (VertexData v) {InterpolatorsVertex i;v.vertex.y -= tex2Dlod(_SnowTex, float4(v.uv.xy,0,0)).r * _SnowFactor;i.pos = UnityObjectToClipPos(v.vertex);i.worldPos.xyz = mul(unity_ObjectToWorld, v.vertex);i.uv.xy = TRANSFORM_TEX(v.uv, _MainTex);i.worldNormal = UnityObjectToWorldNormal(v.normal);return i;}[UNITY_domain("tri")]InterpolatorsVertex MyDomainProgram (TessellationFactors factors,OutputPatch<TessellationControlPoint, 3> patch,float3 barycentricCoordinates : SV_DomainLocation) {VertexData data;#define MY_DOMAIN_PROGRAM_INTERPOLATE(fieldName) data.fieldName = \patch[0].fieldName * barycentricCoordinates.x + \patch[1].fieldName * barycentricCoordinates.y + \patch[2].fieldName * barycentricCoordinates.z;MY_DOMAIN_PROGRAM_INTERPOLATE(vertex)MY_DOMAIN_PROGRAM_INTERPOLATE(normal)MY_DOMAIN_PROGRAM_INTERPOLATE(uv)return MyVertexProgram(data);}fixed4 frag (InterpolatorsVertex i) : SV_Target{float snow = tex2D(_SnowTex, i.uv).r ;fixed4 col = tex2D(_MainTex, i.uv) + _SnowColor * snow; float3 normalizeResult123 = normalize( ( cross( ddx( i.worldPos ) , ddy( i.worldPos ) ) + float3( 1E-09,0,0 ) ) ); fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * col;fixed3 worldNormal = normalize(i.worldNormal); fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); fixed3 diffuse = _LightColor0.rgb * col.rgb * max(0, dot(worldNormal, worldLightDir)); fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));fixed3 halfDir = normalize(worldLightDir + viewDir);fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss); return fixed4(ambient + diffuse , 1.0);}ENDCG}}
}
2-3.shader代码实现(使用surf)
Shader "Custom/Tessellation2"
{Properties{_EdgeLength ( "Edge length", Range( 2, 50 ) ) = 15_MainTex ("Texture", 2D) = "white" {}_BumpTex("BumpTex", 2D) = "bump" {}_SnowTex("SnowTex", 2D) = "white" {}_SnowFactor("SnowFactor", float) = 1_SnowColor("SnowColor", Color) = (1,1,1,1)[HideInInspector] _texcoord( "", 2D ) = "white" {}}SubShader{Tags{ "RenderType" = "Opaque" "Queue" = "Geometry+0" }Cull BackCGPROGRAM#include "Tessellation.cginc"#pragma target 4.6#pragma surface surf Standard keepalpha addshadow fullforwardshadows vertex:vertexDataFunc tessellate:tessFunction struct Input{float2 uv_texcoord;};sampler2D _MainTex;float4 _MainTex_ST;sampler2D _BumpTex;float4 _BumpTex_ST;sampler2D _SnowTex;float4 _SnowTex_ST;float _SnowFactor;float4 _SnowColor;uniform float _EdgeLength;float4 tessFunction( appdata_full v0, appdata_full v1, appdata_full v2 ){return UnityEdgeLengthBasedTess (v0.vertex, v1.vertex, v2.vertex, _EdgeLength);}void vertexDataFunc( inout appdata_full v ){v.vertex.y -= tex2Dlod(_SnowTex, float4(v.texcoord.xy,0,0)).r * _SnowFactor;}void surf( Input i , inout SurfaceOutputStandard o ){float2 uv_Albedo = i.uv_texcoord * _MainTex_ST.xy + _MainTex_ST.zw;float snow = tex2D(_SnowTex, float2(i.uv_texcoord)).r ;o.Albedo =tex2D(_MainTex, uv_Albedo).rgb + _SnowColor * snow;o.Alpha = 1;}ENDCG}Fallback "Diffuse"}
总结
以上就是今天要讲的内容,本文仅仅简单介绍了曲面着色器的大致应用。我们可以看到使用表面着色器和使用Unlit着色器,代码量上的差距,表面着色器,unity帮我们实现了大部分逻辑,仅仅暴露出细分因子函数,可手动修改的部分比较少。而且据说unity自带的细分因子函数有Bug,在某些复杂地形下细分会出现空隙。Unlit则需要我们补足每个函数逻辑,手动化更高,编辑性更强。但是本次demo除了细节上不足之外,有个致命的问题,就是法线信息没有随着曲面细分,顶点下拉而改变,导致他光线计算有误,没有亮暗的交替变化,这个问题我还不知道怎么解决,也希望有知道这方面的大佬能私信我,将感激不尽。接下来自己将进入urp的学习。
曲面着色器初试--地面轨迹模拟(部分细节不完善)相关推荐
- OpenGL 4.0的Tessellation Shader(细分曲面着色器)
细分曲面着色器(Tessellation Shader)处于顶点着色器阶段的下一个阶段,我们可以看以下链接的OpenGL渲染流水线的图:Rendering Pipeline Overview - Op ...
- Tessellation Shader(细分曲面着色器)
Tessellation Shader)是OpenGLES4.0引入的,处于顶点着色器阶段的下一个阶段,它是由ATI在2001年率先设计出来的. 细分曲面着色器 直到这个阶段,对于操作几何图元而言,只 ...
- DirectX11进阶8_计算着色器(入门、流体模拟)
一.计算着色器:入门 GPU通常被设计为从一个位置或连续的位置读取并处理大量的内存数据(即流操作),而CPU则被设计为专门处理随机内存的访问. 由于顶点数据和像素数据可以分开处理,GPU架构使得它能够 ...
- “着色器”是什么意思? 如何使用HTML5和WebGL创建它们
本文是Microsoft的Web开发技术系列的一部分. 感谢您支持使SitePoint成为可能的合作伙伴. 您可能已经注意到,去年我们第一次谈论了babylon.js ,最近发布了带有3D声音定位(使 ...
- webgl 着色器_“着色器”是什么意思? 如何使用HTML5和WebGL创建它们
webgl 着色器 本文是Microsoft的Web开发技术系列的一部分. 感谢您支持使SitePoint成为可能的合作伙伴. 您可能已经注意到,去年我们第一次谈论了babylon.js ,最近我们发 ...
- Unity开发备忘录000006:用Unity标准着色器构建金属材质效果(二)
按照Unity开发备忘录000005:用Unity标准着色器构建金属材质效果(一)所介绍的方法,我们又做了一个如下的模型渲染. 在此基础上我们再给它加一个高度贴图,其立体感的细节会更加丰富,如下图: ...
- unity地面添加材质球_为Unity3D创建素材(1):图片、着色器、材质球
图片 Unity3D支持使用大部分位图格式作为图片素材,甚至包括带图层和图层效果的.psd格式文件. 但在实际使用中,并不推荐直接使用非通用的文件格式.这是因为对于任何格式的图片素材,Unity3D在 ...
- 关于在寒假用两周从零手写包含模拟着色器的软渲染器这件事
当你重新踏上旅途之后,一定要记得旅途本身的意义. --巴巴托斯 轮子哥说过,编译原理,操作系统,图形学是程序员的三大浪漫,既然以后想从事游戏方面的工作,造这个轮子是不可避免的.其实早在本科的时候我就有 ...
- OpenGL中的曲面细分和几何着色器
[摘要]本文我们先介绍OpenGL中的曲面细分的一些基本概念,然后给两个例子说明不得不用这项技术的理由. 曲面细分是OpenGL 4.0之后才定义的功能,使用之前请确认你的显卡驱动支持OpenGL4. ...
最新文章
- python 浮点数未解之谜
- Java基于对象基础 基于对象和面向对象的区别(转)
- Android UI SurfaceView的使用-绘制组合图型,并使其移动
- Linux命令行笔记
- Android OkHttp(1)
- python在日常工作处理中的应用-Python在工作中的应用
- Python标准库:itertools迭代器函数
- 计算机科学与技术创新实验班是什么意思,计算机科学与技术系成立2010级创新实验班(图)...
- java 字段为空设置默认值_java – 当字段为空时使用MyBatis添加默认值
- HTML keygen控件
- 【Python爬虫学习笔记3】requests库
- winform 填充圆形 锯齿_Qt项目中,三种图形渐变填充方式详细总结
- PAIP.HIBERNATE ORA-02289 sequence does not exist的解决
- 谷歌地球下载及功能介绍
- 腾讯云轻量应用服务器免费升级2核4G8M升级4核4G8M不花钱
- openvswitch vxlan 源码分析
- 小程序亚马逊服务器,亚马逊aws服务器搭建实现微信小程序换脸(草草收尾)
- java数组初始化 new_java 数组初始化
- gym101908 F. Music Festival(状压dp)
- springboot远程心电诊断系统毕业设计源码091759