Shader知识普及之:素描效果的实现
csdh11 2024-12-12 11:18 4 浏览
本篇文章我们一起来学习下如何用shader为模型添加素描效果。
素描画(丢勒作品)
我们观察下素描画作,可以借鉴到素描风格模型的大致实现思路:事先我们要准备六张不同疏密程度、不同颜色深浅的素描贴图,根据模型表面情况,混合贴图比例到模型,实现模型素描化。
场景动物模型(素描效果处理)
我们先来看一下在Unity中对动物模型的shader代码处理过程:
Shader "Unlit/Sketch"
{
Properties
{
_Color("Color",Color) = (1,1,1,1)
_TileFactor("TileFactor", Range(0, 10)) = 1
_Hatch0("Hatch0",2D)="white"{}
_Hatch1("Hatch1",2D) = "white"{}
_Hatch2("Hatch2",2D) = "white"{}
_Hatch3("Hatch3",2D) = "white"{}
_Hatch4("Hatch4",2D) = "white"{}
_Hatch5("Hatch5",2D) = "white"{}
_OutlineFactor("OutlineFactor",Range(0.0,0.1))=0.01
}
SubShader
{
Tags{ "Queue" = "Transparent" }
Pass
{
Cull Front
ZWrite Off
Offset 1,1
CGPROGRAM
#include "UnityCG.cginc"
#pragma vertex vert
#pragma fragment frag
float _OutlineFactor;
struct v2f
{
float4 pos : SV_POSITION;
};
v2f vert(appdata_full v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
float3 vnormal = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);
float2 offset = TransformViewToProjection(vnormal.xy);
o.pos.xy += offset * _OutlineFactor;
return o;
}
fixed4 frag(v2f i) : SV_Target
{
return float4(0,0,0,1);
}
ENDCG
}
Pass
{
CGPROGRAM
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
float4 _Color;
float _TileFactor;
sampler2D _Hatch0;
sampler2D _Hatch1;
sampler2D _Hatch2;
sampler2D _Hatch3;
sampler2D _Hatch4;
sampler2D _Hatch5;
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float3 hatchWeights0:TEXCOORD1;
float3 hatchWeights1:TEXCOORD2;
SHADOW_COORDS(4)
float3 worldPos:TEXCOORD3;
};
v2f vert (appdata_full v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord* _TileFactor;
float3 worldLightDir = normalize(WorldSpaceLightDir(v.vertex));
float3 worldNormal = UnityObjectToWorldNormal(v.normal);
float diffuse = max(0, dot(worldLightDir, worldNormal));
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz ;
o.hatchWeights0 = float3(0, 0, 0);
o.hatchWeights1 = float3(0, 0, 0);
float hatchFactor = diffuse * 7.0;
if (hatchFactor > 6.0) {
}
else if (hatchFactor > 5.0) {
o.hatchWeights0.x = hatchFactor - 5.0;
}
else if (hatchFactor > 4.0) {
o.hatchWeights0.x = hatchFactor - 4.0;
o.hatchWeights0.y = 1.0 - o.hatchWeights0.x;
}
else if (hatchFactor > 3.0) {
o.hatchWeights0.y = hatchFactor - 3.0;
o.hatchWeights0.z = 1.0 - o.hatchWeights0.y;
}
else if (hatchFactor > 2.0) {
o.hatchWeights0.z = hatchFactor - 2.0;
o.hatchWeights1.x = 1.0 - o.hatchWeights0.z;
}
else if (hatchFactor > 1.0) {
o.hatchWeights1.x = hatchFactor - 1.0;
o.hatchWeights1.y = 1.0 - o.hatchWeights1.x;
}
else {
o.hatchWeights1.y = hatchFactor;
o.hatchWeights1.z = 1.0 - o.hatchWeights1.y;
}
TRANSFER_SHADOW(o);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
float4 hatchTex0 = tex2D(_Hatch0, i.uv) * i.hatchWeights0.x;
float4 hatchTex1 = tex2D(_Hatch1, i.uv) * i.hatchWeights0.y;
float4 hatchTex2 = tex2D(_Hatch2, i.uv) * i.hatchWeights0.z;
float4 hatchTex3 = tex2D(_Hatch3, i.uv) * i.hatchWeights1.x;
float4 hatchTex4 = tex2D(_Hatch4, i.uv) * i.hatchWeights1.y;
float4 hatchTex5 = tex2D(_Hatch5, i.uv) * i.hatchWeights1.z;
float4 whiteColor = float4(1, 1, 1, 1)*(1 - i.hatchWeights0.x - i.hatchWeights0.y - i.hatchWeights0.z - i.hatchWeights1.x - i.hatchWeights1.y - i.hatchWeights1.z);
float4 hatchColor = hatchTex0 + hatchTex1 + hatchTex2 + hatchTex3 + hatchTex4 + hatchTex5+ whiteColor;
UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
return float4(hatchColor.rgb*_Color.rgb*atten, 1.0);
}
ENDCG
}
}
}
首先对模型进行描边操作,通过计算光源与物体表面漫反射值确定权重系数,从而确定贴图采集情况。
下面我们对逻辑进行拆分和解析:
描边逻辑:使用两个通道,其中一个通道沿法线方向挤出一点,输出形成描边的颜色
投影转换操作:将法线方向转换到最终投影阶段输出并进行偏移操作:
float3 vnormal = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);
float2 offset = TransformViewToProjection(vnormal.xy);
o.pos.xy += offset * _OutlineFactor;
计算模型表面漫反射:
float diffuse = max(0, dot(worldLightDir, worldNormal));
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz ;
对漫反射结果与不同贴图特征进行混合操作:漫反射越暗,线条越密集
float hatchFactor = diffuse * 7.0;
if (hatchFactor > 6.0) {
}
else if (hatchFactor > 5.0) {
o.hatchWeights0.x = hatchFactor - 5.0;
}
else if (hatchFactor > 4.0) {
o.hatchWeights0.x = hatchFactor - 4.0;
o.hatchWeights0.y = 1.0 - o.hatchWeights0.x;
}
else if (hatchFactor > 3.0) {
o.hatchWeights0.y = hatchFactor - 3.0;
o.hatchWeights0.z = 1.0 - o.hatchWeights0.y;
}
else if (hatchFactor > 2.0) {
o.hatchWeights0.z = hatchFactor - 2.0;
o.hatchWeights1.x = 1.0 - o.hatchWeights0.z;
}
else if (hatchFactor > 1.0) {
o.hatchWeights1.x = hatchFactor - 1.0;
o.hatchWeights1.y = 1.0 - o.hatchWeights1.x;
}
else {
o.hatchWeights1.y = hatchFactor;
o.hatchWeights1.z = 1.0 - o.hatchWeights1.y;
}
混合白色基础颜色信息:漫反射深色部分权重越大,白色越少
float4 whiteColor = float4(1, 1, 1, 1)*(1 - i.hatchWeights0.x - i.hatchWeights0.y - i.hatchWeights0.z - i.hatchWeights1.x - i.hatchWeights1.y - i.hatchWeights1.z);
将所以颜色信息进行混合操作
float4 hatchColor = hatchTex0 + hatchTex1 + hatchTex2 + hatchTex3 + hatchTex4 + hatchTex5+ whiteColor;
叠加阴影效果
UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
返回最终效果
return float4(hatchColor.rgb*_Color.rgb*atten, 1.0);
效果调整:
我们设置一个范围0-10的贴图平铺系数,修改系数处理贴图疏密程度
相关代码:o.uv = v.texcoord* _TileFactor;
调整平铺系数大小,实现线条稀疏密度的效果调整,如下图
设置高密度线条
设置低密度线条
准备好六张素描纹理贴图,在顶点着色阶段计算逐顶点的漫反射光照,通过光照结果决定六张纹理混合权重,然后将数据传输到片元着色器,片元着色器再根据权重结果混合六张纹理的采样结果。
本期的素描风格shader到此就结束了,我们下期再见!
相关推荐
- Micheal Nielsen's神经网络学习之二
-
依然是跟着MichaelNielsen的神经网络学习,基于前一篇的学习,已经大概明白了神经网络的基本结构和BP算法,也能通过神经网络训练数字识别功能,之后我试验了一下使用神经网络训练之前的文本分类,...
- CocoaPods + XCTest进行单元测试 c单元测试工具
-
在使用XCTest进行单元测试时,我们经常会遇到一些CocoaPods中的开源框架的调用,比如“Realm”或“Alamofire”在测试的时候,如果配置不当,会导致“frameworknotfo...
- Java基础知识回顾第四篇 java基础讲解
-
1、&和&&的区别作为逻辑运算符:&(不管左边是什么,右边都参与运算),&&(如果左边为false,右边则不参与运算,短路)另外&可作为位运算符...
- 项目中的流程及类似业务的设计模式总结
-
说到业务流程,可能是我做过的项目中涉及业务最多的一个方面了。除了在流程设计之外,在一些考核系统、产业审批、还有很多地方,都用到相似的设计思路,在此一并总结一下。再说到模式,并不是因为流行才用这个词,而...
- 联想三款显示器首批获得 Eyesafe Certified 2.0 认证
-
IT之家7月31日消息,据外媒报道,三款全新联想显示器是全球首批满足EyesafeCertified2.0的设备。据报道,联想获得EyesafeCertified2.0认证的显...
- maven的生命周期,插件介绍(二) 一个典型的maven构建生命周期
-
1.maven生命周期一个完整的项目构建过程通常包括清理、编译、测试、打包、集成测试、验证、部署等步骤,Maven从中抽取了一套完善的、易扩展的生命周期。Maven的生命周期是抽象的,其中的具体任务都...
- 多线程(3)-基于Object的线程等待与唤醒
-
概述在使用synchronized进行线程同步中介绍了依赖对象锁定线程,本篇文章介绍如何依赖对象协调线程。同synchronized悲观锁一样,线程本身不能等待与唤醒,也是需要对象才能完成等待与唤醒的...
- jquery mobile + 百度地图 + phonegap 写的一个"校园助手"的app
-
1jquerymobile+百度地图+phonegap写的一个"校园助手"的app,使用的是基于Flat-UI的jQueryMobile,请参考:https://github.com/...
- Apache 服务启动不了 apache系统服务启动不了
-
{我是新手,从未遇到此问题,请各位大大勿喷}事由:今天早上上班突然发现公司网站出现问题。经过排查,发现是Apache出现问题。首先检查配置文件没有出问题后,启动服务发现Apache服务能启动,但是没法...
- 健康债和技术债都不能欠 公众号: 我是攻城师(woshigcs)
-
在Solr4.4之后,Solr提供了SolrCloud分布式集群的模式,它带来的主要好处是:(1)大数据量下更高的性能(2)更好扩展性(3)更高的可靠性(4)更简单易用什么时候应该使用Sol...
- Eye Experience怎么用?HTC告诉你 eyebeam怎么用
-
IT之家(www.ithome.com):EyeExperience怎么用?HTC告诉你HTC上周除了发布HTCDesireEYE自拍机和HTCRE管状运动相机之外,还发布了一系列新的智能手机...
- Android系统应用隐藏和应用禁止卸载
-
1、应用隐藏与禁用Android设置中的应用管理器提供了一个功能,就是【应用停用】功能,这是针对某些系统应用的。当应用停用之后,应用的图标会被隐藏,但apk还是存在,不会删除,核心接口就是Packag...
- 计算机软件技术分享--赠人玫瑰,手遗余香
-
一、Netty介绍Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。也就是说,Netty...
- Gecco爬虫框架的线程和队列模型 爬虫通用框架
-
简述爬虫在抓取一个页面后一般有两个任务,一个是解析页面内容,一个是将需要继续抓取的url放入队列继续抓取。因此,当爬取的网页很多的情况下,待抓取url的管理也是爬虫框架需要解决的问题。本文主要说的是g...
- 一点感悟(一) 初识 初读感知的意思
-
时间过得很快,在IT业已从业了两年多。人这一辈子到底需要什么,在路边看着人来人往,大部分人脸上都是很匆忙。上海真是一个魔都,它有魅力,有底蕴,但是一个外地人在这里扎根置业,真的是举全家之力,还贷3...
- 一周热门
-
-
Boston Dynamics Founder to Attend the 2024 T-EDGE Conference
-
IDC机房服务器托管可提供的服务
-
详解PostgreSQL 如何获取当前日期时间
-
新版腾讯QQ更新Windows 9.9.7、Mac 6.9.25、Linux 3.2.5版本
-
一文看懂mysql时间函数now()、current_timestamp() 和sysdate()
-
流星蝴蝶剑:76邵氏精华版,强化了流星,消失了蝴蝶
-
PhotoShop通道
-
查看 CAD文件,电脑上又没装AutoCAD?这款CAD快速看图工具能帮你
-
WildBit Viewer 6.13 快速的图像查看器,具有幻灯片播放和编辑功能
-
光与灯具的专业术语 你知多少?
-
- 最近发表
-
- Micheal Nielsen's神经网络学习之二
- CocoaPods + XCTest进行单元测试 c单元测试工具
- Java基础知识回顾第四篇 java基础讲解
- 项目中的流程及类似业务的设计模式总结
- 联想三款显示器首批获得 Eyesafe Certified 2.0 认证
- maven的生命周期,插件介绍(二) 一个典型的maven构建生命周期
- 多线程(3)-基于Object的线程等待与唤醒
- jquery mobile + 百度地图 + phonegap 写的一个"校园助手"的app
- Apache 服务启动不了 apache系统服务启动不了
- 健康债和技术债都不能欠 公众号: 我是攻城师(woshigcs)
- 标签列表
-
- serv-u 破解版 (19)
- huaweiupdateextractor (27)
- thinkphp6下载 (25)
- mysql 时间索引 (31)
- mydisktest_v298 (34)
- sql 日期比较 (26)
- document.appendchild (35)
- 头像打包下载 (61)
- oppoa5专用解锁工具包 (23)
- acmecadconverter_8.52绿色版 (39)
- oracle timestamp比较大小 (28)
- f12019破解 (20)
- np++ (18)
- 魔兽模型 (18)
- java面试宝典2019pdf (17)
- beamoff下载 (17)
- unity shader入门精要pdf (22)
- word文档批量处理大师破解版 (36)
- pk10牛牛 (22)
- server2016安装密钥 (33)
- mysql 昨天的日期 (37)
- 加密与解密第四版pdf (30)
- pcm文件下载 (23)
- jemeter官网 (31)
- iteye (18)