見出し画像

Stable Diffusionで部屋を作る その3 Unity Shaderも投入

結論から書きますと、時刻で生成するには自分のプロンプト力が足りませんでした(笑


前回からの言い訳

部屋はフォトグラメトリーして3Dで作る方針へ、といったな。あれは嘘だ。

いまだ決定打に至らずだけど、健忘録として書く。何かメモしておくと夜中寝てる時にハッと気づいたりするじゃん?

フォトグラメトリーにするには四方八方から撮った写真が必要

 1枚の写真から深度を推測するのはControlNet のDepthプリプロセッサーでもできるんだけど、所詮推測なわけで変なところが出っ張ったりしちゃう。

 へた絵からデプスを作ると余計なものがでてきて生成後のデプスバッファをいちいちクリスタで手で消ないといけなくて、めんどくさくなった。
 しかもよくみたらパース狂ってるんですよ!
 いや、元のへた絵のパースが狂ってるから悪いのは自分なんですが!!

 という事で、Unityで部屋の3Dオブジェクトを並べて、そこからデプスバッファの値を表示すればいいんじゃーん、と考えました。

Unityの素材探し

 Unityのアセットストアで4階建のアパートがフリーで手に入ります。

Apartment Kit。画像をクリックでジャンプ

 いろいろな部屋と家具が配置されているという理想的なアセットです。
 気に入ったら作者のページから有料アセットも買ってあげてね!

 さらにCameraとDepthバッファを表示するプログラムをお借りしました。
 ちくわ様の該当ページ

 そのままでは距離に対してオフセットや深度の倍率がつけられず殆どのシーンで真っ黒か真っ白になってしまうので、そこを実行時に変更できるようにしました。

実行時に右のDisp Depth のTimesの値を1から32くらいまでいい感じに調整します

Depth.shader

Shader "Unlit/depth"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            float  _Times = 22.; // 倍率。4-32くらいまで
            float   _Offset = 0.; // 追加。-1 〜 1 の範囲
            sampler2D _CameraDepthTexture;

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

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

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                fixed depth = UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture,i.uv)) * _Times + _Offset;
                return fixed4(depth,depth,depth,1);
            }
            ENDCG
        }
    }
}

で、今度はc#のスクリプト

using UnityEngine;

public class DispDepth : MonoBehaviour {
    public Material mat;
    // shaderに渡す光具合の倍率。2-32程度
    public float Times = 22;   
    // shaderに渡すデプスのオフセット -1〜1 だけど0でいい
    public float Offset = 0;    
    
    void Start()
    {
        GetComponent<Camera>().depthTextureMode |= DepthTextureMode.Depth;
    }

    public void OnRenderImage(RenderTexture source, RenderTexture dest)
    {                
        Graphics.Blit(source, dest, mat);
    }

    private void Update()
    {
        Shader.SetGlobalFloat("_Times", Times);
        Shader.SetGlobalFloat("_Offset", Offset);
    }
}

 CameraにC#のスクリプト(Depth.cs)をくっつけて、シェーダー(Depth.shader)がついたマテリアル(Depth.material)をInspector上のMatに追加。そして実行します。
 実行すると画面が真っ黒や真っ白になる場合は、Timesの値を1から64程度までいい感じになるまで手動で値を調整します。
 今回は倍率(Times)24倍、オフセット 0でいい感じの白黒画像がでました。
 これをスナップショットして、512x512に整形します。

512x512にした Depth.png

 ControlNetをEnableにしてSingle Imageにさっきクリスタで整形したDepth.pngを貼り付け。Preprocessorはnone、modelは control_v11f1p_sd15_depth を選択

下半分のss

Negativeプロンプトは EasyNegativeだけ入れて、実行だ!

master peace,room,(early morning:1.4), no people, 1 table,(brown leather sofa1.2),steel office desk, pink wall,white floor,white ceiling, The wall behind the sofa is white,
master peace,room,(sunset:1.4), no people, 1 table,brown leather sofa,steel office desk, pink wall,white floor,white ceiling, The wall behind the sofa is white,
master peace,room,(dark night outside window:1.4), no people, (white all wall:1.2), 1 table,(brown leather sofa1.2),steel office desk, ,white floor,white ceiling,

なんで夜は壁が黒くなるんだよぉぉ

 プロンプト力か、そうなのか?
 かっちり正確にするんだったら、普通に3DでUnity Assetのアパートをそのまま使ってUWPでライトを凝った方がいいんじゃないかな〜。
(Stable Diffusion 意味なくない?と凹む)

終わりに

 でもまぁ統一感はあるから、early moning を元に、それをテクスチャーとしてUnityに貼り直すとかすればいいかも。UWPで高級なソファーを表現するのってそれだけでも職人技が必要なんですよね。

次のアイディアがでるまで、キャラクターでも作るか

この記事が気に入ったらサポートをしてみませんか?