📽️

【Unity】HDRPで投影テクスチャマッピング

2023/12/04に公開

Unity HDRPで投影テクスチャマッピングを行う方法ついて解説します。
検証に使用しているUnityのバージョンは2022.3.12です。

投影テクスチャマッピングの手法については基本的に以下の記事を参考にしています。
https://light11.hatenadiary.com/entry/2020/02/22/181705

HDRPなのでシェーダーを直接書くかわりにShader Graphを使用します。Shader Graphのネットワークは以下のようになります。


プロパティとしてViewProjection行列を渡すようにして、シェーダー内でWorld座標からスクリーン座標を求めて0~1の値に変換し、その値でテクスチャをサンプルします。値が範囲外(0~1以外)のときは、テクスチャからサンプルした値を使わずに適当な色を表示するようにしています。

Unity HDRPではShader GraphのPositionノードSpaceプロパティがWorldのときに取得できる位置はカメラ座標系になるので、SpaceプロパティをAbsolute WorldにしてWorld座標が取得できるようにする必要があります。

以下のスクリプトからViewProjection行列をマテリアルに設定します。

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

public class ProjectiveTextureMapping : MonoBehaviour
{
    [SerializeField] Transform lookFrom;
    [SerializeField] float fov = 60f;
    [SerializeField] float aspect = 1f;
    [SerializeField] float zNear = 0.1f;
    [SerializeField] float zFar = 100f;
    Material material;

    void Start()
    {
        material = GetComponent<MeshRenderer>().material;
    }

    void Update()
    {
        var viewMatrix = Matrix4x4.Scale(new Vector3(1, 1, -1)) * lookFrom.worldToLocalMatrix;
        var projectionMatrix = Matrix4x4.Perspective(fov, aspect, zNear, zFar);
        var viewProjectionMatrix = projectionMatrix * viewMatrix;
        material.SetMatrix("_ProjectiveMatrix", viewProjectionMatrix);
    }

    private void OnDrawGizmos()
    {
        var gizmosMatrix = Gizmos.matrix;
        Gizmos.matrix = Matrix4x4.TRS(lookFrom.position, lookFrom.rotation, Vector3.one);
        Gizmos.DrawFrustum(Vector3.zero, fov, zFar, zNear, aspect);
        Gizmos.matrix = gizmosMatrix;
    }

    void OnDestroy()
    {
        Destroy(material);
    }
}

カメラから投影する場合は以下のようにカメラのView行列とProjection行列を使用します。

using UnityEngine;

public class ProjectiveTextureMappingFromCamera : MonoBehaviour
{
    [SerializeField] Camera camera;
    Material material;

    void Start()
    {
        material = GetComponent<MeshRenderer>().material;
    }

    void Update()
    {
        var viewMatrix = camera.worldToCameraMatrix;
        var projectionMatrix = camera.projectionMatrix;
        var viewProjectionMatrix = projectionMatrix * viewMatrix;
        material.SetMatrix("_ProjectiveMatrix", viewProjectionMatrix);
    }

    void OnDestroy()
    {
        Destroy(material);
    }
}

以上のシェーダーを使用するマテリアルとスクリプトをメッシュに適用すると、以下のように投影テクスチャマッピングをHDRPで行うことができます。

Discussion