Inking(描边)

2024-01-05 01:38
文章标签 描边 inking

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

Inking为了能够能够从背景中更加清晰地勾出网格附加在蒙皮网格上的模型特效,一般采用比较细的灰黑色的线条勾勒出网格的轮廓

1.Rim-Light(边缘光)

背景边缘光即对应当前视角方向,对物体上位于边缘的地方额外施加一个光的效果。

原理:通过N(法线方向)和V(视线方向)的夹角来判断判断一个点是否在物体的边缘。当V(视线方向)与N(法线方向)垂直时,这个法线对应的面就与视线方向平行,说明当前这个点对于当前视角来说就处在边缘;而视线方向与法线方向一致时,这个法线对应的面就垂直于视线方向,说明当前是直视这个面。所以,我们就可以根据dot(N,V)来获得视线方向与法线方向的余弦值,通过这个值来区分该像素是否处在边缘,进而判断是否需要增加以及增加边缘光的强弱。

公式:最终颜色 = (漫反射系数 x 纹理颜色 x RGB颜色)+自发光颜色

  FinalColor=(Diffuse x Texture x RGBColor)+Emissive

Code:

Shader "Nina/Shader/Inking/Rim Light"
{//属性Properties{//主颜色_MainColor("Main Color", Color) = (0.5,0.5,0.5,1)//主纹理_MainTexture("Main Texture", 2D) = "white" {}//边缘发光颜色_RimColor("Rim Color", Color) = (0.5,0.5,0.5,1)//边缘发光强度_RimPower("Rim Power", Range(0.0, 36)) = 0.1//边缘发光强度系数_RimIntensity("Rim Intensity", Range(0.0, 100)) = 3}//子着色器SubShader{//渲染类型:不透明Tags{"RenderType" = "Opaque"}//通道Pass{//通道名称Name "ForwardBase"//光照模式:ForwardBaseTags{"LightMode" = "ForwardBase"}//开启CG着色器编程语言段CGPROGRAM//声明:顶点和片段着色函数名称#pragma vertex vert#pragma fragment frag//引入头文件:UnityCG AutoLight#include "UnityCG.cginc"#include "AutoLight.cginc"//指定Shader Model:3.0#pragma target 3.0//变量//系统光照颜色uniform float4 _LightColor0;//主颜色uniform float4 _MainColor;//主纹理uniform sampler2D _MainTexture;//主纹理_ST(sample texture)uniform float4 _MainTexture_ST;//边缘光颜色uniform float4 _RimColor;//边缘光强度uniform float _RimPower;//边缘光强度系数uniform float _RimIntensity;//顶点输入结构体struct VertexInput{//顶点位置float4 vertex : POSITION;//法线向量坐标float3 normal : NORMAL;//一级纹理坐标float4 texcoord : TEXCOORD0;};//顶点输出结构体struct VertexOutput{//像素位置float4 pos : SV_POSITION;//一级纹理坐标float2 uv : TEXCOORD0;//法线向量坐标float3 normal : NORMAL;//世界空间中的坐标位置float4 posWorld : TEXCOORD1;//创建光源坐标,用于内置的光照LIGHTING_COORDS(3,4)};//顶点着色函数VertexOutput vert(VertexInput v){//声明一个顶点输出结构对象VertexOutput o;//将输入纹理坐标赋值给输出纹理坐标,通过TRANSFORM_TEX宏转化纹理坐标,//主要处理了Offset和Tiling的改变,默认时等同于o.uv = v.texcoord.xy;  o.uv = TRANSFORM_TEX(v.texcoord, _MainTexture);//获取顶点在世界空间中的法线向量坐标  o.normal = mul(float4(v.normal,0), unity_WorldToObject).xyz;//获得顶点在世界空间中的位置坐标  o.posWorld = mul(unity_ObjectToWorld, v.vertex);//获取像素位置o.pos = mul(UNITY_MATRIX_MVP, v.vertex);//返回此输出结构对象return o;}//片段着色函数fixed4 frag(VertexOutput i) : COLOR{//方向参数(V N L),归一化,即使在vert归一化也不行,从vert到frag阶段有差值处理,传入的法线方向并不是vertex shader直接传出//视角方向float3 ViewDirection = normalize(_WorldSpaceCameraPos.xyz - i.posWorld.xyz);//法线方向float3 Normalection = normalize(i.normal);//光照方向float3 LightDirection = normalize(_WorldSpaceLightPos0.xyz);//计算光照的衰减//衰减值float Attenuation = LIGHT_ATTENUATION(i);//衰减后颜色值float3 AttenColor = Attenuation * _LightColor0.xyz;//计算漫反射float NdotL = dot(Normalection, LightDirection);//环境光,unity自身的diffuse也是带了环境光fixed3 Ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * _MainColor.xyz;//兰伯特(或者半兰伯特)*材质diffuse颜色*衰减后光颜色值+环境光float3 Diffuse = max(0.0, NdotL) * AttenColor + Ambient;//准备自发光参数//计算边缘强度,视线方向与法线方向的夹角,half Rim = 1.0 - max(0, dot(i.normal, ViewDirection));//计算出边缘自发光强度float3 Emissive = _RimColor.rgb * pow(Rim,_RimPower) *_RimIntensity;//计在最终颜色中加入自发光颜色//最终颜色 = (漫反射系数 x 纹理颜色 x rgb颜色)+自发光颜色float3 finalColor = Diffuse * (tex2D(_MainTexture, i.uv).rgb * _MainColor.rgb) + Emissive;//返回最终颜色return fixed4(finalColor,1);}ENDCG}}//后备着色器为普通漫反射FallBack "Diffuse"}

2.Fresnel(菲尼尔)

背景菲涅耳公式用来描述光在不同折射率的介质之间的行为。菲涅尔公式是光学中的重要公式,用它能解释反射光的强度、折射光的强度、相位与入射光的强度的关系

反射公式: fresnel = fresnel基础值 + fresnel缩放量*pow( 1 - dot( N, V ), 5 )

原理类似于Rim Lighting, 使用视线方向(V)和点法线方向(N)的点积来判断边缘, 并将边缘高亮化.

优点: 效率高; 不需要单独的Pass就可以实现; 几乎所有的平滑的边缘都会得到高亮效果; 甚至对透明和半透明物体也有效.

缺点: 无法控制Inking线条的粗细, 这是因为Fresnel方法是针对于模型法线和摄像机视线的, 从而导致其仅与每个表面的法线方向有关, 而与表面的深度信息无关.

Code:

3.Mesh Doubling (复制网格) 

背景: 类似于卡通Toon特效,重新绘制一个将所有表面都沿着法线方向延展过的模型,。两次渲染,第一次渲染背面,剔除正面,然后将正面剪裁掉。把模型顶点沿法线方向扩伸一定距离(用来表现描边的粗细);第二次渲染,渲染正面,剔除背面。

公式:P_{new}=P_{old}+ L \times W_{outline} / D_{cam}
  L = Normalize(MV_{IT} \times lerp(V, N, f))

其中, L表示偏移向量; W表示轮廓线条粗细; D是物体和摄像机间的距离. V是标准化后的顶点坐标, 表示方向; N是顶点向量; f是插值参数.

优点: 效率高; 平台适应性好; 可以控制描边的线条粗细.。

缺点: 线条并不连续, 在平滑表面的表现虽然很好, 但是在锐利的表面上经常会出现断层; 只能绘制最外层轮廓, 而不对内部结构做任何处理。

Code:

Shader "Nina/Shader/Inking/Mesh Doubling"
{//属性Properties{//主纹理_MainTexture("Base (RGB)", 2D) = "white" { }//边缘发光颜色_RimColor("Rim Color", Color) = (0, 0, 0, 1)//边缘发光宽度_RimWidth("Rim width", Range(0.0, 1.0)) = .005}//子着色器SubShader{//1通道Pass{//剔除正面Cull front//开启CG着色器编程语言段CGPROGRAM//声明:顶点和片段着色函数名称#pragma vertex vert#pragma fragment frag//引入头文件:UnityCG#include "UnityCG.cginc"//指定Shader Model:3.0#pragma target 3.0//变量//边缘发光颜色uniform float4 _RimColor;//边缘发光宽度uniform float _RimWidth;//顶点输入结构体struct VertexInput{//顶点位置float4 vertex : POSITION;//法线向量坐标float3 normal : NORMAL;};//顶点输出结构体struct VertexOutput{//像素位置float4 pos : POSITION;};//顶点着色函数VertexOutput vert(VertexInput v){//声明一个顶点输出结构对象VertexOutput o;//设置顶点偏移v.vertex.xyz += v.normal * _RimWidth;//获取像素位置o.pos = mul(UNITY_MATRIX_MVP, v.vertex);//返回此输出结构对象return o;}//片段着色函数half4 frag(VertexOutput i) : COLOR{//返回边缘颜色return _RimColor;}ENDCG}//通道2Pass{SetTexture[_MainTexture]{Combine Primary * Texture}}/*或者通道2Pass  {//开启CG着色器编程语言段CGPROGRAM//引入头文件:UnityCG #include "UnityCG.cginc"  //声明:顶点和片段着色函数名称#pragma vertex vert_img   #pragma fragment frag             //变量uniform sampler2D _MainTex;//片段着色函数float4 frag(v2f_img i) : COLOR{//获取颜色float4 col = tex2D(_MainTex, i.uv);//返回最终颜色return col;}ENDCG}*/}
}


这篇关于Inking(描边)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

CSS文字描边

// 方法3const p = document.querySelector("p")p.dataset.content = p.textContent @mixin text-stroke($color: #fff, $width: 1px) {text-shadow: 0 -#{$width} #{$color}, #{$width} 0 #{$color},0 #{$width}

遮挡描边(实现篇)

在上一篇中,我们基本上说明了遮挡描边实现的一种基本原理。这一篇中我们将了解一下基于这种原理的具体实现代码。本篇中的内容和前几篇教程相比,相对比较难一些,建议先有一些基本的Unity的C#脚本编程经验和基本的Unity Shader基础(可参考前几篇教程)。   下面我们就开始讲解具体的实现代码(由于代码较多,所以这里只对需要讲解的地方进行讲解):  C#脚本部分     与之前不

前端 CSS 经典:文字描边

前言:文字描边有两种实现方式 1. text-shadow 设置 8 个方向的文字阴影,缺点是只有八个方向,文字转角处可能有锯齿状。不支持文字透明,设置 color: transparent,文字会成描边颜色。 <!DOCTYPE html><html lang="en"><head><meta charset="utf-8" /><meta http-equiv="X-UA-Comp

PS给logo加白色描边

步骤1:打开你的Logo文件 步骤2:选择Logo层 在“图层”面板中找到你的Logo所在的图层。如果你的Logo是在背景图层上,可以将它转换为普通图层(右键点击背景图层,选择“从背景图层转换”)(此处也可以使用快速选择工具选中logo) 步骤3:添加描边 确保Logo所在的图层被选中。 选择 `图层 > 图层样式 > 描边`。 步骤4:设置描边属性 1. 在弹出的“图层样式”

quick cocos使用shader给图片描边再挖空

Cocos2dx底层图形绘制使用OpenGL ES可编程着色器(Shader)。OpenGL ES(OpenGl for Embedded System)是OpenGL三维图形API的子集,针对手机,PDA和游戏主机等嵌入式设备而设计。 2d_effect_frag.material 文件: material Outline{technique{pass{shader{vertexShade

2D图片的描边

第一种 Sprite 外边框 原理是找到边缘像素,然后设置颜色,边缘像素的特点是像素的八个方向的邻像素不全是透明或者不全是不透明,这样的像素就是边缘上的像素,下面是找到的shader源码,很简单 Shader "Custom/Sprite Outline"{Properties{_MainTex ("Sprite Texture", 2D) = "white" {}_Color ("Tint

Button样式设计 圆角、实心、渐变、描边

Android中常常使用shape来定义控件的一些显示属性,今天看了一些shape的使用,对shape有了大体的了解,稍作总结: 先看下面的代码:

CSS文字描边,文字间隔,div自定义形状切割

clip-path: polygon(     0 0,     68% 0,     100% 32%,     100% 100%,     0 100% );//这里切割出来是少一角的正方形 letter-spacing: 1vw; //文字间隔 -webkit-text-stroke: 1px #fff; //文字描边1px uniapp微信小程序顶部导航栏设置透明,下拉改变透明度

[IOS 开发] UILabel文字描边

可以达到文字描一圈黑边的效果 继承UILabel以后重载drawTextInRect - (void)drawTextInRect:(CGRect)rect {CGSize shadowOffset = self.shadowOffset;UIColor *textColor = self.textColor;CGContextRef c = UIGraphicsGetC

Unity 模型描边的几种方法. (Shader、GL、代码生成描绘边)

前言 1、前段时间工作,需要给模型描边,由于对Shader不熟悉,就直接网上找了描边Shader文件,无奈项目发布环境是WebGL,WebGL对Shader的需求比较特殊,故无法使用。 2、因为项目需要描边的物体并不多,所以萌生出,动态生成整个模型所有的边(线条),给各个边附上需要的材质球即可。(当然,也可以直接请美术在模型上描边,但这样不能实现泛光之类的效果) 3、现写下三种实现模型描边的