精华内容
下载资源
问答
  • UE4获取深度缓存

    2020-07-25 20:45:17
    UE4对场景使用“反向”深度缓冲区。 获取 在任意tick函数或者其他函数添加以下的命令: struct DepthPixel //定义深度像素结构体 { float depth; char stencil; char unused1; char unused2; char unused...

    深度像素格式

    在这里插入图片描述

    键入命令vis scenedepthz uv0以查看实际使用的深度缓冲区。UE4对场景使用“反向”深度缓冲区。

    获取

    在任意tick函数或者其他函数添加以下的命令:

    struct DepthPixel	//定义深度像素结构体
    	{
    		float depth;
    		char stencil;
    		char unused1;
    		char unused2;
    		char unused3;
    	};
    
    	float* cpuDataPtr;	// Texture深度值数组首地址
    	TArray<DepthPixel> mydata;	//最终获取色深度值数据
    	FIntPoint buffsize;	//深度长宽大小X和Y
    
    	ENQUEUE_RENDER_COMMAND(ReadSurfaceFloatCommand)(	// 将读取深度数据的命令推给渲染线程进行执行
    		[&cpuDataPtr, &mydata, &buffsize](FRHICommandListImmediate& RHICmdList) //&cpuDataPtr, &mydata, &buffsize为传入的外部参数
    	{
    		FSceneRenderTargets::Get(RHICmdList).AdjustGBufferRefCount(RHICmdList, 1);
    		FTexture2DRHIRef uTex2DRes = FSceneRenderTargets::Get(RHICmdList).GetSceneDepthSurface();	
    		buffsize = uTex2DRes->GetSizeXY();
             uint32 sx = buffsize.X;
    		uint32 sy = buffsize.Y;
             mydata.AddUninitialized(sx * sy);
             uint32 Lolstrid = 0;
    		cpuDataPtr = (float*)RHILockTexture2D(uTex2DRes,0,RLM_ReadOnly,Lolstrid,true);	// 加锁 获取可读depth Texture深度值数组首地址
    		memcpy(mydata.GetData(), cpuDataPtr, sx * sy * sizeof(DepthPixel));		//复制深度数据
    		RHIUnlockTexture2D(uTex2DRes, 0, true);	//解锁
    		FSceneRenderTargets::Get(RHICmdList).AdjustGBufferRefCount(RHICmdList, -1);	
    
    	});
    	FlushRenderingCommands();	//等待渲染线程执行
    
    	mydata; 	//最终获取深度数据
    

    最终返回的mydata数据就是最终的深度值数组,其中每个深度值的结构是DepthPixel,其中一个成员为depth,另外四个不不使用。其中使用上面的几个命令需要添加"RHI.h"头文件

    展开全文
  • 该范例主要在移动端打开osgb场景缓存,通过点击获取选中模型的属性,并以弹框的形式显示属性信息。
  • 1、深度   所谓深度,就是在openGL坐标系中,像素点Z坐标距离摄像机的距离。摄像机可能放在坐标系的任何位置,那么,就不能简单的说Z数值越大或越小,就是越靠近摄像机。  2、深度缓冲区  深度缓冲区原理就是把一...

         1、深度

         所谓深度,就是在openGL坐标系中,像素点Z坐标距离摄像机的距离。摄像机可能放在坐标系的任何位置,那么,就不能简单的说Z数值越大或越小,就是越靠近摄像机。

         2、深度缓冲区

          深度缓冲区原理就是把一个距离观察平面(近裁剪面)的深度值(或距离)与窗口中的每个像素相关联。
          首先,使用glClear(GL_DEPTH_BUFFER_BIT),把所有像素的深度值设置为最大值(一般是远裁剪面)。
          然后,在场景中以任意次序绘制所有物体。硬件或者软件所执行的图形计算把每一个绘制表面转换为窗口上一些像素的集合,此时并不考虑是否被其他物体遮挡。
          其次,OpenGL会计算这些表面和观察平面的距离。如果启用了深度缓冲区,在绘制每个像素之前,OpenGL会把它的深度值和已经存储在这个像素的深度值进行比较。新像素深度值<原先像素深度值,则新像素值会取代原先的;反之,新像素值被遮挡,他颜色值和深度将被丢弃。

          为了启动深度缓冲区,必须先启动它,即glEnable(GL_DEPTH_TEST)。每次绘制场景之前,需要先清除深度缓冲区,即glClear(GL_DEPTH_BUFFER_BIT),然后以任意次序绘制场景中的物体。

          数学基础:

          待渲染的照相机空间中的深度经常定义为近距 near 到远距 far 之间的 z 值,Z坐标和X、Y坐标一样。在变换、裁减和透视除法后,Z的范围为-1.0~1.0。DepthRange映射指定Z坐标的变换,这与用于将X和Y映射到窗口坐标的视口变换类似,透视变换之后,得到新的 z' 值:

    z'=\frac{\mathit{far}+\mathit{near}}{\mathit{far}-\mathit{near}} +\frac{1}{z} (\frac{-2 \cdot \mathit{far} \cdot \mathit{near}}{\mathit{far}-\mathit{near}} )

         其中 z 是照相机空间的值,它有时候也表示为 w 或者 w'。

          结果 z' 是在 -1 到 1 之间归一化之后的值,其中近距 near 平面位于 -1 处,远距 far 平面位于 1 处。在这个范围之外的相应点在视图体之外,不需要进行渲染。

         为了实现深度缓冲,在整个屏幕空间上的对当前多边形顶点之间进行插值来计算 z' 的值,通常这些中间数值在深度缓冲区中用定点数格式保存。距离近距 near 平面越近,z' 值越密;距离越远,z' 值越稀。这样距离照相机越近精度越高。near 平面距离照相机越近,则远距离位置的精度越低。near 平面距离照相机太近是在远距离物体产生人为误差的一个常见因素。

           3、深度测试

           OpenGL中的深度测试是采用深度缓存器算法,消除场景中的不可见面。在默认情况下,深度缓存中深度值的范围在0.0到1.0之间,这个范围值可以通过函数:
            glDepthRange (nearNormDepth, farNormalDepth);
           将深度值的范围变为nearNormDepth到farNormalDepth之间。这里nearNormDepth和farNormalDepth可以取0.0到1.0范围内的任意值,甚至可以让nearNormDepth > farNormalDepth。这样,通过glDepthRange函数可以在透视投影有限观察空间中的任意区域进行深度测试。
           另一个非常有用的函数是:
            glClearDepth (maxDepth);
           参数maxDepth可以是0.0到1.0范围内的任意值。glClearDepth用maxDepth对深度缓存进行初始化,而默认情况下,深度缓存用1.0进行初始化。由于在进行深度测试中,大于深度缓存初始值的多边形都不会被绘制,因此glClearDepth函数可以用来加速深度测试处理。这里需要注意的是指定了深度缓存的初始化值之后,应调用:
            glClear(GL_DEPTH_BUFFER_BIT);   完成深度缓存的初始化。
           在深度测试中,默认情况是将需要绘制的新像素的z值与深度缓冲区中对应位置的z值进行比较,如果比深度缓存中的值小,那么用新像素的颜色值更新帧缓存中对应像素的颜色值。这种比较测试的方式可以通过函数:
            glDepthFunc(func);
    进行修改。其中参数func的值可以为GL_NEVER(没有处理)、GL_ALWAYS(处理所有)、GL_LESS(小于)、GL_LEQUAL(小于等于)、GL_EQUAL(等于)、GL_GEQUAL(大于等于)、GL_GREATER(大于)或GL_NOTEQUAL(不等于),其中默认值是GL_LESS。这些测试可以在各种应用中减少深度缓存处理的的计算。

    展开全文
  • OPENGL深度缓存精度问题及解决

    千次阅读 2015-11-09 22:24:32
    前段时间做的小项目需要读取场景的深度图,本打算使用OPENGL自带函数glReadPiexles()去实现此功能,但OPENGL中只提供读取单个像素处的深度信息,不支持读取整个深度缓存的功能。且当时感觉读取到深度是个单字节的,...

        前段时间做的小项目需要读取场景的深度图,本打算使用OPENGL自带函数glReadPiexles()去实现此功能,但OPENGL中只提供读取单个像素处的深度信息,不支持读取整个深度缓存的功能。且当时感觉读取到深度是个单字节的,也看到网上有人说深度缓冲和模板缓冲共用4个字节,就自己使用GLSL改写了渲染管道,将深度信息直接渲染出来,这种方法可生成32位精度的深度图。这段时间又翻阅了OPENGL,发现深度缓冲并不是像网上某些人说的(他们可能指的很久以前或者其它渲染引擎)只占一个或两个字节。OPENGL深度缓冲的可为8,16,24,32都可以,但GLUT没有提出直接 设置方式,自动选择最优的深度位数。而我们若想改变深度缓冲的每个像素所占字节,有以下两种方案:  

        一,使用WINDOWS下的提出的设置渲染场景的方式,设置像素格式,可实现深度位设置。.

      pfd.cDetpBit=24;

      二,使用帧缓存P Frame Buffer为帧缓存设置深度缓存时设置深度位数 //创建FBO

    
      glGenFramebuffersEXT(1, &fbo);
      glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
      // 创建深度缓存
      glGenRenderbuffersEXT(1, &depthBuffer);
      glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthBuffer);
      glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT32, width, height);//设置为32

         如果想查询当前环境的深度缓存可使用 glGetIntegerv(GL_DEPTH_BITS,&x); 深度缓存的作用就不多说了,下面说说为什么设置深度缓冲的位数和对应的解决方法。深度缓存位数越高,代表深度缓冲的精度也就越高,在通过ZBUFFE进行比较渲染时就不容易出现Z-fight问题,如果当前深度缓冲下,仍出现了Z-fight问题,说明此时深度缓冲精度不够,此外在使用阴影贴图(shadow Map)方式生成阴影时也需要高精度的深度缓冲。

        解决方法主要有三个:

          一,OPENGL中可使用改变深度缓存位数的方式稍加改善,有的显卡已经支持浮点数深度缓存,这个时候使用浮点缓存可更加提高,这个思路 就是尽可能提高深度缓存精度,可解决部分Z-Fighting问题。对于生成阴影的方面,除了采用这个方式外,还可通过过自己SHADER语言重写ZBUFFER缓存的方式来提高精度,这个时候深度信息你可以设置DOUBLE型,也就没有这么多限制,但这种方式增加了计算量。

    二,就是通过深度偏移方式来解决Z-fignth问题,OPENGL使用下面方式,

    rdener1()//绘制物体glEnable(GL_POLYGON_OFFSET_FILL);
    glPolygonOffset(0.0f,-1.0f)
    rdener2()//绘制物体

    这种方式,不同移动,移动后渲染,物体不在原来位置,而使用深度偏移后,物体 仍在原来位置。

    三,是网上一位前辈说的,增大近裁剪面距离,公式推导有兴趣的阅读http://www.cnitblog.com/lethep/articles/25570.html

     

    展开全文
  • 深度(Depth),在各种效果中都会用到,学会在Unity中如何获取,也是很有用的。 后续很多一些其他的效果都会与深度有关。 获取深度的方法 下面再简单介绍一次吧: 在Unity中获取,可以通过脚本层(CSharp层)设置...

    深度(Depth),在各种效果中都会用到,学会在Unity中如何获取,也是很有用的。
    后续很多一些其他的效果都会与深度有关。
    Unity官方在SIGGRAPH2011有分享过一些使用深度制作的特效,文档:SIGGRAPH2011 Special Effect with Depth.pdf
    如果多年后,下载不了,链接无效了,可以点击这里(Passworld:cmte)下载(我收藏到网盘了)

    由于篇幅原因,本文只介绍:

    • 如何获取纹理;
    • 如何读取数据;
    • 理解数据的来源。

    获取深度的方法

    下面再简单介绍一次吧:

    • 在Unity中获取,可以通过脚本层(CSharp层)设置Camera.depthTextureMode属性;然后在Shader定义对应变量获取。之前写过一篇,关于后处理获取深度描边的文章此方法要留意设置好Shader tag的Queue=Geometry(<=2500),和LightMode=ShadowCaster。
    • 通过Camera.RenderWithShader替换Shader,渲染到RT,在传入Shader的方式。之前写过一篇,关于Camera.RenderWithShader等相关用法此方法,通常只要有RenderType=Opaque就好了。

    设置Camera.depthTextureMode方式获取

    在CSharp脚本层,设置Camera.depthTextureMode = DepthTextureMode.Depth;或是Camera.depthTextureMode = DepthTextureMode.DepthNormals;,然后在Shader层声明_CameraDepthTexture或是_CameraDepthNormalsTexture;来获取,如下伪代码:

    CSharp脚本

    public class ScriptName : MonoBehaviour {
    	private Camera cam;
    	private void Start() {
    		cam = gameObject.GetComponent<Camera>();
    		cam.depthTextureMode |= DepthTextureMode.Depth;
    		cam.depthTextureMode |= DepthTextureMode.DepthNormals;
    	}
    	...
    }
    

    Shader

    ...
    sampler2D _CameraDepthTexture; // 如果Camera.depthTextureMode = DepthTextureMode.Dept的Flag就可以获取这个uniform
    sampler2D _CameraDepthNormalsTexture; // 如果Camera.depthTextureMode = DepthTextureMode.DepthNormals的Flag就可以获取该uniform
    ...
    

    Camera.RenderWithShader方式获取

    现在脚本层对Camera.RenderWithShader到RT上,再传入Shader,如下伪代码:

    参考这篇:定制自己的 Depth Texture

    用于绘制深度的Shader

    // vertex:
    ## o.depth = o.pos.z; // 这是错误的
    o.depth = -mul(UNITY_MATRIX_MV, i.vertex).z; // 这是正确的
    
    // fragment:
    // 这是错误的
    {
        ## float n = _ProjectionParams.y;
        ## float f = _ProjectionParams.z;
        ## float c = (i.depth - n) / f;
        ## return c;
    }
    // 这是正确的
    {
        float f = _ProjectionParams.z;
        float c = i.depth / f;
    }
    

    或是这篇:Unity Shader 基础(3) 获取深度纹理

    v2f vert( appdata_base v ) 
    {
        v2f o;
        o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
        o.nz.xyz = COMPUTE_VIEW_NORMAL;
        o.nz.w = COMPUTE_DEPTH_01;
        return o;
    }
    
    fixed4 _Color;
    fixed4 frag(v2f i) : SV_Target 
    {
        //clip(_Color.a-0.01);
        return EncodeDepthNormal (i.nz.w, i.nz.xyz);
    }
    

    调用Camera.RenderWithShader的CSharp

    public class ScriptName : MonoBehaviour {
    	...
    	private Camera cam;
    	private int depthHash;
    	private RenderTexture customDepthRT;
    	private void Start() {
    		depthHash = Shader.PropertyToID("_CustomDepthTexture");
    		cam = gameObject.GetComponent<Camera>();
    		customDepthRT = RenderTexture.GetTemporary(Screen.width, Screen.height);
    	}
    	private void OnPreRender() {
            var srcTT = cam.targetTexture;
            var srcClearFlags = cam.clearFlags;
            var srcBgColor = cam.backgroundColor;
    
            // 测试RenderWithShader
            // RenderWithShader是调用时就会去执行替换,并渲染相机的内容
            cam.backgroundColor = Color.black;
            cam.clearFlags = CameraClearFlags.Color;
            cam.targetTexture = replaceColorRT;                     // 渲染目标到rt
            // 立刻渲染Shader中的pass有"RenderType"的tag的对象
            // 所以你的替换使用的Shader中的pass的tag要设置好友"RenderType"="Opaque"就好了
            // 这里最好用"RenderType"="Opaque",因为内置的很多shader,也都是对不透明对象用这个tag标记了的
            cam.RenderWithShader(replaceShader, "RenderType");
    
            cam.targetTexture = srcTT;                              // 恢复渲染目标,等设置
            cam.clearFlags = srcClearFlags;
            cam.backgroundColor = srcBgColor;
    		// 设置全局的_CustomDepthTexture纹理
    		Shader.SetGlobalTexture(depthHash , replaceColorRT);
    	}
    	...
    }
    

    使用_CustomDepthTexture的Shader

    ...
    sampler2D _CustomDepthTexture; // 声明一下对应的全局纹理就好了,然后在后续着色器中都可以使用到了
    ...
    

    使用Unity提供的深度纹理时,注意下面的问题:

    • 直接使用_CameraDepthTexture纹理R通道值显示时,几乎黑色或是白色的问题,一般都是因为Camera的near,far差值太大导致,因为该_CameraDepthTexture R通道存储的不是线性,它存储的是NDC下的z值。
    • _CameraDepthNormalTexture解码BA通道出来的深度值不会有_CameraDepthTexture的问题,因为在编码时,就处理了线性。
    • 深度纹理只绘制shader中的tag的"Queue"="Geometry"队列之前的所有物体,Geometry=2500,就是说<=2500的,都会绘制到深度纹理中。并且shader中要有某个pass的tag有LightMode=ShadowCaster的。关于LightMode的pass tag可以查看官方手册或是API的说明。

    实践

    简写说明

    什么是ndc,ndc.z

    什么是ndc,它是NDC(Normalized Device Coordinates)的简写。
    ndc.z就是ndc坐标空间下的z轴的值。

    ndc是在GPU内置的几何变换管线中的一部分处理,有兴趣可以参考之前写的一篇用英文总结(因为这些描述用英文表达比较准确):OpenGL Transformation 几何变换的顺序概要(MVP,NDC,Window坐标变换过程)

    什么是eyeZ

    eyeZ中的eye代表:View/Eye/Camera Space。
    所以eyeZ可以理解为:视图空间下z轴值。

    使用unity内置_CameraDepthTexture纹理

    注意:在unity的_CameraDepthTexture中R通道存储的是非线性的ndc下的z值,这点与后面使用的_CameraDepthNormalsTexture的不同。参考:Unity3D中的深度纹理和法线纹理

    但是unity在正交相机下,_CameraDepthTexture的是一个EyeZ/Far的线性值(后面有将)==Linear01Depth。

    Shader

    先准备好要获取,并显示深度的shader

    // jave.lin 2020.03.09
    Shader "Custom/GetDepthTexture" {
        SubShader {
            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 _CameraDepthTexture;
                v2f vert (appdata v) {
                    v2f o;
                    o.vertex = UnityObjectToClipPos(v.vertex);
                    o.uv = v.uv;
                    return o;
                }
                fixed4 frag (v2f i) : SV_Target {
                    return Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv));
                }
                ENDCG
            }
        }
    }
    
    

    Material

    材质:GetDepthTextureMat,设置好使用上面的shader
    在这里插入图片描述

    CSharp

    脚本挂载到Camera上,设置好Mat材质:GetDepthTextureMat

    // jave.lin 2020.03.09
    using UnityEngine;
    public class GetDepthTextureScript1 : MonoBehaviour
    {
        public Material mat;
        private Camera cam;
        private void Start()
        {
            cam = gameObject.GetComponent<Camera>();
            cam.depthTextureMode |= DepthTextureMode.Depth;
            cam.depthTextureMode |= DepthTextureMode.DepthNormals;
        }
        private void OnRenderImage(RenderTexture source, RenderTexture destination)
        {
            Graphics.Blit(null, destination, mat);
        }
    }
    
    

    运行效果

    在这里插入图片描述

    使用_CameraDepthNormalsTexture纹理

    注意:在unity的_CameraDepthNormalsTexture中BA(ZW)通道存储的是Linear01Depth=线性z值/far的比例值,这点与后面使用的_CameraDepthTexture的不同。Unity3D中的深度纹理和法线纹理

    就只调整shader就好了。

    // jave.lin 2020.03.09
    Shader "Custom/GetDepthTexture" {
        SubShader {
            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 _CameraDepthTexture;
                sampler2D _CameraDepthNormalsTexture;
                v2f vert (appdata v) {
                    v2f o;
                    o.vertex = UnityObjectToClipPos(v.vertex);
                    o.uv = v.uv;
                    return o;
                }
                fixed4 frag (v2f i) : SV_Target {
                    //return Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv));
                    float4 depthNormals = SAMPLE_RAW_DEPTH_TEXTURE(_CameraDepthNormalsTexture, i.uv);
                    return DecodeFloatRG (depthNormals.zw);
                }
                ENDCG
            }
        }
    }
    
    

    可以看到frag函数中,我们该用了_CameraDepthNormalsTexture的方式了。

    自定义的深度图

    深度纹理像素编码的Shader

    在VS阶段使用COMPUTE_VIEW_NORMAL宏得到视图空间下的法线,COMPUTE_DEPTH_01宏得到视图空间下的深度。

    COMPUTE_VIEW_NORMAL宏内容如下:

    #define COMPUTE_VIEW_NORMAL normalize(mul((float3x3)UNITY_MATRIX_IT_MV, v.normal))
    

    COMPUTE_DEPTH_01宏内容如下:

    #define COMPUTE_DEPTH_01 -(UnityObjectToViewPos( v.vertex ).z * _ProjectionParams.w)
    

    然后在FS阶段EncodeDepthNormal(depth, normal),将法线编码到像素的xy(rg)通道,将深度编码到像素的zw(ba)通道。

    EncodeDepthNormal宏内容如下:

    // Encoding/decoding [0..1) floats into 8 bit/channel RG. Note that 1.0 will not be encoded properly.
    inline float2 EncodeFloatRG( float v )
    {
        float2 kEncodeMul = float2(1.0, 255.0);
        float kEncodeBit = 1.0/255.0;
        float2 enc = kEncodeMul * v;
        enc = frac (enc);
        enc.x -= enc.y * kEncodeBit;
        return enc;
    }
    // Encoding/decoding view space normals into 2D 0..1 vector
    inline float2 EncodeViewNormalStereo( float3 n )
    {
        float kScale = 1.7777;
        float2 enc;
        enc = n.xy / (n.z+1);
        enc /= kScale;
        enc = enc*0.5+0.5;
        return enc;
    }
    inline float4 EncodeDepthNormal( float depth, float3 normal )
    {
        float4 enc;
        enc.xy = EncodeViewNormalStereo (normal);
        enc.zw = EncodeFloatRG (depth);
        return enc;
    }
    

    然后是我们的shader

    // jave.lin 2020.03.09
    Shader "Custom/CustomDepthTexture" {
        SubShader {
            Tags { "RenderType"="Opaque" }
            LOD 100
            Pass {
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #include "UnityCG.cginc"
                struct appdata {
                    float4 vertex : POSITION;
                    float3 normal : NORMAL;
                };
                struct v2f {
                    float4 vertex : SV_POSITION;
                    float4 depthNormals : TEXCOORD0;
                };
                sampler2D _MainTex;
                float4 _MainTex_ST;
                v2f vert (appdata v) {
                    v2f o;
                    o.vertex = UnityObjectToClipPos(v.vertex);
                    o.depthNormals.xyz = COMPUTE_VIEW_NORMAL;
                    o.depthNormals.w = COMPUTE_DEPTH_01;
                    return o;
                }
                fixed4 frag (v2f i) : SV_Target { 
                    return EncodeDepthNormal(i.depthNormals.w, i.depthNormals.xyz);
                }
                ENDCG
            }
        }
    }
    
    

    Unity 官方提供的:获取对象的深度信息的例子

    下面是例子:

    Shader "Render Depth" {
        SubShader {
            Tags { "RenderType"="Opaque" }
            Pass {
                CGPROGRAM
    
                #pragma vertex vert
                #pragma fragment frag
                #include "UnityCG.cginc"
    
                struct v2f {
                    float4 pos : SV_POSITION;
                    float2 depth : TEXCOORD0;
                };
    
                v2f vert (appdata_base v) {
                    v2f o;
                    o.pos = UnityObjectToClipPos(v.vertex);
                    UNITY_TRANSFER_DEPTH(o.depth);
                    return o;
                }
    
                half4 frag(v2f i) : SV_Target {
                    UNITY_OUTPUT_DEPTH(i.depth);
                }
                ENDCG
            }
        }
    }
    

    CSharp

    调用深度纹理像素编码的Shader
    然后设置到全局的uniform纹理_CustomDepthNormalsTexture;

    // jave.lin 2020.03.09
    using UnityEngine;
    public class GetDepthTextureScript2 : MonoBehaviour
    {
        public Material mat;        // 将_CustomDepthNormalsTexture解码并显示用的shader材质
        public Shader shader;       // 将深度,与法线编码到_CustomDepthNormalsTexture上的shader
        private GameObject camGO;   // 临时用的Camera,用于每帧绘制前先将_CustomDepthNormalsTexture绘制到RT
        private Camera cam;         // 原来主Camera
        [SerializeField] private RenderTexture rt;  // 打上[SerializeField]的Attribute方便在Inspector上双击查看RT的内容
        private int depthHash;      // 获取属性字符的HASH
        private void Start()
        {
            camGO = new GameObject("DrawCustomDepthNormalsTextureCam");
            camGO.SetActive(false);
            cam = camGO.AddComponent<Camera>();
            cam.CopyFrom(gameObject.GetComponent<Camera>());
            depthHash = Shader.PropertyToID("_CustomDepthNormalsTexture");
        }
        private void OnPreRender()
        {
            if (rt == null || rt.width != Screen.width || rt.height != Screen.height)
            {
                if (rt != null) RenderTexture.ReleaseTemporary(rt);
                rt = RenderTexture.GetTemporary(Screen.width, Screen.height, 24);
            }
            // 临时Camera不需要备份
             备份原始属性
            //var srcTT = cam.targetTexture;
            //var srcClearFlags = cam.clearFlags;
            //var srcBgColor = cam.backgroundColor;
    
            // 测试RenderWithShader
            // RenderWithShader是调用时就会去执行替换,并渲染相机的内容
            cam.backgroundColor = new Color(0.5f, 0.5f, 1f); // 默认的法线值
            cam.clearFlags = CameraClearFlags.Color;
            // 渲染目标到rt
            cam.targetTexture = rt;
            // 立刻渲染Shader中的pass有"RenderType"的tag的对象
            // 所以你的替换使用的Shader中的pass的tag要设置好友"RenderType"="Opaque"就好了
            // 这里最好用"RenderType"="Opaque",因为内置的很多shader,也都是对不透明对象用这个tag标记了的
            // 所以自定义的替换绘制,不需要"LightMode"="ShadowCaster"的tag也可以绘制到我们想要的目标纹理
            cam.RenderWithShader(shader, "RenderType");
    
            // 临时Camera不需要恢复
             恢复渲染目标,等设置
            //cam.targetTexture = srcTT;
            //cam.clearFlags = srcClearFlags;
            //cam.backgroundColor = srcBgColor;
    
            // 设置全局的_CustomDepthTexture纹理
            Shader.SetGlobalTexture(depthHash, rt);
        }
        private void OnRenderImage(RenderTexture source, RenderTexture destination)
        {
            // 显示到destination
            Graphics.Blit(null, destination, mat);
        }
        private void OnDestroy()
        {
            if (rt != null) RenderTexture.ReleaseTemporary(rt);
            Destroy(cam);
        }
    }
    
    

    后处理显示Shader

    读取_CustomDepthNormalsTexture,解码_CustomDepthNormalsTexture.zw为depth,并显示。

    如果我们的自定义的纹理不是深度+法线的编码,只是简单的将ndcZ值写入,那么我们解码就不如要任何处理,直接读取 tex2D(_CustomDepthTexture, screenPos.xy).r 即可,即可得到ndcZ值。

    如果要解码的深度与法线,还可以使用另一个函数:(下面这例子是深度与法线)

    inline float3 DecodeViewNormalStereo( float4 enc4 )
    {
        float kScale = 1.7777;
        float3 nn = enc4.xyz*float3(2*kScale,2*kScale,0) + float3(-kScale,-kScale,1);
        float g = 2.0 / dot(nn.xyz,nn.xyz);
        float3 n;
        n.xy = g*nn.xy;
        n.z = g-1;
        return n;
    }
    inline void DecodeDepthNormal( float4 enc, out float depth, out float3 normal )
    {
        depth = DecodeFloatRG (enc.zw);
        normal = DecodeViewNormalStereo (enc);
    }
    

    下面是我们用到解码的shader

    // jave.lin 2020.03.09
    Shader "Custom/GetCustomDepthTexture" {
        SubShader {
            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 _CustomDepthNormalsTexture;
                v2f vert (appdata v) {
                    v2f o;
                    o.vertex = UnityObjectToClipPos(v.vertex);
                    o.uv = v.uv;
                    return o;
                }
                fixed4 frag (v2f i) : SV_Target {
                    //return tex2D(_CustomDepthNormalsTexture, i.uv);
                    float4 depthNormals = SAMPLE_RAW_DEPTH_TEXTURE(_CustomDepthNormalsTexture, i.uv);
                    return DecodeFloatRG (depthNormals.zw);
                }
                ENDCG
            }
        }
    }
    
    

    运行效果

    先不解码的内容显示:

                fixed4 frag (v2f i) : SV_Target {
                    return tex2D(_CustomDepthNormalsTexture, i.uv);//先显示未解码的内容
                    //float4 depthNormals = SAMPLE_RAW_DEPTH_TEXTURE(_CustomDepthNormalsTexture, i.uv);
                    //return DecodeFloatRG (depthNormals.zw);
                }
    

    在这里插入图片描述

    解码后的显示

                fixed4 frag (v2f i) : SV_Target {
                    //return tex2D(_CustomDepthNormalsTexture, i.uv); //先显示未解码的内容
                    float4 depthNormals = SAMPLE_RAW_DEPTH_TEXTURE(_CustomDepthNormalsTexture, i.uv);
                    return DecodeFloatRG (depthNormals.zw);
                }
    

    在这里插入图片描述

    注意:以上是自定义获取与内置的_CameraDepthNormalsTexture数据一样的方式。这个深度+法线编码在一起的纹理。前面说过,里面的depth是经过线性处理的。

    如果你要自定义编码深度缓存保存的是ndc中z值的,那就是类似_CameraDepthTexture中的R通道值,但没有线性处理:tex2D(_CameraDepthTexture, screenPos.xy).r == ndcZ
    你可以在编码的shader的vert函数拿到clipPos=UnityObjectToClipPos(v.vertex);,然后frag函数取ndc.z == clip.z / clip.w

    			...
                struct v2f {
                    float4 vertex : SV_POSITION;
                    float depth : TEXCOORD0;
                };
                sampler2D _MainTex;
                float4 _MainTex_ST;
                v2f vert (appdata v) {
                    v2f o;
                    o.vertex = UnityObjectToClipPos(v.vertex);
                    return o;
                }
                fixed4 frag (v2f i) : SV_Target { 
                    return i.vertex.z / i.vertex.w; // ndc.z == clip.z / clip.w
                }
                ...
    

    这样渲染出来的深度纹理,就是非线性的。按需求来使用对应的纹理就好了。

    LinearEyeDepth, Linear01Depth

    LinearEyeDepth, Linear01Depht得官方文档也有介绍:Using Depth Textures

    为了方便理解,亲手用Windows的Paint.exe话了个图,难画。。。(手动哭笑+无语 -_-!)
    在这里插入图片描述

    LinearEyeDepth 作用

    上图中,要注意说明,LinearEyeDepth得出来的值,我们通常叫:EyeZ,它的意思是,视图空间(注意不是透视空间)下的z轴的距离值

    作用是:将ndc.z值转为view space(视图空间)z,就是上图的EyeZ(距离A点的距离,如,far=1000,near=0.3(上图可能是550),透视空间中的G点的线性z轴值,对应的,就是在视图空间中的F点的z轴值,就是F距离A可能是800,就是说EyeZ=800)。

    Linear01Depth 作用

    作用是:将ndc.z值转为一个线性比例值(view space(视图空间)z轴值除以far的比例值),就是上图的Linear01Depth = AG/AE,图中AG假设为800,AE(far)=1000,那么Linear01Depth = AG/AE=800/1000=0.8。

    下面是两个函数的源码:

    // Z buffer to linear 0..1 depth
    inline float Linear01Depth( float z )
    {
        return 1.0 / (_ZBufferParams.x * z + _ZBufferParams.y);
    }
    // Z buffer to linear depth
    inline float LinearEyeDepth( float z )
    {
        return 1.0 / (_ZBufferParams.z * z + _ZBufferParams.w);
    }
    ...
        // Values used to linearize the Z buffer (http://www.humus.name/temp/Linearize%20depth.txt)
        // x = 1-far/near
        // y = far/near
        // z = x/far
        // w = y/far
        // or in case of a reversed depth buffer (UNITY_REVERSED_Z is 1)
        // x = -1+far/near
        // y = 1
        // z = x/far
        // w = 1/far
        float4 _ZBufferParams;
    

    Unity中的这两个inline函数都是参考这个总结的:Linearize depth.txt
    我就将它的内容copy出来,方便阅读吧:

    Some math I did ... (not 100% verified, but looks like it works)
    
    n = near
    f = far
    z = depth buffer Z-value
    EZ  = eye Z value
    LZ  = depth buffer Z-value remapped to a linear [0..1] range (near plane to far plane)
    LZ2 = depth buffer Z-value remapped to a linear [0..1] range (eye to far plane)
    
    
    DX:
    EZ  = (n * f) / (f - z * (f - n))
    LZ  = (eyeZ - n) / (f - n) = z / (f - z * (f - n))
    LZ2 = eyeZ / f = n / (f - z * (f - n))
    
    
    GL:
    EZ  = (2 * n * f) / (f + n - z * (f - n))
    LZ  = (eyeZ - n) / (f - n) = n * (z + 1.0) / (f + n - z * (f - n))
    LZ2 = eyeZ / f = (2 * n) / (f + n - z * (f - n))
    
    
    
    LZ2 in two instructions:
    LZ2 = 1.0 / (c0 * z + c1)
    
    DX:
      c1 = f / n
      c0 = 1.0 - c1
    
    GL:
      c0 = (1 - f / n) / 2
      c1 = (1 + f / n) / 2
    
    
    -------------------
    http://www.humus.ca
    

    快速的获取当前片段的Linear01Depth

    来看一段代码:(该源代码在此,是国外一名在暴雪公司工作的女性图形程序员,有兴趣可以到她首页看看一些教程。)
    在这里插入图片描述
    还记得我之前说过的吗?Linear01Depth其实就是EyeZ/Far的一个比例值。
    代码中vert shader中的output.linearDepth = -(UnityObjectToViewPos(input.vertex).z * _ProjectionParams.w);中可能大家有疑问:_ProjectionParam.w是什么东西,为何相乘就可以等于linearDepth了,按照上面Linear01Depth=EyeZ/Far来推算,只有一种可能,那就是_ProjectionParam.w==1/far

    -(UnityObjectToViewPos(input.vertex).z很明显就是==EyeZ的运算了(从函数名就可以看出来,object to view),至于取负数,是因为:Camera下的view space是右手坐标系,X轴,Y轴,Z轴,分别是:X拇指指向右(X轴正方向),食指指向上(Y轴正方向),中指指向你自己(Z轴正方向),所以可以知道,Z轴是指向镜头内为正的方向,与我们世界坐标是反的,因为世界坐标、投影坐标是用左手坐标表示的,所以需要取反。

    然后我们打开UnityCG.glslinc和UnityShaderVariables.cginc文件中都有定义、说明:

    // x = 1 or -1 (-1 if projection is flipped)
    // y = near plane
    // z = far plane
    // w = 1/far plane // 没错,就是1/far
    uniform vec4 _ProjectionParams;
    

    _CameraDepthTexture和_CameraDepthNormalsTexture 存的深度是什么

    关于这两纹理也可以先参考官方文档:Camera’s Depth Texture

    • 写入只有深度值的纹理_CameraDepthTexture:在顶点着色器COMPUTE_EYEDEPTH(ndc.z),在片段着色器的取ndc.z==clipPos.z/clipPos.w就好了。
    • 读取只有深度值的纹理_CameraDepthTexture:tex2D(_CameraDepthTexture).r == ndcZ
    • 写入深度+法线值的纹理_CameraDepthNormalsTexture:在顶点o.depthNormals.xyz = COMPUTE_VIEW_NORMAL; o.depthNormals.w = COMPUTE_DEPTH_01;,这里要留意COMPUTE_DEPTH_01是有线性处理后的,在片段着色器 return EncodeDepthNormal(i.depthNormals.w, i.depthNormals.xyz);编码即可。
    • 读取深度+法线值的纹理_CameraDepthNormalsTexture:在片段着色器DecodeDepthNormal( tex2D(_CameraDepthNormalsTexture, screenPos.xy), depth, normal),这里读取的深度值是有线性处理过的,如果要将线性值,转回ndc.z值,可以反线性处理,意思说我们DecodeDepthNormal( tex2D(_CameraDepthNormalsTexture, screenPos.xy), depth, normal)出来的depth值0~1范围的,所以我们按Linear01Depth的逆运算,即可求得ndc.z
    • Linear01Depth的逆运算 Linear01Depth的函数inline float Linear01Depth( float z ) { return 1.0 / (_ZBufferParams.x * z + _ZBufferParams.y); },逆运算就是已知Linear01Depth的结果,求参数z。
      L i n e a r 01 D e p t h = 1.0 / ( Z B u f f e r P a r a m s . x ∗ z + Z B u f f e r P a r a m s . y ) ; Linear01Depth = 1.0 / (_ZBufferParams.x * z + _ZBufferParams.y); Linear01Depth=1.0/(ZBufferParams.xz+ZBufferParams.y);
      ( Z B u f f e r P a r a m s . x ∗ z + Z B u f f e r P a r a m s . y ) ∗ L i n e a r 01 D e p t h = 1 (_ZBufferParams.x * z + _ZBufferParams.y) * Linear01Depth = 1 (ZBufferParams.xz+ZBufferParams.y)Linear01Depth=1
      ( Z B u f f e r P a r a m s . x ∗ z + Z B u f f e r P a r a m s . y ) = 1 / L i n e a r 01 D e p t h (_ZBufferParams.x * z + _ZBufferParams.y) = 1/Linear01Depth (ZBufferParams.xz+ZBufferParams.y)=1/Linear01Depth
      ( Z B u f f e r P a r a m s . x ∗ z ) = 1 / L i n e a r 01 D e p t h − Z B u f f e r P a r a m s . y (_ZBufferParams.x * z) = 1/Linear01Depth - _ZBufferParams.y (ZBufferParams.xz)=1/Linear01DepthZBufferParams.y
      z = ( 1 / L i n e a r 01 D e p t h − Z B u f f e r P a r a m s . y ) / Z B u f f e r P a r a m s . x z = (1/Linear01Depth - _ZBufferParams.y) / _ZBufferParams.x z=(1/Linear01DepthZBufferParams.y)/ZBufferParams.x
      所以逆运算为:z = (1/Linear01Depth - _ZBufferParams.y) / _ZBufferParams.x,这个z就是相当远_CameraDepthTexture的R通道值。
    • _CameraDepthTexture.r==ndc.z,那么_CameraDepthNormalsTexture.ba解码出来的线性值是什么呢?
      借用一下puppet_master的博主的一张图:(原文:Unity Shader-深度相关知识总结与效果实现(LinearDepth,Reverse Z,世界坐标重建,软粒子,高度雾,运动模糊,扫描线效果)
      在这里插入图片描述
      在引用他的原文:

    上图中,A为相机位置,G为空间中我们要重建的一点,那么该点的世界坐标为A(worldPos) + 向量AG,我们要做的就是求得向量AG即可。根据三角形相似的原理,三角形AGH相似于三角形AFC,则得到AH / AC = AG / AF。由于三角形相似就是比例关系,所以我们可以把AH / AC看做01区间的比值,那么AC就相当于远裁剪面距离,即为1,AH就是我们深度图采样后变换到01区间的深度值,即Linear01Depth的结果d。那么,AG = AF * d。

    如果还不了解,我再补充一下:_CameraDepthNormalsTexture.ba解码出来的线性值就是depth,而depth = AG / AF的一个比例值,结果肯定是0~1的。然后你可以用上面讲到的Linear01Depth的逆运算ndcZ = (1/Linear01Depth - _ZBufferParams.y) / _ZBufferParams.x,将depth代入Linear01Depth,就可以求出ndcZ,或是理解为:Linear01Depth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv)) == DecodeDepthNormal(tex2D(_CameraDepthNormalsTexture, i.uv), out float outLinear01Depth, out float3 normal)中的outLinear01Depth

    题外话

    如果你要写软渲染器,就要处理如果坐标转换,并将一些坐标写入DepthBuffer深度缓存。可参考下列资料:

    D e p t h V i e w = > D e p t h S c r e e n Depth_{View} => Depth_{Screen} DepthView=>DepthScreen
    视空间深度 转化到 屏幕空间深度的公式如下:
    a = F / ( F − N ) a = F / (F - N) a=F/(FN)
    b = N F / ( N − F ) b = NF / (N - F) b=NF/(NF)
    d e p t h 屏 幕 空 间 = ( a Z + b ) / Z 为 视 空 间 深 度 depth_{屏幕空间} = (aZ + b)/ Z_{为视空间深度} depth=(aZ+b)/Z
    d e p t h = ( a Z + b ) / Z depth = (aZ + b) / Z depth=(aZ+b)/Z

    D e p t h S c r e e n = > D e p t h V i e w Depth_{Screen} => Depth_{View} DepthScreen=>DepthView
    反推得 屏幕空间深度 转化到 视图空间深度的等于以下公式:
    d e p t h = ( a Z + b ) / Z depth = (aZ + b) / Z depth=(aZ+b)/Z
    d e p t h = a + b / Z depth = a + b / Z depth=a+b/Z
    d e p t h − a = b / Z depth - a = b / Z deptha=b/Z
    ( d e p t h − a ) / b = 1 / Z (depth - a) / b = 1 / Z (deptha)/b=1/Z
    b / ( d e p t h − a ) = Z b / (depth - a) = Z b/(deptha)=Z

    D e p t h S c r e e n = > D e p t h V i e w Depth_{Screen} => Depth_{View} DepthScreen=>DepthView 公式: b / ( d e p t h − a ) = Z b / (depth - a) = Z b/(deptha)=Z,代入a,b:
    ( N F / ( N − F ) / ( d e p t h − ( F / ( F − N ) ) ) = Z (NF / (N - F) / (depth - (F / (F - N))) = Z (NF/(NF)/(depth(F/(FN)))=Z

    假设N=0.3, F=1000,代入N,F:
    ((0.3 * 1000) / (0.3 - 1000)) / (depth - (1000 / (1000 - 0.3))) = Z
    (300 / (-999.7)) / (depth - (1000 / 999.7)) = Z
    -0.3000900270081024 / (depth - 1.000300090027008)= Z

    假设depth = 0.5,代入depth
    -0.3000900270081024 / (0.5 - 1.000300090027008) = Z
    -0.3000900270081024 / -0.500300090027008 = Z
    0.5998200539838049 = Z
    当depth(屏幕空间) = 0.5,Z(Z为视空间深度) = 0.5998200539838049
    那么屏幕空间的depth就是要输入深度纹理的值。


    另外,还有一篇文章写得非常不错:OpenGL阴影映射
    里面有将阴影如何生成,以及如何将片段转换到灯光坐标系空间下来获取深度图,然后判断片段深度与灯光坐标空间下的深度图的深度值做比较的决定是否在阴影中。

    里面的深度图,就是将ndc中的z值写入到深度纹理的:tex2D(_CameraDepthTexture, screenPos.xy).r == ndcZ
    我借一下他文章中引用的learnopengl中借来的图
    在这里插入图片描述

    注意Unity正交相机中的深度纹理的编码

    我虽然没去下载Unity的内置CameraDepthTexture.shader相关的代码。
    但是试验后证明,Unity的正交相机的_CameraDepthTexture存着的内容与透视不一样。

    • 透视下存储的是ndc.z
    • 正交下存储的是线性深度比例值,而且他没有处理:UNITY_REVERSED_Z的宏的情况。而透视下的是处理了。所以可以看到我们的shader代码中,透视的是没有处理这个UNITY_REVERSED_Z的代码的。

    先用Profiler>Frame Debugger看看_CameraDepthTexture的内容效果:
    在这里插入图片描述

    可以看到,我镜头距离模型很近时,反而深度值越大,距离模型很远时,深度值越小。
    这就与透视的不一样了。从这点大概猜到:随着Unity shader内置代码的升级,官方也不断完善处理。让外部使用透明化,但我现在用的是:unity 2018.3.0f2版本的,正交相机下的,他们漏了处理这块内容,我猜大概是正交相机下比较少人用这块深度功能?用正交的一般都是2D游戏。但现在很多2D,或是固定视角2.5D的也有一部分是3D的。

    注意:

            // 正交相机下,_CameraDepthTexture存储的是线性值,且:距离镜头远的物体,深度值小,距离镜头近的物体,深度值大,可以使用UNITY_REVERSED_Z宏做处理
            // 透视相机下,_CameraDepthTexture存储的是ndc.z值,且:不是线性的。
            // _CameraDepthNormalsTexture的纹理,正交相机,与透视相机下都没问题一样这么使用
    

    具体可以参考:Unity Shader - 根据片段深度重建片段的世界坐标。只看在正交相机下的深度纹理重构世界坐标,在里头有详细的试验。

    总结

    在Unity中,获取深度的方式有多种多样。
    理解如何编解码深度,对理解深度纹理存储的是什么内容有帮助。
    理解Unity提供的深度纹理存储的是什么,才能知道什么地方,什么时候去使用它。
    因为总有某些功能在实现时,是基于深度值来实现。

    Project

    backup : UnityShader_GetDepthNormalsTextureTesting_2018.03.2f0

    • Camera.depthTextureMode方式运行:GetBuiltInDepthTextureScene.unity场景。
    • 自定义深度纹理方式运行:GetCustomDepthTextureScene.unity场景。

    References

    展开全文
  • Unity 深度图片获取

    千次阅读 2017-03-07 20:07:07
    2、 深度缓存,或者深度纹理,其实就是一个包含有场景里物体离照相机的距离值的一张纹理图。 3、 为了让摄像机生成一张深度纹理,只需要设置Camera.depthTextureMode即可。但这个时候生成了纹理,还需要我们去获取...
  • 深度解析数据缓存技术

    万次阅读 2018-03-21 17:54:39
    缓存是分布式系统中的重要组件,主要解决高并发,大数据场景下,热点数据访问的性能问题。提供高性能的数据快速访问。 1.1.缓存的原理 将数据写入/读取速度更快的存储(设备); 将数据缓存到离应用最近的...
  • MyBatis 缓存机制深度解剖 / 自定义二级缓存 缓存概述 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持;一级缓存基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域 为 ...
  • 高并发系统之HTTP缓存协议深度剖析

    千次阅读 2016-08-25 07:50:00
    因本文主要以浏览器缓存场景介绍,所以非浏览器场景下的一些用法本文不会介绍,而且本文以chrome为测试浏览器。 浏览器缓存是指当我们使用浏览器访问一些网站页面或者http服务时,根据服务端返回的缓存设置响应头...
  • 导读:Alluxio 项目诞生于 UC Berkeley AMP 实验室,自开源以来经过 7 年的不断开发迭代,支撑大数据处理场景的数据统一管理和高效缓存功能日趋成熟。然而,随着云原生人工智能(Cloud Native AI)的兴起,灵活的...
  • 导读:Alluxio 项目诞生于 UC Berkeley AMP 实验室,自开源以来经过 7 年的不断开发迭代,支撑大数据处理场景的数据统一管理和高效缓存功能日趋成熟。然而,随着云原生人工智能(Cloud Native AI)的兴起,灵活的...
  • Shader笔记十五 获取深度和法线纹理

    千次阅读 2018-06-13 14:37:55
    很多时候不仅需要当前屏幕的信息,同时希望得到深度和法线信息。...获取深度和法线纹理首先深度纹理是一张纹理图,既然是一张纹理图,那么其值的范围是在[0,1]之间的,那么这个值的范围是如何转化得到的呢?...
  • 前言 在第 12 章【屏幕后处理效果】中,我们学习的屏幕后处理效果都只是在屏幕颜色图像上进行各种操作来实现的。...一种更好的方法是,我们可以在深度纹理和法线纹理上进行边缘检测,这些图像不会受...
  •  文章链接: http://blog.csdn.net/zhmxy555/article/details/8607864作者:毛星云(浅墨) 邮箱: happylifemxy@163.com 在游戏三维场景中,想创造出唯美而具画面感和真实感的画面,常常需要绘制大量的物体。...
  • 基于OpenGL环境,提出利用场景渲染结果即帧缓存数据(主要包括颜色缓存及深度缓存)进行局部三维场景重构的方法。根据投影变换原理和深度缓存特点研究了逆投影变换,得到了三维点元的重构方法。在此基础上,利用帧...
  • 最大元素(或最大空间) 缓存中可以存放的最大元素的数量,一旦缓存中元素数量超过这个值(或者缓存数据所占空间超过其最大支持空间),那么将会触发缓存启动清空策略根据不同的场景合理的设置最大元素值往往可以...
  • 实际上就是一张渲染纹理,只不过它里面储存的像素值不是颜色值,而是一个高精度的深度值,由于被储存在一张纹理中,深度纹理里的深度范围是[0,1],而且通常是 非线性分布的。 深度值来自顶点变换后得到的归一化的...
  • 取而代之的是,HotRing用访问成本来触发Rehash(获取数据时平均内存访问次数)。如下图所示,HotRing的无锁Rehash分为如下3个主要步骤: 初始化 首先HotRing创建一个rehash的后台线程,这个线程初始化一个size是旧...
  • 缓存一致性?get

    2021-09-15 18:41:41
    人人都懂缓存一致性,咱也得懂。
  • 本文是秒杀系统的第四篇,我们来讨论秒杀系统中缓存热点数据的问题,进一步延伸到数据库和缓存的双写一致性问题,并且给出了实现代码。 前文回顾和文章规划 零基础上手秒杀系统(一):防止超卖 零基础上手秒杀系统...
  • 高并发服务设计——缓存

    千次阅读 2017-09-17 18:34:29
    缓存回收策略1 基于空间即设置缓存的存储空间,如设置为10MB,当达到存储空间时,按照一定的策略移除数据。2 基于容量基于容量指缓存设置了最大大小,当缓存的条目超过最大大小,则按照一定的策略将旧数据移除。3 ...
  • 分布式应用缓存

    2018-07-17 08:59:27
    缓存命中率 缓存回收策略 基于空间 基于容量 基于时间 基于Java对象引用 回收算法 Java缓存类型 堆内存 Guava Cache实现 Ehcache实现 非堆内存 磁盘缓存 EhCache实现 分布式缓存 多级缓存 示例代码 多级缓存...
  • 最近测试遇到修改host文件后,清除浏览器缓存后,重启浏览器后,发现浏览器还是访问老DNS服务,于是网上查查原因,豁然开朗。 这里对互联网上一些文章进行整理,原文可查看参。 1、DNS 缓存 1.1 什么是DNS ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 28,811
精华内容 11,524
关键字:

获取场景深度缓存