You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

269 lines
15 KiB

2 years ago
<!DOCTYPE html><html lang="ja"><head>
<meta charset="utf-8">
<title>のフォグ</title>
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@threejs">
<meta name="twitter:title" content="Three.js – のフォグ">
<meta property="og:image" content="https://threejs.org/files/share.png">
<link rel="shortcut icon" href="/files/favicon_white.ico" media="(prefers-color-scheme: dark)">
<link rel="shortcut icon" href="/files/favicon.ico" media="(prefers-color-scheme: light)">
<link rel="stylesheet" href="/manual/resources/lesson.css">
<link rel="stylesheet" href="/manual/resources/lang.css">
<!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>
<script type="importmap">
{
"imports": {
"three": "../../build/three.module.js"
}
}
</script>
</head>
<body>
<div class="container">
<div class="lesson-title">
<h1>のフォグ</h1>
</div>
<div class="lesson">
<div class="lesson-main">
<p>この記事はThree.jsの連載記事の1つです。
最初の記事は<a href="fundamentals.html">Three.jsの基礎知識</a>です。
まだ読んでいない場合、そこから始めると良いかもしれません。
カメラの記事を読んでない方は、まずは<a href="cameras.html">この記事</a>を読んでみて下さい。</p>
<p>一般的には3Dエンジンでのフォグ(霧)は、カメラからの距離によって特定の色にフェードアウトする方法です。
three.jsでは <a href="/docs/#api/ja/scenes/Fog"><code class="notranslate" translate="no">Fog</code></a> または <a href="/docs/#api/ja/scenes/FogExp2"><code class="notranslate" translate="no">FogExp2</code></a> オブジェクトを作成し、シーンに<a href="/docs/#api/ja/scenes/Scene#fog"><code class="notranslate" translate="no">fog</code></a> プロパティを設定してフォグを追加します。</p>
<p><a href="/docs/#api/ja/scenes/Fog"><code class="notranslate" translate="no">Fog</code></a> はカメラからの距離を表す <code class="notranslate" translate="no">near</code><code class="notranslate" translate="no">far</code> があります。
<code class="notranslate" translate="no">near</code> よりも近いものはフォグの影響を受けません。
<code class="notranslate" translate="no">far</code> より遠いものはフォグの影響を受けます。
<code class="notranslate" translate="no">near</code><code class="notranslate" translate="no">far</code> の中間部分では、マテリアルの色からフォグの色にグラデーションします。</p>
<p>また、カメラからの距離で急激にグラデーションする <a href="/docs/#api/ja/scenes/FogExp2"><code class="notranslate" translate="no">FogExp2</code></a> もあります。</p>
<p>どちらのタイプのフォグも使用するにはフォグを作成してシーンに割り当てます。</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const scene = new THREE.Scene();
{
const color = 0xFFFFFF; // white
const near = 10;
const far = 100;
scene.fog = new THREE.Fog(color, near, far);
}
</pre>
<p><a href="/docs/#api/ja/scenes/FogExp2"><code class="notranslate" translate="no">FogExp2</code></a> の場合は次のようなコードになります。</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const scene = new THREE.Scene();
{
const color = 0xFFFFFF;
const density = 0.1;
scene.fog = new THREE.FogExp2(color, density);
}
</pre>
<p><a href="/docs/#api/ja/scenes/FogExp2"><code class="notranslate" translate="no">FogExp2</code></a> は現実表現に近いですが、<a href="/docs/#api/ja/scenes/Fog"><code class="notranslate" translate="no">Fog</code></a> の方が一般的によく使われています。
Fogは適用する場所を選択できるので、ある距離まではクリアなシーンを表示し、その距離を過ぎるとフェードアウトした色にできます。</p>
<div class="spread">
<div>
<div data-diagram="fog" style="height: 300px;"></div>
<div class="code">THREE.Fog</div>
</div>
<div>
<div data-diagram="fogExp2" style="height: 300px;"></div>
<div class="code">THREE.FogExp2</div>
</div>
</div>
<p>ここで注意すべき点は、フォグは <em>レンダリングされる</em> ものに適用される事です。
以下はオブジェクトの色の各ピクセルの計算の一部です。
つまり、シーンを特定の色にフェードさせたい場合、フォグ <strong></strong> 背景色を同じ色に設定します。
背景色は <a href="/docs/#api/ja/scenes/Scene#background"><code class="notranslate" translate="no">scene.background</code></a> プロパティで設定します。
背景色は <a href="/docs/#api/ja/math/Color"><code class="notranslate" translate="no">THREE.Color</code></a> で指定します。例えば</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">scene.background = new THREE.Color('#F00'); // red
</pre>
<div class="spread">
<div>
<div data-diagram="fogBlueBackgroundRed" style="height: 300px;" class="border"></div>
<div class="code">fog blue, background red</div>
</div>
<div>
<div data-diagram="fogBlueBackgroundBlue" style="height: 300px;" class="border"></div>
<div class="code">fog blue, background blue</div>
</div>
</div>
<p>以下はフォグを追加した例です。
シーンにフォグを追加し背景色を設定します。</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const scene = new THREE.Scene();
+{
+ const near = 1;
+ const far = 2;
+ const color = 'lightblue';
+ scene.fog = new THREE.Fog(color, near, far);
+ scene.background = new THREE.Color(color);
+}
</pre>
<p>以下の例ではカメラの <code class="notranslate" translate="no">near</code> は 0.1、<code class="notranslate" translate="no">far</code> は 5です。
カメラは <code class="notranslate" translate="no">z = 2</code> にあります。
立方体は1の大きさで z = 0 です。
つまり、フォグを <code class="notranslate" translate="no">near = 1</code><code class="notranslate" translate="no">far = 2</code> と設定し、立方体の中心付近でフェードアウトしています。</p>
<p></p><div translate="no" class="threejs_example_container notranslate">
<div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/fog.html"></iframe></div>
<a class="threejs_center" href="/manual/examples/fog.html" target="_blank">ここをクリックして別のウィンドウで開きます</a>
</div>
<p></p>
<p>フォグを調整するインターフェースを追加してみましょう。
ここでも<a href="https://github.com/georgealways/lil-gui">lil-gui</a>を使用します。
lil-guiはオブジェクトとプロパティを受け取り、インタフェースを自動生成します。
これでフォグの <code class="notranslate" translate="no">near</code><code class="notranslate" translate="no">far</code> プロパティを簡単に操作できます。
しかし、 <code class="notranslate" translate="no">near</code><code class="notranslate" translate="no">far</code> より大きい場合は無効になります。
lil-guiで <code class="notranslate" translate="no">near</code><code class="notranslate" translate="no">far</code> を操作するヘルパーを作ってみましょう。</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">// We use this class to pass to lil-gui
// so when it manipulates near or far
// near is never &gt; far and far is never &lt; near
class FogGUIHelper {
constructor(fog) {
this.fog = fog;
}
get near() {
return this.fog.near;
}
set near(v) {
this.fog.near = v;
this.fog.far = Math.max(this.fog.far, v);
}
get far() {
return this.fog.far;
}
set far(v) {
this.fog.far = v;
this.fog.near = Math.min(this.fog.near, v);
}
}
</pre>
<p>次のコードを追加します。</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">{
const near = 1;
const far = 2;
const color = 'lightblue';
scene.fog = new THREE.Fog(color, near, far);
scene.background = new THREE.Color(color);
+
+ const fogGUIHelper = new FogGUIHelper(scene.fog);
+ gui.add(fogGUIHelper, 'near', near, far).listen();
+ gui.add(fogGUIHelper, 'far', near, far).listen();
}
</pre>
<p><code class="notranslate" translate="no">near</code><code class="notranslate" translate="no">far</code> のパラメーターは、フォグを調整する最小値と最大値を設定します。
これはカメラ設定時にセットします。</p>
<p>最後の2行の <code class="notranslate" translate="no">.listen()</code> をlil-guiに変更し <em>listen</em> するようにします。
これで <code class="notranslate" translate="no">near</code><code class="notranslate" translate="no">far</code> の変更時、lil-guiが他のプロパティのUIを更新してくれます。</p>
<p>フォグの色を変更できますが、上記で述べたようにフォグの色と背景色を同期させる必要があります。
lil-gui操作時に両方の色を変更する <em>virtual</em> プロパティをヘルパーに追加してみましょう。</p>
<p>lil-guiでは4つの方法で色を操作できます。</p>
<ol>
<li><p>CSSの6桁の16進数(例: <code class="notranslate" translate="no">#112233</code>)</p>
</li>
<li><p>色相、彩度、値、オブジェクト (例: <code class="notranslate" translate="no">{h: 60, s: 1, v: }</code>)</p>
</li>
<li><p>RGB (例: <code class="notranslate" translate="no">[255, 128, 64]</code>)</p>
</li>
<li><p>RGBA(例:<code class="notranslate" translate="no">[127, 200, 75, 0.3]</code></p>
</li>
</ol>
<p>lil-guiが単一の値を操作するので、16進数を使うのが一番簡単です。
幸運な事に <a href="/docs/#api/ja/math/Color"><code class="notranslate" translate="no">THREE.Color</code></a><a href="/docs/#api/ja/math/Color#getHexString"><code class="notranslate" translate="no">getHexString</code></a> を使用でき、文字列を簡単に取得できます。</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">// We use this class to pass to lil-gui
// so when it manipulates near or far
// near is never &gt; far and far is never &lt; near
+// Also when lil-gui manipulates color we'll
+// update both the fog and background colors.
class FogGUIHelper {
* constructor(fog, backgroundColor) {
this.fog = fog;
+ this.backgroundColor = backgroundColor;
}
get near() {
return this.fog.near;
}
set near(v) {
this.fog.near = v;
this.fog.far = Math.max(this.fog.far, v);
}
get far() {
return this.fog.far;
}
set far(v) {
this.fog.far = v;
this.fog.near = Math.min(this.fog.near, v);
}
+ get color() {
+ return `#${this.fog.color.getHexString()}`;
+ }
+ set color(hexString) {
+ this.fog.color.set(hexString);
+ this.backgroundColor.set(hexString);
+ }
}
</pre>
<p><code class="notranslate" translate="no">gui.addColor</code> を呼び出し、ヘルパーのvirtualプロパティにcolorのlil-guiを追加します。</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">{
const near = 1;
const far = 2;
const color = 'lightblue';
scene.fog = new THREE.Fog(color, near, far);
scene.background = new THREE.Color(color);
* const fogGUIHelper = new FogGUIHelper(scene.fog, scene.background);
gui.add(fogGUIHelper, 'near', near, far).listen();
gui.add(fogGUIHelper, 'far', near, far).listen();
+ gui.addColor(fogGUIHelper, 'color');
}
</pre>
<p></p><div translate="no" class="threejs_example_container notranslate">
<div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/fog-gui.html"></iframe></div>
<a class="threejs_center" href="/manual/examples/fog-gui.html" target="_blank">ここをクリックして別のウィンドウで開きます</a>
</div>
<p></p>
<p><code class="notranslate" translate="no">near</code> を1.9、<code class="notranslate" translate="no">far</code> を2.0にすると以下のようになりました。
曇っていない状態と完全に曇っている状態との中間では、シャープなグラデーションします。
<code class="notranslate" translate="no">near</code> = 1.1、<code class="notranslate" translate="no">far</code> = 2.9 とすると、カメラから 2 離れて回転する立方体で最も滑らかになります。</p>
<p>最後に、マテリアルでレンダリングされたオブジェクトがフォグの影響を受けるか判断するために、マテリアルにはboolean型の<a href="/docs/#api/ja/materials/Material#fog"><code class="notranslate" translate="no">fog</code></a>プロパティがあります。
そのマテリアルを使用してる場合は、フォグの影響を受けます。
ほとんどのマテリアルのデフォルトは <code class="notranslate" translate="no">true</code> です。
フォグを消去する理由は、運転席やコックピットからの視点で3Dの車のシミュレーターを作っている時を想像して下さい。
車内から見ると、車内の全てのものはフォグを外しておきたいと思うでしょう。</p>
<p>フォグの良い例としては、家の外に濃いフォグが出ている場合が挙げられます。
例えば、フォグが2m先(near = 2)から始まり、4m先(far = 4)でフォグがあるとします。
部屋の長さは2メートル以上、家の長さは4メートル以上で、家の中にフォグがかからないように設定が必要です。
設定しない場合に家の中に立っている時に部屋の奥の壁の外を見ると、フォグの中にいるように見えてしまいます。</p>
<div class="spread">
<div>
<div data-diagram="fogHouseAll" style="height: 300px;" class="border"></div>
<div class="code">fog: true, all</div>
</div>
</div>
<p>部屋の奥の壁と天井にフォグがかかっています。
家のマテリアルのフォグをオフにすると、この問題が解決できます。</p>
<div class="spread">
<div>
<div data-diagram="fogHouseInsideNoFog" style="height: 300px;" class="border"></div>
<div class="code">fog: true, only outside materials</div>
</div>
</div>
<p><canvas id="c"></canvas></p>
<script type="module" src="../resources/threejs-fog.js"></script>
</div>
</div>
</div>
<script src="/manual/resources/prettify.js"></script>
<script src="/manual/resources/lesson.js"></script>
</body></html>