【Unity3D】素描特效

2023-10-31 17:50
文章标签 特效 unity3d 素描

本文主要是介绍【Unity3D】素描特效,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1 非真实渲染

        法线贴图和凹凸映射中讲述了普通光照的渲染原理,实现的效果比较贴近真实世界(照相写实主义,Photorealism),非真实渲染(Non-Photorealism Rendering,NPR)在照相写实主义的基础上添加了一些风格处理,如:卡通、水彩、素描等风格。

        本文完整资源见→Unity3D素描特效。

2 素描特效原理

        素描特效不直接渲染漫反射效果,而是通过线条的疏密程度表现漫反射效果,即:较亮处线条稀疏,较暗处线条密集。

        线条采样方法:先计算顶点对应的漫反射强度,假设为 diffuse,再根据 diffuse 所处的区间在多个素描纹理(如下)中采样。

        diffuse 计算如下,其中 normal 为顶点对应的单位法线向量,lightDir 为顶点指向光源的单位方向向量。

float diffuse = max(0, dot(normal, lightDir));

        为方便划分区间,我们将 diffuse 乘以 7(6 个素描纹理 + 空白纹理),记为 factor,即 factor = diffuse * 7,我们将 factor 均匀划分 7 个区间,假设 factor 值对应的空白纹理和 line1 ~ line6 纹理的权值分别为 w0 ~ w6,则 w0 ~ w6 的计算如下:

fixed w0 = 1; // 白色纹理权值
fixed w1 = 0, w2 = 0, w3 = 0, w4 = 0, w5 = 0, w6 = 0; // line_1~line_6纹理权值
if (factor > 6) { // 区间: (6, 7]return; // 白色, 直接跳出
} else if (factor > 5) { // 区间: (5, 6]w1 = factor - 5;
} else if (factor > 4) { // 区间: (4, 5]w1 = factor - 4;w2 = 1 - w1;
} else if (factor > 3) { // 区间: (3, 4]w2 = factor - 3;w3 = 1 - w2;
} else if (factor > 2) { // 区间: (2, 3]w3 = factor - 2;w4 = 1 - w3;
} else if (factor > 1) { // 区间: (1, 2]w4 = factor - 1;w5 = 1 - w4;
} else { // 区间: [0, 1]w5 = factor;w6 = 1 - w5;
}
w0 = 1 - w1 - w2 - w3 - w4 - w5 - w6;

        根据 w0 ~ w6 对白色纹理和 line1 ~ line6 纹理进行加权求和,得到顶点对应的素描颜色。

3 素描特效实现

        SketchEffect.cs

using UnityEngine;[DisallowMultipleComponent] // 不允许在同一对象上挂载多个该组件
public class SketchEffect : MonoBehaviour {private Material sketchMat; // 素描材质private void Awake() {sketchMat = Resources.Load<Material>("Sketch/Materials/SketchMat");}private void OnEnable() {Renderer[] renderers = GetComponentsInChildren<Renderer>();foreach (var renderer in renderers) { // 将rneder里的所有材质球都替换为sketchMat材质Material[] materials = new Material[renderer.sharedMaterials.Length];for (int i = 0; i < materials.Length; i++) {materials[i] = sketchMat;}renderer.materials = materials;}}
}

        说明:SketchEffect 脚本组件挂在需要渲染素描特效的对象上。 

        SketchEffect.shader

Shader "MyShader/SketchEffect" {Properties {_Color ("Color", Color) = (1, 1, 1, 1) // 背景颜色_Tilling ("Tilling", Float) = 1 // 纹理缩放, 值越大线条越密集_Line1 ("Line 1", 2D) = "white" {} // 素描纹理1_Line2 ("Line 2", 2D) = "white" {} // 素描纹理2_Line3 ("Line 3", 2D) = "white" {} // 素描纹理3_Line4 ("Line 4", 2D) = "white" {} // 素描纹理4_Line5 ("Line 5", 2D) = "white" {} // 素描纹理5_Line6 ("Line 6", 2D) = "white" {} // 素描纹理6}SubShader {Tags { "RenderType"="Opaque" "Queue"="Geometry"}Pass {Tags { "LightMode"="ForwardBase" }CGPROGRAM#pragma vertex vert#pragma fragment frag #include "UnityCG.cginc"fixed4 _Color; // 背景颜色float _Tilling; // 纹理缩放, 值越大线条越密集sampler2D _Line1; // 素描纹理1sampler2D _Line2; // 素描纹理2sampler2D _Line3; // 素描纹理3sampler2D _Line4; // 素描纹理4sampler2D _Line5; // 素描纹理5sampler2D _Line6; // 素描纹理6struct v2f {float4 pos : SV_POSITION;half2 uv : TEXCOORD0;fixed4 w1 : TEXCOORD1; // 前三张素描纹理的权值(w维存储白色)fixed3 w2 : TEXCOORD2; // 后三张素描纹理的权值};void getLineWeights(float diffuse, out fixed4 w1, out fixed3 w2) { // 根据漫反射值获取6张素描纹理的权重float factor = diffuse * 7.0;w1 = fixed4(0, 0, 0, 1);w2 = fixed3(0, 0, 0);if (factor > 6) { // 区间: (6, 7]return; // 白色, 直接跳出} else if (factor > 5) { // 区间: (5, 6]w1.x = factor - 5;} else if (factor > 4) { // 区间: (4, 5]w1.x = factor - 4;w1.y = 1 - w1.x;} else if (factor > 3) { // 区间: (3, 4]w1.y = factor - 3;w1.z = 1 - w1.y;} else if (factor > 2) { // 区间: (2, 3]w1.z = factor - 2;w2.x = 1 - w1.z;} else if (factor > 1) { // 区间: (1, 2]w2.x = factor - 1;w2.y = 1 - w2.x;} else { // 区间: [0, 1]w2.y = factor;w2.z = 1 - w2.y;}w1.w = 1 - w1.x - w1.y - w1.z - w2.x - w2.y - w2.z; // w维存储白色}v2f vert(appdata_base v) {v2f o;o.pos = UnityObjectToClipPos(v.vertex); // 计算裁剪坐标系中顶点坐标, 等价于: mul(unity_MatrixMVP, v.vertex)o.uv = v.texcoord * _Tilling; // 对uv坐标进行缩放, 用于调整素描图像的稀疏和宽窄程度fixed3 worldLightDir = normalize(WorldSpaceLightDir(v.vertex)); // 计算世界空间中顶点指向光源的向量fixed3 worldNormal = UnityObjectToWorldNormal(v.normal); // 计算世界空间中顶点法线向量fixed diffuse = max(0, dot(worldLightDir, worldNormal)); // 计算漫反射值getLineWeights(diffuse, o.w1, o.w2); // 根据漫反射值获取6张素描纹理的权重return o; }fixed4 frag(v2f i) : SV_Target {			fixed4 lineTex1 = tex2D(_Line1, i.uv) * i.w1.x;fixed4 lineTex2 = tex2D(_Line2, i.uv) * i.w1.y;fixed4 lineTex3 = tex2D(_Line3, i.uv) * i.w1.z;fixed4 lineTex4 = tex2D(_Line4, i.uv) * i.w2.x;fixed4 lineTex5 = tex2D(_Line5, i.uv) * i.w2.y;fixed4 lineTex6 = tex2D(_Line6, i.uv) * i.w2.z;fixed4 whiteColor = fixed4(1, 1, 1, 1) * i.w1.w;fixed4 sketchColor = lineTex1 + lineTex2 + lineTex3 + lineTex4 + lineTex5 + lineTex6 + whiteColor;return fixed4(sketchColor.rgb * _Color.rgb, 1.0);}ENDCG}}FallBack "Diffuse"
}

        说明:在 Assets/Resources/Sketch/Materials 目录下创建 Material,重命名为 SketchMat ,将 SketchEffect.shader 赋给 SketchMat 材质,并将 line1 ~ line6 纹理拖拽到 SketchMat 材质中对应位置,调整 Tilling 属性的值。

4 运行效果

        1)原图

        2)素描特效

这篇关于【Unity3D】素描特效的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/317065

相关文章

Unity3D自带Mouse Look鼠标视角代码解析。

Unity3D自带Mouse Look鼠标视角代码解析。 代码块 代码块语法遵循标准markdown代码,例如: using UnityEngine;using System.Collections;/// MouseLook rotates the transform based on the mouse delta./// Minimum and Maximum values can

Unity3D 运动之Move函数和translate

CharacterController.Move 移动 function Move (motion : Vector3) : CollisionFlags Description描述 A more complex move function taking absolute movement deltas. 一个更加复杂的运动函数,每次都绝对运动。 Attempts to

『功能项目』战士的平A特效【35】

我们打开上一篇34武器的切换实例的项目, 本章要做的事情是在战士的每次按A键时在指定位置生成一个平A特效 首先将之前下载的技能拖拽至场景中 完全解压缩后重命名为AEffect 拖拽至预制体文件夹 进入主角动画的战士动画层级 双击第一次攻击 选择Animation 创建事件 创建的动画事件帧放在攻击动画挥剑指定处 命名为PerpetualAtt

第49课 Scratch入门篇:骇客任务背景特效

骇客任务背景特效 故事背景:   骇客帝国特色背景在黑色中慢慢滚动着! 程序原理:  1 、 角色的设计技巧  2 、克隆体的应用及特效的使用 开始编程   1、使用 黑色的背景: ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/7d74c872f06b4d9fbc88aecee634b074.png#pic_center)   2

【生日视频制作】酒吧一群美女车展模特大屏幕视频改字AE模板修改文字软件生成器教程特效素材【AE模板】

生日视频制作教程酒吧一群美女车展模特大屏幕视频改字AE模板修改文字特效广软件告生成神器素材祝福玩法AE模板工程 怎么如何做的【生日视频制作】酒吧一群美女车展模特大屏幕视频改字AE模板修改文字软件生成器教程特效素材【AE模板】 生日视频制作步骤: 安装AE软件 下载AE模板 把AE模板导入AE软件 修改图片或文字 渲染出视频

Unity3D在2D游戏中获取触屏物体的方法

我们的需求是: 假如屏幕中一个棋盘,每个棋子是button构成的,我们希望手指或者鼠标在哪里,就显示那个位置的button信息。 网上有很多获取触屏物体信息的信息的方法如下面代码所示: Camera cam = Camera.main; // pre-defined...if (touch.phase == TouchPhase.Bagan)){ // 如果触控点状态为按下Ray

【生日视频制作】劳斯莱斯库里南中控改名软件AE模板修改文字软件生成器教程特效素材【AE模板】

生日视频制作教程豪车劳斯莱斯库里南中控改名软件AE模板修改文字特效广告生成神器素材祝福玩法AE模板工程 怎么如何做的【生日视频制作】劳斯莱斯库里南中控改名软件AE模板修改文字软件生成器教程特效素材【AE模板】 生日视频制作步骤: 下载AE模板 安装AE软件 把AE模板导入AE软件 修改图片或文字 渲染出视频

印度再现超级大片,豪华阵容加顶级特效

最近,印度影坛再次掀起了风潮,一部名为《毗湿奴降临》的神话大片强势登陆各大影院,上映首周票房就飙升至105亿卢比,成功占据了票房榜首的位置。之后,这部电影也在北美上映,海外市场的表现同样不俗,收获了相当亮眼的票房成绩。作为一部印度神话科幻大片,《毗湿奴降临》不仅在本土大火,在国际市场上也引发了不小的关注。 《毗湿奴降临》由印度著名导演纳格·阿什温执导,卡司阵容极其豪华,集结了迪皮卡·帕度柯妮

Unity3D Shader详解:只画顶点或只画线框

在Unity3D开发中,Shader是控制渲染过程的关键组件,它允许开发者自定义物体的渲染方式。有时,为了特定的视觉效果,我们可能需要只渲染模型的顶点或者只显示其线框。下面,我们将详细探讨这两种效果的技术实现,并给出相应的代码示例。 对惹,这里有一个游戏开发交流小组,大家可以点击进来一起交流一下开发经验呀! 只画顶点 在Unity中直接“只画顶点”的概念可能不是非常直观,因为顶点本身只是模型

Unity3D ARPG(动作角色扮演游戏)设计与实现详解

动作角色扮演游戏(Action Role-Playing Game, ARPG)结合了传统角色扮演游戏(RPG)的深度与动作游戏(Action Game)的即时反应和流畅战斗体验。Unity3D 作为一款强大的跨平台游戏开发引擎,为开发者提供了丰富的工具和资源来创建高质量的 ARPG 游戏。本文将详细介绍如何使用 Unity3D 设计和实现一个基本的 ARPG 游戏,包括技术选型、游戏架构、关键系