热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

[Unityshader]在unity中尝试实现三渲二的效果

文章目录在Unity中实现三渲二,我尝试从两个途径去实现,一个是用Unity官方的可视化着色器插件shadergraph实现一.ShaderGraphshadergraph搭建设置

文章目录

  • 在Unity中实现三渲二,我尝试从两个途径去实现,一个是用Unity官方的可视化着色器插件shadergraph实现
    • 一.ShaderGraph
      • shadergraph搭建设置请自行百度
      • 最后将三个模块得到的颜色信息加起来,就能获得结果了。
    • 二,使用shaderlab即编写shader代码,自由度很高,就是上手有点难。
在Unity中实现三渲二,我尝试从两个途径去实现,一个是用Unity官方的可视化着色器插件shadergraph实现

一.ShaderGraph

shadergraph搭建设置请自行百度

《[Unityshader]在unity中尝试实现三渲二的效果》
我们先看下效果图,没有很多复杂的效果,从最简单的只有一盏光源考虑。
《[Unityshader]在unity中尝试实现三渲二的效果》
在shadergraph中我们无法简单的获取光源信息,如果想要获取光源信息,需要实现自定义节点来获取光源的信息,太过复杂,所以我们先假定一个光源的方向。
给出shader图。
《[Unityshader]在unity中尝试实现三渲二的效果》图有点大,看不清,我们一个组一个组来讲解。
可以看到图上分了三大块。
三大块分别为:

  • diffuse漫反射
  • highlight高光
  • border边缘线

先看漫反射:《[Unityshader]在unity中尝试实现三渲二的效果》
漫反射比较简单,首先对于方向向量都要归一化(normalize),因为这样点积得到的结果才能在-1,1区间。将光和物体世界坐标的法向量点乘,得到两个向量的余弦值,以此来模拟漫反射,由于我们是想要实现二次元效果所以,不能有过渡,所以我们要使用step函数消除过渡:将大于x的值置为1,将小于x的值置为0。随后,我们希望暗部的亮度值是可以控制的,我们引入自定义属性darkSideValue(dsv)来控制结果,首先我们将得到的结果使用OneMinus(1-输入的值)节点来进行反转,这样暗部就为1,亮部为0,此时将值乘上dSV就能够改变暗部的亮度了。(图中还考虑了环境光的亮度能影响到暗部,所以先把暗部值乘上了ambient的亮度,或许改为加会好一些。)然后我们把反转后的值加回没反转之前(不用担心亮部值会爆出,因为dsv值的亮部为0),最后将结果乘上物体本身的固有色贴图采样。

再来看看高光
《[Unityshader]在unity中尝试实现三渲二的效果》高光部分前面和大部分着色器一样处理,需要注意的是,Viewdirection节点获得的摄像机视角并没有归一化,需要先进行归一化处理,不然会得到很奇怪的结果。我们将使用reflection节点将光源以物体表面法线反射出去,将这个向量和摄像机视角做点乘,得到的值仍然需要使用step去过渡,得到了高光区域后,我们可以考虑使用贴图的alpha通道来改变高光的显示,使得高光能够表现出物体的结构。

最后看下边缘处理《[Unityshader]在unity中尝试实现三渲二的效果》
由于是在shadergraph中所以我们无法对一个物体进行多个pass渲染,只好使用边缘光的方式来模拟描边,我们可以使用菲涅尔节点来获取物体的菲涅尔信息。然后对这个值进行step处理,不过这样的结果得到的边缘是亮形式的,我们往往希望描边是黑色的,于是进行了OneMinus处理进行反转,最后将这个值乘上边缘颜色。

最后将三个模块得到的颜色信息加起来,就能获得结果了。

二,使用shaderlab即编写shader代码,自由度很高,就是上手有点难。

大部分思想和上面一样,描边原理不一样,这里采用的描边是先用一个pass去渲染物体的背面,同时把物体的体积扩大。再用一个pass绘制正常的物体。

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
Shader "Unlit/anim"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_LightTex("HighlightTex",2D)="white"{}
_BorderEdge("borderEgde",Range(-1,1))=0
_BaseColor("baseColor",Color)=(1,1,1,1)
_DarkSideBrightness("dsBrightness",Range(0,1))=1
_HighLightEdge("highLightEdge",Range(-1,1))=0
_Factor("factor",Range(0,0.1)) = 0.01 //描边粗细因子
_OutLineColor("outline color",Color) = (0,0,0,1)//描边颜色
}
SubShader
{
Tags { "RenderType"="ForwardBase" }
LOD 100
Pass
{
Cull Front //剔除前面
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f
{
float4 vertex :POSITION;
};
float _Factor;
half4 _OutLineColor;
v2f vert(appdata_full v)
{
v2f o;
//将顶点沿法线方向向外扩展一下
v.vertex.xyz += v.normal * _Factor;
o.vertex = UnityObjectToClipPos(v.vertex);
return o;
}
half4 frag(v2f v) :COLOR
{
//只显示描边的颜色
return _OutLineColor;
}
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
float _BorderEdge;
sampler2D _MainTex;
sampler2D _LightTex;
float4 _MainTex_ST;
float4 _LightTex_ST;
fixed4 _BaseColor;
float _DarkSideBrightness;
float _HighLightEdge;
float _HighLightPower;
struct appdata
{
float4 vertex : POSITION;
float3 normal:NORMAL;
float2 uv:TEXCOORD0;
};
struct v2f
{
float2 uv:TEXCOORD0;
float3 worldNormal:TEXCOORD1;
float3 worldPos:TEXCOORD2;
float4 vertex : POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex=UnityObjectToClipPos(v.vertex);
o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;//获取世界空间的顶点位置
o.worldNormal=mul(unity_ObjectToWorld,v.normal);//获取世界空间的法线向量
o.uv=TRANSFORM_TEX(v.uv,_LightTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed3 lightTex=tex2D(_LightTex,i.uv);

float3 lightDir=normalize(UnityWorldSpaceLightDir(i.worldPos));
float3 viewDir=normalize(UnityWorldSpaceViewDir(i.worldPos));
// sample the texture
float3 worldNormal=normalize(i.worldNormal);
float diffuseV=dot(worldNormal,lightDir);
float diffStep=step(_BorderEdge,diffuseV);
float tmp=1-diffStep;
float ds=tmp*_DarkSideBrightness;
float highLightV=dot(viewDir,reflect(-lightDir,worldNormal));
float hlvSp=step(_HighLightEdge,highLightV);

fixed4 dsColor=(UNITY_LIGHTMODEL_AMBIENT+ds*_BaseColor);

return _LightColor0*_BaseColor*diffStep+dsColor+hlvSp*fixed4(1,1,1,1)*_LightColor0*fixed4(lightTex,1);
}
ENDCG
}
}
Fallback "Specular"
}

推荐阅读
  • 本文由编程笔记#小编整理,主要介绍了关于数论相关的知识,包括数论的算法和百度百科的链接。文章还介绍了欧几里得算法、辗转相除法、gcd、lcm和扩展欧几里得算法的使用方法。此外,文章还提到了数论在求解不定方程、模线性方程和乘法逆元方面的应用。摘要长度:184字。 ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 树莓派语音控制的配置方法和步骤
    本文介绍了在树莓派上实现语音控制的配置方法和步骤。首先感谢博主Eoman的帮助,文章参考了他的内容。树莓派的配置需要通过sudo raspi-config进行,然后使用Eoman的控制方法,即安装wiringPi库并编写控制引脚的脚本。具体的安装步骤和脚本编写方法在文章中详细介绍。 ... [详细]
  • 本文由编程笔记小编整理,主要介绍了使用Junit和黄瓜进行自动化测试中步骤缺失的问题。文章首先介绍了使用cucumber和Junit创建Runner类的代码,然后详细说明了黄瓜功能中的步骤和Steps类的实现。本文对于需要使用Junit和黄瓜进行自动化测试的开发者具有一定的参考价值。摘要长度:187字。 ... [详细]
  • 基于移动平台的会展导游系统APP设计与实现的技术介绍与需求分析
    本文介绍了基于移动平台的会展导游系统APP的设计与实现过程。首先,对会展经济和移动互联网的概念进行了简要介绍,并阐述了将会展引入移动互联网的意义。接着,对基础技术进行了介绍,包括百度云开发环境、安卓系统和近场通讯技术。然后,进行了用户需求分析和系统需求分析,并提出了系统界面运行流畅和第三方授权等需求。最后,对系统的概要设计进行了详细阐述,包括系统前端设计和交互与原型设计。本文对基于移动平台的会展导游系统APP的设计与实现提供了技术支持和需求分析。 ... [详细]
  • Python脚本编写创建输出数据库并添加模型和场数据的方法
    本文介绍了使用Python脚本编写创建输出数据库并添加模型数据和场数据的方法。首先导入相应模块,然后创建输出数据库并添加材料属性、截面、部件实例、分析步和帧、节点和单元等对象。接着向输出数据库中添加场数据和历程数据,本例中只添加了节点位移。最后保存数据库文件并关闭文件。文章还提供了部分代码和Abaqus操作步骤。另外,作者还建立了关于Abaqus的学习交流群,欢迎加入并提问。 ... [详细]
  • Tag类:EVAL_BODY_INCLUDE在doStartTag中返回表示执行标签体的内容SKIP_BODY在doStartTag方法中返回表示不执行标签体EVAL ... [详细]
  • 前言本篇为大家总结社区多人合作常见的场景和对应的git操作命令。本篇非新手教程,阅读本篇前需具备Git基础知识。Git入门教程请参考https://www ... [详细]
author-avatar
死性Oo不改2502917357
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有