一、前面心情

1.公司我的架构发生变动,从技术中心到项目组了,但不管怎么样,该看的还要看,总会用到

二、实现

三、参考:

http://blog.csdn.net/cubesky/article/details/38588723

四、代码和关键流程

1.使用surface shader实现:

首先:viewDir:世界坐标系下,vertex为起点,Camera为终点的向量,即Camera到vertex的反向量。

Shader "Custom/outLineTest" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_OutLineColor("outLineColor",Color)=(1.0,0.0,0.0,1.0)
_threshold("outLine threshold ",Range(0.0,1.0))=0.21
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200 CGPROGRAM
#pragma surface surf Lambert sampler2D _MainTex;
float4 _OutLineColor;
float _threshold; struct Input {
float2 uv_MainTex;
float3 worldNormal;
float3 viewDir;
}; void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D (_MainTex, IN.uv_MainTex);
float angleF=dot(normalize(IN.worldNormal),normalize(IN.viewDir));//求dot是否很小,如果很小,则说明normal和viewDir为90度,达到边缘。
o.Emission =_OutLineColor.rgb*step(angleF,_threshold);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}

  

2.vs ps实现:

当Camera位置变化时,cs文件传递pos到shader中去:

cs绑定到球体上:

using UnityEngine;
using System.Collections; public class cameraCoordTest : MonoBehaviour { // Use this for initialization
public GameObject camer;
const float cameraSpeed = 10.0f;
Vector4 SetTempV()
{
Vector4 tempV = Vector4.zero;
tempV.x = camer.transform.position.x;
tempV.y = camer.transform.position.y;
tempV.z = camer.transform.position.z;
tempV.w = 1;
return tempV;
} // Update is called once per frame
void Update () { if (Input.GetKey(KeyCode.W))
{
camer.transform.Translate(Vector3.forward * Time.deltaTime * cameraSpeed); transform.renderer.material.SetVector("_camPos", SetTempV());
}
else if (Input.GetKey(KeyCode.S))
{
camer.transform.Translate(Vector3.forward * Time.deltaTime * -cameraSpeed);
transform.renderer.material.SetVector("_camPos", SetTempV());
}
else if (Input.GetKey(KeyCode.A))
{
camer.transform.Translate(Vector3.left * Time.deltaTime * cameraSpeed);
transform.renderer.material.SetVector("_camPos", SetTempV());
}
else if(Input.GetKey(KeyCode.D))
{
camer.transform.Translate(Vector3.left * Time.deltaTime * -cameraSpeed);
transform.renderer.material.SetVector("_camPos", SetTempV());
}
}
}

  

shader中,把surface修改为vs ps实现方式:

Shader "Custom/outLineTest" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_threshold("outLine threshold ",Range(0.0,1.0))=0.1
_camPos("cam pos",Vector)=(0,0,-10.0,1.0)
}
SubShader{
Pass{
Fog{Mode Off}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc" uniform float _threshold;
uniform float4 _camPos; struct v2f1{
float4 pos :SV_POSITION;
float3 norm : TEXCOORD1;
float3 verToViewDir : TEXCOORD2;
}; v2f1 vert(appdata_base inV)
{
v2f1 o;
o.pos = mul(UNITY_MATRIX_MVP,inV.vertex);
o.norm = mul ((float3x3)_Object2World, inV.normal);//normal转化到世界坐标系下
o.verToViewDir = normalize(_camPos.xyz-mul(_Object2World,inV.vertex).xyz);
return o;
} float4 frag(v2f1 inV):SV_Target
{
float4 reColor;
reColor.a = 1.0f;
float angleF=dot(normalize(inV.norm),normalize(inV.verToViewDir)); reColor.rgb=float3(0,0,0)+float3(1,1,1)*step(angleF,0.3); return reColor;
}
ENDCG
}
}
Fallback off
}

  

五、下一步

这种方式对平滑曲面有效,当立方体或非渐变的法线物体,此法无效,比如说plane,由于背面没有normal,无法获取

以前轮廓边检测生成阴影时,可以通过GS来判断邻边,判断line是否是轮廓边。作为以后学习内容吧。

六:注意点:

1.appdata_base 类中全是本地坐标系下的数据,需要转化到worldSpace下,所以,normal需要进行object2World的转化;
2.为了达到surface中viewDir数据,需要Camera的pos和vertex的pos进行处理,
3.如果写好surface实现,vs ps写不好,参考surface编译后的代码,仔细看,总会写好vs ps实现

简易的轮廓边生成(N和V dot点乘方式)(surface方式和vs ps 方式的分别实现)的更多相关文章

  1. ASP.NET 生成二维码(采用ThoughtWorks.QRCode和QrCode.Net两种方式)

    最近做项目遇到生成二维码的问题,发现网上用的最多的是ThoughtWorks.QRCode和QrCode.Net两种方式.访问官网看着例子写了两个Demo,使用过程中发现两个都挺好用的,Thought ...

  2. android的dmtracedump工具生成trace文件图片 'dot' 不是内部或外部命令,也不是可运行的程序 或批处理文件。

    http://jingyan.baidu.com/article/c910274bfa6c1fcd361d2df7.html http://www.cnblogs.com/albert1017/p/3 ...

  3. c# iText 生成PDF 有文字,图片,表格,文字样式,对齐方式,页眉页脚,等等等,

    #region 下载说明书PDF protected void lbtnDownPDF_Click(object sender, EventArgs e) { int pid = ConvertHel ...

  4. Ubuntu操作用户账户

    Git Gerrit $是普通管员,#是系统管理员,在Ubuntu下,root用户默认是没有密码的,因此也就无法使用(据说是为了安全).想用root的话,得给root用户设置一个密码: sudo pa ...

  5. miaov- 自动生成正V反V大于号V小于号V楼梯等图案

    1. 核心:控制 数量的长度-1-i的位置,是放在left上还是top上?是放在前面还是后面! <!DOCTYPE html> <html lang="en"&g ...

  6. opencv6.5-imgproc图像处理模块之轮廓

    接opencv6.4-imgproc图像处理模块之直方图与模板 这部分的<opencv_tutorial>上都是直接上代码,没有原理部分的解释的. 十一.轮廓 1.图像中找轮廓 /// 转 ...

  7. Why数学图像生成工具

    该软件能够以给定的数学公式及算法生成各种绚烂的数学图像.软件中有两种生成图像的方法: (1)通过一种我自定义的脚本语言生成: 软件中定义一套简单易学的脚本语言,用于描述数学表达式.使用时需要先要将数学 ...

  8. 由zImage生成uImage

    一.手动使用mkimage命令 mkimage -A arm -O linux -T kernel -C none -a 30007fc0 -e 30007fc0 -n uImage   -d /wo ...

  9. 对xlslib库与libxls库的简易封装

    一.简介 xlslib库是用来创建excel文件.libxls是用来读取excel文件的,在使用C++或者QT语言来设计对excel文件的读取.都需要事先下载这两个库编译成功后再进行程序设计的.之所以 ...

随机推荐

  1. PHP正则表达式

    1.PHP中两个常用的正则函数 a.preg_match 正则函数,以perl语言为基础 语法:preg_match( mode,string subject,array matches) 说明:mo ...

  2. Lock、ReentrantLock、synchronized、ReentrantReadWriteLock使用

    先来看一段代码,实现如下打印效果: 1 2 A 3 4 B 5 6 C 7 8 D 9 10 E 11 12 F 13 14 G 15 16 H 17 18 I 19 20 J 21 22 K 23 ...

  3. for循环语句的笔试

    首先对for循环的初始条件进行调用打印A,之后判断语句输出B,第三个条件先不使用,直接进入循环内部 打印D,再到C:第二次判断i=1,A这个条件不使用了,进入B判定,再是D,C,最后进行判定输出B

  4. ProxyPattern

    代理模式是aop编程的基础,其主要作用是操作对象,并将你需要的新功能切入若干个你想要的切入点,静态代理模式比较简单,但是缺点比较大,这里就不上代码了,下面写上动态代理模式的代码(jdk方式,而不是采用 ...

  5. .net开发过程中Bin目录下面几种文件格式的解释

    在.NET开发中,我们经常会在bin目录下面看到这些类型的文件: .pdb..xsd..vshost.exe..exe..exe.config..vshost.exe.config 项目发布的时候,往 ...

  6. 浅谈tornado项目应用设计

    一.预备知识 最近开始尝试做一些tornado商城项目,在开始之前需要引入一些项目设计知识,如接口,抽象方法抽象类,组合,程序设计原则等,个人理解项目的合理设计可增加其灵活性,降低数据之间的耦合性,提 ...

  7. line-height行高与图片的隐匿文本间隙消除方法

    (标注 文章来源 http://www.zhangxinxu.com/wordpress/2015/08/css-deep-understand-vertical-align-and-line-hei ...

  8. 简单介绍JSON

    如下图:

  9. 高性能javascript学习笔记系列(5) -快速响应的用户界面和编程实践

    参考高性能javascript 理解浏览器UI线程  用于执行javascript和更新用户界面的进程通常被称为浏览器UI线程  UI线程的工作机制可以理解为一个简单的队列系统,队列中的任务按顺序执行 ...

  10. 12种不适宜使用的javascript语法

    1. == (o゜▽゜)o☆[BINGO!] Javascript有两组相等运算符,一组是==和!=,另一组是===和!==.前者只比较值的相等,后者除了值以外,还比较类型是否相同. 请尽量不要使用前 ...