three.js利用卷积法如何实现物体描边效果
法线延展法
网上使用法线延展法实现物体描边效果的文章比较多,这里不再描述。
这种方法有个缺点当两个面的法线夹角差别较大时,两个面的描边无法完美连接。如下图所示
卷积法
这里使用另一种方法卷积法实现物体描边效果,一般机器学习使用该方法比较多。先看效果图
使用three.js具体的实现方法如下
- 创建着色器材质,隐藏不需要描边的物体进行渲染,将需要描边的位置渲染成白色,其他位置渲染成黑色。
- 利用片源着色器计算卷积,白色是物体内部,黑色是物体外部,灰色是边框。
- 设置材质透明、不融合,将边框叠加到原图上,可以使用FXAA抗锯齿。
这三步就可以实现了,很简单吧。狼蚁网站SEO优化我们将详细介绍实现方法,不想看的可以直接去看完整实现代码
完整代码https://gitee./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 });
MaskVertex
void main() { gl_Position = projectionMatrix modelViewMatrix vec4( position, 1.0 ); }
MaskFragment
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 });
其中texSize是计算卷积的canvas宽度和高度,为了让边框更平滑,可以设置为原来canvas的两倍。color是边框颜色,thickness是边框粗细。
注意,要将材质transparent设置为true。
EdgeVertex
varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix modelViewMatrix vec4( position, 1.0 ); }
EdgeFragment
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. 描边实现完整代码
2. 基于three.js的开源三维场景编辑器
3. three.js后期处理描边
4. 卷积工作原理
5. 法线延展法实现物体描边
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对狼蚁SEO的支持。
编程语言
- 如何快速学会编程 如何快速学会ug编程
- 免费学编程的app 推荐12个免费学编程的好网站
- 电脑怎么编程:电脑怎么编程网咯游戏菜单图标
- 如何写代码新手教学 如何写代码新手教学手机
- 基础编程入门教程视频 基础编程入门教程视频华
- 编程演示:编程演示浦丰投针过程
- 乐高编程加盟 乐高积木编程加盟
- 跟我学plc编程 plc编程自学入门视频教程
- ug编程成航林总 ug编程实战视频
- 孩子学编程的好处和坏处
- 初学者学编程该从哪里开始 新手学编程从哪里入
- 慢走丝编程 慢走丝编程难学吗
- 国内十强少儿编程机构 中国少儿编程机构十强有
- 成人计算机速成培训班 成人计算机速成培训班办
- 孩子学编程网上课程哪家好 儿童学编程比较好的
- 代码编程教学入门软件 代码编程教程