グラフィックス入門: VR ディストーションの後処理

      最近とても忙しく、プロジェクトの要件が大幅に変更され、夜には成人向け英語のテストを復習しなければなりません。
      「VRのワンクリック生成」の要件が追加されました。既存のフレームワーク上で、通常のキーボードとマウスとVRハンドルの操作をプリコンパイルして同期し、PCとVRのさまざまなインターフェイスの使用を同期します。ビジネス開発者は、処理機能を実行するための新しい基本クラスとAPIを派生および呼び出し、エディタ機能を使用してワンクリックでVRとPCのデュアルエンドシーンを生成し、完全に実行できます。
      リーダーとしては、新たな要求に応じて変化していくしかない、つまり、無駄な仕事に費やした時間は取り戻せません。
      今、VRの需要として映像の歪みが問題になっていますが、このVRヘッドセットも同様で、同じヘッドセットを違う人が使っても、違和感、特に空間感覚の違いが生じてしまうので、この問題を解決する方法が必要です。画像の後処理を使用して歪みを解決します。
      伝統的な画像の歪みの方法を見てください: 樽歪み
      Baidu 樽歪み
      wiki 歪み
      テクスチャ uv グリッドは、ワインを保存するための木製の樽のように見えます。これに似ています。
ここに画像の説明を挿入      画像から、uv が中心 (0.5,0.5) から四隅に向かって「膨張」していることがわかります。uv をこれに変換できる計算方法があるかどうかを推測できます。私はインターネット上でアルゴリズムを見つけ、次のように独自の変更をいくつか組み合わせました。
      まず、インターネット上のアルゴリズムです。

Shader "VRDistort/VRDistortImageEffectShader"
{
    
    
    Properties
    {
    
    
        _MainTex ("Texture", 2D) = "white" {
    
    }
        _Distort("Distort",Range(-4,4)) = 0
        _Adjust("Adjust",Range(0,4)) = 1
    }
    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;
            };

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

            sampler2D _MainTex;
            float _Distort;             //畸变系数
            float _Adjust;              //矫正系数

            //桶形畸变
            float2 barreldistort(float2 uv)
            {
    
    
                //得到pixeluv相对center坐标d
                float2 d = uv.xy-float2(0.5,0.5);
                //d的长度方(0<d<0.5)
                float2 d2 = d.x*d.x+d.y*d.y;
                //畸变权重(-1<f<3)
                float f = 1.0+d2*_Distort;
                //畸变uv
                //(f*_Adjust)用于修正权重
                //再*d后“还原”相对坐标d
                //再+center还原pixeluv
                float2 buv = f*_Adjust*d+float2(0.5,0.5);
                return buv;
            }

            fixed4 frag (v2f i) : SV_Target
            {
    
    
                fixed4 col = tex2D(_MainTex, barreldistort(i.uv));
                return col;
            }
            ENDCG
        }
    }
}

      このアルゴリズムは非常に巧妙に設計されており、pixeluv と centeruv の相対座標 d を使用して変換し、pixeluv に復元し、次にディストーション パラメータと補正パラメータを調整すると、次のようにバレル ディストーションの効果を得ることができます: ここでは、OnRenderImage を使用して画像を後処理しており、ディストーション効果は良好であることがわかります
ここに画像の説明を挿入
      。
      同時に、問題も見つかります。UV 間隔 [0,1] の変更により、歪みが生じた後、テクスチャの「四隅」に再度一致するように補正パラメータを手動で調整する必要があります。
      したがって、アルゴリズムを変更して _Adjust パラメータを削除する必要があります。アルゴリズムは次のことを保証する必要があります:
      1. _Adjust パラメータを自動的に計算する
      2. 4 つの UV エンドポイントが変換された後も UV が同じであること 上記の計算は、
0
      P0(0,0) と P1(1,1) を元の BarrelDistort アルゴリズムに取り込むことであり、_Adjust = 1/(1+0.5*_Distort) を取得できます。
      コードを変更します。

float2 barrel(float2 uv)
{
    
    
    float j = 1/(1+0.5*_Distort);
    float2 d = uv.xy-float2(0.5,0.5);
    float d2 = d.x*d.x+d.y*d.y;
    float f = 1.0+d2*_Distort;
    float2 buv = f*j*d+float2(0.5,0.5);
    return buv;
}

      結果は次のとおりです:
ここに画像の説明を挿入
      _Distort>0 の区間ではアルゴリズムに問題がないことがわかりますが、_Distort<0 の区間では問題があります。問題は次のとおりです: 1. 画面が「凹」になった後、画面の 4 辺の「凹」の UV を「完了」できません
      。
      2. _Distort=-2、分母=0の場合、計算は間違っています。
      次に、_Distort<0 の場合の正しい UV マッピング関係を次のように考えなければなりません。4
ここに画像の説明を挿入
      つの辺の中心点のピクセル UV は、変換後も元のピクセル UV のままであり、計算は次のとおりです。計算方法は逆
ここに画像の説明を挿入
      演繹、単純な 1 次元線形方程式です。
      コードを変更します。

float2 barrel(float2 uv)
{
    
    
    float j = _Distort >= 0 ? (1/(1+0.5*_Distort)) : (1/(1+0.25*_Distort));
    float2 d = uv.xy-float2(0.5,0.5);
    float d2 = d.x*d.x+d.y*d.y;
    float f = 1.0+d2*_Distort;
    float2 buv = f*j*d+float2(0.5,0.5);
    return buv;
}

      効果は次のとおりです。
ここに画像の説明を挿入
      このようにして効果が達成され、ユーザーはユーザー設定インターフェイスの「バンプ」パラメーターについて画面を微調整するだけで済みます。
      もちろん、シェーダーの計算時間を節約するために、次のように _Distort と _Adjust を計算して C# で渡すことをお勧めします。

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

public class VRDistortSetting : MonoBehaviour
{
    
    
    public Slider slider;

    public Material mat;

    void Start()
    {
    
    
        slider.onValueChanged.AddListener(SliderValueChange);
    }

    private void SliderValueChange(float val)
    {
    
    
        float distort = val;
        float adjust = distort >= 0 ? (1 / (1 + 0.5f * distort)) : (1 / (1 + 0.25f * distort));
        mat.SetFloat("_Distort", distort);
        mat.SetFloat("_Adjust", adjust );
    }
}

      さて、今日はここで、しばらくはメーデーだけが無料になると思います。

おすすめ

転載: blog.csdn.net/yinhun2012/article/details/124208313