简易的轮廓边生成(N和V dot点乘方式)(surface方式和vs ps 方式的分别实现)
一、前面心情
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 方式的分别实现)的更多相关文章
- ASP.NET 生成二维码(采用ThoughtWorks.QRCode和QrCode.Net两种方式)
最近做项目遇到生成二维码的问题,发现网上用的最多的是ThoughtWorks.QRCode和QrCode.Net两种方式.访问官网看着例子写了两个Demo,使用过程中发现两个都挺好用的,Thought ...
- android的dmtracedump工具生成trace文件图片 'dot' 不是内部或外部命令,也不是可运行的程序 或批处理文件。
http://jingyan.baidu.com/article/c910274bfa6c1fcd361d2df7.html http://www.cnblogs.com/albert1017/p/3 ...
- c# iText 生成PDF 有文字,图片,表格,文字样式,对齐方式,页眉页脚,等等等,
#region 下载说明书PDF protected void lbtnDownPDF_Click(object sender, EventArgs e) { int pid = ConvertHel ...
- Ubuntu操作用户账户
Git Gerrit $是普通管员,#是系统管理员,在Ubuntu下,root用户默认是没有密码的,因此也就无法使用(据说是为了安全).想用root的话,得给root用户设置一个密码: sudo pa ...
- miaov- 自动生成正V反V大于号V小于号V楼梯等图案
1. 核心:控制 数量的长度-1-i的位置,是放在left上还是top上?是放在前面还是后面! <!DOCTYPE html> <html lang="en"&g ...
- opencv6.5-imgproc图像处理模块之轮廓
接opencv6.4-imgproc图像处理模块之直方图与模板 这部分的<opencv_tutorial>上都是直接上代码,没有原理部分的解释的. 十一.轮廓 1.图像中找轮廓 /// 转 ...
- Why数学图像生成工具
该软件能够以给定的数学公式及算法生成各种绚烂的数学图像.软件中有两种生成图像的方法: (1)通过一种我自定义的脚本语言生成: 软件中定义一套简单易学的脚本语言,用于描述数学表达式.使用时需要先要将数学 ...
- 由zImage生成uImage
一.手动使用mkimage命令 mkimage -A arm -O linux -T kernel -C none -a 30007fc0 -e 30007fc0 -n uImage -d /wo ...
- 对xlslib库与libxls库的简易封装
一.简介 xlslib库是用来创建excel文件.libxls是用来读取excel文件的,在使用C++或者QT语言来设计对excel文件的读取.都需要事先下载这两个库编译成功后再进行程序设计的.之所以 ...
随机推荐
- PHP正则表达式
1.PHP中两个常用的正则函数 a.preg_match 正则函数,以perl语言为基础 语法:preg_match( mode,string subject,array matches) 说明:mo ...
- 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 ...
- for循环语句的笔试
首先对for循环的初始条件进行调用打印A,之后判断语句输出B,第三个条件先不使用,直接进入循环内部 打印D,再到C:第二次判断i=1,A这个条件不使用了,进入B判定,再是D,C,最后进行判定输出B
- ProxyPattern
代理模式是aop编程的基础,其主要作用是操作对象,并将你需要的新功能切入若干个你想要的切入点,静态代理模式比较简单,但是缺点比较大,这里就不上代码了,下面写上动态代理模式的代码(jdk方式,而不是采用 ...
- .net开发过程中Bin目录下面几种文件格式的解释
在.NET开发中,我们经常会在bin目录下面看到这些类型的文件: .pdb..xsd..vshost.exe..exe..exe.config..vshost.exe.config 项目发布的时候,往 ...
- 浅谈tornado项目应用设计
一.预备知识 最近开始尝试做一些tornado商城项目,在开始之前需要引入一些项目设计知识,如接口,抽象方法抽象类,组合,程序设计原则等,个人理解项目的合理设计可增加其灵活性,降低数据之间的耦合性,提 ...
- line-height行高与图片的隐匿文本间隙消除方法
(标注 文章来源 http://www.zhangxinxu.com/wordpress/2015/08/css-deep-understand-vertical-align-and-line-hei ...
- 简单介绍JSON
如下图:
- 高性能javascript学习笔记系列(5) -快速响应的用户界面和编程实践
参考高性能javascript 理解浏览器UI线程 用于执行javascript和更新用户界面的进程通常被称为浏览器UI线程 UI线程的工作机制可以理解为一个简单的队列系统,队列中的任务按顺序执行 ...
- 12种不适宜使用的javascript语法
1. == (o゜▽゜)o☆[BINGO!] Javascript有两组相等运算符,一组是==和!=,另一组是===和!==.前者只比较值的相等,后者除了值以外,还比较类型是否相同. 请尽量不要使用前 ...