基于法线的边缘检测

边缘高亮效果中我提到过两种方法, 各有优缺点吧

图像空间域的边缘检测效果比较好, 中间没有多余的线条. 缺点是PS中计算比较慢

第二种把模型"放大"(其实是变胖)的做法, 可以在VS中完成, 不需要额外的RenderTarget, 适合低端显卡使用, 适应性好. 不如果模型法线信息不对的话, 会造成画面错乱. 实际使用时可以根据W值(不用Z深度)来画出远近粗细一样的线条

这次提到的基于法线的方法, 其实跟2D的空间域边缘检测很相似, 如果要求结果是绘制物体的线条图而不仅仅是一个边缘轮廓时, 它就派上用场了. (还是要用PS去算, 实际使用时要注意性能问题)

基本的渲染流程(2 pass):

第一个pass用于生成法线图到一张RenderTarget上, 第二个pass跟据这张法线图来做边缘检测. 实际使用时可以采用Multi-RenderTarget来加速

法线信息要在pixel shader里进行向量化, 不然会在一些面上出块很淡的颜色. 如果对质量要求不高, 可以在VS中进行向量化.

RenderTarget要Clear成单位化的值, 我用的(0,0,1), 即纯蓝色

/*********************VS*********************/ 
float4x4 matViewProjection;  
struct VS_INPUT   
{  
   float4 Position : POSITION0;  
   float3 Normal   : NORMAL0;  
};  
struct VS_OUTPUT   
{  
   float4 Position : POSITION0;  
   float3 Normal   : TEXCOORD0;  
};  
VS_OUTPUT vs_main( VS_INPUT Input )  
{  
   VS_OUTPUT Output;  
   Output.Position = mul( Input.Position, matViewProjection );  
   Output.Normal = mul( Input.Normal, matViewProjection );  
 return( Output );  
}  
/*********************PS*********************/ 
float4 ps_main(float3 normal : TEXCOORD0) : COLOR0  
{     
 return(float4(normalize(normal), 1.0f));  
}  

注意法线图的格式是浮点数格式, 我用的是D3DFMT_A16B16G16R16F(因为法线有负值, 你也可以自己压缩到[0,1]再解开)

有了这张法线图就很好办了, 对每个像素计算它与周围像素的法线夹角余弦值的和, 再取反(1-degree), 这样就能计算出来边缘了

依据就是边缘处的法线夹角比较大, 余弦值更接近0甚至为负值.

.sampler TexNormal;  
float2 fInverseViewportDimensions;  
float2 PixelKernel[4] =  
{  
    { 0,  1},  
    { 1,  0},  
    { 0, -1},  
    {-1,  0}  
};  
float4 ps_main(float2 texCoord : TEXCOORD0) : COLOR0  
{  
   float4 origin = tex2D(TexNormal, texCoord);  
   float3 sum = 0;  
 for (int i = 0; i < 4; i++)  
   {  
      float2 texel = texCoord + PixelKernel[i] * fInverseViewportDimensions;  
      sum += saturate(1.0f - dot(origin.xyz, tex2D(TexNormal, texel).xyz));  
   }  
 return float4(sum, 1.0f);  
}  

最终效果:

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏zingpLiu

机器学习之线性代数

  完整内容已上传到github:https://github.com/ZingP/machine-learning/tree/master/linear_al...

20210
来自专栏WindCoder

TensorFlow入门:一篇机器学习教程

TensorFlow是一个由Google创建的开源软件库,用于实现机器学习和深度学习系统。这两个名称包含一系列强大的算法,它们共享一个共同的挑战——让计算机学习...

40510
来自专栏每日一篇技术文章

OpenGL ES _ 着色器_片断着色器详解

输入值:片段着色器接受顶点管线最终输出的迭代值,这些值包括片段的位置,已解析的主颜色和辅助颜色,一系列的纹理坐标以及片段的雾坐标距离。

29710
来自专栏CreateAMind

Adversarial Variational Bayes: 统一VAE和GAN 及代码

Adversarial Variational Bayes: Unifying Variational Autoencoders and Generative ...

14230
来自专栏北京马哥教育

十分钟入门 Python 绘图库 Matplotlib 入门教程

Matplotlib是一个Python语言的2D绘图库,它支持各种平台,并且功能强大,能够轻易绘制出各种专业的图像。本文是对它的一个入门教程。

13400
来自专栏Bay的专栏

如何使用 scikit-learn 为机器学习准备文本数据

文本数据需要特殊处理,然后才能开始将其用于预测建模。

23350
来自专栏帮你学MatLab

《Experiment with MATLAB》读书笔记(四)

读书笔记(四) 这是第四部分数组与矩阵 将代码复制到m文件即可运行 函数部分需新建m文件保存 %% 向量与矩阵 x = [2; 4] % ...

383110
来自专栏PPV课数据科学社区

【学习】ggplot2绘图入门系列之二:图层控制与直方图

如前文所述,ggplot2使用图层将各种图形元素逐步添加组合,从而形成最终结果。第一层必须是原始数据层,其中data参数控制数据来源,注意数据形式...

26960
来自专栏程序生活

数据挖掘作业第4章 算法设计第5章 程序实现第六章 实现结果

第4章 算法设计 4.1 实现方式1:欧式距离 实验原理如下图: ? 图 1 实验原理 4.1.1 步骤1:数据预处理 这一部分对应实验代码1的preproce...

29780
来自专栏懒人开发

(1.6)James Stewart Calculus 5th Edition: Inverse Functions and Logarithms

前面我们有提到 e,e的对数,我们可以简写, 理解为 Natural Logarithms 自然对数

13430

扫码关注云+社区

领取腾讯云代金券