マガジン

生成画像の「光の方向」を揃える:複数枚を一つの場面にする

遊びをつくる

執筆にClaudeを使用しています。

プリズムの光、紙ひこうき、植物の芽を並べた実験机。
記事のテーマをもとに制作したAI生成イメージ。実際のゲーム画面ではありません。

背景、手前の小物、キャラクターを別々に生成して重ねると、一枚ずつは良くできているのに、並べた途端に場面が崩れることがあります。背景では木漏れ日が左から差しているのに、キャラクターの影は左へ伸びている、といった状態です。光の向きがずれると、人は理由が分からなくても「貼り合わせた絵だ」と感じます。 この記事で確かめるのは、「光の向きを文章で指定すると、どのくらい揃うのか。揃わなかったとき、どの順で直すのが手間に見合うのか」という二点です。結果はここには書きません。読者が自分のツールと自分の絵柄で測れるよう、問いの立て方、準備、手順、記録の取り方、結果の読み方、誤りやすい点を順に示します。 「手描きで影を足す」という最後の手段までを含めて設計するのが、このシリーズらしい点です。生成だけで揃えられる範囲と、手を入れたほうが早い範囲の境目を、自分のデータで見つけます。

この記事の目次
  1. 問いと準備:何を、何で比べるのか
  2. 手順:光源を変えながら、同じ場面を生成する
  3. 記録の取り方:何を、どの単位で残すか
  4. 結果の読み方と直し方:揃わなかったときの順番
  5. 誤りやすい点
  6. 次の行動

問いと準備:何を、何で比べるのか

問いは一つに絞ります。「光源の指示の書き方を変えると、影の向きが揃う枚数は変わるか」です。色や画風、構図の良し悪しは今回の対象外です。

比べる指示は次の四条件にします。

  • 条件A:「左上からの光」とだけ書く。
  • 条件B:画面を基準に、光の来る方向、影の落ちる方向、光の高さ、主光源が一つであることを書く。
  • 条件C:条件Bに加えて、最初に気に入った一枚を参照画像として渡す。ツールが参照画像に対応している場合だけ行います。
  • 条件D:指示では向きを指定せず、生成後に左右反転で揃える。

条件Bの文面の例です。

画面の左上から差す、午後の暖かい日差し。影は被写体の右下へ短く落ちる。光源は一つだけ。

「左」を被写体から見た左と読むか、画面を見る側の左と読むかで、結果が割れる可能性があります。どちらに解釈されやすいかも、この実験で分かります。そのため文面では「画面の」と明記します。

準備するものは次のとおりです。

  • 使う画像生成ツール。条件Cを行うなら参照画像に対応したもの。
  • 場面の要素を三種。例として、背景(地面のある野外)、小物(木箱や切り株)、人物またはキャラクターを想定します。
  • 記録用の表(表計算ソフトで十分です)。
  • 画像編集ソフト。レイヤーと左右反転が使えれば何でも構いません。
  • 次の節のコードを保存した判定用HTML。

手順:光源を変えながら、同じ場面を生成する

要素ごとの主題は固定し、変えるのは光の指示だけにします。主題の文は三要素それぞれで条件A〜Dに共通させてください。

  1. 要素(背景・小物・人物)ごとに、主題の文を一文で決めます。
  2. 条件Aの指示を付けて、各要素を5枚ずつ生成します。気に入った枚だけを選ぶことはしません。生成した順に全部を残します。
  3. 条件Bで同じことを行います。
  4. 条件Cは、条件Bで最初に出た背景の一枚を参照画像にして、小物と人物を5枚ずつ生成します。
  5. 条件Dは、指示に光の向きを入れず、5枚ずつ生成して保存します。これは反転で直せるかを見る条件なので、判定後に反転版も作ります。
  6. 画像に通し番号とファイル名(例:B_char_03)を付けます。

枚数は目安です。要素3種、条件4種、各5枚なら合計60枚になり、負担が大きければ要素を人物と背景の二種に絞って構いません。ただし、条件間で枚数と要素は必ず揃えてください。

ここで、影の向きを判定する小さな補助ページを使います。画像を複数選び、「足元」と「影の先端」を順にクリックすると、画面基準の8方向で記録します。外部ライブラリは不要で、単独で動きます。

html
<!doctype html>
<meta charset="utf-8">
<input type="file" id="f" accept="image/*" multiple>
<canvas id="c" width="480" height="480"></canvas>
<pre id="o">画像を選び、足元→影の先端の順に2回クリックします。</pre>
<script>
const f=document.getElementById('f'),c=document.getElementById('c'),
x=c.getContext('2d'),o=document.getElementById('o');
const names=['右','右下','下','左下','左','左上','上','右上'];
let imgs=[],i=0,pts=[],log=[];
function show(){
  if(i>=imgs.length){o.textContent=log.join('\n');return;}
  const m=imgs[i].img;
  c.width=480;c.height=Math.round(480*m.height/m.width);
  x.drawImage(m,0,0,c.width,c.height);
}
f.onchange=e=>{
  imgs=[];log=[];i=0;
  const files=[...e.target.files];
  files.forEach(file=>{
    const img=new Image();
    img.onload=()=>{imgs.push({img,name:file.name});
      if(imgs.length===files.length)show();};
    img.src=URL.createObjectURL(file);
  });
};
c.onclick=e=>{
  if(i>=imgs.length)return;
  const r=c.getBoundingClientRect();
  pts.push([e.clientX-r.left,e.clientY-r.top]);
  if(pts.length===2){
    const a=Math.atan2(pts[1][1]-pts[0][1],pts[1][0]-pts[0][0]);
    const k=(Math.round(a/(Math.PI/4))+8)%8;
    log.push(imgs[i].name+' : 影は'+names[k]+'向き');
    pts=[];i++;show();
  }
};
</script>

読み込みの順序は選んだ順と一致しないことがありますが、結果にファイル名が付くので、表への転記では名前を見て照合してください。

記録の取り方:何を、どの単位で残すか

一枚ごとに一行、次の項目を残します。

  • 画像ID、記入の仕方:条件と要素と番号(例:B_char_03)
  • 影の向き、記入の仕方:補助ページが出した8方向
  • 明るい面の向き、記入の仕方:目視で8方向。影と反対側になっているかの確認用
  • 影の長さ、記入の仕方:短・中・長の3段階
  • 色温度、記入の仕方:暖・中立・寒の3段階
  • 光源の数、記入の仕方:1つ/複数/判定不能
  • 判定不能、記入の仕方:逆光や曇天で影が見えないときに印を付ける

揃っているかの基準は、場面の「基準画像」に決めます。たとえば条件Bの背景で最初に出た一枚の影の向きを基準にし、同じ8方向なら一致、隣の方向なら「ずれ小」、それ以外は「不一致」と三段階にします。隣の方向まで含めて一致とみなすかは、重ねたときの見え方で決めてください。自分の絵柄で許容できるかを確かめる作業でもあります。

集計の単位は「条件ごとの一致枚数÷枚数」です。パーセントにすると五枚程度の差が大きく見えるので、「5枚中何枚」のまま比べます。

判定の安定性のため、全画像を日を置いてもう一度判定します。二回の判定で食い違う画像が多いなら、基準が曖昧です。その場合、結果を読む前に判定基準を見直してください。

結果の読み方と直し方:揃わなかったときの順番

集計後は、次のように読みます。

  • AよりBの一致が明らかに多い:向きの指示は効いています。以降は条件Bの文面をひな形にします。
  • AとBに差がほとんどない:書き足しの効果は薄い可能性があります。ただ、枚数が少なければ偶然の範囲かもしれません。差が1枚程度なら判断を保留し、各条件を10枚に増やして再確認します。
  • BよりCの一致が多い:参照画像が効いています。背景を最初に決めてから他を作る順序が向いています。
  • 不一致の多くが「正反対」:左右の解釈が割れている可能性が高いです。画面基準の表現に変えるか、条件Dのように反転で直します。
  • 向きは合うが影の長さが違う:光の高さの指定が弱い状態です。「低い角度で長い影」など高さを足して再生成します。
  • 向きは合うが色が違う:色補正で直します。

直し方は手間の少ない順に並べると、次のようになります。

  1. 再生成:数枚の範囲で当たりが出るなら、これが最も安くなります。
  2. 左右反転:向きだけが逆のときに有効です。ただし文字、看板、時計、服の非対称な模様、顔の分け目などは反転すると不自然になります。反転前に、そうした要素がないか確認します。
  3. 色・明るさの補正:色温度は色相の調整レイヤーで寄せられます。明るい面と暗い面の差が弱いときは、光の来る側から反対側へかけた弱いグラデーションを重ねます。
  4. 手描きで影を足す:影を別のレイヤーに乗算で描き、基準の向きに合わせます。元の影が逆向きなら、薄くして残すか、消してから描き直します。

三番目までで直らない場合に四番目へ進む、と決めておくと迷いません。時間がかかるのは手描きですが、再生成を何十回も回すより早く済む場合もあります。その分かれ目は、再生成で一致した枚数を記録しておけば自分で判断できます。

誤りやすい点

  • 条件を同時に変える:向きの指示と画風の指示を同時に変えると、何が効いたか分からなくなります。一回に変えるのは一つだけです。
  • 良い一枚だけを残す:気に入った絵だけを集計すると、揃い率が実際より高くなります。生成した全枚数を記録します。
  • 「左」の基準が混ざる:指示文では画面基準で統一し、判定も画面基準で行います。
  • 逆光や曇天の場面を混ぜる:影が見えない画像は判定できません。「判定不能」の列を作り、一致率の分母から外すか、別に集計します。
  • 切り抜き後の縁:背景を消した人物の縁に、元の背景の明るい色が残ることがあります。向きが揃っていても、縁の光だけが逆に見える原因になります。
  • 解像度や拡大率を揃えずに比べる:影の長さは、画像の拡大率が違うと比べられません。重ねる前に同じ縮尺にそろえてください。
  • 複数の光源を許す:窓と焚き火が両方ある場面は、影が二方向になります。最初は主光源が一つの場面で測り、複雑な場面は後に回します。

次の行動

まず背景と人物の二要素だけで、条件AとBを各5枚ずつ生成し、補助ページで影の向きを記録してみてください。一致が足りない要素が見つかったら、上の直し方を手間の少ない順に試します。

ゲームに組み込むときは、画像を相対パスで参照し、直下のindex.htmlから読み込む構成にしておくと、アソバースへのアップロードでも差し替えが楽です。画像を多く使う場合は、アップロードの容量(20MiB以内)も意識しておくと安心です。