diff --git a/docs/user-manual/gaussian-splatting/building/custom-shaders.md b/docs/user-manual/gaussian-splatting/building/custom-shaders.md
index 702d2f81964..8bae1ff3da1 100644
--- a/docs/user-manual/gaussian-splatting/building/custom-shaders.md
+++ b/docs/user-manual/gaussian-splatting/building/custom-shaders.md
@@ -1,299 +1,137 @@
---
title: Custom Shaders
-description: "Customize non-unified GSplat rendering with the gsplatModifyVS shader chunk: API reference, GLSL and WGSL examples, and live demo links."
+description: "Customize Gaussian splat rendering with the gsplatModifyVS shader chunk on the scene gsplat material: overridable functions, GLSL/WGSL, and a live example."
---
-The PlayCanvas Engine supports custom shaders for Gaussian Splats, allowing you to create advanced visual effects and customize the rendering behavior beyond the standard implementation.
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
-:::note Non-Unified Rendering Only
-
-This page covers shader customization for **non-unified rendering** (when `entity.gsplat.unified = false`). Each component has its own material that can be customized independently.
-
-For **unified rendering**, see [Work Buffer Rendering](/user-manual/gaussian-splatting/rendering-architecture/work-buffer-rendering) which provides similar customization capabilities through a global render modifier.
-
-:::
-
-## Introduction
-
-Override the `gsplatModifyVS` shader chunk to customize splat position, size, and color. This allows you to override only the relevant parts of the shader while leaving the core shader functionality intact.
+The PlayCanvas Engine lets you customize how Gaussian Splats are rendered by overriding the `gsplatModifyVS` shader chunk. The chunk is set on the scene-wide gsplat material ([`app.scene.gsplat.material`](https://api.playcanvas.com/engine/classes/GSplatParams.html#material)), so a single custom shader applies to **all** splats in the scene.
**View Live Example** - See shader chunk customization in action with animated splats.
-## API Reference
-
-The `gsplatModifyVS` shader chunk allows you to override three functions that customize how splats are rendered:
-
-### modifySplatCenter
-
-Transform the position of splat centers in model space.
-
-**GLSL:**
-
-```glsl
-void modifySplatCenter(inout vec3 center)
-```
-
-**WGSL:**
-
-```wgsl
-fn modifySplatCenter(center: ptr)
-```
-
-**Parameters:**
-
-- `center` - The splat center position in model space
-
-**Example:**
-
-```glsl
-// Offset all splats up by 1 unit
-void modifySplatCenter(inout vec3 center) {
- center.y += 1.0;
-}
-```
+## Overridable Functions
-### modifySplatRotationScale
+The `gsplatModifyVS` chunk lets you override three functions in the splat vertex stage:
-Modify the splat size and shape by adjusting the rotation quaternion and scale vector.
+| Function | Purpose |
+| --- | --- |
+| `modifySplatCenter` | Transform the splat center position (model space) |
+| `modifySplatRotationScale` | Adjust the splat rotation quaternion and scale |
+| `modifySplatColor` | Transform the splat color and opacity |
-**GLSL:**
+
+
```glsl
-void modifySplatRotationScale(vec3 originalCenter, vec3 modifiedCenter, inout vec4 rotation, inout vec3 scale)
+void modifySplatCenter(inout vec3 center);
+void modifySplatRotationScale(vec3 originalCenter, vec3 modifiedCenter, inout vec4 rotation, inout vec3 scale);
+void modifySplatColor(vec3 center, inout vec4 color);
```
-**WGSL:**
+
+
```wgsl
-fn modifySplatRotationScale(originalCenter: vec3f, modifiedCenter: vec3f, rotation: ptr, scale: ptr)
+fn modifySplatCenter(center: ptr);
+fn modifySplatRotationScale(originalCenter: vec3f, modifiedCenter: vec3f, rotation: ptr, scale: ptr);
+fn modifySplatColor(center: vec3f, color: ptr);
```
-**Parameters:**
+
+
-- `originalCenter` - The original splat center position before modification
-- `modifiedCenter` - The splat center position after `modifySplatCenter()` was applied
-- `rotation` - Quaternion (x, y, z, w) representing the splat's rotation
-- `scale` - Scale vector representing the splat's size in each axis
+You only need to implement the functions you want to change.
-**Example:**
+## How the Example Works
-```glsl
-// Scale all splats by 2x
-void modifySplatRotationScale(vec3 originalCenter, vec3 modifiedCenter, inout vec4 rotation, inout vec3 scale) {
- scale *= 2.0;
-}
-```
-
-### modifySplatColor
-
-Transform splat colors and opacity.
-
-**GLSL:**
-
-```glsl
-void modifySplatColor(vec3 center, inout vec4 color)
-```
-
-**WGSL:**
-
-```wgsl
-fn modifySplatColor(center: vec3f, color: ptr)
-```
-
-**Parameters:**
+The live example above animates every splat with a sine-wave displacement and a golden color pulse. It comes together in three steps.
-- `center` - The splat center position (after `modifySplatCenter()` was applied)
-- `color` - The splat color (RGBA)
+**1. Write the shader chunk**, overriding the functions you need. The example animates using a `uTime` uniform:
-**Example:**
+
+
```glsl
-// Darken all splats by 50%
-void modifySplatColor(vec3 center, inout vec4 color) {
- color.rgb *= 0.5;
-}
-```
-
-## Usage Examples
-
-### Basic Setup
-
-To apply a custom shader chunk to a Gaussian Splat material:
-
-```javascript
-// Get the shader language for the current device
-const shaderLanguage = device.isWebGPU ? 'wgsl' : 'glsl';
-
-// Define your custom shader code
-const customShader = `
- // Your shader functions here
-`;
-
-// Set the custom shader chunk override on the gsplat material
-gsplatMaterial.getShaderChunks(shaderLanguage).set('gsplatModifyVS', customShader);
-
-// Update the material to recompile with the new shader
-gsplatMaterial.update();
-```
-
-### GLSL Example: Position and Color Animation
-
-```javascript
-const customShader = `
uniform float uTime;
void modifySplatCenter(inout vec3 center) {
- // Create a wave effect based on height
float heightIntensity = center.y * 0.2;
center.x += sin(uTime * 5.0 + center.y) * 0.3 * heightIntensity;
}
void modifySplatRotationScale(vec3 originalCenter, vec3 modifiedCenter, inout vec4 rotation, inout vec3 scale) {
- // No modification to size
+ // no modification
}
-void modifySplatColor(vec3 center, inout vec4 color) {
- // Add a golden tint to the wave peaks
+void modifySplatColor(vec3 center, inout vec4 clr) {
float sineValue = abs(sin(uTime * 5.0 + center.y));
vec3 gold = vec3(1.0, 0.85, 0.0);
float blend = smoothstep(0.9, 1.0, sineValue);
- color.rgb = mix(color.rgb, gold, blend);
+ clr.xyz = mix(clr.xyz, gold, blend);
}
-`;
-
-// Set the custom shader chunk override on the gsplat material
-const shaderLanguage = app.graphicsDevice.isWebGPU ? 'wgsl' : 'glsl';
-gsplatMaterial.getShaderChunks(shaderLanguage).set('gsplatModifyVS', customShader);
-gsplatMaterial.update();
-
-// Update the uniform each frame
-const uTime = app.graphicsDevice.scope.resolve('uTime');
-let time = 0;
-app.on('update', (dt) => {
- time += dt;
- uTime.setValue(time);
-});
```
-### WGSL Example: Position and Color Animation
+
+
-```javascript
-const customShader = `
+```wgsl
uniform uTime: f32;
fn modifySplatCenter(center: ptr) {
- // Create a wave effect based on height
let heightIntensity = (*center).y * 0.2;
(*center).x += sin(uniform.uTime * 5.0 + (*center).y) * 0.3 * heightIntensity;
}
fn modifySplatRotationScale(originalCenter: vec3f, modifiedCenter: vec3f, rotation: ptr, scale: ptr) {
- // No modification to size
+ // no modification
}
-fn modifySplatColor(center: vec3f, color: ptr) {
- // Add a golden tint to the wave peaks
+fn modifySplatColor(center: vec3f, clr: ptr) {
let sineValue = abs(sin(uniform.uTime * 5.0 + center.y));
let gold = vec3f(1.0, 0.85, 0.0);
let blend = smoothstep(0.9, 1.0, sineValue);
- (*color) = vec4f(mix((*color).rgb, gold, blend), (*color).a);
+ (*clr) = vec4f(mix((*clr).xyz, gold, blend), (*clr).a);
}
-`;
-
-// Set the custom shader chunk override on the gsplat material
-const shaderLanguage = app.graphicsDevice.isWebGPU ? 'wgsl' : 'glsl';
-gsplatMaterial.getShaderChunks(shaderLanguage).set('gsplatModifyVS', customShader);
-gsplatMaterial.update();
```
-### Removing Custom Shaders
+
+
-To remove a custom shader and revert to default rendering:
+**2. Apply the chunk to the scene gsplat material**, then update the material so it recompiles. Setting both the GLSL and WGSL chunk covers WebGL and WebGPU devices:
```javascript
-// Remove the custom shader chunk override from the gsplat material
-const shaderLanguage = app.graphicsDevice.isWebGPU ? 'wgsl' : 'glsl';
-gsplatMaterial.getShaderChunks(shaderLanguage).delete('gsplatModifyVS');
-gsplatMaterial.update();
-```
-
-## Helper Functions
-
-The following helper functions are available in `modifySplatRotationScale()` for manipulating splat size and shape:
-
-### gsplatGetSizeFromScale
-
-Extract the current size of a splat from its scale vector.
-
-**GLSL:**
-
-```glsl
-float gsplatGetSizeFromScale(vec3 scale)
-```
-
-**WGSL:**
-
-```wgsl
-fn gsplatGetSizeFromScale(scale: vec3f) -> f32
-```
-
-**Example:**
-
-```glsl
-// Clamp splat size to a specific range
-float size = gsplatGetSizeFromScale(scale);
-float newSize = clamp(size, 0.01, 0.5);
-scale *= newSize / size;
-```
-
-### gsplatMakeSpherical
-
-Make splats spherical with a specific radius.
-
-**GLSL:**
-
-```glsl
-void gsplatMakeSpherical(inout vec3 scale, float radius)
-```
-
-**WGSL:**
+const sceneMat = app.scene.gsplat.material;
-```wgsl
-fn gsplatMakeSpherical(scale: ptr, radius: f32)
+sceneMat.getShaderChunks('glsl').set('gsplatModifyVS', glslVertShader);
+sceneMat.getShaderChunks('wgsl').set('gsplatModifyVS', wgslVertShader);
+sceneMat.update();
```
-**Example:**
-
-```glsl
-// Make all splats perfectly spherical with uniform size
-float size = gsplatGetSizeFromScale(scale);
-gsplatMakeSpherical(scale, size * 0.5);
+**3. Drive any uniforms each frame:**
-// Or hide a splat by setting scale to zero
-scale = vec3(0.0);
+```javascript
+let currentTime = 0;
+app.on('update', (dt) => {
+ currentTime += dt;
+ sceneMat.setParameter('uTime', currentTime);
+ sceneMat.update();
+});
```
-### Direct Scale Manipulation
+## Removing a Custom Shader
-Since the new API provides direct access to the scale vector, you can easily modify splat sizes:
+To revert to default rendering, delete the chunk override and update the material:
-```glsl
-// Double the size of all splats
-scale *= 2.0;
-
-// Scale non-uniformly
-scale.x *= 2.0; // Stretch horizontally
-
-// Hide a splat
-scale = vec3(0.0);
+```javascript
+const sceneMat = app.scene.gsplat.material;
+sceneMat.getShaderChunks('glsl').delete('gsplatModifyVS');
+sceneMat.getShaderChunks('wgsl').delete('gsplatModifyVS');
+sceneMat.update();
```
-## Examples
-
-Here are some examples demonstrating custom shader techniques:
-
-### Animation Effects
+## See Also
-**Simple Sinusoidal Animation** - Applies a simple shader to animate Gaussian color and position using a sine wave. This example demonstrates how to create dynamic, procedural motion effects by modifying splat properties in real-time.
+- [Work Buffer Rendering](/user-manual/gaussian-splatting/rendering-architecture/work-buffer-rendering) — customize the global render pass that draws the sorted splats
diff --git a/docs/user-manual/gaussian-splatting/building/picking.md b/docs/user-manual/gaussian-splatting/building/picking.md
index 1585988e4ca..3a1b08597ef 100644
--- a/docs/user-manual/gaussian-splatting/building/picking.md
+++ b/docs/user-manual/gaussian-splatting/building/picking.md
@@ -1,6 +1,6 @@
---
title: Picking
-description: "Use the PlayCanvas Picker with splats in unified and non-unified modes: setup, depth picking, and code examples."
+description: "Use the PlayCanvas Picker with Gaussian splats: ID setup, depth picking, retrieving world position, and code examples."
---
The PlayCanvas Engine provides a [Picker API](https://api.playcanvas.com/engine/classes/Picker.html) which can query the object rendered at a specified pixel. The picker works with splats in the same way that it does for meshes.
@@ -9,13 +9,6 @@ The PlayCanvas Engine provides a [Picker API](https://api.playcanvas.com/engine/
-## Unified vs Non-Unified Mode
-
-GSplat components can operate in unified or non-unified rendering mode (see [Splat Rendering Architecture](/user-manual/gaussian-splatting/rendering-architecture) for details). The picking behavior differs between these modes:
-
-- **Unified mode**: Picking returns the `GSplatComponent` directly.
-- **Non-unified mode**: Picking returns a mesh instance, which you then match to find the owning entity.
-
## Setting Up the Picker
To pick splats, create a Picker instance with depth enabled (third parameter set to `true`):
@@ -27,24 +20,13 @@ const picker = new pc.Picker(app, 1, 1, true);
The depth buffer is required if you want to retrieve the 3D world position of the picked point, not just identify which object was clicked.
-### Unified Mode Setup
-
-When using unified mode, you must enable ID tracking on the scene's gsplat manager. This should be done before rendering any splats:
+You must also enable ID tracking on the scene's gsplat manager. This should be done before rendering any splats:
```javascript
-// Enable gsplat ID for unified picking
+// Enable gsplat IDs so the picker can identify splat components
app.scene.gsplat.enableIds = true;
```
-And ensure your gsplat components are created with `unified: true`:
-
-```javascript
-entity.addComponent('gsplat', {
- asset: splatAsset,
- unified: true
-});
-```
-
## Preparing for Picking
Before querying the picker, you must render the ID texture by calling `prepare()`:
@@ -71,38 +53,21 @@ const scaledY = mouseY * pickerScale;
## Identifying Picked Objects
-Use `getSelectionAsync()` to get the picked objects at a screen position. The return value differs based on the rendering mode.
-
-### Unified Mode
-
-In unified mode, the picker returns the `GSplatComponent` directly:
+Use `getSelectionAsync()` to get the picked objects at a screen position. The picker returns the `GSplatComponent` directly:
```javascript
const selection = await picker.getSelectionAsync(x, y, 1, 1);
if (selection.length > 0) {
- // In unified mode, selection contains GSplatComponent instances
+ // selection contains GSplatComponent instances
const gsplatComponent = selection[0];
// Find the entity that owns this component
const entity = entities.find(e => e.gsplat === gsplatComponent);
}
```
-### Non-Unified Mode
-
-In non-unified mode, the picker returns mesh instances:
-
-```javascript
-const meshInstances = await picker.getSelectionAsync(x, y, 1, 1);
-if (meshInstances.length > 0) {
- const meshInstance = meshInstances[0];
- // Find entity with matching mesh instance
- const entity = entities.find(e => e.gsplat.instance.meshInstance === meshInstance);
-}
-```
-
## Getting World Position
-Use `getWorldPointAsync()` to get the 3D world position of a picked point. This works the same for both modes:
+Use `getWorldPointAsync()` to get the 3D world position of a picked point:
```javascript
const worldPoint = await picker.getWorldPointAsync(x, y);
@@ -112,19 +77,18 @@ if (worldPoint) {
}
```
-## Complete Example (Unified Mode)
+## Complete Example
-Here's a typical picking workflow for unified mode:
+Here's a typical picking workflow:
```javascript
-// Enable ID tracking for unified picking
+// Enable ID tracking for splat picking
app.scene.gsplat.enableIds = true;
-// Create splat entities with unified mode
+// Create a splat entity
const splat = new pc.Entity('splat');
splat.addComponent('gsplat', {
- asset: splatAsset,
- unified: true
+ asset: splatAsset
});
app.root.addChild(splat);
@@ -151,7 +115,7 @@ const handlePick = async (mouseX, mouseY) => {
const selection = await picker.getSelectionAsync(x, y, 1, 1);
if (selection.length === 0) return;
- // In unified mode, selection contains the GSplatComponent directly
+ // selection contains the GSplatComponent directly
const gsplatComponent = selection[0];
// Find the entity that owns this component
@@ -181,72 +145,6 @@ app.touch.on(pc.EVENT_TOUCHSTART, (event) => {
});
```
-## Complete Example (Non-Unified Mode)
-
-Here's a typical picking workflow for non-unified mode:
-
-```javascript
-// Create splat entities (non-unified is the default)
-const splat = new pc.Entity('splat');
-splat.addComponent('gsplat', {
- asset: splatAsset
-});
-app.root.addChild(splat);
-
-// Create picker with depth support
-const picker = new pc.Picker(app, 1, 1, true);
-
-const handlePick = async (mouseX, mouseY) => {
- // Use lower resolution for performance
- const pickerScale = 0.25;
- picker.resize(canvas.clientWidth * pickerScale, canvas.clientHeight * pickerScale);
-
- // Prepare the picker
- const worldLayer = app.scene.layers.getLayerByName('World');
- picker.prepare(camera.camera, app.scene, [worldLayer]);
-
- const x = mouseX * pickerScale;
- const y = mouseY * pickerScale;
-
- // Get the world position
- const worldPoint = await picker.getWorldPointAsync(x, y);
- if (!worldPoint) return;
-
- // Get the picked object
- const meshInstances = await picker.getSelectionAsync(x, y, 1, 1);
- if (meshInstances.length === 0) return;
-
- const meshInstance = meshInstances[0];
-
- // Find the gsplat entity that owns this mesh instance
- const entity = splatEntities.find(
- e => e.gsplat.instance.meshInstance === meshInstance
- );
-
- if (entity) {
- // Convert world position to entity's local space if needed
- const localPos = entity.getWorldTransform()
- .clone()
- .invert()
- .transformPoint(worldPoint);
-
- console.log('Picked entity:', entity.name);
- console.log('Local position:', localPos);
- }
-};
-
-// Handle mouse clicks
-app.mouse.on(pc.EVENT_MOUSEDOWN, (event) => {
- handlePick(event.x, event.y);
-});
-
-// Handle touch events
-app.touch.on(pc.EVENT_TOUCHSTART, (event) => {
- const touch = event.touches[0];
- handlePick(touch.x, touch.y);
-});
-```
-
## Debugging
The picker exposes its internal buffers which can be useful for debugging:
diff --git a/docs/user-manual/gaussian-splatting/building/shadows.md b/docs/user-manual/gaussian-splatting/building/shadows.md
index 66283bb7b1a..f35f8b4bf89 100644
--- a/docs/user-manual/gaussian-splatting/building/shadows.md
+++ b/docs/user-manual/gaussian-splatting/building/shadows.md
@@ -38,22 +38,12 @@ entity.light.castShadows = true;
For better shadow quality, you can adjust the alpha clip threshold. This controls how transparent splats contribute to shadows — lower values include more semi-transparent splats in the shadow, while higher values create sharper but potentially incomplete shadows.
-### Unified Mode
-
-In unified rendering mode, set the alpha clip threshold on the global GSplat settings:
+Set the alpha clip threshold on the global GSplat settings:
```javascript
app.scene.gsplat.alphaClip = 0.4;
```
-### Non-Unified Mode
-
-In non-unified mode, set the alpha clip threshold directly on the component's material:
-
-```javascript
-entity.gsplat.material.setParameter('alphaClip', 0.4);
-```
-
## Receiving Shadows
Splats cannot directly receive shadows from other objects. However, you can work around this limitation by using a shadow catcher - an invisible mesh that approximates the splat's shape and writes to the depth buffer to receive shadows.
diff --git a/docs/user-manual/gaussian-splatting/rendering-architecture/splat-data-format.md b/docs/user-manual/gaussian-splatting/rendering-architecture/splat-data-format.md
index 1a2610ab810..1d07fd663f8 100644
--- a/docs/user-manual/gaussian-splatting/rendering-architecture/splat-data-format.md
+++ b/docs/user-manual/gaussian-splatting/rendering-architecture/splat-data-format.md
@@ -3,6 +3,9 @@ title: Splat Data Format
description: "GSplatFormat and GPU texture streams: how splat attributes are stored, shader access, and customizing splat data layout (beta)."
---
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
`GSplatFormat` describes how splat data is stored in GPU textures and generates the shader code needed to read that data. It defines texture streams (name and pixel format) and shader code for extracting splat attributes.
:::info Beta Feature
@@ -29,18 +32,25 @@ The format generates shader functions to read splat data from texture streams. T
By default, each splat reads its own data. To read from a different splat, use `setSplat(index)`:
+
+
+
```glsl
-// GLSL
setSplat(otherIndex); // Set the splat index for subsequent reads
vec3 pos = getCenter(); // Now reads from otherIndex
```
+
+
+
```wgsl
-// WGSL
setSplat(otherIndex);
let pos = getCenter();
```
+
+
+
### Load Functions
For each stream, two load functions are generated:
@@ -55,16 +65,24 @@ For example, a stream named `dataCenter` generates:
- `loadDataCenter()` - reads using current splat index
- `loadDataCenterWithIndex(index)` - reads from specified index
+
+
+
```glsl
-// GLSL - Read from specific index without changing current splat
+// Read from specific index without changing current splat
vec4 otherCenter = loadDataCenterWithIndex(neighborIndex);
```
+
+
+
```wgsl
-// WGSL
let otherCenter = loadDataCenterWithIndex(neighborIndex);
```
+
+
+
This is useful when you need to access neighbor splats or compare data across multiple splats.
## Format for Loaded Resources
diff --git a/docusaurus.config.js b/docusaurus.config.js
index 55a1536bb87..bea54798411 100644
--- a/docusaurus.config.js
+++ b/docusaurus.config.js
@@ -418,7 +418,7 @@ const config = {
prism: {
theme: prismThemes.github,
darkTheme: prismThemes.dracula,
- additionalLanguages: ['glsl'],
+ additionalLanguages: ['glsl', 'wgsl'],
},
}),
};
diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/gaussian-splatting/building/custom-shaders.md b/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/gaussian-splatting/building/custom-shaders.md
index ef34283f1a3..c19b2cf81e4 100644
--- a/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/gaussian-splatting/building/custom-shaders.md
+++ b/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/gaussian-splatting/building/custom-shaders.md
@@ -1,299 +1,137 @@
---
title: カスタムシェーダー
-description: "非統合GSplatレンダリングをgsplatModifyVSシェーダーチャンクでカスタマイズ。APIリファレンス、GLSLとWGSLの例、ライブデモへのリンクです。"
+description: "Gaussianスプラットのレンダリングをシーンのgsplatマテリアル上のgsplatModifyVSシェーダーチャンクでカスタマイズ:オーバーライド可能な関数、GLSL/WGSL、ライブサンプルです。"
---
-PlayCanvas Engineは、Gaussian Splats用のカスタムシェーダーをサポートしており、高度な視覚効果を作成し、標準実装を超えたレンダリング動作をカスタマイズできます。
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
-:::note 非統合レンダリング専用
-
-このページは**非統合レンダリング**(`entity.gsplat.unified = false`の場合)のシェーダーカスタマイズについて説明します。各コンポーネントには独立してカスタマイズできる独自のマテリアルがあります。
-
-**統合レンダリング**については、グローバルレンダリングモディファイアを通じて同様のカスタマイズ機能を提供する[ワークバッファレンダリング](/user-manual/gaussian-splatting/rendering-architecture/work-buffer-rendering)を参照してください。
-
-:::
-
-## はじめに
-
-`gsplatModifyVS`シェーダーチャンクをオーバーライドして、スプラットの位置、サイズ、色をカスタマイズします。これにより、コアシェーダー機能はそのままに、関連する部分のみをオーバーライドできます。
+PlayCanvas Engineでは、`gsplatModifyVS`シェーダーチャンクをオーバーライドすることで、Gaussian Splatsのレンダリング方法をカスタマイズできます。このチャンクはシーン全体のgsplatマテリアル([`app.scene.gsplat.material`](https://api.playcanvas.com/engine/classes/GSplatParams.html#material))に設定されるため、1つのカスタムシェーダーがシーン内の**すべての**スプラットに適用されます。
**ライブサンプルを見る** - アニメーションスプラットでシェーダーチャンクのカスタマイズを実際に見てください。
-## APIリファレンス
-
-`gsplatModifyVS`シェーダーチャンクでは、スプラットのレンダリング方法をカスタマイズする3つの関数をオーバーライドできます:
-
-### modifySplatCenter
-
-モデル空間でスプラット中心の位置を変換します。
-
-**GLSL:**
-
-```glsl
-void modifySplatCenter(inout vec3 center)
-```
-
-**WGSL:**
-
-```wgsl
-fn modifySplatCenter(center: ptr)
-```
-
-**パラメータ:**
-
-- `center` - モデル空間でのスプラット中心位置
-
-**例:**
-
-```glsl
-// すべてのスプラットを1ユニット上にオフセット
-void modifySplatCenter(inout vec3 center) {
- center.y += 1.0;
-}
-```
+## オーバーライド可能な関数
-### modifySplatRotationScale
+`gsplatModifyVS`チャンクでは、スプラットの頂点ステージで3つの関数をオーバーライドできます:
-回転クォータニオンとスケールベクトルを調整してスプラットのサイズと形状を変更します。
+| 関数 | 目的 |
+| --- | --- |
+| `modifySplatCenter` | スプラットの中心位置を変換(モデル空間) |
+| `modifySplatRotationScale` | スプラットの回転クォータニオンとスケールを調整 |
+| `modifySplatColor` | スプラットの色と不透明度を変換 |
-**GLSL:**
+
+
```glsl
-void modifySplatRotationScale(vec3 originalCenter, vec3 modifiedCenter, inout vec4 rotation, inout vec3 scale)
+void modifySplatCenter(inout vec3 center);
+void modifySplatRotationScale(vec3 originalCenter, vec3 modifiedCenter, inout vec4 rotation, inout vec3 scale);
+void modifySplatColor(vec3 center, inout vec4 color);
```
-**WGSL:**
+
+
```wgsl
-fn modifySplatRotationScale(originalCenter: vec3f, modifiedCenter: vec3f, rotation: ptr, scale: ptr)
+fn modifySplatCenter(center: ptr);
+fn modifySplatRotationScale(originalCenter: vec3f, modifiedCenter: vec3f, rotation: ptr, scale: ptr);
+fn modifySplatColor(center: vec3f, color: ptr);
```
-**パラメータ:**
+
+
-- `originalCenter` - 変更前の元のスプラット中心位置
-- `modifiedCenter` - `modifySplatCenter()`適用後のスプラット中心位置
-- `rotation` - スプラットの回転を表すクォータニオン(x, y, z, w)
-- `scale` - 各軸でのスプラットのサイズを表すスケールベクトル
+変更したい関数だけを実装すれば十分です。
-**例:**
+## サンプルの仕組み
-```glsl
-// すべてのスプラットを2倍にスケール
-void modifySplatRotationScale(vec3 originalCenter, vec3 modifiedCenter, inout vec4 rotation, inout vec3 scale) {
- scale *= 2.0;
-}
-```
-
-### modifySplatColor
-
-スプラットの色と不透明度を変換します。
-
-**GLSL:**
-
-```glsl
-void modifySplatColor(vec3 center, inout vec4 color)
-```
-
-**WGSL:**
-
-```wgsl
-fn modifySplatColor(center: vec3f, color: ptr)
-```
-
-**パラメータ:**
+上記のライブサンプルは、サイン波による変位と金色のカラーパルスですべてのスプラットをアニメーションさせています。これは3つのステップで構成されます。
-- `center` - スプラット中心位置(`modifySplatCenter()`適用後)
-- `color` - スプラットの色(RGBA)
+**1. シェーダーチャンクを記述**し、必要な関数をオーバーライドします。サンプルでは`uTime`ユニフォームを使ってアニメーションさせています:
-**例:**
+
+
```glsl
-// すべてのスプラットを50%暗くする
-void modifySplatColor(vec3 center, inout vec4 color) {
- color.rgb *= 0.5;
-}
-```
-
-## 使用例
-
-### 基本的なセットアップ
-
-Gaussian Splatマテリアルにカスタムシェーダーチャンクを適用するには:
-
-```javascript
-// 現在のデバイスのシェーダー言語を取得
-const shaderLanguage = device.isWebGPU ? 'wgsl' : 'glsl';
-
-// カスタムシェーダーコードを定義
-const customShader = `
- // ここにシェーダー関数を記述
-`;
-
-// gsplatマテリアルにカスタムシェーダーチャンクのオーバーライドを設定
-gsplatMaterial.getShaderChunks(shaderLanguage).set('gsplatModifyVS', customShader);
-
-// 新しいシェーダーで再コンパイルするためにマテリアルを更新
-gsplatMaterial.update();
-```
-
-### GLSLの例:位置と色のアニメーション
-
-```javascript
-const customShader = `
uniform float uTime;
void modifySplatCenter(inout vec3 center) {
- // 高さに基づいて波のエフェクトを作成
float heightIntensity = center.y * 0.2;
center.x += sin(uTime * 5.0 + center.y) * 0.3 * heightIntensity;
}
void modifySplatRotationScale(vec3 originalCenter, vec3 modifiedCenter, inout vec4 rotation, inout vec3 scale) {
- // サイズの変更なし
+ // 変更なし
}
-void modifySplatColor(vec3 center, inout vec4 color) {
- // 波のピークにゴールドのティントを追加
+void modifySplatColor(vec3 center, inout vec4 clr) {
float sineValue = abs(sin(uTime * 5.0 + center.y));
vec3 gold = vec3(1.0, 0.85, 0.0);
float blend = smoothstep(0.9, 1.0, sineValue);
- color.rgb = mix(color.rgb, gold, blend);
+ clr.xyz = mix(clr.xyz, gold, blend);
}
-`;
-
-// gsplatマテリアルにカスタムシェーダーチャンクのオーバーライドを設定
-const shaderLanguage = app.graphicsDevice.isWebGPU ? 'wgsl' : 'glsl';
-gsplatMaterial.getShaderChunks(shaderLanguage).set('gsplatModifyVS', customShader);
-gsplatMaterial.update();
-
-// 毎フレームユニフォームを更新
-const uTime = app.graphicsDevice.scope.resolve('uTime');
-let time = 0;
-app.on('update', (dt) => {
- time += dt;
- uTime.setValue(time);
-});
```
-### WGSLの例:位置と色のアニメーション
+
+
-```javascript
-const customShader = `
+```wgsl
uniform uTime: f32;
fn modifySplatCenter(center: ptr) {
- // 高さに基づいて波のエフェクトを作成
let heightIntensity = (*center).y * 0.2;
(*center).x += sin(uniform.uTime * 5.0 + (*center).y) * 0.3 * heightIntensity;
}
fn modifySplatRotationScale(originalCenter: vec3f, modifiedCenter: vec3f, rotation: ptr, scale: ptr) {
- // サイズの変更なし
+ // 変更なし
}
-fn modifySplatColor(center: vec3f, color: ptr) {
- // 波のピークにゴールドのティントを追加
+fn modifySplatColor(center: vec3f, clr: ptr) {
let sineValue = abs(sin(uniform.uTime * 5.0 + center.y));
let gold = vec3f(1.0, 0.85, 0.0);
let blend = smoothstep(0.9, 1.0, sineValue);
- (*color) = vec4f(mix((*color).rgb, gold, blend), (*color).a);
+ (*clr) = vec4f(mix((*clr).xyz, gold, blend), (*clr).a);
}
-`;
-
-// gsplatマテリアルにカスタムシェーダーチャンクのオーバーライドを設定
-const shaderLanguage = app.graphicsDevice.isWebGPU ? 'wgsl' : 'glsl';
-gsplatMaterial.getShaderChunks(shaderLanguage).set('gsplatModifyVS', customShader);
-gsplatMaterial.update();
```
-### カスタムシェーダーの削除
+
+
-カスタムシェーダーを削除してデフォルトのレンダリングに戻すには:
+**2. チャンクをシーンのgsplatマテリアルに適用**し、マテリアルを更新して再コンパイルします。GLSLとWGSLの両方のチャンクを設定すると、WebGLとWebGPUの両方のデバイスに対応できます:
```javascript
-// gsplatマテリアルからカスタムシェーダーチャンクのオーバーライドを削除
-const shaderLanguage = app.graphicsDevice.isWebGPU ? 'wgsl' : 'glsl';
-gsplatMaterial.getShaderChunks(shaderLanguage).delete('gsplatModifyVS');
-gsplatMaterial.update();
-```
-
-## ヘルパー関数
-
-以下のヘルパー関数は、スプラットのサイズと形状を操作するために`modifySplatRotationScale()`で利用できます:
-
-### gsplatGetSizeFromScale
-
-スケールベクトルからスプラットの現在のサイズを抽出します。
-
-**GLSL:**
-
-```glsl
-float gsplatGetSizeFromScale(vec3 scale)
-```
-
-**WGSL:**
-
-```wgsl
-fn gsplatGetSizeFromScale(scale: vec3f) -> f32
-```
-
-**例:**
-
-```glsl
-// スプラットサイズを特定の範囲にクランプ
-float size = gsplatGetSizeFromScale(scale);
-float newSize = clamp(size, 0.01, 0.5);
-scale *= newSize / size;
-```
-
-### gsplatMakeSpherical
-
-特定の半径でスプラットを球形にします。
-
-**GLSL:**
-
-```glsl
-void gsplatMakeSpherical(inout vec3 scale, float radius)
-```
-
-**WGSL:**
+const sceneMat = app.scene.gsplat.material;
-```wgsl
-fn gsplatMakeSpherical(scale: ptr, radius: f32)
+sceneMat.getShaderChunks('glsl').set('gsplatModifyVS', glslVertShader);
+sceneMat.getShaderChunks('wgsl').set('gsplatModifyVS', wgslVertShader);
+sceneMat.update();
```
-**例:**
-
-```glsl
-// すべてのスプラットを均一なサイズの完全な球形にする
-float size = gsplatGetSizeFromScale(scale);
-gsplatMakeSpherical(scale, size * 0.5);
+**3. ユニフォームを毎フレーム更新します:**
-// またはスケールをゼロに設定してスプラットを非表示にする
-scale = vec3(0.0);
+```javascript
+let currentTime = 0;
+app.on('update', (dt) => {
+ currentTime += dt;
+ sceneMat.setParameter('uTime', currentTime);
+ sceneMat.update();
+});
```
-### 直接スケール操作
+## カスタムシェーダーの削除
-新しいAPIはスケールベクトルへの直接アクセスを提供するため、スプラットサイズを簡単に変更できます:
+デフォルトのレンダリングに戻すには、チャンクのオーバーライドを削除してマテリアルを更新します:
-```glsl
-// すべてのスプラットのサイズを2倍にする
-scale *= 2.0;
-
-// 非均一にスケール
-scale.x *= 2.0; // 水平方向に伸ばす
-
-// スプラットを非表示にする
-scale = vec3(0.0);
+```javascript
+const sceneMat = app.scene.gsplat.material;
+sceneMat.getShaderChunks('glsl').delete('gsplatModifyVS');
+sceneMat.getShaderChunks('wgsl').delete('gsplatModifyVS');
+sceneMat.update();
```
-## サンプル
-
-カスタムシェーダーテクニックを示すいくつかの例:
-
-### アニメーションエフェクト
+## 関連項目
-**シンプルな正弦波アニメーション** - 正弦波を使用してGaussianの色と位置をアニメーションするシンプルなシェーダーを適用します。この例では、スプラットプロパティをリアルタイムで変更して動的なプロシージャルモーションエフェクトを作成する方法を示しています。
+- [ワークバッファレンダリング](/user-manual/gaussian-splatting/rendering-architecture/work-buffer-rendering) — ソート済みスプラットを描画するグローバルなレンダーパスをカスタマイズ
diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/gaussian-splatting/building/picking.md b/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/gaussian-splatting/building/picking.md
index cdd72403899..0da843ac804 100644
--- a/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/gaussian-splatting/building/picking.md
+++ b/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/gaussian-splatting/building/picking.md
@@ -1,6 +1,6 @@
---
title: ピッキング
-description: "統合モードと非統合モードのスプラットでPlayCanvas Pickerを使う設定、深度ピッキング、コード例です。"
+description: "Gaussianスプラットで PlayCanvas Picker を使う:ID設定、深度ピッキング、ワールド位置の取得、コード例です。"
---
PlayCanvas Engine は、指定されたピクセルでレンダリングされたオブジェクトをクエリできる[Picker API](https://api.playcanvas.com/engine/classes/Picker.html)を提供します。ピッカーは、メッシュの場合と同じ方法でスプラットと連携します。
@@ -9,13 +9,6 @@ PlayCanvas Engine は、指定されたピクセルでレンダリングされ
-## Unified モードと Non-Unified モード
-
-GSplat コンポーネントは Unified または Non-Unified レンダリングモードで動作できます(詳細は[スプラットレンダリングアーキテクチャ](/user-manual/gaussian-splatting/rendering-architecture)を参照)。ピッキングの動作はこれらのモード間で異なります:
-
-- **Unified モード**:ピッキングは `GSplatComponent` を直接返します。
-- **Non-Unified モード**:ピッキングはメッシュインスタンスを返し、それを使用して所有するエンティティを見つけます。
-
## Picker のセットアップ
スプラットをピッキングするには、深度を有効にして(3番目のパラメータを `true` に設定)Picker インスタンスを作成します:
@@ -27,24 +20,13 @@ const picker = new pc.Picker(app, 1, 1, true);
深度バッファは、クリックされたオブジェクトを識別するだけでなく、ピッキングされたポイントの3Dワールド位置を取得する場合に必要です。
-### Unified モードのセットアップ
-
-Unified モードを使用する場合、シーンの gsplat マネージャーで ID トラッキングを有効にする必要があります。これはスプラットをレンダリングする前に行う必要があります:
+また、シーンの gsplat マネージャーで ID トラッキングを有効にする必要があります。これはスプラットをレンダリングする前に行う必要があります:
```javascript
-// Unified ピッキング用に gsplat ID を有効化
+// ピッカーがスプラットコンポーネントを識別できるよう gsplat ID を有効化
app.scene.gsplat.enableIds = true;
```
-また、gsplat コンポーネントを `unified: true` で作成することを確認してください:
-
-```javascript
-entity.addComponent('gsplat', {
- asset: splatAsset,
- unified: true
-});
-```
-
## ピッキングの準備
ピッカーにクエリを送る前に、`prepare()` を呼び出してIDテクスチャをレンダリングする必要があります:
@@ -71,38 +53,21 @@ const scaledY = mouseY * pickerScale;
## ピッキングされたオブジェクトの識別
-`getSelectionAsync()` を使用して、スクリーン位置でピッキングされたオブジェクトを取得します。戻り値はレンダリングモードによって異なります。
-
-### Unified モード
-
-Unified モードでは、ピッカーは `GSplatComponent` を直接返します:
+`getSelectionAsync()` を使用して、スクリーン位置でピッキングされたオブジェクトを取得します。ピッカーは `GSplatComponent` を直接返します:
```javascript
const selection = await picker.getSelectionAsync(x, y, 1, 1);
if (selection.length > 0) {
- // Unified モードでは、selection には GSplatComponent インスタンスが含まれます
+ // selection には GSplatComponent インスタンスが含まれます
const gsplatComponent = selection[0];
// このコンポーネントを所有するエンティティを見つける
const entity = entities.find(e => e.gsplat === gsplatComponent);
}
```
-### Non-Unified モード
-
-Non-Unified モードでは、ピッカーはメッシュインスタンスを返します:
-
-```javascript
-const meshInstances = await picker.getSelectionAsync(x, y, 1, 1);
-if (meshInstances.length > 0) {
- const meshInstance = meshInstances[0];
- // 一致するメッシュインスタンスを持つエンティティを見つける
- const entity = entities.find(e => e.gsplat.instance.meshInstance === meshInstance);
-}
-```
-
## ワールド位置の取得
-`getWorldPointAsync()` を使用して、ピッキングされたポイントの3Dワールド位置を取得します。これは両方のモードで同じように動作します:
+`getWorldPointAsync()` を使用して、ピッキングされたポイントの3Dワールド位置を取得します:
```javascript
const worldPoint = await picker.getWorldPointAsync(x, y);
@@ -112,19 +77,18 @@ if (worldPoint) {
}
```
-## 完全なサンプル(Unified モード)
+## 完全なサンプル
-Unified モードの一般的なピッキングワークフローは次のとおりです:
+一般的なピッキングワークフローは次のとおりです:
```javascript
-// Unified ピッキング用に ID トラッキングを有効化
+// スプラットピッキング用に ID トラッキングを有効化
app.scene.gsplat.enableIds = true;
-// Unified モードでスプラットエンティティを作成
+// スプラットエンティティを作成
const splat = new pc.Entity('splat');
splat.addComponent('gsplat', {
- asset: splatAsset,
- unified: true
+ asset: splatAsset
});
app.root.addChild(splat);
@@ -151,7 +115,7 @@ const handlePick = async (mouseX, mouseY) => {
const selection = await picker.getSelectionAsync(x, y, 1, 1);
if (selection.length === 0) return;
- // Unified モードでは、selection には GSplatComponent が直接含まれます
+ // selection には GSplatComponent が直接含まれます
const gsplatComponent = selection[0];
// このコンポーネントを所有するエンティティを見つける
@@ -181,72 +145,6 @@ app.touch.on(pc.EVENT_TOUCHSTART, (event) => {
});
```
-## 完全なサンプル(Non-Unified モード)
-
-Non-Unified モードの一般的なピッキングワークフローは次のとおりです:
-
-```javascript
-// スプラットエンティティを作成(Non-Unified がデフォルト)
-const splat = new pc.Entity('splat');
-splat.addComponent('gsplat', {
- asset: splatAsset
-});
-app.root.addChild(splat);
-
-// 深度サポート付きでピッカーを作成
-const picker = new pc.Picker(app, 1, 1, true);
-
-const handlePick = async (mouseX, mouseY) => {
- // パフォーマンスのために低解像度を使用
- const pickerScale = 0.25;
- picker.resize(canvas.clientWidth * pickerScale, canvas.clientHeight * pickerScale);
-
- // ピッカーを準備
- const worldLayer = app.scene.layers.getLayerByName('World');
- picker.prepare(camera.camera, app.scene, [worldLayer]);
-
- const x = mouseX * pickerScale;
- const y = mouseY * pickerScale;
-
- // ワールド位置を取得
- const worldPoint = await picker.getWorldPointAsync(x, y);
- if (!worldPoint) return;
-
- // ピッキングされたオブジェクトを取得
- const meshInstances = await picker.getSelectionAsync(x, y, 1, 1);
- if (meshInstances.length === 0) return;
-
- const meshInstance = meshInstances[0];
-
- // このメッシュインスタンスを所有する gsplat エンティティを見つける
- const entity = splatEntities.find(
- e => e.gsplat.instance.meshInstance === meshInstance
- );
-
- if (entity) {
- // 必要に応じてワールド位置をエンティティのローカル空間に変換
- const localPos = entity.getWorldTransform()
- .clone()
- .invert()
- .transformPoint(worldPoint);
-
- console.log('ピッキングされたエンティティ:', entity.name);
- console.log('ローカル位置:', localPos);
- }
-};
-
-// マウスクリックを処理
-app.mouse.on(pc.EVENT_MOUSEDOWN, (event) => {
- handlePick(event.x, event.y);
-});
-
-// タッチイベントを処理
-app.touch.on(pc.EVENT_TOUCHSTART, (event) => {
- const touch = event.touches[0];
- handlePick(touch.x, touch.y);
-});
-```
-
## デバッグ
ピッカーは内部バッファを公開しており、デバッグに役立ちます:
diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/gaussian-splatting/building/shadows.md b/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/gaussian-splatting/building/shadows.md
index e827ab707d4..419dd4edaf9 100644
--- a/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/gaussian-splatting/building/shadows.md
+++ b/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/gaussian-splatting/building/shadows.md
@@ -38,22 +38,12 @@ entity.light.castShadows = true;
アルファクリップしきい値を調整することで、影の品質を向上させることができます。これは半透明のスプラットが影にどのように寄与するかを制御します。値が低いほど、より多くの半透明スプラットが影に含まれます。値が高いほど、よりシャープですが不完全な影になる可能性があります。
-### 統合モード
-
-統合レンダリングモードでは、グローバルGSplat設定でアルファクリップしきい値を設定します:
+グローバルGSplat設定でアルファクリップしきい値を設定します:
```javascript
app.scene.gsplat.alphaClip = 0.4;
```
-### 非統合モード
-
-非統合モードでは、コンポーネントのマテリアルに直接アルファクリップしきい値を設定します:
-
-```javascript
-entity.gsplat.material.setParameter('alphaClip', 0.4);
-```
-
## 影の受け取り
スプラットは他のオブジェクトからの影を直接受け取ることができません。ただし、シャドウキャッチャーを使用することでこの制限を回避できます。シャドウキャッチャーは、スプラットの形状を近似し、デプスバッファに書き込んで影を受け取る不可視のメッシュです。
diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/gaussian-splatting/rendering-architecture/splat-data-format.md b/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/gaussian-splatting/rendering-architecture/splat-data-format.md
index 4ecf2a51456..11e68308f34 100644
--- a/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/gaussian-splatting/rendering-architecture/splat-data-format.md
+++ b/i18n/ja/docusaurus-plugin-content-docs/current/user-manual/gaussian-splatting/rendering-architecture/splat-data-format.md
@@ -3,6 +3,9 @@ title: スプラットデータフォーマット
description: "GSplatFormatとGPUテクスチャストリーム:スプラット属性の格納、シェーダーからのアクセス、データレイアウトのカスタマイズ(ベータ)。"
---
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
`GSplatFormat`は、スプラットデータがGPUテクスチャにどのように格納されるかを記述し、そのデータを読み取るために必要なシェーダーコードを生成します。テクスチャストリーム(名前とピクセルフォーマット)とスプラット属性を抽出するためのシェーダーコードを定義します。
:::info ベータ機能
@@ -29,18 +32,25 @@ GSplatデータは**ストリーム**と呼ばれるGPUテクスチャに格納
デフォルトでは、各スプラットは自身のデータを読み取ります。別のスプラットから読み取るには、`setSplat(index)`を使用します:
+
+
+
```glsl
-// GLSL
setSplat(otherIndex); // 後続の読み取りのためにスプラットインデックスを設定
vec3 pos = getCenter(); // otherIndexから読み取る
```
+
+
+
```wgsl
-// WGSL
setSplat(otherIndex);
let pos = getCenter();
```
+
+
+
### ロード関数
各ストリームに対して、2つのロード関数が生成されます:
@@ -55,16 +65,24 @@ let pos = getCenter();
- `loadDataCenter()` - 現在のスプラットインデックスを使用して読み取る
- `loadDataCenterWithIndex(index)` - 指定されたインデックスから読み取る
+
+
+
```glsl
-// GLSL - 現在のスプラットを変更せずに特定のインデックスから読み取る
+// 現在のスプラットを変更せずに特定のインデックスから読み取る
vec4 otherCenter = loadDataCenterWithIndex(neighborIndex);
```
+
+
+
```wgsl
-// WGSL
let otherCenter = loadDataCenterWithIndex(neighborIndex);
```
+
+
+
これは、隣接するスプラットにアクセスしたり、複数のスプラット間でデータを比較する必要がある場合に便利です。
## ロードされたリソースのフォーマット