unity NPR 卡通渲染

文章目录

  • 一、 介绍
  • 二、 素材准备
  • 三、 步骤
  • 四、 shader代码
  • 五、工程链接


一、 介绍

NPR是计算机图形学中的一类,即非真实感绘制(Non-photorealistic rendering),主要用于模拟艺术式的绘制风格,也用于发展新绘制风格,形式一般是卡通造影。

NPR是Unity中的一种非真实渲染技术,它使用一种称为"NPR"的算法来模拟非真实渲染效果。这种技术可以用于制作各种类型的视觉效果,包括卡通效果、手绘效果、水彩画效果等等。

NPR算法的核心思想是将3D模型表面的每个点映射到一个二维平面上,这个平面上的每个像素点对应一个颜色。然后,NPR算法会根据这个颜色和周围像素点的颜色来计算这个像素点的最终颜色。这个过程可以看作是在这个二维平面上进行一次扫描,并且根据扫描到的每个像素点的颜色和周围像素点的颜色来生成最终的渲染结果。

NPR技术的优点在于它可以在保证画面美观的前提下,极大地降低了渲染的计算量和硬件要求,使得游戏能够在较低配置的设备上运行。此外,NPR技术还可以用于制作各种类型的视觉效果,使得游戏画面更加丰富和多样化。

本文将介绍如何将一个原始的3D角色通过NPR渲染技术转换成类似《原神》中的卡通角色。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


二、 素材准备


三、 步骤

前期角色外观:
在这里插入图片描述
在这里插入图片描述
显示纹理:
在这里插入图片描述
描边:
在这里插入图片描述
高光和边缘光:

在这里插入图片描述
最终渲染效果:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


四、 shader代码

Shader "Custom/ToonShader"
{Properties {[NoScaleOffset] _MainTex ("MainTex", 2D) = "white" {} // 主纹理,用于对象的颜色贴图_MainColor ("MainColor", Color) = (1,1,1,1)// 主颜色,用于设置对象的主要颜色_OutLineWidth ("OutlLineWidth", Range(0, 0.1)) = 0.002// 描边宽度_OutLineColor ("OutLineColor", Color) = (0,0,0,1)// 描边颜色[NoScaleOffset] _GradientTex ("GradientTex", 2D) = "white" {}// 用于阴影梯度采样的纹理,暂时就叫这个名词吧_GradientIntensity ("GradientIntensity", Range(0,1)) = 1// 阴影梯度采样纹理强度_SpecularPower ("SpecularPower", Range(1,100)) = 80// 高光平滑度_SpecularIntensity ("SpecularItensity", Range(0,1)) = 1// 高光强度_SpecularThreshold ("SpecularThreshold", Range(0,1)) = 0.3// 高光阈值_SpecularBrightness ("SpecularBrightness", Range(0,1)) = 0.1// 高光添加的亮度量_SpecularValue ("SpecularValue", Range(0,1)) = 1// 高光值_RimIntensity ("RimIntensity", Range(0,5)) = 1// 边缘光强度[Toggle] _RimShowAtBackToLight ("RimShowAtBackToLight", Float) = 0// 边缘光是否被光照时才显示的开关}SubShader {Tags { "RenderType"="Opaque" }LOD 100Pass { // solidName "Solid"Tags { "LightMode"="ForwardBase" }// 阴影需要,正向渲染光照基础passCGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#include "AutoLight.cginc"#pragma multi_compile_fwdbase_fullshadows// 阴影需要#pragma fragmentoption ARB_precision_hint_fastest// 最快速精度struct appdata {float4 vertex : POSITION;float2 uv : TEXCOORD0;half3 normal : NORMAL;};struct v2f {float4 pos : SV_POSITION;float2 uv : TEXCOORD0;half3 worldNormal : TEXCOORD1;float3 worldPos : TEXCOORD2;UNITY_LIGHTING_COORDS(3,4)// 阴影需要};sampler2D _MainTex;fixed4 _MainColor;sampler2D _GradientTex;fixed _GradientIntensity;fixed _SpecularPower;fixed _SpecularIntensity;fixed _SpecularThreshold;fixed _SpecularBrightness;fixed _SpecularValue;fixed _RimIntensity;fixed _RimShowAtBackToLight;v2f vert (appdata v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.uv = v.uv;o.worldNormal = UnityObjectToWorldNormal(v.normal);o.worldPos = mul(unity_ObjectToWorld, v.vertex);TRANSFER_VERTEX_TO_FRAGMENT(o)// 阴影需要return o;}fixed4 frag (v2f i) : SV_Target {i.worldNormal = normalize(i.worldNormal);half3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos);half3 lightDir = normalize(_WorldSpaceLightPos0.xyz);UNITY_LIGHT_ATTENUATION(atten,i,i.worldPos);atten = atten * 0.5 + 0.5;fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;fixed LdotN = dot(lightDir, i.worldNormal);fixed halfLambert = LdotN * 0.5 + 0.5;fixed lightShadowCoef = halfLambert * atten;fixed3 diffuse = tex2D(_MainTex, i.uv).rgb * _MainColor;fixed3 dGradient = tex2D(_GradientTex, float2(lightShadowCoef, 0)).rgb;diffuse = lerp(diffuse,  diffuse * dGradient, _GradientIntensity);half3 hDir = normalize(viewDir + lightDir);fixed HdotN = max(0, dot(hDir, i.worldNormal));fixed specular = pow(HdotN, _SpecularPower) * _SpecularIntensity;specular *= atten;specular = step(_SpecularThreshold, specular) * _SpecularValue;fixed rimFactor = (1 - dot(viewDir, i.worldNormal)) * _RimIntensity;rimFactor = lerp(rimFactor, rimFactor * max(0, dot(-lightDir, viewDir)), _RimShowAtBackToLight);rimFactor *= atten;rimFactor = step(_SpecularThreshold, rimFactor) * _SpecularValue;specular = max(specular, rimFactor);return fixed4(ambient + diffuse + diffuse * specular + specular * _SpecularBrightness, 1);}ENDCG}Pass { // outlineName "Outline"Cull FrontCGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#pragma fragmentoption ARB_precision_hint_fastestfixed _OutLineWidth;fixed4 _OutLineColor;float4 vert (float4 vertex : POSITION, float3 normal : NORMAL) : SV_POSITION {// 投影空间float4 pos = UnityObjectToClipPos(vertex);// 转换到视图空间的法线fixed3 vNormal = mul((float3x3)UNITY_MATRIX_IT_MV, normal);fixed2 offset = TransformViewToProjection(vNormal.xy);// 由于在顶点后处理会有透视除法,所以我们首先乘上pos.w以抵消透视,这样无论多远多近都可以按恒定的描边边宽来显示pos.xy += offset * _OutLineWidth * pos.w;return pos;}fixed4 frag () : SV_Target { return _OutLineColor; }ENDCG}}Fallback "Diffuse"
}

这个Unity卡通渲染的Shader代码使用了以下技术和功能:

  1. 主纹理和颜色属性:使用了主纹理 _MainTex 和主颜色 _MainColor 来控制对象的颜色。

  2. 描边效果:通过 _OutLineWidth_OutLineColor 控制描边的宽度和颜色。

  3. 阴影梯度采样:使用 _GradientTex_GradientIntensity 控制阴影梯度采样纹理和强度。

  4. 高光效果:通过 _SpecularPower_SpecularIntensity_SpecularThreshold_SpecularBrightness_SpecularValue 控制高光的平滑度、强度、阈值和亮度。

  5. 边缘光效果:使用 _RimIntensity 控制边缘光的强度,以及 _RimShowAtBackToLight 控制边缘光是否受光照方向影响。

  6. 正向渲染光照:使用 TagsCGPROGRAM 中的相关指令来支持正向渲染光照,包括阴影的处理。

  7. 顶点着色器和片元着色器:定义了顶点着色器 vert 和片元着色器 frag,并在这里执行了主要的渲染计算。

  8. 光照计算:计算了光照方向、光照强度、阴影、漫反射、高光等光照效果。

  9. 描边效果的后处理:在 Outline Pass 中,实现了对象的描边效果。

  10. Shader Fallback:如果渲染模式不支持这个Shader,会回退到使用 “Diffuse” Shader。

这个Shader包含了多种效果,包括卡通风格的渲染、高光、描边和阴影梯度,以及一些参数控制这些效果的强度和外观。这些效果可以用于实现卡通风格的游戏或动画渲染。


五、工程链接


https://download.csdn.net/download/qq_20179331/88454844

内含exe文件

1.滑动鼠标中键滚轮,可以放大、缩小视角

2.按一下q键,场景相机顺时针旋转90度;按一下w键,场景相机逆时针旋转90度。

在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/113508.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

冰蝎默认加密的流量解密

破解冰蝎的默认加密 流量包分析 上传的冰蝎流量包 POST /web-zh/DVWA/vulnerabilities/upload/ HTTP/1.1 Host: 192.168.197.111 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/118.0 Accept: text/html,application/xhtmlxml,a…

vscode调试container(进行rocksdb调试)+vscode比较git项目不同分支和fork的哪个分支

vscode调试container(进行rocksdb调试) 参考链接: https://blog.csdn.net/qq_29809823/article/details/128445308#t5 https://blog.csdn.net/qq_29809823/article/details/121978762#t7 使用vscode中的插件dev containners->点击左侧的…

【微信小程序开发】小程序微信用户授权登录(用户信息手机号)

🥳🥳Welcome Huihuis Code World ! !🥳🥳 接下来看看由辉辉所写的关于小程序的相关操作吧 目录 🥳🥳Welcome Huihuis Code World ! !🥳🥳 授权流程讲解 一.用户信息授权登录 1.w…

MD-MTSP:粒子群优化算法PSO求解多仓库多旅行商问题MATLAB(可更改数据集,旅行商的数量和起点)

一、多仓库多旅行商问题MD-MTSP 多旅行商问题(Multiple Traveling Salesman Problem, MTSP)是著名的旅行商问题(Traveling Salesman Problem, TSP)的延伸,多旅行商问题定义为:给定一个𝑛座城市…

LabVIEW中管理大型数据

LabVIEW中管理大数据 LabVIEW的最大优势之一是自动内存管理。这种内存管理允许用户轻松创建字符串、数组和集群,而无需C/C用户经常担心。但是,这种内存管理设计为绝对安全,因此数据被非常频繁地复制。这通常不会造成任何问题,但是…

vue3 列表页开发【选择展示列】功能

目录 背景描述: 开发流程: 详细开发流程: 总结: 背景描述: 这个功能是基于之前写的 封装列表页 的功能继续写的,加了一个选择展示列的功能,可以随时控制表格里展示那些列的数据&#xf…

深度强化学习 第 4 章 DQN 与 Q 学习

4.1 DQN 最优动作价值函数的用途 假如我们知道 Q ⋆ Q_⋆ Q⋆​,我们就能用它做控制。 我们希望知道 Q ⋆ Q_⋆ Q⋆​,因为它就像是先知一般,可以预见未来,在 t t t 时刻就预见 t t t 到 n n n时刻之间的累计奖励的期望。假如…

5G来临,迎客莱带你探索运营商大数据的应用

随着5G时代的来临,不仅在算力的基础上得到了加强和保障,同时也丰富了计算的方式和模式,如边缘计算、霾计算等。计算方式和模式的改变,对于运营商来说,意味着更丰富的数据维度,更鲜活的数据和更强大的数据处…

无人机航拍图像拼接与目标识别

一、简介 无人机用来做图像侦察是常见功能,现有技术基本是无人机对某片区域进行飞行,人工实时监控飞行图像,将图像录制成视频供事后回放。此方法对人员业务要求比较高、反应速度足够快、不利于信息收集、录制视频丢失空间信息、对于后期开展区…

Qt判断一个点在多边形内还是外(支持凸边形和凹变形)

这里实现的方法是转载于https://blog.csdn.net/trj14/article/details/43190653和https://blog.csdn.net/WilliamSun0122/article/details/77994526 来实现的,并且按照Qt的规则进行了调整。 以下实现方法有四种,每种方法的具体讲解在转载的博客中有说明&…

Python之爬虫

目录 HTTP请求HTTP响应获得页面响应伪装用户访问打包数据爬取豆瓣top250 HTTP请求 HTTP:HypertextTransferProtcol 超文本传输协议 1、请求行 POST/user/info?new_usertrue HTTP/1.1#资源了路径user/info 查询参数new_usertrue 协议版本HTTP/1.1 2、请求头 Ho…

element ui 下拉框 选择月份和天数

一、背景 目前做的管理系统项目&#xff0c;期望实现功能为&#xff1a;设置出账周期和出账日&#xff0c;考虑使用element ui下拉框实现功能 二、所用技术 vue2element ui 三、实现效果 四、具体代码 <template><popup-frame :title"批量设置出账日" …

Leetcode—2530.执行K次操作后的最大分数【中等】(C语言向上取整数学公式)

2023每日刷题&#xff08;五&#xff09; Leetcode—2530.执行K次操作后的最大分数 向上取整思想 参考了这篇文章 有人肯定会问&#xff0c;这个向上取整为什么是这样来的。接下来我简单讲解一下。 数学式&#xff1a; x y 数学式&#xff1a;\frac{x}{y} 数学式&#xff1a…

配置Linux

首先安装VMware&#xff1a; 安装说明&#xff1a;&#xff08;含许可证的key&#xff09; https://mp.weixin.qq.com/s/XE-BmeKHlhfiRA1bkNHTtg 给大家提供了VMware Workstation Pro16&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1q8VE3TkPzDnM3u9bkTdA_g 提取码&…

文件的物理结构(连续分配,链接分配,索引分配)

1.文件块&#xff0c;磁盘块 类似于内存分页&#xff0c;磁盘中的存储单元也会被分为一个个“块/磁盘块/物理块”。 很多操作系统中&#xff0c;磁盘块的大小与内存块、页面的大小相同。 内存与磁盘之间的数据交换&#xff08;即读/写操作、磁盘I/O&#xff09;都是以“块”为…

详细解读DALLE 3技术报告:Improving Image Generation with Better Captions

Diffusion models代码解读&#xff1a;入门与实战 前言&#xff1a;OpenAI是推动大模型创新的领头羊&#xff0c;最近发布的DALLE 3凭借着远超市面上其他图片生成模型的表现&#xff0c;再次火出圈。最近OpenAI官方发布了DALLE 3的技术报告《Improving Image Generation with B…

Catalan 数 和 Stirling 数

这个也可以理解为栈&#xff0c;用 ( 表示 入栈 &#xff0c; ) 表示出栈 , 任何情况下表示入栈的 ( 都必须大于等于 ) 的个数 这个思路和入栈出栈的思路是等价的

ms-sql server sql 把逗号分隔的字符串分开

案例&#xff1a; sql 查询-字段里是逗号,分隔开的数组&#xff0c;查询匹配数据 sql 查询-字段里是逗号,分隔开的数组&#xff0c;查询匹配数据_sql server 数组匹配-CSDN博客 SQL SERVER 把逗号隔开的字符串拆分成行 SQL SERVER 把逗号隔开的字符串拆分成行_sqlserver拆分…

【暴力剪枝】CF1708D

https://codeforces.com/contest/1708/problem/D 题意 思路 这样的操作下&#xff0c;数列减的速度是非常快的&#xff0c;也就是说&#xff0c;易出现很多的0&#xff0c;0的操作没啥意义&#xff0c;所以我们要找到第一个 >0 的数对其后的序列进行排序&#xff0c;就能大…

051校园短期闲置资源置换平台

大家好✌&#xff01;我是CZ淡陌。一名专注以理论为基础实战为主的技术博主&#xff0c;将再这里为大家分享优质的实战项目&#xff0c;本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#xff0c;希望你能有所收获&#xff0c;少走一些弯路…