diff --git a/docs/user-manual/graphics/shaders/index.md b/docs/user-manual/graphics/shaders/index.md
index e2ab1b30f63..6f5492fb3f4 100644
--- a/docs/user-manual/graphics/shaders/index.md
+++ b/docs/user-manual/graphics/shaders/index.md
@@ -3,6 +3,9 @@ title: Shaders
description: Author ShaderMaterial with paired GLSL and WGSL, declare attributes, and integrate with the engine shader system.
---
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
When you import your 3D models into PlayCanvas, by default, they will use our [Physical Material](/user-manual/graphics/physical-rendering/physical-materials/). This is a versatile material type that can cover a lot of your rendering needs.
However, you will often want to perform special effects or special cases for your materials. To do this you will need to write a custom shader. In this case, you need to use `ShaderMaterial`.
@@ -127,6 +130,9 @@ The engine provides predefined shader includes that handle common transformation
For example:
+
+
+
```glsl
// Includes transformation-related functionality provided by the engine.
// - Automatically declares the `vertex_position` attribute.
@@ -168,12 +174,67 @@ void main(void)
}
```
+
+
+
+```wgsl
+// Includes transformation-related functionality provided by the engine.
+// - Automatically declares the `vertex_position` attribute.
+// - Handles skinning and morphing if necessary.
+// - Adds the following uniforms:
+// - `matrix_viewProjection`
+// - `matrix_model`
+// - `matrix_normal`
+// - Provides utility functions:
+// - `getModelMatrix()`
+// - `getLocalPosition()`
+#include "transformCoreVS"
+
+// Includes normal-related functionality provided by the engine.
+// - Automatically declares the `vertex_normal` attribute.
+// - Handles skinning and morphing if necessary.
+// - Provides utility functions:
+// - `getNormalMatrix()`
+// - `getLocalNormal()`
+#include "normalCoreVS"
+
+@vertex
+fn vertexMain(input: VertexInput) -> VertexOutput
+{
+ var output: VertexOutput;
+
+ // Retrieve the model matrix, accounting for skinning, morphing, or instancing.
+ let modelMatrix: mat4x4f = getModelMatrix();
+ let localPos: vec3f = getLocalPosition(vertex_position.xyz);
+ let worldPos: vec4f = modelMatrix * vec4f(localPos, 1.0);
+
+ // Retrieve the normal matrix and compute the world normal.
+ let normalMatrix: mat3x3f = getNormalMatrix(modelMatrix);
+ let localNormal: vec3f = getLocalNormal(vertex_normal);
+ let worldNormal: vec3f = normalize(normalMatrix * localNormal);
+
+ // Example: Apply simple wrap-around diffuse lighting using the world normal.
+ output.brightness = (dot(worldNormal, uniform.uLightDir) + 1.0) * 0.5;
+
+ // Transform the geometry.
+ output.position = uniform.matrix_viewProjection * worldPos;
+
+ return output;
+}
+```
+
+
+
+
#### Fragment Shader {#fragment-shader}
The engine provides predefined shader chunks you can include for common color processing effects such as gamma correction, tone mapping and fog. These includes ensure that colors are processed correctly according to the rendering settings.
Example Usage
+
+
+
```glsl
#include "gammaPS" // Adds support for gamma correction of inputs and outputs
#include "tonemappingPS" // Adds support for tone mapping
@@ -196,6 +257,38 @@ void main(void)
}
```
+
+
+
+```wgsl
+#include "gammaPS" // Adds support for gamma correction of inputs and outputs
+#include "tonemappingPS" // Adds support for tone mapping
+#include "fogPS" // Adds support for fog effects
+
+@fragment
+fn fragmentMain(input: FragmentInput) -> FragmentOutput
+{
+ var output: FragmentOutput;
+
+ // Evaluate color in linear color space
+ let colorLinear: vec3f = ...;
+
+ // Apply fog if enabled
+ let fogged: vec3f = addFog(colorLinear);
+
+ // Apply tone mapping if enabled
+ let toneMapped: vec3f = toneMap(fogged);
+
+ // Apply gamma correction and output the final color
+ output.color = vec4f(gammaCorrectOutput(toneMapped), alpha);
+
+ return output;
+}
+```
+
+
+
+
These functions are automatically configured based on the engine's settings, ensuring that color processing is consistent across different rendering conditions.
:::note
@@ -204,6 +297,140 @@ For more complete examples, and also for details on how to implement instancing,
:::
+#### Shadow Pass {#shadow-pass}
+
+To allow meshes using your custom shader to cast shadows, the fragment shader needs to output data appropriate for the shadow type being rendered during the shadow pass. Include the engine-provided `shadowCasterPS` chunk when `SHADOW_PASS` is defined, and write the value returned by `getShadowOutput()` to the output color:
+
+
+
+
+```glsl
+#ifdef SHADOW_PASS
+ // Provides getShadowOutput(), which returns the data for the shadow type being rendered
+ #include "shadowCasterPS"
+#endif
+
+void main(void)
+{
+ #ifdef SHADOW_PASS
+
+ // output shadow data (alpha-tested materials can discard before this)
+ gl_FragColor = getShadowOutput();
+
+ #else
+
+ // normal color rendering
+ gl_FragColor = ...;
+
+ #endif
+}
+```
+
+
+
+
+```wgsl
+#ifdef SHADOW_PASS
+ // Provides getShadowOutput(), which returns the data for the shadow type being rendered
+ #include "shadowCasterPS"
+#endif
+
+@fragment
+fn fragmentMain(input: FragmentInput) -> FragmentOutput
+{
+ var output: FragmentOutput;
+
+ #ifdef SHADOW_PASS
+
+ // output shadow data (alpha-tested materials can discard before this)
+ output.color = getShadowOutput();
+
+ #else
+
+ // normal color rendering
+ output.color = ...;
+
+ #endif
+
+ return output;
+}
+```
+
+
+
+
+The same vertex shader is used when rendering shadows, so skinning, morphing and instancing handled by `transformCoreVS` work automatically. It is recommended to skip work not needed by shadow rendering (for example lighting) using `#ifndef SHADOW_PASS`, to make the shadow rendering faster. Note that some engine uniforms, such as `matrix_normal`, are not available during the shadow pass.
+
+Supported are all shadow types for directional lights, and PCF shadows for spot lights. Omni light shadows are not supported.
+
+:::note
+
+For a complete example, see the Shader Material Shadows example in the engine examples browser.
+
+:::
+
+#### Picker Pass {#picker-pass}
+
+To allow meshes using your custom shader to be identified by the [`Picker`](https://api.playcanvas.com/engine/classes/Picker.html), the fragment shader needs to output the mesh instance ID during the pick pass. Include the engine-provided `pickPS` chunk when `PICK_PASS` is defined, and write the value returned by `getPickOutput()` to the output color:
+
+
+
+
+```glsl
+#ifdef PICK_PASS
+ // Provides getPickOutput(), which returns the encoded ID of the mesh instance
+ #include "pickPS"
+#endif
+
+void main(void)
+{
+ #ifdef PICK_PASS
+
+ // output the mesh instance ID
+ gl_FragColor = getPickOutput();
+
+ #else
+
+ // normal color rendering
+ gl_FragColor = ...;
+
+ #endif
+}
+```
+
+
+
+
+```wgsl
+#ifdef PICK_PASS
+ // Provides getPickOutput(), which returns the encoded ID of the mesh instance
+ #include "pickPS"
+#endif
+
+@fragment
+fn fragmentMain(input: FragmentInput) -> FragmentOutput
+{
+ var output: FragmentOutput;
+
+ #ifdef PICK_PASS
+
+ // output the mesh instance ID
+ output.color = getPickOutput();
+
+ #else
+
+ // normal color rendering
+ output.color = ...;
+
+ #endif
+
+ return output;
+}
+```
+
+
+
+
#### Generated Shaders {#generated-shaders}
If you have a need to inspect the generated shaders, you can add this to your script
diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/index.md b/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/index.md
index 5132aae9135..41ad25c4a06 100644
--- a/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/index.md
+++ b/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/graphics/shaders/index.md
@@ -3,6 +3,9 @@ title: シェーダー
description: 対になる GLSL と WGSL で ShaderMaterial を記述し、attribute を宣言してエンジンのシェーダーシステムに統合します。
---
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
3DモデルをPlayCanvasにインポートすると、デフォルトで当社の[Physical Material](/user-manual/graphics/physical-rendering/physical-materials/)が使用されます。これは、レンダリングの多くのニーズをカバーできる多用途なマテリアルタイプです。
しかし、マテリアルに特殊効果や特殊なケースを適用したいと思うことがよくあります。これを行うには、カスタムシェーダーを記述する必要があります。この場合、`ShaderMaterial`を使用する必要があります。
@@ -119,6 +122,9 @@ camera.setShaderPass('custom');
例:
+
+
+
```glsl
// エンジンが提供する変換関連の機能を含みます。
// - `vertex_position`アトリビュートを自動的に宣言します。
@@ -160,12 +166,67 @@ void main(void)
}
```
+
+
+
+```wgsl
+// エンジンが提供する変換関連の機能を含みます。
+// - `vertex_position`アトリビュートを自動的に宣言します。
+// - 必要に応じてスキニングとモーフィングを処理します。
+// - 以下のユニフォームを追加します:
+// - `matrix_viewProjection`
+// - `matrix_model`
+// - `matrix_normal`
+// - ユーティリティ関数を提供します:
+// - `getModelMatrix()`
+// - `getLocalPosition()`
+#include "transformCoreVS"
+
+// エンジンが提供する法線関連の機能を含みます。
+// - `vertex_normal`アトリビュートを自動的に宣言します。
+// - 必要に応じてスキニングとモーフィングを処理します。
+// - ユーティリティ関数を提供します:
+// - `getNormalMatrix()`
+// - `getLocalNormal()`
+#include "normalCoreVS"
+
+@vertex
+fn vertexMain(input: VertexInput) -> VertexOutput
+{
+ var output: VertexOutput;
+
+ // スキニング、モーフィング、またはインスタンス化を考慮してモデル行列を取得します。
+ let modelMatrix: mat4x4f = getModelMatrix();
+ let localPos: vec3f = getLocalPosition(vertex_position.xyz);
+ let worldPos: vec4f = modelMatrix * vec4f(localPos, 1.0);
+
+ // 法線行列を取得し、ワールド法線を計算します。
+ let normalMatrix: mat3x3f = getNormalMatrix(modelMatrix);
+ let localNormal: vec3f = getLocalNormal(vertex_normal);
+ let worldNormal: vec3f = normalize(normalMatrix * localNormal);
+
+ // 例:ワールド法線を使用してシンプルなラップアラウンド拡散ライティングを適用します。
+ output.brightness = (dot(worldNormal, uniform.uLightDir) + 1.0) * 0.5;
+
+ // ジオメトリを変換します。
+ output.position = uniform.matrix_viewProjection * worldPos;
+
+ return output;
+}
+```
+
+
+
+
#### フラグメントシェーダー {#fragment-shader}
エンジンは、ガンマ補正、トーンマッピング、フォグなどの一般的な色処理効果のために含めることができる事前定義されたシェーダーチャンクを提供します。これらのインクルードにより、レンダリング設定に従って色が正しく処理されます。
使用例
+
+
+
```glsl
#include "gammaPS" // 入出力のガンマ補正をサポートします
#include "tonemappingPS" // トーンマッピングをサポートします
@@ -188,6 +249,38 @@ void main(void)
}
```
+
+
+
+```wgsl
+#include "gammaPS" // 入出力のガンマ補正をサポートします
+#include "tonemappingPS" // トーンマッピングをサポートします
+#include "fogPS" // フォグ効果をサポートします
+
+@fragment
+fn fragmentMain(input: FragmentInput) -> FragmentOutput
+{
+ var output: FragmentOutput;
+
+ // リニアカラースペースで色を評価します
+ let colorLinear: vec3f = ...;
+
+ // 有効な場合はフォグを適用します
+ let fogged: vec3f = addFog(colorLinear);
+
+ // 有効な場合はトーンマッピングを適用します
+ let toneMapped: vec3f = toneMap(fogged);
+
+ // ガンマ補正を適用し、最終的な色を出力します
+ output.color = vec4f(gammaCorrectOutput(toneMapped), alpha);
+
+ return output;
+}
+```
+
+
+
+
これらの関数はエンジンの設定に基づいて自動的に構成され、異なるレンダリング条件下でも色処理が一貫していることを保証します。
:::note
@@ -196,6 +289,140 @@ void main(void)
:::
+#### シャドウパス {#shadow-pass}
+
+カスタムシェーダーを使用するメッシュがシャドウをキャストできるようにするには、シャドウパス中に、レンダリングされるシャドウタイプに応じたデータをフラグメントシェーダーから出力する必要があります。`SHADOW_PASS`が定義されている場合にエンジン提供の`shadowCasterPS`チャンクをインクルードし、`getShadowOutput()`が返す値を出力カラーに書き込みます:
+
+
+
+
+```glsl
+#ifdef SHADOW_PASS
+ // レンダリングされるシャドウタイプに応じたデータを返すgetShadowOutput()を提供します
+ #include "shadowCasterPS"
+#endif
+
+void main(void)
+{
+ #ifdef SHADOW_PASS
+
+ // シャドウデータを出力します(アルファテストを行うマテリアルはこの前にdiscardできます)
+ gl_FragColor = getShadowOutput();
+
+ #else
+
+ // 通常のカラーレンダリング
+ gl_FragColor = ...;
+
+ #endif
+}
+```
+
+
+
+
+```wgsl
+#ifdef SHADOW_PASS
+ // レンダリングされるシャドウタイプに応じたデータを返すgetShadowOutput()を提供します
+ #include "shadowCasterPS"
+#endif
+
+@fragment
+fn fragmentMain(input: FragmentInput) -> FragmentOutput
+{
+ var output: FragmentOutput;
+
+ #ifdef SHADOW_PASS
+
+ // シャドウデータを出力します(アルファテストを行うマテリアルはこの前にdiscardできます)
+ output.color = getShadowOutput();
+
+ #else
+
+ // 通常のカラーレンダリング
+ output.color = ...;
+
+ #endif
+
+ return output;
+}
+```
+
+
+
+
+シャドウのレンダリングには同じ頂点シェーダーが使用されるため、`transformCoreVS`によって処理されるスキニング、モーフィング、インスタンス化は自動的に機能します。シャドウレンダリングに不要な処理(例えばライティング)は`#ifndef SHADOW_PASS`を使用してスキップすることをお勧めします。これによりシャドウのレンダリングが高速になります。また、`matrix_normal`などの一部のエンジンユニフォームは、シャドウパス中には利用できないことに注意してください。
+
+サポートされているのは、ディレクショナルライトのすべてのシャドウタイプと、スポットライトのPCFシャドウです。オムニライトのシャドウはサポートされていません。
+
+:::note
+
+完全な例については、エンジンのサンプルブラウザのShader Material Shadowsの例を参照してください。
+
+:::
+
+#### ピッカーパス {#picker-pass}
+
+カスタムシェーダーを使用するメッシュを[`Picker`](https://api.playcanvas.com/engine/classes/Picker.html)で識別できるようにするには、ピックパス中にメッシュインスタンスIDをフラグメントシェーダーから出力する必要があります。`PICK_PASS`が定義されている場合にエンジン提供の`pickPS`チャンクをインクルードし、`getPickOutput()`が返す値を出力カラーに書き込みます:
+
+
+
+
+```glsl
+#ifdef PICK_PASS
+ // メッシュインスタンスのエンコードされたIDを返すgetPickOutput()を提供します
+ #include "pickPS"
+#endif
+
+void main(void)
+{
+ #ifdef PICK_PASS
+
+ // メッシュインスタンスIDを出力します
+ gl_FragColor = getPickOutput();
+
+ #else
+
+ // 通常のカラーレンダリング
+ gl_FragColor = ...;
+
+ #endif
+}
+```
+
+
+
+
+```wgsl
+#ifdef PICK_PASS
+ // メッシュインスタンスのエンコードされたIDを返すgetPickOutput()を提供します
+ #include "pickPS"
+#endif
+
+@fragment
+fn fragmentMain(input: FragmentInput) -> FragmentOutput
+{
+ var output: FragmentOutput;
+
+ #ifdef PICK_PASS
+
+ // メッシュインスタンスIDを出力します
+ output.color = getPickOutput();
+
+ #else
+
+ // 通常のカラーレンダリング
+ output.color = ...;
+
+ #endif
+
+ return output;
+}
+```
+
+
+
+
#### 生成されたシェーダー {#generated-shaders}
生成されたシェーダーを検査する必要がある場合は、これをスクリプトに追加できます