基于Unity ComputeShader 实现正向DIBR

这篇具有很好参考价值的文章主要介绍了基于Unity ComputeShader 实现正向DIBR。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

什么是DIBR?

就是根据1张或者n张带有深度信息的图片,也就是RGBD图,通过插值的方式,生成出虚拟视点下的效果图。

深度信息如果不够精确,效果上,容易出现一些错误。

以及视角的变化,导致一些信息不足,会存在空洞问题。

如果在Unity中怎么实现呢。

通过DIBR算法,在场景中预制两个相机,通过脚本分别获取颜色图和深度图。

然后通过computeshader,将两个深度图插值为中间视点的图。

基于Unity ComputeShader 实现正向DIBR

根据几何关系,可以推导出左右视图的关系。

相关像素的水平视差 dispararity满足如上公式。

这是针对一般用相机拍摄的图片来说的。f代表相机的焦距。

在unity下的相机,没有焦距的概念。怎么办呢。

由于以上公式,都是以物理实际距离尺度计算的。需要变换到像素空间尺度下,便于计算和插值,得到像素关系。

所以上面的公式,两面同时除以像素宽度pitch。

像素尺度视差=disparity/pitch=B*f/(Z*pitch)=B/Z*f/pitch

令F=f/pitch得到B/Z*F

这个F刚好可以推导出和fov的关系。

基于Unity ComputeShader 实现正向DIBR

 可以假定有个投影面,仿照真实相机的物理结构。

投影面也就是cmos感光元器件。假设水平分辨率为Res,每个像素宽度为pitch。

所以有w=Res*pitch。

又有,w/2/f=tan(fov/2)

所以Res*pitch/2/f=tan(fov/2)

可以推导出 F=f/pitch=f*Res/w=Res/(2tan(fov/2))

比如水平fov=90度,分辨率是3840,那么F=1920

可以看出F只和fov和分辨率有关了。

于是根据左图的深度图得到深度(需要从0-1区间变换到view坐标系)

和两个相机的距离,就可以插值出虚拟视点的图了。大概就是这个原理。

其中最大视差的计算方法为 B/near*F  因为near平面的视差最大。

如果有最大视差要求,怎么判端两个相机最远能离开多远呢?

B=near*最大视察/F。

例如最大视差为64,near=0.3 F=1920 那么相机最大距离为 0.01

也就是两个相机距离1厘米时,最大视差是64个像素。

这个用在反向DIBR时也很有用(因为需要遍历搜索,所以估算遍历次数很重要)

以下是C#源代码。

首先是获取相机深度的代码;挂载相机物体上。

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


public class RenderWithDepth : MonoBehaviour
{
    public RenderTexture colorRT;
    public RenderTexture depthRT;

    // Start is called before the first frame update
    void Start()
    {

        colorRT = new RenderTexture(3840, 2160, 0);
        depthRT = new RenderTexture(3840, 2160, 24, RenderTextureFormat.Depth);

        GetComponent<Camera>().SetTargetBuffers(colorRT.colorBuffer, depthRT.depthBuffer);
    }

}

其次是C#和computeshader代码,挂载到虚拟视点相机上。

public class RenderByCSDIBR : MonoBehaviour
{
    int width = 3840;
    int height = 2160;
    public ComputeShader dibrCS;
    public RenderWithDepth lDep, rDep;
    RenderTexture resultRT_L, resultRT_R;

    // Start is called before the first frame update
    void Start()
    {
        resultRT_L = new RenderTexture(width, height, 0, RenderTextureFormat.ARGB32);
        resultRT_L.enableRandomWrite = true;
        resultRT_L.Create();

        resultRT_R = new RenderTexture(width, height, 0, RenderTextureFormat.ARGB32);
        resultRT_R.enableRandomWrite = true;
        resultRT_R.Create();
    }


    public void ClearOutRenderTexture(RenderTexture renderTexture)
    {
        RenderTexture rt = RenderTexture.active;
        RenderTexture.active = renderTexture;
        GL.Clear(true, true, Color.clear);
        RenderTexture.active = rt;
    }

    private void OnPostRender()
    {

        ClearOutRenderTexture(resultRT_L);
        ClearOutRenderTexture(resultRT_R);

        int k1 = dibrCS.FindKernel("CSMain");
        dibrCS.SetTexture(k1, "ResultL", resultRT_L);
        dibrCS.SetTexture(k1, "ResultR", resultRT_R);

        dibrCS.SetTexture(k1, "LC", lDep.colorRT);
        dibrCS.SetTexture(k1, "RC", rDep.colorRT);
        dibrCS.SetTexture(k1, "LD", lDep.depthRT);
        dibrCS.SetTexture(k1, "RD", rDep.depthRT);

        dibrCS.SetFloat("_LCamPos", lDep.transform.position.x);
        dibrCS.SetFloat("_RCamPos", rDep.transform.position.x);
        dibrCS.SetFloat("_CurCamPos", transform.position.x);

        dibrCS.SetFloat("_Far", 1000);
        dibrCS.SetFloat("_Near", 0.3f);

        dibrCS.Dispatch(k1, width / 8, height / 8, 1);

    }
    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        Graphics.Blit(resultRT_L, destination);
    }
}

 computeshader代码文章来源地址https://www.toymoban.com/news/detail-415287.html

#pragma kernel CSMain

#define RES_W 3840

// Create a RenderTexture with enableRandomWrite flag and set it
// with cs.SetTexture
RWTexture2D<float4> ResultL, ResultR;
Texture2D<float4> LC, RC;
Texture2D<float4> LD, RD;
float _LCamPos, _RCamPos, _CurCamPos;
float _Far, _Near;

float LinearEyeDepth(float _z)
{
    float x = 1.0 - _Far / _Near;
    float y = _Far / _Near;
    float z = x / _Far;
    float w = y / _Far;
    return 1.0 / (z * _z + w);
}


float getViewZ(uint2 pos, bool isLeft) {
    float z;
    if (isLeft)
        z = LinearEyeDepth(1-LD[pos].x);
    else
        z = LinearEyeDepth(1-RD[pos].x);
    return z;
}

[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
    // TODO: insert actual code here!
    float maxBaseLine = _RCamPos - _LCamPos;
    float fov = radians(90.0f);
    float near = 0.3f;
    float focal = RES_W / (2.0f * tan(fov / 2));
    float maxDis = maxBaseLine * focal / _Near;

    float baselineL = _CurCamPos - _LCamPos;
    float baselineR = maxBaseLine - baselineL;

    // 左眼视图
    float z = getViewZ(id.xy, true);
    int dis = int(baselineL * focal / z);
    int x = max(0, id.x - dis);

    float dis_h = int(dis / 256) / 255.0f;
    float dis_l = int(dis % 256) / 255.0f;

    float4 cur = ResultR[int2(x, id.y)];
    float discur = cur.x * 255 * 256 + cur.y * 255;

    float4 col = LC[id.xy];
    if (dis > discur) {
        ResultL[int2(x, id.y)] = col;//float4(dis_h, dis_l, 0, 1);
        ResultR[int2(x, id.y)] = float4(dis_h, dis_l, 0, 1);
    }
        

    //Result[id.xy] =  float4(z, z, z, 1);
    // 右眼视图
    z = getViewZ(id.xy, false);
    dis = uint(baselineR * focal / z);
    x = min(RES_W-1, id.x + dis);
    dis_h = int(dis / 256) / 255.0f;
    dis_l = int(dis % 256) / 255.0f;
    cur = ResultR[uint2(x, id.y)];
    discur = cur.x * 255 * 256 + cur.y * 255;

    col = RC[id.xy];
    if (dis > discur) {
        ResultL[int2(x, id.y)] = col;//float4(dis_h, dis_l, 0, 1);
        ResultR[int2(x, id.y)] = float4(dis_h, dis_l, 0, 1);// RC[id.xy];
    }
        


}

到了这里,关于基于Unity ComputeShader 实现正向DIBR的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 51、基于注解方式开发Spring WebFlux,实现生成背压数据,就是实现一直向客户端发送消息

    什么是背压: 这个是Reactive(反应) 的概念,当订阅者的消费能力,远低于发布者时,订阅者(也就是消费者)有通知取消或终止发布者生产数据的机制,这种机制可以称作为“背压”。 说白了就是:当消费者消费积压的时候,反向告诉推送生产者,我不需要你生产了,你

    2024年02月09日
    浏览(51)
  • 关于nginx,正向代理和反向代理是什么意思

    很多公司会用到nginx做代理服务器,为什么用nginx,tomcat服务器不行吗? tomcat缺点:并发量小,用户使用的少 nginx:高并发,高性能,cpu、内存等资源消耗却非常低,运行非常稳定。 nginx作用:反向代理,负载均衡。完全听不懂。。。。 先来了解下什么叫正向代理和方向代理

    2024年02月11日
    浏览(39)
  • 【Elasticsearch专栏 01】深入探索:Elasticsearch的正向索引和倒排索引是什么

    首先,要明确的是,Elasticsearch本质上只使用倒排索引来实现高效的搜索和查询功能。正向索引虽然在某些数据库和搜索系统中被提及,但在Elasticsearch的上下文中并不是一个核心概念。下面我详细解释倒排索引,并简要提及正向索引以提供对比。 倒排索引是Elasticsearch中用于实

    2024年02月22日
    浏览(51)
  • 软件行业迫切需要基于正向生成的编码模型

    软件行业长期面临生产率瓶颈。程序员的工作强度已经接近极限,要继续提高软件交付速度似乎难上加难。近年来在开发流程和工具上,如GPT显然提供了一定的提效,但是实质上没有改变软件开发的基本模式————逆向生成。目前软件项目的大部分工作时间都花在理解“现

    2023年04月18日
    浏览(31)
  • 自动驾驶就是在扯?比亚迪你凭什么?

    比亚迪“炮轰”自动驾驶         上周,在比亚迪2022年财报交流会上,有投资人问比亚迪在自动驾驶方面的发展进度和规划,比亚迪集团董事长王传福直言:“无人驾驶那都是扯淡,弄个虚头巴脑的东西那都是忽悠,它就是一场皇帝的新装......自动驾驶一场车祸就让品牌

    2023年04月22日
    浏览(50)
  • 为什么LTD独立站就是Web3.0网站!

    Web3.0再次进入大众的视野,中国证监会科技监管局局长姚前发表文章《Web3.0 是渐行渐近的新一代互联网》,这篇文章中说到,Web1.0为“可读”(read),Web2.0 为“可读 + 可写”(read+write),Web3.0 则是“可读 +可写 + 拥有”(read+write+own)。 Web3.0数字经济时代破浪而来 初代互

    2024年01月23日
    浏览(72)
  • 17.2 实现无管道正向CMD

    WSASocket 无管道正向CMD,使用 WSASocket 函数创建一个TCP套接字,并绑定到一个本地地址和端口上。然后使用 CreateProcess 函数创建一个新的 CMD 进程,并将标准输入、输出和错误输出重定向到套接字的句柄上。这样,客户端可以通过网络连接到这个套接字,发送 CMD 命令并获取命令

    2024年02月08日
    浏览(43)
  • 深度解析Nginx正向代理的原理与实现

    目录 前言 1. 什么是正向代理 2. Nginx正向代理的配置 3. Nginx正向代理的实现原理 4. 示例代码 5. 总结 Nginx是一个高性能的Web服务器和反向代理服务器,但它也可以用作正向代理服务器。本文将深入解析Nginx正向代理的原理和实现,并提供相关代码示例。 正向代理是一种代理服务

    2024年04月16日
    浏览(33)
  • 线性代数的学习和整理6:如何表示向量/矩阵? 矩阵就是向量组,矩阵的本质是什么?

    目录 0 参考的知识点和目录 1 向量 1.1 向量的概念 1.2 向量如何表示 1.3 向量/矩阵的优秀表示方法:即向量空间内的有向线段 2 矩阵 2.1 矩阵就是多个列向量的集合/合并( 而不是 +),矩阵就是多个列向量的一种简化书写方式? 2.2 矩阵的加法  =等价于=  向量的加法 2.3 矩阵

    2024年02月07日
    浏览(54)
  • 利用Nginx正向代理实现局域网电脑访问外网

    在网络环境中,有时候我们需要让局域网内的电脑访问外网,但是由于网络策略或其他原因,直接访问外网是不可行的。这时候,可以借助 Nginx 来搭建一个正向代理服务器,实现局域网内电脑通过 Nginx 转发访问外网的需求。 在工作中我遇到了一个类似的情况:在公司网络中

    2024年03月27日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包