基于深度法线纹理检测使用Robert算子的边缘检测——UnityShader学习笔记

自言自语

此次学习基于深度法线纹理的边缘检测 法线此效果 只能对正确设置了渲染顺序的物体生效 即 “Queue”=“Geometry” 所以并不适合正式项目。 且发现做片段着色器中,插值控制参数 非1即0,但比较方法中的细节参数 却能影响描边效果 不解为何 。 按我的理解 既然控制总参数 非1即0 那么最终效果也就只有两种极端情况。 但此效果却能做到细微的变化 没能明白是为何。记录于此,理解后再更

2020/01/26 更新

一开始把 int isSameNormal = (diffNormal.x+diffNormal.y)<0.1 理解为三元运算, 却发现实际效果差很大 因此后边做了修改。 所以int isSameNormal = (diffNormal.x+diffNormal.y)<0.1并不能简单的直接理解为三元运算 但他到底是什么意思呢。 也许弄明白了以后就可以理解细微参数变化对描边状态的影响了

            //int isSameNormal = (diffNormal.x+diffNormal.y)<0.1?1.0:0;
            int isSameNormal = (diffNormal.x+diffNormal.y)<0.1;

效果

面板

在这里插入图片描述

GIF演示 (错误效果版 稍晚些时候回家再更新修改过代码的正确效果版)

在这里插入图片描述

正确效果版


在这里插入图片描述


C#部分

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteInEditMode]
public class OutlineRobertWithDepthNormalsTexture : PostProcessWangBase
{
    [Range(0f,4f)]
    public float outLineWidth = 1f;
    public float sensitivityN = 1f;
    public float sensitivityD = 1f;
    [Range(0f,1f)]
    public float edgeOnly = 1f;
    public Color outLineColor = Color.black;
    public Color backGroundColor = Color.white;

    public Shader outlineShder;
    private Material material;
    public Material outlineMaterial
    {
        get
        {
            material = CheckShaderAndMaterial(outlineShder, material);
            return material;
        }
    }

    private void OnEnable()
    {
        GetComponent<Camera>().depthTextureMode |= DepthTextureMode.DepthNormals;
    }

    protected void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        //这个没啥说的 传参就行了
        if(outlineMaterial == null )
        {
            Graphics.Blit(source, destination);
        }
        else
        {
            outlineMaterial.SetFloat("_OutlineWidth", outLineWidth);
            //原本书中所写存入一个向量中  但我为了方便区分 直接设置两个参数 
            //outlineMaterial.SetVector("_Sensitivity", new Vector4(sensitivity.x, sensitivity.y, 0, 0));
            outlineMaterial.SetFloat("_SensitivityN", sensitivityN);
            outlineMaterial.SetFloat("_SensitivityD", sensitivityD);
            outlineMaterial.SetFloat("_EdgeOnly", edgeOnly);
            outlineMaterial.SetColor("_OutlineColor", outLineColor);
            outlineMaterial.SetColor("_BackGroundColor", backGroundColor);

            Graphics.Blit(source, destination, outlineMaterial);
        }
    }
}

shader部分

Shader "TNShaderPractise/ShaderPractise_OutLineRobertWithDepthNormalsTexture"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" "Queue" ="Transparent" }

      	CGINCLUDE
		#include "UnityCG.cginc"

		sampler2D _MainTex;
		float4 _MainTex_TexelSize;
		sampler2D _CameraDepthNormalsTexture;
		float _OutlineWidth;
		float _SensitivityN;
		float _SensitivityD;
		float _EdgeOnly;
		float4 _OutlineColor;
		float4 _BackGroundColor;

		struct v2f 
		{
			float4 pos : SV_POSITION;
			//存储UV数组
			float2 uv[5] : TEXCOORD1;
		};
	 //这次尝试直接使用Unity封装好的 appdata结构体
		v2f vert (appdata_base v)
		{
			v2f o;
			o.pos = UnityObjectToClipPos(v.vertex);
			half2 uv = v.texcoord;

			//保存正常UV
			o.uv[0]=uv;

			//判定平台
			#if UNITY_UV_STARTS_AT_TOP
			 if (_MainTex_TexelSize.y <0)
			 uv.y = 1- uv.y;
			 #endif
			   //根据Robert算子 对UV进行偏移采样 并通过 outlinewidth控制采样距离 也可以理解为粗细  在顶点着色器是为了减少运送  反正可以插值到片段着色器
			 o.uv[1] = uv + _MainTex_TexelSize.xy*half2(1,1)*_OutlineWidth;
			 o.uv[2] = uv + _MainTex_TexelSize.xy*half2(-1,-1)*_OutlineWidth;
			 o.uv[3] = uv + _MainTex_TexelSize.xy*half2(-1,1)*_OutlineWidth;
			 o.uv[4] = uv + _MainTex_TexelSize.xy*half2(1,-1)*_OutlineWidth;

			 return o;
		}
		//定义check函数 判定是否有差异
		   half CheckSame (half4 center,half4 sampleDN )
		{	
		//获得法线数据 但并不需要解码 因为只要比较差异就行了
			float2 centerNormal = center.xy;
			//获得深度值 直接解码得到
			float centerDepth = DecodeFloatRG(center.zw);

			float2 sampleDNNormal = sampleDN.xy;
			float sampleDNDepth = DecodeFloatRG(sampleDN.zw);

			//通过控制差值大小 影响采样权重
			float2 diffNormals = abs(centerNormal-sampleDNNormal)*_SensitivityN;
			//这里相当于三元运算 	   (diffNormals.x+diffNormals.y)<0.1?:1.0:0;
			int isSameNormal =  (diffNormals.x+diffNormals.y)<0.1;

			// 直接控制深度差值大小
			float diffDepth = abs(centerDepth-sampleDNDepth)*_SensitivityD;
			//同理三元运算  diffDepth<0.1?:1.0:0  * centerDepth
			int isSameDepth = diffDepth<0.1*centerDepth;


			//****最后在得出综合差值 非10  这里并不能直接将三元运算写在等式右边 会造成显示翻转的情况
			//****int isSame = isSameNormal*isSameDepth<0.1?1.0:0;
			int isSame = isSameNormal*isSameDepth<0.1;
			//****要在这里直接做判断返回 10 才可
			return isSame<0.1?1.0:0;
		}
		float4 frag (v2f i ): SV_Target
		{
			half4 depthNormalsTexture1 = tex2D(_CameraDepthNormalsTexture ,i.uv[1]);
			half4 depthNormalsTexture2 = tex2D(_CameraDepthNormalsTexture ,i.uv[2]);
			half4 depthNormalsTexture3 = tex2D(_CameraDepthNormalsTexture ,i.uv[3]);
			half4 depthNormalsTexture4 = tex2D(_CameraDepthNormalsTexture ,i.uv[4]);

			float edge =1;

			//调用其差值比较后的结果 累乘到 edge 非10   疑问 都是 10   为什么调节参数还能有变化...
			edge *= CheckSame(depthNormalsTexture1,depthNormalsTexture2);
			edge *= CheckSame(depthNormalsTexture3,depthNormalsTexture4);
			
			//****因为上边做了相应书写规范处理 所以这边也要调整插值顺序
			//以下插值顺序与书中正好相反,因为这样才符合预期
			//****fixed4 withTexture = lerp (tex2D(_MainTex,i.uv[0]),_OutlineColor,edge) ;
			//****fixed4 edgeOnly = lerp (_BackGroundColor,_OutlineColor,edge);

			//****fixed4 finalColor = lerp (edgeOnly,withTexture,_EdgeOnly);

			fixed4 withTexture = lerp (_OutlineColor,tex2D(_MainTex,i.uv[0]),edge) ;
			fixed4 edgeOnly = lerp (_OutlineColor,_BackGroundColor,edge);

			fixed4 finalColor = lerp (withTexture,edgeOnly,_EdgeOnly);
			return finalColor;
		}

		
		ENDCG

		pass
		{
			ZWrite Off ZTest Always Cull Off

			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			ENDCG
		}
    }

	FallBack Off
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
深度边缘检测是指在使用Intel RealSense D435深度相机进行图像处理时,通过分析深度图像中的深度值差异来检测物体的边界。深度图像是由相机测量到的每个像素点与相机的距离值组成的。深度边缘检测可以通过比较相邻像素点的深度值来确定边界位置。 在进行深度边缘检测时,可以使用基于颜色的边缘检测方法,通过比较像素点的深度值差异来确定边界。这种方法的优点是只需要深度图像本身,无需额外信息。然而,如果两个物体的深度差异不明显,即使存在边界,也可能无法检测出来。因此,对于需要更准确的边缘效果,可以使用其他更精确的边缘检测方法,如基于法线深度差异的方法。通过计算当前采样点周围像素点的法线深度差异,并设置阈值,可以确定边界位置。 深度边缘检测在计算机视觉中具有广泛的应用,例如图像分割、对象检测和视频对象分割。然而,由于复杂的背景和不一致的注释等因素,深度边缘检测是一个具有挑战性的问题。因此,在实际应用中,需要根据具体情况选择适合的边缘检测方法和参数设置,以获得准确的边界和视觉上显著的边缘。 #### 引用[.reference_title] - *1* [Unity Shader-边缘检测效果(基于颜色,基于深度法线边缘流光效果,转场效果)](https://blog.csdn.net/puppet_master/article/details/83759180)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [深度学习边缘检测算法论文解读(EDTER: Edge Detection with Transformer)](https://blog.csdn.net/qq_41627642/article/details/128568272)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [深度学习传统CV算法——边缘检测算法综述](https://blog.csdn.net/weixin_42917352/article/details/121977458)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值