ue-mcp-plugin-voxel-plugin 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -50
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/package.json +4 -3
- package/ue-mcp.plugin.yml +11 -60
- package/dist/shared/voxelGraph.d.ts +0 -31
- package/dist/shared/voxelGraph.js +0 -65
- package/dist/shared/voxelGraph.js.map +0 -1
- package/dist/tasks/BakeHeightmap.d.ts +0 -37
- package/dist/tasks/BakeHeightmap.js +0 -101
- package/dist/tasks/BakeHeightmap.js.map +0 -1
- package/dist/tasks/ScatterMeshes.d.ts +0 -25
- package/dist/tasks/ScatterMeshes.js +0 -52
- package/dist/tasks/ScatterMeshes.js.map +0 -1
- package/dist/tasks/SpawnStamps.d.ts +0 -23
- package/dist/tasks/SpawnStamps.js +0 -51
- package/dist/tasks/SpawnStamps.js.map +0 -1
- package/knowledge/landscape.md +0 -34
- package/knowledge/pcg.md +0 -50
package/README.md
CHANGED
|
@@ -2,55 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
[Voxel Plugin](https://voxelplugin.com) actions for [ue-mcp](https://github.com/db-lyon/ue-mcp).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Status
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
**v0.1.1 ships no actions.** The `0.1.0` release injected three placeholder
|
|
8
|
+
actions (`voxel_scatter_meshes`, `voxel_spawn_stamps`, `voxel_bake_heightmap`)
|
|
9
|
+
that called ue-mcp tasks with wrong parameter names and passed PCG node-type
|
|
10
|
+
strings that do not exist. They have been removed rather than left as broken
|
|
11
|
+
surface.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Real tools, grounded in the actual Voxel Plugin C++ API, are tracked in
|
|
14
|
+
[`TODO.md`](TODO.md). Every entry there cites the header file and class it
|
|
15
|
+
wraps.
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
Do not depend on this package yet — it intentionally exposes nothing.
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
## Requirements (for future versions)
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
The CLI runs `npm install --save`, validates the plugin manifest, adds an entry under `plugins:` in your `ue-mcp.yml`, and prints a restart instruction. Injected actions appear on the next ue-mcp server start.
|
|
24
|
-
|
|
25
|
-
## Requirements
|
|
26
|
-
|
|
27
|
-
- ue-mcp `>= 1.0.15`.
|
|
28
|
-
- Voxel Plugin enabled in your `.uproject` (`Plugins[].Name == "Voxel"`). The installer warns at install time if it's missing.
|
|
29
|
-
- An active Voxel Plugin Pro subscription if your project's use case requires it - the upstream source repo is public-readable but commercial use is gated by the upstream license.
|
|
30
|
-
|
|
31
|
-
## Usage
|
|
32
|
-
|
|
33
|
-
The actions appear natively inside their host categories - no new tool to learn:
|
|
34
|
-
|
|
35
|
-
```text
|
|
36
|
-
pcg(action="voxel_scatter_meshes",
|
|
37
|
-
graphPath="/Game/PCG/Scatter",
|
|
38
|
-
mesh="/Game/Foliage/Rock.Rock",
|
|
39
|
-
density=0.25)
|
|
40
|
-
|
|
41
|
-
pcg(action="execute", graphPath="/Game/PCG/Scatter")
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
Or via the bundled flow:
|
|
45
|
-
|
|
46
|
-
```text
|
|
47
|
-
flow(action="run", flowName="voxel_scatter_setup", params={
|
|
48
|
-
graphPath: "/Game/PCG/Scatter",
|
|
49
|
-
mesh: "/Game/Foliage/Rock.Rock"
|
|
50
|
-
})
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
See `knowledge/pcg.md` and `knowledge/landscape.md` for the full parameter reference. The same content is attached to the host category's AI-facing docs at server start so MCP agents see it natively.
|
|
21
|
+
- ue-mcp `>= 1.0.15`
|
|
22
|
+
- Voxel Plugin enabled in your `.uproject` (`Plugins[].Name == "Voxel"`)
|
|
54
23
|
|
|
55
24
|
## Develop
|
|
56
25
|
|
|
@@ -61,12 +30,6 @@ npm install
|
|
|
61
30
|
npm run build
|
|
62
31
|
```
|
|
63
32
|
|
|
64
|
-
The plugin compiles to `dist/`. To test against a local checkout of ue-mcp, `npm link` this package and `npm link ue-mcp-plugin-voxel-plugin` from your project directory.
|
|
65
|
-
|
|
66
|
-
## Why a plugin?
|
|
67
|
-
|
|
68
|
-
ue-mcp's plugin model injects new actions into existing built-in categories rather than creating a separate tool. The agent already working in `pcg` discovers `voxel_scatter_meshes` exactly when it's relevant - it does not need to know there is a separate Voxel surface to open. See the [ue-mcp plugin docs](https://db-lyon.github.io/ue-mcp/plugins/) for the full author contract.
|
|
69
|
-
|
|
70
33
|
## License
|
|
71
34
|
|
|
72
35
|
MIT - see `LICENSE`.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ue-mcp-plugin-voxel-plugin",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Voxel Plugin actions for ue-mcp
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Voxel Plugin actions for ue-mcp. Scaffold only at this version - real tools tracked in TODO.md.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"files": [
|
|
@@ -34,7 +34,8 @@
|
|
|
34
34
|
"typescript": "^5.7.0"
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
|
-
"
|
|
37
|
+
"clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
38
|
+
"build": "npm run clean && tsc",
|
|
38
39
|
"prepublishOnly": "npm run build"
|
|
39
40
|
},
|
|
40
41
|
"engines": {
|
package/ue-mcp.plugin.yml
CHANGED
|
@@ -2,63 +2,14 @@ actionPrefix: voxel
|
|
|
2
2
|
minServerVersion: 1.0.15
|
|
3
3
|
uePluginDependency: Voxel
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
seed: { type: number }
|
|
17
|
-
spawn_stamps:
|
|
18
|
-
task: voxel.spawn_stamps
|
|
19
|
-
description: "Build a PCG graph that places voxel stamp assets on a voxel terrain. Params: graphPath, stampAsset, count?, radius?, seed?"
|
|
20
|
-
schema:
|
|
21
|
-
graphPath: { type: string, required: true }
|
|
22
|
-
stampAsset: { type: string, required: true }
|
|
23
|
-
count: { type: number }
|
|
24
|
-
radius: { type: number }
|
|
25
|
-
seed: { type: number }
|
|
26
|
-
|
|
27
|
-
landscape:
|
|
28
|
-
bake_heightmap:
|
|
29
|
-
task: voxel.bake_heightmap
|
|
30
|
-
description: "Bake a region of a voxel terrain into a standard Landscape heightmap. Params: landscapeLabel, bounds, resolution?"
|
|
31
|
-
schema:
|
|
32
|
-
landscapeLabel: { type: string, required: true }
|
|
33
|
-
bounds: { type: object, required: true }
|
|
34
|
-
resolution: { type: number }
|
|
35
|
-
|
|
36
|
-
knowledge:
|
|
37
|
-
pcg: knowledge/pcg.md
|
|
38
|
-
landscape: knowledge/landscape.md
|
|
39
|
-
|
|
40
|
-
tasks:
|
|
41
|
-
voxel.scatter_meshes:
|
|
42
|
-
class_path: tasks/ScatterMeshes
|
|
43
|
-
description: "Build the PCG graph for voxel-terrain mesh scatter"
|
|
44
|
-
voxel.spawn_stamps:
|
|
45
|
-
class_path: tasks/SpawnStamps
|
|
46
|
-
description: "Build the PCG graph for voxel stamps"
|
|
47
|
-
voxel.bake_heightmap:
|
|
48
|
-
class_path: tasks/BakeHeightmap
|
|
49
|
-
description: "Bake a voxel-terrain region into a Landscape heightmap"
|
|
50
|
-
|
|
51
|
-
flows:
|
|
52
|
-
voxel_scatter_setup:
|
|
53
|
-
description: "Create a PCG mesh-scatter graph on a voxel terrain and execute it"
|
|
54
|
-
rollback_on_failure: true
|
|
55
|
-
steps:
|
|
56
|
-
1: { task: voxel.scatter_meshes }
|
|
57
|
-
2: { task: pcg.execute }
|
|
58
|
-
|
|
59
|
-
voxel_stamps_setup:
|
|
60
|
-
description: "Create a PCG voxel-stamp graph and execute it"
|
|
61
|
-
rollback_on_failure: true
|
|
62
|
-
steps:
|
|
63
|
-
1: { task: voxel.spawn_stamps }
|
|
64
|
-
2: { task: pcg.execute }
|
|
5
|
+
# No actions ship in this version. The 0.1.0 release injected three
|
|
6
|
+
# placeholder actions (voxel_scatter_meshes, voxel_spawn_stamps,
|
|
7
|
+
# voxel_bake_heightmap) that called ue-mcp tasks with the wrong parameter
|
|
8
|
+
# names and passed fabricated PCG node-type strings - none of them worked.
|
|
9
|
+
# They have been removed. See TODO.md in the repo for the real API surface
|
|
10
|
+
# and the prioritized list of tools being built against it.
|
|
11
|
+
|
|
12
|
+
inject: {}
|
|
13
|
+
knowledge: {}
|
|
14
|
+
tasks: {}
|
|
15
|
+
flows: {}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cross-task helpers for building Voxel-Plugin-flavoured PCG graphs. None of
|
|
3
|
-
* these are referenced by ue-mcp.plugin.yml directly - task files import them.
|
|
4
|
-
*
|
|
5
|
-
* The exact PCG node-type names depend on the Voxel Plugin version installed.
|
|
6
|
-
* They are intentionally string constants so they can be updated in one
|
|
7
|
-
* place when the plugin's exposed nodes shift.
|
|
8
|
-
*/
|
|
9
|
-
export declare const VOXEL_NODES: {
|
|
10
|
-
/** Samples the active voxel volume in PCG space. */
|
|
11
|
-
readonly voxelSampler: "VoxelSampler";
|
|
12
|
-
/** Surface sampler that filters points to voxel-terrain surface positions. */
|
|
13
|
-
readonly surfaceSampler: "PCGSurfaceSampler";
|
|
14
|
-
/** Static-mesh spawner consuming the points from the surface sampler. */
|
|
15
|
-
readonly staticMeshSpawner: "PCGStaticMeshSpawner";
|
|
16
|
-
/** Stamp-spawner specific to Voxel Plugin's stamp asset format. */
|
|
17
|
-
readonly voxelStamp: "VoxelStamp";
|
|
18
|
-
/** Density filter for thinning out sampled points. */
|
|
19
|
-
readonly densityFilter: "PCGDensityFilter";
|
|
20
|
-
/** Transform-randomiser for scale/rotation jitter. */
|
|
21
|
-
readonly transformPoints: "PCGTransformPoints";
|
|
22
|
-
};
|
|
23
|
-
export type VoxelNodeKey = keyof typeof VOXEL_NODES;
|
|
24
|
-
/**
|
|
25
|
-
* Type-safe wrapper around `this.call('pcg.add_node', ...)`. Returns the
|
|
26
|
-
* caller-visible node id reported by the bridge, or throws so the task gets
|
|
27
|
-
* a meaningful error.
|
|
28
|
-
*/
|
|
29
|
-
export declare function addNode(task: unknown, graphPath: string, nodeKey: VoxelNodeKey): Promise<string>;
|
|
30
|
-
export declare function connectNodes(task: unknown, graphPath: string, sourceId: string, targetId: string): Promise<void>;
|
|
31
|
-
export declare function setNodeSettings(task: unknown, graphPath: string, nodeId: string, settings: Record<string, unknown>): Promise<void>;
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cross-task helpers for building Voxel-Plugin-flavoured PCG graphs. None of
|
|
3
|
-
* these are referenced by ue-mcp.plugin.yml directly - task files import them.
|
|
4
|
-
*
|
|
5
|
-
* The exact PCG node-type names depend on the Voxel Plugin version installed.
|
|
6
|
-
* They are intentionally string constants so they can be updated in one
|
|
7
|
-
* place when the plugin's exposed nodes shift.
|
|
8
|
-
*/
|
|
9
|
-
export const VOXEL_NODES = {
|
|
10
|
-
/** Samples the active voxel volume in PCG space. */
|
|
11
|
-
voxelSampler: "VoxelSampler",
|
|
12
|
-
/** Surface sampler that filters points to voxel-terrain surface positions. */
|
|
13
|
-
surfaceSampler: "PCGSurfaceSampler",
|
|
14
|
-
/** Static-mesh spawner consuming the points from the surface sampler. */
|
|
15
|
-
staticMeshSpawner: "PCGStaticMeshSpawner",
|
|
16
|
-
/** Stamp-spawner specific to Voxel Plugin's stamp asset format. */
|
|
17
|
-
voxelStamp: "VoxelStamp",
|
|
18
|
-
/** Density filter for thinning out sampled points. */
|
|
19
|
-
densityFilter: "PCGDensityFilter",
|
|
20
|
-
/** Transform-randomiser for scale/rotation jitter. */
|
|
21
|
-
transformPoints: "PCGTransformPoints",
|
|
22
|
-
};
|
|
23
|
-
function callable(task) {
|
|
24
|
-
return task;
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Type-safe wrapper around `this.call('pcg.add_node', ...)`. Returns the
|
|
28
|
-
* caller-visible node id reported by the bridge, or throws so the task gets
|
|
29
|
-
* a meaningful error.
|
|
30
|
-
*/
|
|
31
|
-
export async function addNode(task, graphPath, nodeKey) {
|
|
32
|
-
const r = await callable(task).call("pcg.add_node", {
|
|
33
|
-
graphPath,
|
|
34
|
-
nodeType: VOXEL_NODES[nodeKey],
|
|
35
|
-
});
|
|
36
|
-
if (!r.success) {
|
|
37
|
-
throw new Error(`pcg.add_node ${nodeKey} failed: ${r.error?.message ?? "unknown"}`);
|
|
38
|
-
}
|
|
39
|
-
const id = (r.data?.nodeId ?? r.data?.id);
|
|
40
|
-
if (!id) {
|
|
41
|
-
throw new Error(`pcg.add_node ${nodeKey} did not return a node id`);
|
|
42
|
-
}
|
|
43
|
-
return id;
|
|
44
|
-
}
|
|
45
|
-
export async function connectNodes(task, graphPath, sourceId, targetId) {
|
|
46
|
-
const r = await callable(task).call("pcg.connect_nodes", {
|
|
47
|
-
graphPath,
|
|
48
|
-
sourceNodeId: sourceId,
|
|
49
|
-
targetNodeId: targetId,
|
|
50
|
-
});
|
|
51
|
-
if (!r.success) {
|
|
52
|
-
throw new Error(`pcg.connect_nodes failed: ${r.error?.message ?? "unknown"}`);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
export async function setNodeSettings(task, graphPath, nodeId, settings) {
|
|
56
|
-
const r = await callable(task).call("pcg.set_node_settings", {
|
|
57
|
-
graphPath,
|
|
58
|
-
nodeId,
|
|
59
|
-
settings,
|
|
60
|
-
});
|
|
61
|
-
if (!r.success) {
|
|
62
|
-
throw new Error(`pcg.set_node_settings failed: ${r.error?.message ?? "unknown"}`);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
//# sourceMappingURL=voxelGraph.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"voxelGraph.js","sourceRoot":"","sources":["../../src/shared/voxelGraph.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,oDAAoD;IACpD,YAAY,EAAE,cAAc;IAC5B,8EAA8E;IAC9E,cAAc,EAAE,mBAAmB;IACnC,yEAAyE;IACzE,iBAAiB,EAAE,sBAAsB;IACzC,mEAAmE;IACnE,UAAU,EAAE,YAAY;IACxB,sDAAsD;IACtD,aAAa,EAAE,kBAAkB;IACjC,sDAAsD;IACtD,eAAe,EAAE,oBAAoB;CAC7B,CAAC;AAaX,SAAS,QAAQ,CAAC,IAAa;IAC7B,OAAO,IAAmB,CAAC;AAC7B,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,IAAa,EACb,SAAiB,EACjB,OAAqB;IAErB,MAAM,CAAC,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,cAAc,EAAE;QAClD,SAAS;QACT,QAAQ,EAAE,WAAW,CAAC,OAAO,CAAC;KAC/B,CAAC,CAAC;IACH,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,gBAAgB,OAAO,YAAY,CAAC,CAAC,KAAK,EAAE,OAAO,IAAI,SAAS,EAAE,CAAC,CAAC;IACtF,CAAC;IACD,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAuB,CAAC;IAChE,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,MAAM,IAAI,KAAK,CAAC,gBAAgB,OAAO,2BAA2B,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,IAAa,EACb,SAAiB,EACjB,QAAgB,EAChB,QAAgB;IAEhB,MAAM,CAAC,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,mBAAmB,EAAE;QACvD,SAAS;QACT,YAAY,EAAE,QAAQ;QACtB,YAAY,EAAE,QAAQ;KACvB,CAAC,CAAC;IACH,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC,KAAK,EAAE,OAAO,IAAI,SAAS,EAAE,CAAC,CAAC;IAChF,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAa,EACb,SAAiB,EACjB,MAAc,EACd,QAAiC;IAEjC,MAAM,CAAC,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,uBAAuB,EAAE;QAC3D,SAAS;QACT,MAAM;QACN,QAAQ;KACT,CAAC,CAAC;IACH,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC,KAAK,EAAE,OAAO,IAAI,SAAS,EAAE,CAAC,CAAC;IACpF,CAAC;AACH,CAAC"}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { BaseTask, type TaskResult } from "@db-lyon/flowkit";
|
|
2
|
-
interface Bounds {
|
|
3
|
-
min: {
|
|
4
|
-
x: number;
|
|
5
|
-
y: number;
|
|
6
|
-
z?: number;
|
|
7
|
-
};
|
|
8
|
-
max: {
|
|
9
|
-
x: number;
|
|
10
|
-
y: number;
|
|
11
|
-
z?: number;
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
interface Options {
|
|
15
|
-
landscapeLabel: string;
|
|
16
|
-
bounds: Bounds;
|
|
17
|
-
/** Heightmap side length in samples. Default 1009 (UE landscape-friendly). */
|
|
18
|
-
resolution?: number;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Bakes a region of a Voxel Plugin terrain to a Landscape heightmap.
|
|
22
|
-
*
|
|
23
|
-
* Pipeline:
|
|
24
|
-
* 1. Sample the voxel surface at a grid resolution by issuing Python through
|
|
25
|
-
* the editor (the C++ bridge has no direct Voxel Plugin API surface).
|
|
26
|
-
* 2. Pipe the resulting heightfield into `landscape.import_heightmap`.
|
|
27
|
-
*
|
|
28
|
-
* The Python step is the escape hatch documented in CLAUDE.md and is
|
|
29
|
-
* acceptable here because Voxel Plugin exposes no native PCG-side way to
|
|
30
|
-
* extract raw voxel heights into the engine's landscape format.
|
|
31
|
-
*/
|
|
32
|
-
export default class BakeHeightmap extends BaseTask<Options> {
|
|
33
|
-
get taskName(): string;
|
|
34
|
-
protected validate(): void;
|
|
35
|
-
execute(): Promise<TaskResult>;
|
|
36
|
-
}
|
|
37
|
-
export {};
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import { BaseTask } from "@db-lyon/flowkit";
|
|
2
|
-
/**
|
|
3
|
-
* Bakes a region of a Voxel Plugin terrain to a Landscape heightmap.
|
|
4
|
-
*
|
|
5
|
-
* Pipeline:
|
|
6
|
-
* 1. Sample the voxel surface at a grid resolution by issuing Python through
|
|
7
|
-
* the editor (the C++ bridge has no direct Voxel Plugin API surface).
|
|
8
|
-
* 2. Pipe the resulting heightfield into `landscape.import_heightmap`.
|
|
9
|
-
*
|
|
10
|
-
* The Python step is the escape hatch documented in CLAUDE.md and is
|
|
11
|
-
* acceptable here because Voxel Plugin exposes no native PCG-side way to
|
|
12
|
-
* extract raw voxel heights into the engine's landscape format.
|
|
13
|
-
*/
|
|
14
|
-
export default class BakeHeightmap extends BaseTask {
|
|
15
|
-
get taskName() { return "voxel.bake_heightmap"; }
|
|
16
|
-
validate() {
|
|
17
|
-
if (!this.options.landscapeLabel)
|
|
18
|
-
throw new Error("landscapeLabel is required");
|
|
19
|
-
if (!this.options.bounds?.min || !this.options.bounds?.max) {
|
|
20
|
-
throw new Error("bounds.min and bounds.max are required");
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
async execute() {
|
|
24
|
-
const { landscapeLabel, bounds, resolution = 1009 } = this.options;
|
|
25
|
-
// 1. Sample voxel heights via Python. The script writes a raw uint16
|
|
26
|
-
// heightmap to the project's intermediate dir and returns its path.
|
|
27
|
-
const sample = await this.call("editor.execute_python", {
|
|
28
|
-
script: buildVoxelSampleScript(bounds, resolution),
|
|
29
|
-
});
|
|
30
|
-
if (!sample.success)
|
|
31
|
-
return sample;
|
|
32
|
-
const heightmapPath = (sample.data?.result ?? sample.data?.output ?? sample.data?.heightmapPath);
|
|
33
|
-
if (!heightmapPath) {
|
|
34
|
-
return {
|
|
35
|
-
success: false,
|
|
36
|
-
error: new Error("voxel sample script did not return a heightmap path"),
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
// 2. Import the heightmap into the target landscape actor.
|
|
40
|
-
const imported = await this.call("landscape.import_heightmap", {
|
|
41
|
-
actorLabel: landscapeLabel,
|
|
42
|
-
heightmapPath,
|
|
43
|
-
resolution,
|
|
44
|
-
});
|
|
45
|
-
if (!imported.success)
|
|
46
|
-
return imported;
|
|
47
|
-
return {
|
|
48
|
-
success: true,
|
|
49
|
-
data: {
|
|
50
|
-
landscapeLabel,
|
|
51
|
-
heightmapPath,
|
|
52
|
-
resolution,
|
|
53
|
-
bounds,
|
|
54
|
-
},
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
function buildVoxelSampleScript(bounds, resolution) {
|
|
59
|
-
// The script is kept in a single string so the bridge ships it verbatim to
|
|
60
|
-
// Python. It is intentionally defensive: any Voxel Plugin API the host
|
|
61
|
-
// installation may not have is caught and reported as a clear error rather
|
|
62
|
-
// than a traceback.
|
|
63
|
-
return `
|
|
64
|
-
import unreal, os, struct
|
|
65
|
-
|
|
66
|
-
bounds_min = (${bounds.min.x}, ${bounds.min.y})
|
|
67
|
-
bounds_max = (${bounds.max.x}, ${bounds.max.y})
|
|
68
|
-
res = ${resolution}
|
|
69
|
-
|
|
70
|
-
try:
|
|
71
|
-
voxel_lib = unreal.VoxelBlueprintLibrary # exposed by Voxel Plugin at runtime
|
|
72
|
-
except AttributeError:
|
|
73
|
-
raise RuntimeError("Voxel Plugin not loaded - voxel.bake_heightmap requires the Voxel plugin")
|
|
74
|
-
|
|
75
|
-
dx = (bounds_max[0] - bounds_min[0]) / float(res - 1)
|
|
76
|
-
dy = (bounds_max[1] - bounds_min[1]) / float(res - 1)
|
|
77
|
-
|
|
78
|
-
samples = bytearray()
|
|
79
|
-
for j in range(res):
|
|
80
|
-
for i in range(res):
|
|
81
|
-
x = bounds_min[0] + i * dx
|
|
82
|
-
y = bounds_min[1] + j * dy
|
|
83
|
-
try:
|
|
84
|
-
h = voxel_lib.get_voxel_height_at(x, y)
|
|
85
|
-
except Exception:
|
|
86
|
-
h = 0.0
|
|
87
|
-
# Map [-32768, 32767] cm into uint16. Adjust per project needs.
|
|
88
|
-
sample = max(0, min(65535, int(h + 32768)))
|
|
89
|
-
samples += struct.pack("<H", sample)
|
|
90
|
-
|
|
91
|
-
out_dir = os.path.join(unreal.Paths.project_intermediate_dir(), "Voxel")
|
|
92
|
-
os.makedirs(out_dir, exist_ok=True)
|
|
93
|
-
out_path = os.path.join(out_dir, "voxel_heightmap.r16")
|
|
94
|
-
with open(out_path, "wb") as f:
|
|
95
|
-
f.write(samples)
|
|
96
|
-
|
|
97
|
-
# The bridge serialises whatever we print as the script result.
|
|
98
|
-
print(out_path)
|
|
99
|
-
`.trim();
|
|
100
|
-
}
|
|
101
|
-
//# sourceMappingURL=BakeHeightmap.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"BakeHeightmap.js","sourceRoot":"","sources":["../../src/tasks/BakeHeightmap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAmB,MAAM,kBAAkB,CAAC;AAc7D;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,QAAiB;IAC1D,IAAI,QAAQ,KAAa,OAAO,sBAAsB,CAAC,CAAC,CAAC;IAE/C,QAAQ;QAChB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc;YAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChF,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC;YAC3D,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QAEnE,qEAAqE;QACrE,uEAAuE;QACvE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,uBAAuB,EAAE;YACtD,MAAM,EAAE,sBAAsB,CAAC,MAAM,EAAE,UAAU,CAAC;SACnD,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,OAAO,MAAM,CAAC;QAEnC,MAAM,aAAa,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,IAAI,MAAM,CAAC,IAAI,EAAE,MAAM,IAAI,MAAM,CAAC,IAAI,EAAE,aAAa,CAAuB,CAAC;QACvH,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,IAAI,KAAK,CAAC,qDAAqD,CAAC;aACxE,CAAC;QACJ,CAAC;QAED,2DAA2D;QAC3D,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,4BAA4B,EAAE;YAC7D,UAAU,EAAE,cAAc;YAC1B,aAAa;YACb,UAAU;SACX,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,OAAO;YAAE,OAAO,QAAQ,CAAC;QAEvC,OAAO;YACL,OAAO,EAAE,IAAI;YACb,IAAI,EAAE;gBACJ,cAAc;gBACd,aAAa;gBACb,UAAU;gBACV,MAAM;aACP;SACF,CAAC;IACJ,CAAC;CACF;AAED,SAAS,sBAAsB,CAAC,MAAc,EAAE,UAAkB;IAChE,2EAA2E;IAC3E,uEAAuE;IACvE,2EAA2E;IAC3E,oBAAoB;IACpB,OAAO;;;gBAGO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,MAAM,CAAC,GAAG,CAAC,CAAC;gBAC7B,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,MAAM,CAAC,GAAG,CAAC,CAAC;QACrC,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BjB,CAAC,IAAI,EAAE,CAAC;AACT,CAAC"}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { BaseTask, type TaskResult } from "@db-lyon/flowkit";
|
|
2
|
-
interface Options {
|
|
3
|
-
graphPath: string;
|
|
4
|
-
mesh: string;
|
|
5
|
-
density?: number;
|
|
6
|
-
minScale?: number;
|
|
7
|
-
maxScale?: number;
|
|
8
|
-
seed?: number;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Builds a PCG graph that scatters static meshes on a Voxel Plugin
|
|
12
|
-
* terrain. Pipeline: VoxelSampler → SurfaceSampler → DensityFilter →
|
|
13
|
-
* TransformPoints → StaticMeshSpawner.
|
|
14
|
-
*
|
|
15
|
-
* Idempotency: if the graph already exists, the task assumes the caller
|
|
16
|
-
* wants a fresh build and will append nodes. Callers expecting strict
|
|
17
|
-
* idempotency should delete the graph first via `pcg(action="delete_graph")`
|
|
18
|
-
* (or skip the call entirely when no rebuild is needed).
|
|
19
|
-
*/
|
|
20
|
-
export default class ScatterMeshes extends BaseTask<Options> {
|
|
21
|
-
get taskName(): string;
|
|
22
|
-
protected validate(): void;
|
|
23
|
-
execute(): Promise<TaskResult>;
|
|
24
|
-
}
|
|
25
|
-
export {};
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { BaseTask } from "@db-lyon/flowkit";
|
|
2
|
-
import { addNode, connectNodes, setNodeSettings } from "../shared/voxelGraph.js";
|
|
3
|
-
/**
|
|
4
|
-
* Builds a PCG graph that scatters static meshes on a Voxel Plugin
|
|
5
|
-
* terrain. Pipeline: VoxelSampler → SurfaceSampler → DensityFilter →
|
|
6
|
-
* TransformPoints → StaticMeshSpawner.
|
|
7
|
-
*
|
|
8
|
-
* Idempotency: if the graph already exists, the task assumes the caller
|
|
9
|
-
* wants a fresh build and will append nodes. Callers expecting strict
|
|
10
|
-
* idempotency should delete the graph first via `pcg(action="delete_graph")`
|
|
11
|
-
* (or skip the call entirely when no rebuild is needed).
|
|
12
|
-
*/
|
|
13
|
-
export default class ScatterMeshes extends BaseTask {
|
|
14
|
-
get taskName() { return "voxel.scatter_meshes"; }
|
|
15
|
-
validate() {
|
|
16
|
-
if (!this.options.graphPath)
|
|
17
|
-
throw new Error("graphPath is required");
|
|
18
|
-
if (!this.options.mesh)
|
|
19
|
-
throw new Error("mesh is required");
|
|
20
|
-
}
|
|
21
|
-
async execute() {
|
|
22
|
-
const { graphPath, mesh, density = 0.25, minScale = 0.8, maxScale = 1.4, seed = 1 } = this.options;
|
|
23
|
-
// Create the graph (no-op if pcg.create_graph rejects an existing one;
|
|
24
|
-
// we proceed regardless so add_node can land on a pre-existing graph).
|
|
25
|
-
await this.call("pcg.create_graph", { path: graphPath });
|
|
26
|
-
const sampler = await addNode(this, graphPath, "voxelSampler");
|
|
27
|
-
const surface = await addNode(this, graphPath, "surfaceSampler");
|
|
28
|
-
const density_ = await addNode(this, graphPath, "densityFilter");
|
|
29
|
-
const transform = await addNode(this, graphPath, "transformPoints");
|
|
30
|
-
const spawner = await addNode(this, graphPath, "staticMeshSpawner");
|
|
31
|
-
await setNodeSettings(this, graphPath, surface, { PointsPerSquaredMeter: density });
|
|
32
|
-
await setNodeSettings(this, graphPath, density_, { LowerBound: 0.0, UpperBound: 1.0, Seed: seed });
|
|
33
|
-
await setNodeSettings(this, graphPath, transform, { MinScale: minScale, MaxScale: maxScale, Seed: seed });
|
|
34
|
-
await setNodeSettings(this, graphPath, spawner, { StaticMesh: mesh });
|
|
35
|
-
await connectNodes(this, graphPath, sampler, surface);
|
|
36
|
-
await connectNodes(this, graphPath, surface, density_);
|
|
37
|
-
await connectNodes(this, graphPath, density_, transform);
|
|
38
|
-
await connectNodes(this, graphPath, transform, spawner);
|
|
39
|
-
return {
|
|
40
|
-
success: true,
|
|
41
|
-
data: {
|
|
42
|
-
graphPath,
|
|
43
|
-
nodes: { sampler, surface, density: density_, transform, spawner },
|
|
44
|
-
mesh,
|
|
45
|
-
},
|
|
46
|
-
// No automatic rollback - PCG node creation/connection has no inverse
|
|
47
|
-
// exposed by the bridge. Callers wanting safety should run inside a
|
|
48
|
-
// flow with git_snapshot enabled.
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
//# sourceMappingURL=ScatterMeshes.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ScatterMeshes.js","sourceRoot":"","sources":["../../src/tasks/ScatterMeshes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAmB,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAWjF;;;;;;;;;GASG;AACH,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,QAAiB;IAC1D,IAAI,QAAQ,KAAa,OAAO,sBAAsB,CAAC,CAAC,CAAC;IAE/C,QAAQ;QAChB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACtE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAC9D,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,EAAE,QAAQ,GAAG,GAAG,EAAE,QAAQ,GAAG,GAAG,EAAE,IAAI,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QAEnG,uEAAuE;QACvE,uEAAuE;QACvE,MAAM,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;QAEzD,MAAM,OAAO,GAAK,MAAM,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC;QACjE,MAAM,OAAO,GAAK,MAAM,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,gBAAgB,CAAC,CAAC;QACnE,MAAM,QAAQ,GAAI,MAAM,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;QAClE,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,iBAAiB,CAAC,CAAC;QACpE,MAAM,OAAO,GAAK,MAAM,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,mBAAmB,CAAC,CAAC;QAEtE,MAAM,eAAe,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAI,EAAE,qBAAqB,EAAE,OAAO,EAAE,CAAC,CAAC;QACtF,MAAM,eAAe,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAG,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACpG,MAAM,eAAe,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1G,MAAM,eAAe,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QAExE,MAAM,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAI,OAAO,CAAC,CAAC;QACxD,MAAM,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAI,QAAQ,CAAC,CAAC;QACzD,MAAM,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAG,SAAS,CAAC,CAAC;QAC1D,MAAM,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;QAExD,OAAO;YACL,OAAO,EAAE,IAAI;YACb,IAAI,EAAE;gBACJ,SAAS;gBACT,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE;gBAClE,IAAI;aACL;YACD,sEAAsE;YACtE,oEAAoE;YACpE,kCAAkC;SACnC,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { BaseTask, type TaskResult } from "@db-lyon/flowkit";
|
|
2
|
-
interface Options {
|
|
3
|
-
graphPath: string;
|
|
4
|
-
stampAsset: string;
|
|
5
|
-
count?: number;
|
|
6
|
-
radius?: number;
|
|
7
|
-
seed?: number;
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* Builds a PCG graph that places voxel stamp assets across a terrain. Pipeline:
|
|
11
|
-
* VoxelSampler → SurfaceSampler → DensityFilter (thinning by `count`) →
|
|
12
|
-
* VoxelStamp.
|
|
13
|
-
*
|
|
14
|
-
* `count` is a soft cap - the density filter approximates it from the sampled
|
|
15
|
-
* point cloud, so the final placement count varies with the underlying voxel
|
|
16
|
-
* volume density.
|
|
17
|
-
*/
|
|
18
|
-
export default class SpawnStamps extends BaseTask<Options> {
|
|
19
|
-
get taskName(): string;
|
|
20
|
-
protected validate(): void;
|
|
21
|
-
execute(): Promise<TaskResult>;
|
|
22
|
-
}
|
|
23
|
-
export {};
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { BaseTask } from "@db-lyon/flowkit";
|
|
2
|
-
import { addNode, connectNodes, setNodeSettings } from "../shared/voxelGraph.js";
|
|
3
|
-
/**
|
|
4
|
-
* Builds a PCG graph that places voxel stamp assets across a terrain. Pipeline:
|
|
5
|
-
* VoxelSampler → SurfaceSampler → DensityFilter (thinning by `count`) →
|
|
6
|
-
* VoxelStamp.
|
|
7
|
-
*
|
|
8
|
-
* `count` is a soft cap - the density filter approximates it from the sampled
|
|
9
|
-
* point cloud, so the final placement count varies with the underlying voxel
|
|
10
|
-
* volume density.
|
|
11
|
-
*/
|
|
12
|
-
export default class SpawnStamps extends BaseTask {
|
|
13
|
-
get taskName() { return "voxel.spawn_stamps"; }
|
|
14
|
-
validate() {
|
|
15
|
-
if (!this.options.graphPath)
|
|
16
|
-
throw new Error("graphPath is required");
|
|
17
|
-
if (!this.options.stampAsset)
|
|
18
|
-
throw new Error("stampAsset is required");
|
|
19
|
-
}
|
|
20
|
-
async execute() {
|
|
21
|
-
const { graphPath, stampAsset, count = 50, radius = 500, seed = 1 } = this.options;
|
|
22
|
-
await this.call("pcg.create_graph", { path: graphPath });
|
|
23
|
-
const sampler = await addNode(this, graphPath, "voxelSampler");
|
|
24
|
-
const surface = await addNode(this, graphPath, "surfaceSampler");
|
|
25
|
-
const density_ = await addNode(this, graphPath, "densityFilter");
|
|
26
|
-
const stamp = await addNode(this, graphPath, "voxelStamp");
|
|
27
|
-
// PointsPerSquaredMeter is approximated from count/radius² to give the
|
|
28
|
-
// surface sampler a sensible density for the desired stamp count.
|
|
29
|
-
const pointsPerSqM = Math.max(0.0001, count / (Math.PI * radius * radius));
|
|
30
|
-
await setNodeSettings(this, graphPath, surface, {
|
|
31
|
-
PointsPerSquaredMeter: pointsPerSqM,
|
|
32
|
-
Radius: radius,
|
|
33
|
-
Seed: seed,
|
|
34
|
-
});
|
|
35
|
-
await setNodeSettings(this, graphPath, density_, { LowerBound: 0.5, UpperBound: 1.0, Seed: seed });
|
|
36
|
-
await setNodeSettings(this, graphPath, stamp, { StampAsset: stampAsset });
|
|
37
|
-
await connectNodes(this, graphPath, sampler, surface);
|
|
38
|
-
await connectNodes(this, graphPath, surface, density_);
|
|
39
|
-
await connectNodes(this, graphPath, density_, stamp);
|
|
40
|
-
return {
|
|
41
|
-
success: true,
|
|
42
|
-
data: {
|
|
43
|
-
graphPath,
|
|
44
|
-
nodes: { sampler, surface, density: density_, stamp },
|
|
45
|
-
stampAsset,
|
|
46
|
-
countEstimate: count,
|
|
47
|
-
},
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
//# sourceMappingURL=SpawnStamps.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SpawnStamps.js","sourceRoot":"","sources":["../../src/tasks/SpawnStamps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAmB,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAUjF;;;;;;;;GAQG;AACH,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,QAAiB;IACxD,IAAI,QAAQ,KAAa,OAAO,oBAAoB,CAAC,CAAC,CAAC;IAE7C,QAAQ;QAChB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;QACtE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC1E,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,GAAG,EAAE,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QAEnF,MAAM,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;QAEzD,MAAM,OAAO,GAAI,MAAM,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC;QAChE,MAAM,OAAO,GAAI,MAAM,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,gBAAgB,CAAC,CAAC;QAClE,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;QACjE,MAAM,KAAK,GAAM,MAAM,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;QAE9D,uEAAuE;QACvE,kEAAkE;QAClE,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;QAE3E,MAAM,eAAe,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE;YAC9C,qBAAqB,EAAE,YAAY;YACnC,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI;SACX,CAAC,CAAC;QACH,MAAM,eAAe,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACnG,MAAM,eAAe,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAK,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC;QAE7E,MAAM,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAG,OAAO,CAAC,CAAC;QACvD,MAAM,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAG,QAAQ,CAAC,CAAC;QACxD,MAAM,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QAErD,OAAO;YACL,OAAO,EAAE,IAAI;YACb,IAAI,EAAE;gBACJ,SAAS;gBACT,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE;gBACrD,UAAU;gBACV,aAAa,EAAE,KAAK;aACrB;SACF,CAAC;IACJ,CAAC;CACF"}
|
package/knowledge/landscape.md
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# Voxel Plugin - Landscape actions
|
|
2
|
-
|
|
3
|
-
This plugin contributes one landscape-side action for [Voxel Plugin](https://voxelplugin.com):
|
|
4
|
-
|
|
5
|
-
- `landscape(action="voxel_bake_heightmap", ...)` - bake a region of a voxel terrain into a standard UE Landscape heightmap.
|
|
6
|
-
|
|
7
|
-
## When to use
|
|
8
|
-
|
|
9
|
-
Use it when the user wants to convert a voxel terrain (or a region of it) into a standard Landscape actor for the parts of the workflow that need it: high-quality runtime LOD, foliage painting, landscape materials, etc.
|
|
10
|
-
|
|
11
|
-
The reverse conversion (Landscape → voxel) is not part of this plugin.
|
|
12
|
-
|
|
13
|
-
## Typical sequence
|
|
14
|
-
|
|
15
|
-
```
|
|
16
|
-
landscape(action="voxel_bake_heightmap",
|
|
17
|
-
landscapeLabel="Landscape",
|
|
18
|
-
bounds={ min: {x: 0, y: 0},
|
|
19
|
-
max: {x: 8064, y: 8064} },
|
|
20
|
-
resolution=1009)
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
The action samples voxel heights on a `resolution x resolution` grid spanning `bounds`, writes a raw uint16 heightmap to `Intermediate/Voxel/voxel_heightmap.r16`, then imports it into the target landscape via the built-in `landscape.import_heightmap` action.
|
|
24
|
-
|
|
25
|
-
## Parameters
|
|
26
|
-
|
|
27
|
-
- `landscapeLabel` (required) - the in-editor label of the target Landscape actor.
|
|
28
|
-
- `bounds` (required) - `{ min: {x, y}, max: {x, y} }` in world centimetres.
|
|
29
|
-
- `resolution` (optional, default 1009) - heightmap side length in samples. Use a UE-friendly value: 127, 253, 505, 1009, 2017, 4033, 8129.
|
|
30
|
-
|
|
31
|
-
## Notes
|
|
32
|
-
|
|
33
|
-
- The Python escape hatch is used here because Voxel Plugin exposes its voxel heights to Python but not to PCG or the C++ bridge directly. The script is defensive: if `VoxelBlueprintLibrary` is not loaded it returns a clear error rather than a traceback.
|
|
34
|
-
- Height mapping uses a centred uint16 range (offset +32768). If your voxel volume uses a different scale, adjust the script or wrap this action.
|
package/knowledge/pcg.md
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# Voxel Plugin - PCG actions
|
|
2
|
-
|
|
3
|
-
This plugin contributes two PCG-side actions for [Voxel Plugin](https://voxelplugin.com) terrains:
|
|
4
|
-
|
|
5
|
-
- `pcg(action="voxel_scatter_meshes", ...)` - build a graph that scatters static meshes on a voxel terrain via Voxel Sampler.
|
|
6
|
-
- `pcg(action="voxel_spawn_stamps", ...)` - build a graph that places voxel stamp assets across a voxel terrain.
|
|
7
|
-
|
|
8
|
-
## When to use
|
|
9
|
-
|
|
10
|
-
Reach for these when the user wants procedural placement on a **voxel** terrain. For standard UE Landscape, use the built-in PCG nodes directly.
|
|
11
|
-
|
|
12
|
-
## Typical sequence
|
|
13
|
-
|
|
14
|
-
```
|
|
15
|
-
pcg(action="create_graph", path="/Game/PCG/MyScatter") # if no graph exists
|
|
16
|
-
pcg(action="voxel_scatter_meshes",
|
|
17
|
-
graphPath="/Game/PCG/MyScatter",
|
|
18
|
-
mesh="/Game/Foliage/Rock01.Rock01",
|
|
19
|
-
density=0.25)
|
|
20
|
-
pcg(action="execute", graphPath="/Game/PCG/MyScatter") # materialise
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
The full setup is also available as a flow:
|
|
24
|
-
|
|
25
|
-
```
|
|
26
|
-
flow(action="run", flowName="voxel_scatter_setup", params={
|
|
27
|
-
graphPath: "/Game/PCG/MyScatter",
|
|
28
|
-
mesh: "/Game/Foliage/Rock01.Rock01"
|
|
29
|
-
})
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Parameters
|
|
33
|
-
|
|
34
|
-
`voxel_scatter_meshes`:
|
|
35
|
-
- `graphPath` (required) - asset path of the PCG graph to build (created if missing).
|
|
36
|
-
- `mesh` (required) - StaticMesh asset path to scatter.
|
|
37
|
-
- `density` (optional, default 0.25) - points per square metre at the surface sampler.
|
|
38
|
-
- `minScale` / `maxScale` (optional) - uniform scale jitter, default 0.8 .. 1.4.
|
|
39
|
-
- `seed` (optional) - deterministic seed for the density filter and transform jitter.
|
|
40
|
-
|
|
41
|
-
`voxel_spawn_stamps`:
|
|
42
|
-
- `graphPath` (required).
|
|
43
|
-
- `stampAsset` (required) - Voxel stamp asset path.
|
|
44
|
-
- `count` (optional, default 50) - target stamp count; approximated via density.
|
|
45
|
-
- `radius` (optional, default 500) - radius of the scatter region in cm.
|
|
46
|
-
- `seed` (optional).
|
|
47
|
-
|
|
48
|
-
## Requirements
|
|
49
|
-
|
|
50
|
-
The host project must have the Voxel Plugin enabled in its `.uproject` as `Voxel` (the `.uplugin` filename). The plugin installer warns at install time if `Voxel` is missing; the actions themselves will fail with a clear error if the runtime types aren't loaded.
|