three.js使用卷积法实现物体描边效果
法线延展法
网上使用法线延展法实现物体描边效果的文章比较多,这里不再描述。
但是这种方法有个缺点:当两个面的法线夹角差别较大时,两个面的描边无法完美连接。如下图所示:

卷积法
这里使用另一种方法卷积法实现物体描边效果,一般机器学习使用该方法比较多。先看效果图:

使用three.js具体的实现方法如下:
- 创建着色器材质,隐藏不需要描边的物体进行渲染,将需要描边的位置渲染成白色,其他位置渲染成黑色。
- 利用片源着色器计算卷积,白色是物体内部,黑色是物体外部,灰色是边框。
- 设置材质透明、不融合,将边框叠加到原图上,可以使用FXAA抗锯齿。
这三步就可以实现了,很简单吧。下面我们将详细介绍实现方法,不想看的可以直接去看完整实现代码:
完整代码: https://gitee.com/tengge1/ShadowEditor/blob/master/ShadowEditor.Web/src/helper/SelectHelper.js
详细的实现过程:
1. 使用three.js正常绘制场景,得到下图,这里不介绍了。

2. 创建着色器材质,隐藏所有不需要描边的物体。将需要描边的物体绘制成白色,其他地方绘制成黑色。
隐藏不需要描边的物体后,将整个场景材质替换。
renderScene.overrideMaterial = this.maskMaterial;
着色器材质:
const maskMaterial = new THREE.ShaderMaterial({
vertexShader: MaskVertex,
fragmentShader: MaskFragment,
depthTest: false
});
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
void main() {
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
效果图:

3. 创建着色器材质进行卷积计算,每四个像素颜色求平均值得到一个像素。描边物体内部是白色,外部是黑色,物体边缘处会得到灰色。灰色就是我们所需的边框。
const edgeMaterial = new THREE.ShaderMaterial({
vertexShader: EdgeVertex,
fragmentShader: EdgeFragment,
uniforms: {
maskTexture: {
value: this.maskBuffer.texture
},
texSize: {
value: new THREE.Vector2(width, height)
},
color: {
value: selectedColor
},
thickness: {
type: 'f',
value: 4
},
transparent: true
},
depthTest: false
});
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
uniform sampler2D maskTexture;
uniform vec2 texSize;
uniform vec3 color;
uniform float thickness; varying vec2 vUv; void main() {
vec2 invSize = thickness / texSize;
vec4 uvOffset = vec4(1.0, 0.0, 0.0, 1.0) * vec4(invSize, invSize); vec4 c1 = texture2D( maskTexture, vUv + uvOffset.xy);
vec4 c2 = texture2D( maskTexture, vUv - uvOffset.xy);
vec4 c3 = texture2D( maskTexture, vUv + uvOffset.yw);
vec4 c4 = texture2D( maskTexture, vUv - uvOffset.yw); float diff1 = (c1.r - c2.r)*0.5;
float diff2 = (c3.r - c4.r)*0.5; float d = length(vec2(diff1, diff2));
gl_FragColor = d > 0.0 ? vec4(color, 1.0) : vec4(0.0, 0.0, 0.0, 0.0);
}
效果图:

4. 创建着色器材质,将边框叠加到原来的图片上。由于FXAA比较复杂,这里使用简单的叠加方法。
着色器材质:
const copyMaterial = new THREE.ShaderMaterial({
vertexShader: CopyVertexShader,
fragmentShader: CopyFragmentShader,
uniforms: {
tDiffuse: {
value: edgeBuffer.texture
},
resolution: {
value: new THREE.Vector2(1 / width, 1 / height)
}
},
transparent: true,
depthTest: false
});
注意,transparent要设置为true,否则会把原来的图片覆盖掉。
CopyVertexShader:
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
CopyFragmentShader:
uniform float opacity;
uniform sampler2D tDiffuse;
varying vec2 vUv;
void main() {
vec4 texel = texture2D( tDiffuse, vUv );
gl_FragColor = opacity * texel;
}
得到最终效果图:

参考资料:
1. 描边实现完整代码:https://gitee.com/tengge1/ShadowEditor/blob/master/ShadowEditor.Web/src/helper/SelectHelper.js
2. 基于three.js的开源三维场景编辑器:https://github.com/tengge1/ShadowEditor
3. three.js后期处理描边:https://threejs.org/examples/#webgl_postprocessing_outline
4. 卷积工作原理:https://www.zhihu.com/question/39022858?sort=created
5. 法线延展法实现物体描边:https://blog.csdn.net/srk19960903/article/details/73863853
three.js使用卷积法实现物体描边效果的更多相关文章
- Cesium源码剖析---Post Processing之物体描边(Silhouette)
Cesium在1.46版本中新增了对整个场景的后期处理(Post Processing)功能,包括模型描边.黑白图.明亮度调整.夜视效果.环境光遮蔽等.对于这么炫酷的功能,我们绝不犹豫,先去翻一翻它的 ...
- Unity Shader实现描边效果
http://gad.qq.com/article/detail/28346 描边效果是游戏里面非常常用的一种效果,一般是为了凸显游戏中的某个对象,会给对象增加一个描边效果.本篇文章和大家介绍下利用S ...
- OpenCV 使用光流法检测物体运动
OpenCV 可以使用光流法检测物体运动,贴上代码以及效果. // opticalflow.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" ...
- js实现欧几里得算法
概念 在数学中,辗转相除法,又称欧几里得算法(英语:Euclidean algorithm),是求最大公约数的算法. 证明 首先假设有两个数a和b,其中a是不小于b的数,记a被b除的余数为r,那么a可 ...
- js中json法创建对象(json里面的:相当于js里面的=)
js中json法创建对象(json里面的:相当于js里面的=) 一.总结 json里面的:相当于js里面的= 4.json创建js对象解决命名冲突:多个人为同一个页面写js的话,命名冲突就有可能发生, ...
- Unity 实现物体破碎效果(转)
感谢网友分享,原文地址(How to Make an Object Shatter Into Smaller Fragments in Unity),中文翻译地址(Unity实现物体破碎效果) In ...
- UE4实现描边效果
描边效果属于常见常用的功能,现VR项目中,也需要射线选中一个物体,使物体高亮. 于是在网上找了部分资料,同时也感谢群里的一位大神的提点,总算将描边的功能实现了,这里也写一个简单的示例步骤. 1.我并不 ...
- TouchPoint.js – 可视化展示 HTML 原型点击效果
TouchPoint.js 是一个用于 HTML 原型展示的 JavaScript 库(作为UX过程的一部分),通过视觉表现用户在屏幕上的点击.TouchPoint 是高度可定制,非常适合屏幕录制,用 ...
- Bounce.js – 快速创建漂亮的 CSS3 动画效果
Bounce.js 是一个用于制作漂亮的 CSS3 关键帧动画的 JavaScript 库,使用其特有的方式生成的动画效果.只需添加一个组件,选择预设,然后你就可以得到一个短网址或者导出为 CSS 代 ...
随机推荐
- jquery a标签的锚点点击的时候页面上缓慢滚动
a标签增加一个名字触发效果: $(".transition").click(function(){ if (location.pathname.replace(/^\//, '') ...
- Centos7 安装redis 并新建springboot工程使用Redis 做session
Redis 安装 就是解压运行,根据自己的爱好,放到文件夹中 tar -zxvf redis-5.0.4.tar.gz yum install gcc cd redis-5.0.4 make MALL ...
- 设计模式(三)Template Method模式
在父类中定义处理流程的框架,在子类中实现具体处理的模式就称为Template Method模式即模板方法模式. 根据下面的示例程序理解模板方法模式. package BigJunOba.bjtu.Te ...
- unity 截屏总结
转载与https://www.cnblogs.com/MissLi/p/8005342.html 1.针对指定的相机进行截屏 此中方式要添加yield return waitfortheEndofFr ...
- Oracle ADG环境搭建
部署 环境介绍 1,软件安装前基础部署 (两台做同样操作) 1.1,关闭selinux和防火墙 因为centos7里面没有/etc/sysconfig/iptables这个配置文件所以我们首先用yum ...
- 阿里规范不建议多表Join,可这SQL要怎么写?
阿里开发手册的描述,禁止多表join: 手册上写着[强制],相信很多同学项目里面的代码都不满足这个要求. 但是关键问题是:不用join,这SQL究竟要怎么写?! 分解关联查询 即对每个要关联的表进行单 ...
- js如何展示上传的图片
前言:本文章主要讲的是上传的图片如何展示在页面上. 一般来说,我们会先将本地图片上传到服务器,上传成功后,由后台返回图片的网络地址再在前端显示.但是,我今天讲的是不通过前面说的过程,而是直接使用js将 ...
- API 网关知识看这篇就足够了!
本文已经收录自 JavaGuide (60k+ Star[Java学习+面试指南] 一份涵盖大部分Java程序员所需要掌握的核心知识.) 本文授权转载自:https://github.com/java ...
- 第三十一章 System V信号量(二)
用信号量实现进程互斥示例 #include <unistd.h> #include <sys/types.h> #include <stdlib.h> #inclu ...
- 学习笔记36_Razor
*Razor视图引擎 在添加视图的时候,视图引擎除了有“aspx”外,还有Razor(CSHTML),就会在对应的文件夹下,产生 view.cshtml文件,那么,以后写C#代码,就可以 @for(v ...