主頁 >  其他 > 每次都能讓人頭大的 Shader -- 從一次簡單的功能說起

每次都能讓人頭大的 Shader -- 從一次簡單的功能說起

2020-09-12 23:01:35 其他

  最近有個功能, 要渲染從主相機視角看到的另一個相機的可視范圍和不可見范圍, 大概如下圖 : 

  簡單來說就是主相機視野和觀察者相機視野重合的地方, 能標記出觀察者相機的可見和不可見, 實作原理就跟 ShadowMap 一樣, 就是有關深度圖, 世界坐標轉換之類的, 每次有此類的功能都會很悲催, 雖然它的邏輯很簡單, 可是用Unity3D做起來很麻煩...

  原理 : 在觀察者相機中獲取深度貼圖, 儲存在某張 RenderTexture 中,  然后在主相機中每個片元都獲取對應的世界坐標位置, 將世界坐標轉換到觀察者相機viewPort中, 如果在觀察者相機視野內, 就繼續把視口坐標轉換為UV坐標然后取出儲存在 RenderTexture 中的對應深度, 把深度轉換為實際深度值后做比較, 如果深度小于等于深度圖的深度, 就是觀察者可見 否則就是不可見了.

 

  先來看怎樣獲取深度圖吧, 不管哪種渲染方式, 給相機添加獲取深度圖示記即可:

        _cam = GetComponent<Camera>();
        _cam.depthTextureMode |= DepthTextureMode.Depth;

  

  然后深度圖要精度高點的, 單通道圖即可:

        renderTexture = RenderTexture.GetTemporary(Screen.width, Screen.height, 0, RenderTextureFormat.RFloat);
        renderTexture.hideFlags = HideFlags.DontSave;

  

  之后就直接把相機的貼圖經過后處理把深度圖渲染出來即可 : 

    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if (_material && _cam)
        {
            Shader.SetGlobalFloat("_cameraNear", _cam.nearClipPlane);
            Shader.SetGlobalFloat("_cameraFar", _cam.farClipPlane);

            Graphics.Blit(source, renderTexture, _material);
        }
        Graphics.Blit(source, destination);
    }

  材質就是一個簡單的獲取深度的shader : 

    sampler2D _CameraDepthTexture;    
    uniform float _cameraFar;
    uniform float _cameraNear;
    
    float DistanceToLinearDepth(float d, float near, float far)
    {
        float z = (d - near) / (far - near);
        return z;
    }
    
    fixed4 frag(v2f i) : SV_Target
    {
        float depth  = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);
        depth = LinearEyeDepth(depth);
        depth = DistanceToLinearDepth(depth, _cameraNear, _cameraFar);
        return float4(depth, depth, depth, 1);
    }
    

 

  這里有點奇怪吧, 為什么回傳的不是深度貼圖的深度, 也不是 Linear01Depth(depth) 的歸一化深度, 而是自己計算出來的一個深度?

  這是因為缺少官方檔案........其實看API里面有直接提供 RenderBuffer 給相機的方法 : 

        _cam.SetTargetBuffers(renderTexture.colorBuffer, renderTexture.depthBuffer);

  可是沒有檔案也沒有例子啊, 鬼知道你渲染出來我怎么用啊, 還有 renderTexture.depthBuffer 到底怎樣作為 Texture 傳給 shader 啊... 我之前嘗試過它們之間通過 IntPtr 作的轉換操作, 都是失敗...

  于是就只能用最穩妥的方法, 通過 Shader 渲染一張深度圖出來吧, 然后通過 SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv); 獲取到的深度值, 應該是 NDC 坐標, 深度值的范圍應該是[0, 1]之間吧(非線性), 如果在其它相機程序中獲取實際深度的話, 就需要自己實作 LinearEyeDepth(float z) 這個方法:

inline float LinearEyeDepth( float z )
{
    return 1.0 / (_ZBufferParams.z * z + _ZBufferParams.w);
}

  而在不同平臺, _ZBufferParams 里面的值是不一樣的, 所以如果實作它的話會很麻煩, 并且經過我的測驗, 結果是不對的......

double x, y;

OpenGL would be this:
x = (1.0 - m_FarClip / m_NearClip) / 2.0;
y = (1.0 + m_FarClip / m_NearClip) / 2.0;

D3D is this:
x = 1.0 - m_FarClip / m_NearClip;
y = m_FarClip / m_NearClip;

_ZBufferParams = float4(x, y, x/m_FarClip, y/m_FarClip);

  PS : 使用觀察者相機的 nearClipPlane, farClipPlane 計算出來的深度也是不正確的, 不知道為什么......

  所以就有了我自己計算歸一化深度的方法了:

    float DistanceToLinearDepth(float d, float near, float far)
    {
        float z = (d - near) / (far - near);
        return z;
    }

  簡單好理解, 這樣就獲得了我自己計算的深度圖, 只需要觀察者相機的 far/near clip panel 的值即可. 所以可以看出, 由于缺少官方檔案等原因, 做一個簡單的功能往往會很花費時間, 說真的搜索了很多例子, 直接代碼Shader復制過來都不能用, 簡直了.

 

  接下來是難點的主相機渲染, 主相機需要做這幾件事 :

1. 通過主相機深度圖, 獲取當前片元的世界坐標位置

2. 通過把世界坐標位置轉換到觀察者相機視口空間, 檢測是否在觀察者相機視口之內.

3. 不在觀察者相機視口之內, 正常顯示.

4. 在觀察者相機視口之內的部分, 將視口坐標轉換成觀察者相機的 UV 坐標, 然后對觀察者相機渲染出來的深度圖進行取值, 變換為實際深度值然后進行深度比較, 如果片元在觀察者相機視口的坐標深度小于等于深度圖深度, 則是可見部分, 其它是不可見部分.

 

  主相機也設定打開深度圖渲染 : 

        _cam = GetComponent<Camera>();
        _cam.depthTextureMode |= DepthTextureMode.Depth;

  那么怎樣通過片元獲取世界坐標位置呢? 最穩妥的是參考官方 Fog 相關 Shader, 因為使用的是后處理, 是無法在頂點階段計算世界坐標位置后通過插值在片元階段獲得片元坐標位置的, 我們可以通過視錐的4個射線配合深度圖來進行世界坐標還原. 下圖表示了視錐體 :

  后處理的頂點程序可以看成是渲染 ABCD 組成的近裁面的程序, 它只有4個頂點, 如果我們可以將OA, OB, OC, OD 四條射線存入頂點程式, 那么在片元階段就能獲得自動插值的相機到片元對應的近裁面的射線, 因為深度值 z 是一個非透視值( 也就是說透視投影矩陣雖然變換了z值, 可是z值直接保留到了w中, 其實是沒有被變換的意思 ), 而 x, y 是經過透視變換的, 那么剛好四個射線方向通過GPU插值就符合逆透視變換了( Z在向量插值中不變 ).

  假設 ABCD 面現在不是近裁面, 而是離 O 點距離為1的裁面, 那么 ABCD 的中心 M 點跟 O 點的射線 OM 的長度就是1, 那么 O 點片元代表的位置就可以簡單計算出來了 : 

    float3 interpolatedRay = OM 向量(世界坐標系)
    float linearDepth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, float2(0.5, 0.5))); // 0.5是螢屏中點
    float3 wpos = _WorldSpaceCameraPos + linearDepth * interpolatedRay.xyz;

  使用相機位置 + OM射線方向 * 深度 就可以算出來了. 那么其他片元怎么計算呢? 使用 OA, OB, OC, OD 向量讓 GPU 自動插值計算即可, 其實 OM 向量就是它們的插值結果, 計算這四個向量也有幾種方法, 我試了在頂點階段通過判斷頂點Index來計算, 不過似乎結果不正確, 就直接在 C# 中計算了(老版本的Fog Shader就是這樣計算的) : 

            Matrix4x4 frustumCorners = Matrix4x4.identity;
            //先計算近裁剪平面的四個角對應的向量  
            float fov = _cam.fieldOfView;
            float near = _cam.nearClipPlane;
            float aspect = _cam.aspect;

            var cameraTransform = _cam.transform;

            float halfHeight = near * Mathf.Tan(fov * 0.5f * Mathf.Deg2Rad);
            Vector3 toRight = cameraTransform.right * halfHeight * aspect;
            Vector3 toTop = cameraTransform.up * halfHeight;

            Vector3 topLeft = cameraTransform.forward * near + toTop - toRight;
            float scale = topLeft.magnitude / near;

            topLeft.Normalize();
            topLeft *= scale;

            Vector3 topRight = cameraTransform.forward * near + toRight + toTop;
            topRight.Normalize();
            topRight *= scale;

            Vector3 bottomLeft = cameraTransform.forward * near - toTop - toRight;
            bottomLeft.Normalize();
            bottomLeft *= scale;

            Vector3 bottomRight = cameraTransform.forward * near + toRight - toTop;
            bottomRight.Normalize();
            bottomRight *= scale;
            //將4個向量存盤在矩陣型別的frustumCorners 中  
            frustumCorners.SetRow(0, bottomLeft);
            frustumCorners.SetRow(1, bottomRight);
            frustumCorners.SetRow(2, topRight);
            frustumCorners.SetRow(3, topLeft);

            Shader.SetGlobalMatrix("_FrustumCornersRay", frustumCorners);

  這樣就把  OA, OB, OC, OD 傳入 Shader 了, 只要在頂點階段根據 UV 的象限取出對應的向量來就行了. 我們可以獲取片元對應的世界坐標之后, 就要把世界坐標轉換到觀察者相機的視口之內去, 看看它是不是在觀察者相機視野內 : 

  把觀察者相機的矩陣以及引數傳入Shader

    Shader.SetGlobalFloat("_cameraNear", _cam.nearClipPlane);
    Shader.SetGlobalFloat("_cameraFar", _cam.farClipPlane);

    Shader.SetGlobalMatrix("_DepthCameraWorldToLocalMatrix", _cam.worldToCameraMatrix);
    Shader.SetGlobalMatrix("_DepthCameraProjectionMatrix", _cam.projectionMatrix);

  轉換坐標到觀察者視口( wpos 就是前面計算出來的世界坐標 ) : 

    // 透視投影之后的坐標轉換成NDC坐標, 再轉換成視口坐標 
    float2 ProjPosToViewPortPos(float4 projPos)
    {
        float3 ndcPos = projPos.xyz / projPos.w;
        float2 viewPortPos = float2(0.5f * ndcPos.x + 0.5f, 0.5f * ndcPos.y + 0.5f);
        return viewPortPos;
    }
   float3 viewPosInDepthCamera = mul(_DepthCameraWorldToLocalMatrix, float4(wpos, 1)).xyz;
    float4 projPosInDepthCamera = mul(_DepthCameraProjectionMatrix, float4(viewPosInDepthCamera, 1));
    float2 viewPortPosInDepthCamera = ProjPosToViewPortPos(projPosInDepthCamera);
    float depthCameraViewZ = -viewPosInDepthCamera.z;

  判斷是否在觀察者視野內, 不在視野內的直接回傳原值 : 

    if (viewPortPosInDepthCamera.x < 0 || viewPortPosInDepthCamera.x > 1)
    {
        return col;
    }
    if (viewPortPosInDepthCamera.y < 0 || viewPortPosInDepthCamera.y > 1)
    {
        return col;
    }
    if (depthCameraViewZ< _cameraNear || depthCameraViewZ > _cameraFar)
    {
        return col;
    }

  在視野內的, 就需要從觀察者相機的深度圖獲取深度進行深度對比 : 

    Shader.SetGlobalTexture("_ObserverDepthTexture", getDepthTexture.renderTexture); // 把深度圖傳入主相機Shader
    float2 depthCameraUV = viewPortPosInDepthCamera.xy;
#if UNITY_UV_STARTS_AT_TOP 
    if (_MainTex_TexelSize.y < 0)
    {
        depthCameraUV.y = 1 - depthCameraUV.y;
    }
#endif
    float observer01Depth = tex2D(_ObserverDepthTexture, depthCameraUV).r;
    float observerEyeDepth = LinearDepthToDistance(observer01Depth, _cameraNear, _cameraFar);

    float4 finalCol = col * 0.8;
    float4 visibleColor = _visibleColor * 0.4f;
    float4 unVisibleColor = _unVisibleColor * 0.4f;
    // depth check
    if (depthCameraViewZ <= observerEyeDepth)
    {
        return finalCol + visibleColor;
    }
    else
    {        
        // bias check
        if (abs(depthCameraViewZ - observerEyeDepth) <= _FieldBias)
        {
            return finalCol + visibleColor;
        }
        else
        {
            return finalCol + unVisibleColor;
        }
    }    

  深度貼圖是我們自己計算的01深度值, 這里解壓深度貼圖也是使用觀察者相機的 nearClipPlane, farClipPlane 直接計算得到的, 最基本的功能就完全實作了, 那些一大堆 if else 就由他去吧, 永遠習慣不了著色語言的寫法.

 

  那么說讓人頭大的地方在哪呢? 上面程序中也出現過了, 包括 C# 那邊提供的 API 沒有檔案不會用, 深度圖解壓函式自己實作會出錯( 完全按照官方人員論壇回復來寫的 ), 在頂點階段自己計算視錐射線出錯( 又難測驗又難找資料 ), 還有上文中的宏 UNITY_UV_STARTS_AT_TOP 這些我哪知道什么時候要加什么時候不用加啊, 甚至 C# 中的 GL 函式還有 GL.GetGPUProjectionMatrix() 這樣的功能.

  其實最希望引擎能實作的是我告訴它我希望用那種坐標系或者用哪種標準來編程, 這樣我就使用習慣的寫法就行了啊, 比如螢屏0,0位置我習慣左上角, 你習慣左下角這樣的. 就不需要每個人都對這些宏熟悉才能寫個Shader. 我覺得都是比較習慣D3D標準的吧.

  Shader.SetGlobalStandard("D3D");    // DX標準
  Shader.SetGlobalStandard("OPENGL");  // OpenGL -- 提供全域設定和單獨設定的功能的話

  

  

  

  最后做出來的只是基本功能, 并沒有對距離深度做樣本估計, 所以會像硬陰影一樣有鋸齒邊, 還有像沒開各項異性的貼圖一樣有撕扯感, 解決這些問題的方法跟 ShadowMap 一樣一樣的.

  ShadowMap 我在 Unity4.x 的時候就試著寫過了, 用的是 VSM 做的軟陰影, 現在寫這個感徑訓是跟那年一樣, 沒有便利性上的提升......

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(Camera))]
public class GetDepthTexture : MonoBehaviour
{
    public RenderTexture renderTexture;
    public Color visibleCol = Color.green;
    public Color unVisibleCol = Color.red;

    private Material _material;
    public Camera _cam { get; private set; }

    public LineRenderer lineRendererTemplate;

    void Start()
    {
        _cam = GetComponent<Camera>();
        _cam.depthTextureMode |= DepthTextureMode.Depth;

        renderTexture = RenderTexture.GetTemporary(Screen.width, Screen.height, 0, RenderTextureFormat.RFloat);
        renderTexture.hideFlags = HideFlags.DontSave;
        _material = new Material(Shader.Find("Custom/GetDepthTexture"));

        _cam.SetTargetBuffers(renderTexture.colorBuffer, renderTexture.depthBuffer);

        if(lineRendererTemplate)
        {
            var dirs = VisualFieldRenderer.GetFrustumCorners(_cam);
            for(int i = 0; i < 4; i++)
            {
                Vector3 dir = dirs.GetRow(i);
                var tagPoint = _cam.transform.position + (dir * _cam.farClipPlane);
                var newLine = GameObject.Instantiate(lineRendererTemplate.gameObject).GetComponent<LineRenderer>();
                newLine.useWorldSpace = false;
                newLine.transform.SetParent(_cam.transform, false);
                newLine.transform.localPosition = Vector3.zero;
                newLine.transform.localRotation = Quaternion.identity;
                newLine.SetPositions(new Vector3[2] { Vector3.zero, _cam.transform.worldToLocalMatrix.MultiplyPoint(tagPoint) });
            }
        }
    }

    private void OnDestroy()
    {
        if(renderTexture)
        {
            RenderTexture.ReleaseTemporary(renderTexture);
        }
        if(_cam)
        {
            _cam.targetTexture = null;
        }
    }
    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if(_material && _cam)
        {
            Shader.SetGlobalColor("_visibleColor", visibleCol);
            Shader.SetGlobalColor("_unVisibleColor", unVisibleCol);

            Shader.SetGlobalFloat("_cameraNear", _cam.nearClipPlane);
            Shader.SetGlobalFloat("_cameraFar", _cam.farClipPlane);

            Shader.SetGlobalMatrix("_DepthCameraWorldToLocalMatrix", _cam.worldToCameraMatrix);
            Shader.SetGlobalMatrix("_DepthCameraProjectionMatrix", _cam.projectionMatrix);

            Graphics.Blit(source, renderTexture, _material);
        }
        Graphics.Blit(source, destination);
    }
}
GetDepthTexture.cs
Shader "Custom/GetDepthTexture"
{
    Properties
    {
        _MainTex("Texture", 2D) = "white" {}
    }

    CGINCLUDE
    #include "UnityCG.cginc"
    struct appdata
    {
        float4 vertex : POSITION;
        float2 uv : TEXCOORD0;
    };

    struct v2f
    {
        float2 uv : TEXCOORD0;
        float4 vertex : SV_POSITION;
    };

    sampler2D _CameraDepthTexture;

    uniform float _cameraFar;
    uniform float _cameraNear;

    float DistanceToLinearDepth(float d, float near, float far)
    {
        float z = (d - near) / (far - near);
        return z;
    }

    v2f vert(appdata v)
    {
        v2f o;
        o.vertex = UnityObjectToClipPos(v.vertex);
        o.uv = v.uv;
        return o;
    }

    fixed4 frag(v2f i) : SV_Target
    {
        float depth  = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);
        depth = LinearEyeDepth(depth);
        depth = DistanceToLinearDepth(depth, _cameraNear, _cameraFar);
        return float4(depth, depth, depth, 1);
    }

    ENDCG

    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always
        //Pass 0 Roberts Operator
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            ENDCG
        }
    }
}
GetDepthTexture.shader

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(Camera))]
public class VisualFieldRenderer : MonoBehaviour
{
    public GetDepthTexture getDepthTexture;
    [SerializeField]
    [Range(0.001f, 1f)]
    public float fieldCheckBias = 0.1f;

    private Material _material;
    private Camera _cam;

    void Start()
    {
        _cam = GetComponent<Camera>();
        _cam.depthTextureMode |= DepthTextureMode.Depth;
        _material = new Material(Shader.Find("Custom/VisualFieldRenderer"));
    }

    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if (_cam && getDepthTexture && getDepthTexture.renderTexture && _material)
        {
            if (getDepthTexture._cam)
            {
                if (getDepthTexture._cam.farClipPlane > _cam.farClipPlane - 500)
                {
                    _cam.farClipPlane = getDepthTexture._cam.farClipPlane + 500;
                }
            }

            Matrix4x4 frustumCorners = GetFrustumCorners(_cam);

            Shader.SetGlobalMatrix("_FrustumCornersRay", frustumCorners);
            Shader.SetGlobalTexture("_ObserverDepthTexture", getDepthTexture.renderTexture);
            Shader.SetGlobalFloat("_FieldBias", fieldCheckBias);
            Graphics.Blit(source, destination, _material);
        }
        else
        {
            Graphics.Blit(source, destination);
        }
    }

    public static Matrix4x4 GetFrustumCorners(Camera cam)
    {
        Matrix4x4 frustumCorners = Matrix4x4.identity;

        float fov = cam.fieldOfView;
        float near = cam.nearClipPlane;
        float aspect = cam.aspect;

        var cameraTransform = cam.transform;

        float halfHeight = near * Mathf.Tan(fov * 0.5f * Mathf.Deg2Rad);
        Vector3 toRight = cameraTransform.right * halfHeight * aspect;
        Vector3 toTop = cameraTransform.up * halfHeight;

        Vector3 topLeft = cameraTransform.forward * near + toTop - toRight;
        float scale = topLeft.magnitude / near;

        topLeft.Normalize();
        topLeft *= scale;

        Vector3 topRight = cameraTransform.forward * near + toRight + toTop;
        topRight.Normalize();
        topRight *= scale;

        Vector3 bottomLeft = cameraTransform.forward * near - toTop - toRight;
        bottomLeft.Normalize();
        bottomLeft *= scale;

        Vector3 bottomRight = cameraTransform.forward * near + toRight - toTop;
        bottomRight.Normalize();
        bottomRight *= scale;

        frustumCorners.SetRow(0, bottomLeft);
        frustumCorners.SetRow(1, bottomRight);
        frustumCorners.SetRow(2, topRight);
        frustumCorners.SetRow(3, topLeft);

        return frustumCorners;
    }

}
VisualFieldRenderer.cs
// Upgrade NOTE: replaced '_CameraToWorld' with 'unity_CameraToWorld'
Shader "Custom/VisualFieldRenderer"
{
    Properties
    {
        _MainTex("Texture", 2D) = "white" {}
    }

    CGINCLUDE
    #include "UnityCG.cginc"
    struct appdata
    {
        float4 vertex : POSITION;
        float2 uv : TEXCOORD0;
    };

    struct v2f
    {
        float2 uv : TEXCOORD0;
        float4 vertex : SV_POSITION;
        float2 uv_depth : TEXCOORD1;
        float4 interpolatedRay : TEXCOORD2;
    };

    sampler2D _MainTex;
    half4 _MainTex_TexelSize;

    sampler2D _CameraDepthTexture;

    uniform float _FieldBias;
    uniform sampler2D _ObserverDepthTexture;    
    uniform float4x4 _DepthCameraWorldToLocalMatrix;
    uniform float4x4 _DepthCameraProjectionMatrix;
    uniform float _cameraFar;
    uniform float _cameraNear;
    uniform float4x4 _FrustumCornersRay;

    float4 _unVisibleColor;
    float4 _visibleColor;
    
    float2 ProjPosToViewPortPos(float4 projPos)
    {
        float3 ndcPos = projPos.xyz / projPos.w;
        float2 viewPortPos = float2(0.5f * ndcPos.x + 0.5f, 0.5f * ndcPos.y + 0.5f);
        return viewPortPos;
    }

    float LinearDepthToDistance(float z, float near, float far)
    {
        float d = z * (far - near) + near;
        return d;
    }

    //頂點階段
    v2f vert(appdata v)
    {
        v2f o;
        o.vertex = UnityObjectToClipPos(v.vertex);        // MVP matrix screen pos
        o.uv = v.uv;
        o.uv_depth = v.uv;

#if UNITY_UV_STARTS_AT_TOP  
        if (_MainTex_TexelSize.y < 0)
        {
            o.uv_depth.y = 1 - o.uv_depth.y;
        }
#endif

        int index = 0;
        if (v.uv.x < 0.5 && v.uv.y < 0.5) {
            index = 0;
        }
        else if (v.uv.x > 0.5 && v.uv.y < 0.5) {
            index = 1;
        }
        else if (v.uv.x > 0.5 && v.uv.y > 0.5) {
            index = 2;
        }
        else
        {
            index = 3;
        }
        o.interpolatedRay = _FrustumCornersRay[index];

        return o;
    }

    //片元階段
    fixed4 frag(v2f i) : SV_Target
    {
        float4 col = tex2D(_MainTex, i.uv);

        float z = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);

        float depth = Linear01Depth(z);
        if (depth >= 1)
        {
            return col;
        }

        // correct in Main Camera
        float linearDepth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv_depth));
        float3 wpos = _WorldSpaceCameraPos + linearDepth * i.interpolatedRay.xyz;

        // correct in Depth Camera
        float3 viewPosInDepthCamera = mul(_DepthCameraWorldToLocalMatrix, float4(wpos, 1)).xyz;
        float4 projPosInDepthCamera = mul(_DepthCameraProjectionMatrix, float4(viewPosInDepthCamera, 1));
        float2 viewPortPosInDepthCamera = ProjPosToViewPortPos(projPosInDepthCamera);
        float depthCameraViewZ = -viewPosInDepthCamera.z;

        if (viewPortPosInDepthCamera.x < 0 || viewPortPosInDepthCamera.x > 1)
        {
            return col;
        }
        if (viewPortPosInDepthCamera.y < 0 || viewPortPosInDepthCamera.y > 1)
        {
            return col;
        }
        if (depthCameraViewZ <= _cameraNear || depthCameraViewZ >= _cameraFar)
        {
            return col;
        }


        // correct in depth camera
        float2 depthCameraUV = viewPortPosInDepthCamera.xy;
#if UNITY_UV_STARTS_AT_TOP 
        if (_MainTex_TexelSize.y < 0)
        {
            depthCameraUV.y = 1 - depthCameraUV.y;
        }
#endif
        float observer01Depth = tex2D(_ObserverDepthTexture, depthCameraUV).r;
        float observerEyeDepth = LinearDepthToDistance(observer01Depth, _cameraNear, _cameraFar);

        float4 finalCol = col * 0.8;
        float4 visibleColor = _visibleColor * 0.4f;
        float4 unVisibleColor = _unVisibleColor * 0.4f;
        // depth check
        if (depthCameraViewZ <= observerEyeDepth)
        {
            return finalCol + visibleColor;
        }
        else
        {        
            // bias check
            if (abs(depthCameraViewZ - observerEyeDepth) <= _FieldBias)
            {
                return finalCol + visibleColor;
            }
            else
            {
                return finalCol + unVisibleColor;
            }
        }    
    }

    ENDCG

    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always
        //Pass 0 Roberts Operator
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            ENDCG
        }
    }
}
VisualFieldRenderer.shader

 

2019.12.02 添加VSM進行濾波

  因為VSM是最容易實作的, 切比雪夫不等式應該是最容易理解的, 測驗一下能否改善一下效果. 一些功能代碼在 https://www.cnblogs.com/tiancaiwrk/p/11957545.html 

單邊形式的不等式 : 

1. 在單邊式中, 當t > u 時, 有原始資料 x >= t 的概率小于右邊等式. 那么計算出來的就是當前像素在觀察者相機中被遮擋的概率了.在單邊式中, 當t > u 時, 有原始資料 x >= t 的概率小于右邊等式. 那么計算出來的就是當前像素在觀察者相機中被遮擋的概率了.

2. 把深度作為資料組, 深度的平方作為中間計算資料, 存進雙通道貼圖中即可, 再通過一次 Blur 作為求取平均值的程序, 就得到后續的計算資料了.

因為方差可以根據 平方的均值 - 均值的平方 計算 :

 3. 將式子代入 (5) 中, t 就直接用片元在觀察者相機中的實際深度就可以了.

 

總代碼 : 

using UnityEngine;

public static class GLHelper
{
    public static void Blit(Texture source, Material material, RenderTexture destination, int materialPass = 0)
    {
        if(material.SetPass(materialPass))
        {
            material.mainTexture = source;
            Graphics.SetRenderTarget(destination);

            GL.PushMatrix();
            GL.LoadOrtho();

            GL.Begin(GL.QUADS);
            {
                Vector3 coords = new Vector3(0, 0, 0);
                GL.TexCoord(coords);
                GL.Vertex(coords);

                coords = new Vector3(1, 0, 0);
                GL.TexCoord(coords);
                GL.Vertex(coords);

                coords = new Vector3(1, 1, 0);
                GL.TexCoord(coords);
                GL.Vertex(coords);

                coords = new Vector3(0, 1, 0);
                GL.TexCoord(coords);
                GL.Vertex(coords);
            }
            GL.End();

            GL.PopMatrix();
        }
    }

    public static void CopyTexture(RenderTexture from, Texture2D to)
    {
        if(from && to)
        {
            if((SystemInfo.copyTextureSupport & UnityEngine.Rendering.CopyTextureSupport.RTToTexture) != 0)
            {
                Graphics.CopyTexture(from, to);
            }
            else
            {
                var current = RenderTexture.active;
                RenderTexture.active = from;
                to.ReadPixels(new Rect(0, 0, from.width, from.height), 0, 0);
                to.Apply();
                RenderTexture.active = current;
            }
        }
    }

    #region Blur Imp
    public static Texture2D DoBlur(Texture tex)
    {
        if(tex)
        {
            var material = new Material(Shader.Find("Custom/SimpleBlur"));
            material.mainTexture = tex;

            var tempRenderTexture1 = RenderTexture.GetTemporary(tex.width, tex.height, 0, RenderTextureFormat.ARGB32);
            material.SetVector("_offset", Vector2.up);
            GLHelper.Blit(tex, material, tempRenderTexture1, 0);

            var tempRenderTexture2 = RenderTexture.GetTemporary(tex.width, tex.height, 0, RenderTextureFormat.ARGB32);
            material.SetVector("_offset", Vector2.right);
            GLHelper.Blit(tempRenderTexture1, material, tempRenderTexture2, 0);

            var retTexture = new Texture2D(tex.width, tex.height, TextureFormat.ARGB32, false, true);
            GLHelper.CopyTexture(tempRenderTexture2, retTexture);

            RenderTexture.ReleaseTemporary(tempRenderTexture1);
            RenderTexture.ReleaseTemporary(tempRenderTexture2);

            return retTexture;
        }
        return null;
    }
    public static bool DoBlur(Texture tex, RenderTexture renderTexture)
    {
        if(tex)
        {
            var material = new Material(Shader.Find("Custom/SimpleBlur"));
            material.mainTexture = tex;

            var tempRenderTexture = RenderTexture.GetTemporary(tex.width, tex.height, 0, RenderTextureFormat.ARGB32);
            material.SetVector("_offset", Vector2.up);
            GLHelper.Blit(tex, material, tempRenderTexture, 0);

            material.SetVector("_offset", Vector2.right);
            GLHelper.Blit(tempRenderTexture, material, renderTexture, 0);

            RenderTexture.ReleaseTemporary(tempRenderTexture);

            return true;
        }
        return false;
    }
    #endregion

}
GLHelper.cs
Shader "Custom/SimpleBlur"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_TexelSize;
            uniform float2 _offset;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
#if UNITY_UV_STARTS_AT_TOP
                if (_MainTex_TexelSize.y < 0)
                {
                    o.uv.y = 1 - o.uv.y;
                }
#endif
                return o;
            }
            
            

            fixed4 frag (v2f i) : SV_Target
            {
                float4 col = half4(0, 0, 0, 0);
                // marco for more faster
#define PIXELBLUR(weight, kernel_offset) tex2D(_MainTex, float2(i.uv.xy + _offset * _MainTex_TexelSize.xy * kernel_offset)) * weight

                col += PIXELBLUR(0.05, -4.0);
                col += PIXELBLUR(0.09, -3.0);
                col += PIXELBLUR(0.12, -2.0);
                col += PIXELBLUR(0.15, -1.0);
                col += PIXELBLUR(0.18, 0.0);
                col += PIXELBLUR(0.15, +1.0);
                col += PIXELBLUR(0.12, +2.0);
                col += PIXELBLUR(0.09, +3.0);
                col += PIXELBLUR(0.05, +4.0);

                return col;
            }
            ENDCG
        }
    }
}
SimpleBlur.shader

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(Camera))]
public class GetDepthTexture_VSM : MonoBehaviour
{
    public RenderTexture depthRenderTexture_RG;
    public RenderTexture depthRenderTexture_VSM;
    public Color visibleCol = Color.green;
    public Color unVisibleCol = Color.red;

    private Material _material;
    public Camera _cam { get; private set; }

    public LineRenderer lineRendererTemplate;

    void Start()
    {
        _cam = GetComponent<Camera>();
        _cam.depthTextureMode |= DepthTextureMode.Depth;

        depthRenderTexture_RG = RenderTexture.GetTemporary(Screen.width, Screen.height, 0, RenderTextureFormat.RGFloat, RenderTextureReadWrite.Default, 2);
        depthRenderTexture_RG.hideFlags = HideFlags.DontSave;

        depthRenderTexture_VSM = RenderTexture.GetTemporary(Screen.width, Screen.height, 0, RenderTextureFormat.RGFloat, RenderTextureReadWrite.Default, 2);
        depthRenderTexture_VSM.hideFlags = HideFlags.DontSave;

        _material = new Material(Shader.Find("Custom/GetDepthTexture_VSM"));
        
        if(lineRendererTemplate)
        {
            var dirs = VisualFieldRenderer.GetFrustumCorners(_cam);
            for(int i = 0; i < 4; i++)
            {
                Vector3 dir = dirs.GetRow(i);
                var tagPoint = _cam.transform.position + (dir * _cam.farClipPlane);
                var newLine = GameObject.Instantiate(lineRendererTemplate.gameObject).GetComponent<LineRenderer>();
                newLine.useWorldSpace = false;
                newLine.transform.SetParent(_cam.transform, false);
                newLine.transform.localPosition = Vector3.zero;
                newLine.transform.localRotation = Quaternion.identity;
                newLine.SetPositions(new Vector3[2] { Vector3.zero, _cam.transform.worldToLocalMatrix.MultiplyPoint(tagPoint) });
            }
        }
    }

    private void OnDestroy()
    {
        if(depthRenderTexture_RG)
        {
            RenderTexture.ReleaseTemporary(depthRenderTexture_RG);
        }
        if(_cam)
        {
            _cam.targetTexture = null;
        }
    }
    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if(_material && _cam)
        {
            Shader.SetGlobalColor("_visibleColor", visibleCol);
            Shader.SetGlobalColor("_unVisibleColor", unVisibleCol);

            Shader.SetGlobalFloat("_cameraNear", _cam.nearClipPlane);
            Shader.SetGlobalFloat("_cameraFar", _cam.farClipPlane);

            Shader.SetGlobalMatrix("_DepthCameraWorldToLocalMatrix", _cam.worldToCameraMatrix);
            Shader.SetGlobalMatrix("_DepthCameraProjectionMatrix", _cam.projectionMatrix);

            Graphics.Blit(source, depthRenderTexture_RG, _material);
            GLHelper.DoBlur(depthRenderTexture_RG, depthRenderTexture_VSM);
        }
        Graphics.Blit(source, destination);
    }
}
GetDepthTexture_VSM.cs
Shader "Custom/GetDepthTexture_VSM"
{
    Properties
    {
        _MainTex("Texture", 2D) = "white" {}
    }

    CGINCLUDE
    #include "UnityCG.cginc"
    struct appdata
    {
        float4 vertex : POSITION;
        float2 uv : TEXCOORD0;
    };

    struct v2f
    {
        float2 uv : TEXCOORD0;
        float4 vertex : SV_POSITION;
    };

    sampler2D _CameraDepthTexture;

    uniform float _cameraFar;
    uniform float _cameraNear;

    float DistanceToLinearDepth(float d, float near, float far)
    {
        float z = (d - near) / (far - near);
        return z;
    }

    v2f vert(appdata v)
    {
        v2f o;
        o.vertex = UnityObjectToClipPos(v.vertex);
        o.uv = v.uv;
        return o;
    }

    fixed4 frag(v2f i) : SV_Target
    {
        float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);
        depth = DistanceToLinearDepth(LinearEyeDepth(depth), _cameraNear, _cameraFar);
        return float4(depth, depth * depth, 0, 1);
    }

    ENDCG

    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always
        //Pass 0 Roberts Operator
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            ENDCG
        }
    }
}
GetDepthTexture_VSM.shader

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(Camera))]
public class VisualFieldRenderer_VSM : MonoBehaviour
{
    [SerializeField]
    public GetDepthTexture_VSM getDepthTexture;

    [SerializeField]
    [Range(0.001f, 1f)]
    public float fieldCheckBias = 0.1f;

    private Material _material;
    private Camera _cam;

    void Start()
    {
        _cam = GetComponent<Camera>();
        _cam.depthTextureMode |= DepthTextureMode.Depth;
        _material = new Material(Shader.Find("Custom/VisualFieldRenderer_VSM"));
    }

    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if(_cam && getDepthTexture && getDepthTexture.depthRenderTexture_VSM && _material)
        {
            if(getDepthTexture._cam)
            {
                if(getDepthTexture._cam.farClipPlane > _cam.farClipPlane - 500)
                {
                    _cam.farClipPlane = getDepthTexture._cam.farClipPlane + 500;
                }
            }

            Matrix4x4 frustumCorners = GetFrustumCorners(_cam);

            Shader.SetGlobalMatrix("_FrustumCornersRay", frustumCorners);
            Shader.SetGlobalTexture("_ObserverDepthTexture", getDepthTexture.depthRenderTexture_VSM);
            Shader.SetGlobalFloat("_FieldBias", fieldCheckBias);
            Graphics.Blit(source, destination, _material);
        }
        else
        {
            Graphics.Blit(source, destination);
        }
    }

    public static Matrix4x4 GetFrustumCorners(Camera cam)
    {
        Matrix4x4 frustumCorners = Matrix4x4.identity;

        float fov = cam.fieldOfView;
        float near = cam.nearClipPlane;
        float aspect = cam.aspect;

        var cameraTransform = cam.transform;

        float halfHeight = near * Mathf.Tan(fov * 0.5f * Mathf.Deg2Rad);
        Vector3 toRight = cameraTransform.right * halfHeight * aspect;
        Vector3 toTop = cameraTransform.up * halfHeight;

        Vector3 topLeft = cameraTransform.forward * near + toTop - toRight;
        float scale = topLeft.magnitude / near;

        topLeft.Normalize();
        topLeft *= scale;

        Vector3 topRight = cameraTransform.forward * near + toRight + toTop;
        topRight.Normalize();
        topRight *= scale;

        Vector3 bottomLeft = cameraTransform.forward * near - toTop - toRight;
        bottomLeft.Normalize();
        bottomLeft *= scale;

        Vector3 bottomRight = cameraTransform.forward * near + toRight - toTop;
        bottomRight.Normalize();
        bottomRight *= scale;

        frustumCorners.SetRow(0, bottomLeft);
        frustumCorners.SetRow(1, bottomRight);
        frustumCorners.SetRow(2, topRight);
        frustumCorners.SetRow(3, topLeft);

        return frustumCorners;
    }

}
VisualFieldRenderer_VSM.cs
// Upgrade NOTE: replaced '_CameraToWorld' with 'unity_CameraToWorld'
Shader "Custom/VisualFieldRenderer_VSM"
{
    Properties
    {
        _MainTex("Texture", 2D) = "white" {}
    }

    CGINCLUDE
    #include "UnityCG.cginc"
    struct appdata
    {
        float4 vertex : POSITION;
        float2 uv : TEXCOORD0;
    };

    struct v2f
    {
        float2 uv : TEXCOORD0;
        float4 vertex : SV_POSITION;
        float2 uv_depth : TEXCOORD1;
        float4 interpolatedRay : TEXCOORD2;
    };

    sampler2D _MainTex;
    half4 _MainTex_TexelSize;

    sampler2D _CameraDepthTexture;

    uniform float _FieldBias;
    uniform sampler2D _ObserverDepthTexture;    
    uniform float4x4 _DepthCameraWorldToLocalMatrix;
    uniform float4x4 _DepthCameraProjectionMatrix;
    uniform float _cameraFar;
    uniform float _cameraNear;
    uniform float4x4 _FrustumCornersRay;

    float4 _unVisibleColor;
    float4 _visibleColor;
    
    float2 ProjPosToViewPortPos(float4 projPos)
    {
        float3 ndcPos = projPos.xyz / projPos.w;
        float2 viewPortPos = float2(0.5f * ndcPos.x + 0.5f, 0.5f * ndcPos.y + 0.5f);
        return viewPortPos;
    }

    float LinearDepthToDistance(float z, float near, float far)
    {
        float d = z * (far - near) + near;
        return d;
    }
    float LinearDepthToDistanceSqrt(float z, float near, float far)
    {
        float d = sqrt(z) * (far - near) + near;
        return d * d;
    }

    //頂點階段
    v2f vert(appdata v)
    {
        v2f o;
        o.vertex = UnityObjectToClipPos(v.vertex);        // MVP matrix screen pos
        o.uv = v.uv;
        o.uv_depth = v.uv;

#if UNITY_UV_STARTS_AT_TOP  
        if (_MainTex_TexelSize.y < 0)
        {
            o.uv_depth.y = 1 - o.uv_depth.y;
        }
#endif

        int index = 0;
        if (v.uv.x < 0.5 && v.uv.y < 0.5) {
            index = 0;
        }
        else if (v.uv.x > 0.5 && v.uv.y < 0.5) {
            index = 1;
        }
        else if (v.uv.x > 0.5 && v.uv.y > 0.5) {
            index = 2;
        }
        else
        {
            index = 3;
        }
        o.interpolatedRay = _FrustumCornersRay[index];

        return o;
    }

    //片元階段
    fixed4 frag(v2f i) : SV_Target
    {
        float4 col = tex2D(_MainTex, i.uv);

        float z = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);

        float depth = Linear01Depth(z);
        if (depth >= 1)
        {
            return col;
        }

        // correct in Main Camera
        float linearDepth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv_depth));
        float3 wpos = _WorldSpaceCameraPos + linearDepth * i.interpolatedRay.xyz;

        // correct in Depth Camera
        float3 viewPosInDepthCamera = mul(_DepthCameraWorldToLocalMatrix, float4(wpos, 1)).xyz;
        float4 projPosInDepthCamera = mul(_DepthCameraProjectionMatrix, float4(viewPosInDepthCamera, 1));
        float2 viewPortPosInDepthCamera = ProjPosToViewPortPos(projPosInDepthCamera);
        float depthCameraViewZ = -viewPosInDepthCamera.z;

        if (viewPortPosInDepthCamera.x < 0 || viewPortPosInDepthCamera.x > 1)
        {
            return col;
        }
        if (viewPortPosInDepthCamera.y < 0 || viewPortPosInDepthCamera.y > 1)
        {
            return col;
        }
        if (depthCameraViewZ <= _cameraNear || depthCameraViewZ >= _cameraFar)
        {
            return col;
        }


        // correct in depth camera
        float2 depthCameraUV = viewPortPosInDepthCamera.xy;
#if UNITY_UV_STARTS_AT_TOP
        if (_MainTex_TexelSize.y < 0)
        {
            depthCameraUV.y = 1 - depthCameraUV.y;
        }
#endif

        float2 depthInfo = tex2D(_ObserverDepthTexture, depthCameraUV).rg;
        float observerEyeDepth = LinearDepthToDistance(depthInfo.r, _cameraNear, _cameraFar);

        float4 finalCol = col * 0.8;
        float4 visibleColor = _visibleColor * 0.4f;
        float4 unVisibleColor = _unVisibleColor * 0.4f;
        if (depthCameraViewZ <= observerEyeDepth)
        {
            return finalCol + visibleColor;
        }

        float var = LinearDepthToDistanceSqrt(depthInfo.g, _cameraNear, _cameraFar) - (observerEyeDepth * observerEyeDepth);
        float dis = depthCameraViewZ - observerEyeDepth;
        float ChebychevVal = var / (var + (dis * dis));

        return finalCol + lerp(visibleColor, unVisibleColor, 1 - ChebychevVal);
    }

    ENDCG

    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always
        //Pass 0 Roberts Operator
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            ENDCG
        }
    }
}
VisualFieldRenderer_VSM.shader

 

  這樣使用真實深度作為 t 變數的時候, 其實作為可視域的功能來說不算好, 因為它不像陰影一樣有一個邊緣漸變的程序, 而是應該是個二值化的程序, 看看效果對比 : 

 

 

 

  可以看到VSM在邊緣的地方有模糊, 并且在正方體邊緣也有明顯的縫隙, 這是因為在計算平均深度 (Blur) 的時候這些點周圍是跟無限遠點做的平均, 必然會得到比較大的平均數, 影響了真實計算.

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/17717.html

標籤:其他

上一篇:計算機圖形學學習(1)—— 基礎篇:歡迎來到圖形學的世界

下一篇:關于OpenCASCADE陣列序列的起始值

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more