@hology/core 0.0.210 → 0.0.212
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/dist/effects/sequence/sequence-player.js +1 -1
- package/dist/effects/vfx/initializsers.d.ts +8 -1
- package/dist/effects/vfx/initializsers.js +1 -1
- package/dist/effects/vfx/vfx-collision-behaviour.js +1 -1
- package/dist/effects/vfx/vfx-defs.d.ts +10 -1
- package/dist/effects/vfx/vfx-defs.js +1 -1
- package/dist/effects/vfx/vfx-materializer.js +1 -1
- package/dist/effects/vfx/vfx-renderers.d.ts +1 -0
- package/dist/effects/vfx/vfx-renderers.js +1 -1
- package/dist/gameplay/actors/actor.d.ts +23 -1
- package/dist/gameplay/actors/actor.js +1 -1
- package/dist/gameplay/actors/builtin/components/character/character-animation.js +1 -1
- package/dist/gameplay/actors/builtin/components/character/character-movement-like.d.ts +23 -0
- package/dist/gameplay/actors/builtin/components/character/character-movement-like.js +4 -0
- package/dist/gameplay/actors/builtin/components/character/character-movement-policy.d.ts +26 -0
- package/dist/gameplay/actors/builtin/components/character/character-movement-policy.js +4 -0
- package/dist/gameplay/actors/builtin/components/character/character-movement.d.ts +145 -55
- package/dist/gameplay/actors/builtin/components/character/character-movement.js +1 -1
- package/dist/gameplay/actors/builtin/components/character/net-character-movement-protocol.d.ts +125 -0
- package/dist/gameplay/actors/builtin/components/character/net-character-movement-protocol.js +4 -0
- package/dist/gameplay/actors/builtin/components/character/old-character-movement.d.ts +100 -0
- package/dist/gameplay/actors/builtin/components/character/old-character-movement.js +4 -0
- package/dist/gameplay/actors/builtin/components/index.d.ts +2 -0
- package/dist/gameplay/actors/builtin/components/index.js +1 -1
- package/dist/gameplay/actors/builtin/navmesh-actor.js +1 -1
- package/dist/gameplay/actors/camera/third-person-camera-component.d.ts +3 -0
- package/dist/gameplay/actors/camera/third-person-camera-component.js +1 -1
- package/dist/gameplay/actors/component.js +1 -1
- package/dist/gameplay/actors/controller/actor-controller.d.ts +16 -0
- package/dist/gameplay/actors/controller/actor-controller.js +4 -0
- package/dist/gameplay/actors/factory.d.ts +3 -0
- package/dist/gameplay/actors/factory.js +1 -1
- package/dist/gameplay/actors/index.d.ts +4 -0
- package/dist/gameplay/actors/index.js +1 -1
- package/dist/gameplay/actors/internal/component-init.js +1 -1
- package/dist/gameplay/ai/behavior-tree/move.d.ts +2 -2
- package/dist/gameplay/index.d.ts +3 -1
- package/dist/gameplay/index.js +1 -1
- package/dist/gameplay/initiate.d.ts +4 -0
- package/dist/gameplay/initiate.js +1 -1
- package/dist/gameplay/net/browser/index.d.ts +147 -0
- package/dist/gameplay/net/browser/index.js +4 -0
- package/dist/gameplay/net/index.d.ts +7 -0
- package/dist/gameplay/net/index.js +4 -0
- package/dist/gameplay/net/net-connection.d.ts +25 -0
- package/dist/gameplay/net/net-connection.js +4 -0
- package/dist/gameplay/net/net-session.d.ts +70 -0
- package/dist/gameplay/net/net-session.js +4 -0
- package/dist/gameplay/net/service/net-actor-role.d.ts +12 -0
- package/dist/gameplay/net/service/net-actor-role.js +4 -0
- package/dist/gameplay/net/service/net-decorator.d.ts +29 -0
- package/dist/gameplay/net/service/net-decorator.js +4 -0
- package/dist/gameplay/net/service/net-serializer.d.ts +15 -0
- package/dist/gameplay/net/service/net-serializer.js +4 -0
- package/dist/gameplay/net/service/net-service.d.ts +171 -0
- package/dist/gameplay/net/service/net-service.js +4 -0
- package/dist/gameplay/net/service/net-utils.d.ts +8 -0
- package/dist/gameplay/net/service/net-utils.js +4 -0
- package/dist/gameplay/net/service/replication.d.ts +31 -0
- package/dist/gameplay/net/service/replication.js +4 -0
- package/dist/gameplay/net/service/rpc-decorator.d.ts +21 -0
- package/dist/gameplay/net/service/rpc-decorator.js +4 -0
- package/dist/gameplay/net/service/rpc.d.ts +35 -0
- package/dist/gameplay/net/service/rpc.js +4 -0
- package/dist/gameplay/services/asset-loader.d.ts +3 -2
- package/dist/gameplay/services/asset-loader.js +1 -1
- package/dist/gameplay/services/physics/abstract-physics-system.d.ts +1 -1
- package/dist/gameplay/services/physics/physics-system.d.ts +4 -2
- package/dist/gameplay/services/physics/physics-system.js +1 -1
- package/dist/gameplay/services/world.d.ts +13 -2
- package/dist/gameplay/services/world.js +1 -1
- package/dist/rendering/color-pass.js +1 -1
- package/dist/rendering.d.ts +2 -0
- package/dist/rendering.js +1 -1
- package/dist/scene/asset-resource-loader.js +1 -1
- package/dist/scene/batched-mesh-2.d.ts +9 -0
- package/dist/scene/batched-mesh-2.js +1 -1
- package/dist/scene/bootstrap.d.ts +2 -0
- package/dist/scene/bootstrap.js +1 -1
- package/dist/scene/custom-param-runtime-types.js +1 -1
- package/dist/scene/landscape/landscape-manager.d.ts +2 -1
- package/dist/scene/landscape/landscape-manager.js +1 -1
- package/dist/scene/materializer.d.ts +50 -1
- package/dist/scene/materializer.js +1 -1
- package/dist/scene/model.d.ts +2 -0
- package/dist/scene/scatter/painted-scatter-manager.d.ts +45 -0
- package/dist/scene/scatter/painted-scatter-manager.js +4 -0
- package/dist/scene/scatter/scatter-limits.d.ts +2 -0
- package/dist/scene/scatter/scatter-limits.js +4 -0
- package/dist/scene/scatter/surface-scatter-manager.js +1 -1
- package/dist/scene/storage/storage.d.ts +1 -1
- package/dist/scene/storage/storage.js +1 -1
- package/dist/shader/builtin/standard-shader.js +1 -1
- package/dist/shader/builtin/toon-shader.js +1 -1
- package/dist/shader/builtin/unlit-shader.js +1 -1
- package/dist/shader/color-layer.js +1 -1
- package/dist/shader/graph/compiler.d.ts +7 -4
- package/dist/shader/graph/compiler.js +1 -1
- package/dist/shader/graph/model.d.ts +1 -1
- package/dist/shader/graph/model.js +1 -1
- package/dist/shader/graph/parameters.js +1 -1
- package/dist/shader/parameter.d.ts +1 -1
- package/dist/shader/parameter.js +1 -1
- package/dist/shader/sprite-shader.js +1 -1
- package/dist/shader-nodes/depth.js +1 -1
- package/dist/shader-nodes/scene-sample.js +1 -1
- package/dist/test/batched-mesh-2.test.d.ts +2 -0
- package/dist/test/batched-mesh-2.test.js +4 -0
- package/dist/test/browser-net-session.test.d.ts +2 -0
- package/dist/test/browser-net-session.test.js +4 -0
- package/dist/test/first-person-camera-component.test.js +1 -1
- package/dist/test/net-character-movement.test.d.ts +2 -0
- package/dist/test/net-character-movement.test.js +4 -0
- package/dist/test/net-property-snapshot.test.d.ts +2 -0
- package/dist/test/net-property-snapshot.test.js +4 -0
- package/dist/test/painted-scatter-manager.test.d.ts +2 -0
- package/dist/test/painted-scatter-manager.test.js +4 -0
- package/dist/test/runtime-param-type-inference.test.js +1 -1
- package/dist/test/sequence-animation-retiming.test.js +1 -1
- package/dist/test/sequence-post-process.test.js +1 -1
- package/dist/test/shader-graph.test.js +1 -1
- package/dist/test/vfx-random-color-initializer.test.d.ts +2 -0
- package/dist/test/vfx-random-color-initializer.test.js +4 -0
- package/dist/test/world-prefab-spawn.test.d.ts +2 -0
- package/dist/test/world-prefab-spawn.test.js +4 -0
- package/dist/utils/three/placeholder-texture.d.ts +3 -0
- package/dist/utils/three/placeholder-texture.js +4 -0
- package/package.json +10 -2
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -8,11 +8,20 @@ type Item = {
|
|
|
8
8
|
export declare class BatchedMesh2 extends THREE.BatchedMesh {
|
|
9
9
|
private uniformTextures;
|
|
10
10
|
private uniformSize;
|
|
11
|
+
private instanceCastShadow;
|
|
12
|
+
private instanceCastShadowCount;
|
|
11
13
|
surfaceByInstance: BaseSurfaceDefinition[];
|
|
14
|
+
perInstanceCastShadow: boolean;
|
|
12
15
|
customSort: (list: Item[], camera: THREE.Camera) => void;
|
|
13
16
|
initUniform(name: string, elementSize: number, defaultValue?: number): void;
|
|
14
17
|
setUniformAt(name: string, instanceId: number, value: number | THREE.Vector4 | THREE.Vector3 | THREE.Vector2 | THREE.Color): this;
|
|
15
18
|
getUniformAt<T = number | THREE.Vector3 | THREE.Vector3 | THREE.Vector2 | THREE.Color>(name: string, instanceId: number, target?: T): T;
|
|
19
|
+
setCastShadowAt(instanceId: number, castShadow: boolean): this;
|
|
20
|
+
getCastShadowAt(instanceId: number): boolean;
|
|
21
|
+
private setupInstanceCastShadow;
|
|
22
|
+
private getInstanceInfo;
|
|
23
|
+
deleteInstance(instanceId: number): this;
|
|
24
|
+
onBeforeShadow(renderer: THREE.WebGLRenderer, scene: THREE.Scene, camera: THREE.Camera, shadowCamera: THREE.Camera, geometry: THREE.BufferGeometry, depthMaterial: THREE.Material, group: THREE.Group): void;
|
|
16
25
|
dispose(): this;
|
|
17
26
|
}
|
|
18
27
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import*as t from"three";function
|
|
1
|
+
import*as t from"three";function s(t,s){return t.z-s.z}function e(t,s){return s.z-t.z}export class BatchedMesh2 extends t.BatchedMesh{constructor(){super(...arguments),this.uniformTextures={},this.uniformSize={},this.instanceCastShadowCount=0,this.surfaceByInstance=[],this.perInstanceCastShadow=!1,this.customSort=(t,n)=>{this.material.transparent?t.sort(e):t.sort(s)}}initUniform(s,e,n=0){if(e<1||e>4||3===e)throw"Element size must be between 1,2, or 4";let i=Math.sqrt(this.maxInstanceCount);i=Math.ceil(i);let a=t.RedFormat;2===e?a=t.RGFormat:4===e&&(a=t.RGBAFormat);const o=new Float32Array(i*i*e).fill(n),r=new t.DataTexture(o,i,i,a,t.FloatType);this.uniformTextures[s]=r,this.uniformSize[s]=e;const h=this.material;if(!(h instanceof t.ShaderMaterial))throw"Can not use custom uniforms with other materials than ShaderMaterial";for(const[t,s]of Object.entries(this.uniformTextures))h.uniforms[t]={value:s};h.uniformsNeedUpdate=!0}setUniformAt(s,e,n){const i=this.uniformTextures[s],a=i.image.data,o=this.getInstanceInfo(),r=o[e];if(e>=o.length||null==r||!1===r.active)return this;"number"==typeof n?a[e*this.uniformSize[s]]=n:n.toArray(a,e*this.uniformSize[s]),i.needsUpdate=!0;const h=this.material;h instanceof t.ShaderMaterial&&(h.uniformsNeedUpdate=!0)}getUniformAt(s,e,n){const i=this.uniformTextures[s].image.data,a=this.getInstanceInfo(),o=a[e];return e>=a.length||null==o||!1===o.active?null:1===this.uniformSize[s]?i[e]:void((n instanceof t.Vector2||n instanceof t.Vector2||n instanceof t.Vector3||n instanceof t.Vector4||n instanceof t.Color)&&n.fromArray(i,e*this.uniformSize[s]))}setCastShadowAt(t,s){const e=this.getInstanceInfo(),n=e[t];if(t>=e.length||null==n||!1===n.active)return this;this.setupInstanceCastShadow();const i=this.perInstanceCastShadow;this.perInstanceCastShadow=!0;const a=!0===this.instanceCastShadow[t];return a!==s&&(this.instanceCastShadow[t]=s,this.instanceCastShadowCount+=s?1:-1),this.castShadow=this.instanceCastShadowCount>0,a===s&&i||(this._visibilityChanged=!0),this}getCastShadowAt(t){return this.instanceCastShadow?.[t]??!1}setupInstanceCastShadow(){null==this.instanceCastShadow&&(this.instanceCastShadow=new Array(this.maxInstanceCount).fill(!1),this.instanceCastShadowCount=0)}getInstanceInfo(){return this._drawInfo??this._instanceInfo??[]}deleteInstance(t){const s=this.getInstanceInfo(),e=s[t]?.active&&!0===this.instanceCastShadow?.[t];return super.deleteInstance(t),e&&(this.instanceCastShadow[t]=!1,this.instanceCastShadowCount--,this.castShadow=this.instanceCastShadowCount>0,this._visibilityChanged=!0),this}onBeforeShadow(t,s,e,i,a,o,r){if(!this.perInstanceCastShadow)return void super.onBeforeShadow(t,s,e,i,a,o,r);const h=this.getInstanceInfo();n.length=0;for(let t=0,s=h.length;t<s;t++){const s=h[t];null!=s&&s.visible&&s.active&&!this.getCastShadowAt(t)&&(s.visible=!1,n.push(t))}n.length>0&&(this._visibilityChanged=!0);try{super.onBeforeShadow(t,s,e,i,a,o,r)}finally{for(const t of n){const s=h[t];null!=s&&(s.visible=!0)}n.length>0&&(this._visibilityChanged=!0)}}dispose(){super.dispose();for(const t of Object.values(this.uniformTextures))t.dispose();return this.uniformTextures=null,this}}const n=[];/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -5,6 +5,7 @@ import { RuntimeBackendService } from './runtime-backend-service.js';
|
|
|
5
5
|
import { RuntimeAssetsService } from './runtime-asset-service.js';
|
|
6
6
|
import { ShaderType, ActorType, ActorComponentType } from '../shader/shader.js';
|
|
7
7
|
import { DetailTier } from './model.js';
|
|
8
|
+
import { NetMode } from '../gameplay/net/net-session.js';
|
|
8
9
|
export type ShaderDefinitions = {
|
|
9
10
|
[name: string]: ShaderType;
|
|
10
11
|
};
|
|
@@ -16,6 +17,7 @@ export type ComponentDefinitions = {
|
|
|
16
17
|
};
|
|
17
18
|
export type LoadSceneConfig = {
|
|
18
19
|
detailTier: DetailTier;
|
|
20
|
+
nodeMode?: NetMode;
|
|
19
21
|
};
|
|
20
22
|
export declare function loadScene(view: RenderingView, sceneName: string, dataDir: string, shaders: ShaderDefinitions, actors: ActorDefinitions, components: ComponentDefinitions, actorProvider: ActorProvider, backendService: RuntimeBackendService, assetsService: RuntimeAssetsService, assetResourceLoader: AssetResourceLoader, config?: LoadSceneConfig): Promise<{
|
|
21
23
|
scene: import("three").Scene;
|
package/dist/scene/bootstrap.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{polyfill as e}from"../utils/polyfill.js";import{SceneDataService as t}from"./scene-data-service.js";import{SceneMaterializer as
|
|
1
|
+
import{polyfill as e}from"../utils/polyfill.js";import{SceneDataService as t}from"./scene-data-service.js";import{SceneMaterializer as n}from"./materializer.js";import{basicSceneSetup as i}from"./sky.js";import{NetMode as a}from"../gameplay/net/net-session.js";export async function loadScene(r,s,o,c,m,p,d,l,f,j,w){e();const{scene:y,renderer:u,camera:g}=r;i(y);const S=await l.getScene(s);if(null==S)throw Error(`Could not find scene with name ${s}`);const b=await l.getSceneData(S.id),h=new t;h.initiate(b);const v=Object.entries(c).map(([e,t])=>({name:e,type:t})),O=Object.entries(m).map(([e,t])=>({name:e,type:t})),z=Object.entries(p).map(([e,t])=>({name:e,type:t})),E=new n(y,h,f,j,r,v,O,d,z);return E.inEditor=!1,E.detailTier=w?.detailTier,E.netMode=w?.nodeMode??a.none,await E.initWithInstancing(),{scene:y,view:r,materializer:E,assetResourceLoader:j,assetsService:f,actors:E.actorInstances}}/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{Color as e,Euler as r,Material as t,Object3D as n,Texture as u,Vector2 as o,Vector3 as a,Vector4 as c,AnimationClip as l}from"three";import{BooleanNode as i,FloatNode as s,RgbNode as f,Sampler2DNode as y,Texture2dLookupNode as p,Vec2Node as m,Vec3Node as d,Vec4Node as b}from"three-shader-graph";import{getParameterDefinitionId as A,getParameterDefinitionType as g,isParameterDefinitionStructAssignableTo as S}from"../shader/parameter.js";import{Curve2 as N}from"../utils/curve.js";import{SerializedParamType as V}from"./model.js";export const applyRuntimeParamTypeInference=!0;export function convertConfiguredParamsToRuntimeTypes(e,r={}){const t={},n=[],u=Object.entries(e),o=r.applyRuntimeParamTypeInference??true;if(0===u.length||!o)return o?{params:t,skipped:n}:{params:e,skipped:n};const a=getRuntimeParameterTypeHints(e,r);for(const[e,r]of u){if(!1===r.override){t[e]=r;continue}const u=a.get(e),o=null!=u?convertConfiguredParamValueToRuntimeType(r,u):r;null!=o?t[e]=o:n.push({key:e,sourceType:r.type,targetType:u.type})}return{params:t,skipped:n}}export function getRuntimeParameterTypeHints(e,r={}){const t=new Map,n=Object.keys(e).filter(r=>!1!==e[r]?.override);if(0===n.length)return t;const u=new Set(n),o=r.parameterTarget??function(e){if(null==e)return null;try{return new e}catch{return null}}(r.parameterType),a=function(e,r){if(null!=r.propertyParams)return r.propertyParams;if(null==r.extractPropertyParameters)return[];if(null!=r.parameterType)return h(r.parameterType,r.extractPropertyParameters);if(null!=e)return h(e.constructor,r.extractPropertyParameters);return[]}(o,r);for(const e of a){if(!u.has(e.name))continue;const n=R(e,r.toSerializedParamType);null!=n&&t.set(e.name,n);const a=inferRuntimeSerializedParamTypeHint(C(o,e.name))??inferRuntimeSerializedParamTypeHint(e.options.defaultValue);null!=a&&t.set(e.name,x(a,n))}if(null!=o)for(const e of n){const r=inferRuntimeSerializedParamTypeHint(C(o,e));if(null!=r){const n=t.get(e);t.set(e,x(r,n))}}return t}const v=new WeakMap,P=new WeakMap,T=Symbol("noCachedSerializedParamType");function h(e,r){let t=v.get(r);null==t&&(t=new WeakMap,v.set(r,t));const n=t.get(e);if(null!=n)return n;const u=function(e,r){try{return r(e)}catch{return[]}}(e,r);return t.set(e,u),u}function C(e,r){return null!=e?e[r]:void 0}function R(e,r){const t=function(e,r){if(null==e||null==r)return;const t=function(e,r){const t=P.get(r);if(null==t||!t.has(e))return T;const n=t.get(e);return null===n?void 0:n}(e,r);if(t!==T)return t;try{const t=r(e);return w(e,r,t),t}catch{return void w(e,r,void 0)}}(e.type,r),n=t===V.Struct?A(e.type):void 0;return!0===e.options.array?{type:V.Array,...null!=t?{element:t}:{},...null!=n?{elementStruct:n}:{}}:null!=t?{type:t,...null!=n?{struct:n}:{}}:void 0}function w(e,r,t){let n=P.get(r);null==n&&(n=new WeakMap,P.set(r,n)),n.set(e,t??null)}function x(e,r){return e.type!==V.Array?e:{type:V.Array,element:e.element??r?.element,elementStruct:e.elementStruct??r?.elementStruct}}export function inferRuntimeSerializedParamTypeHint(g){if(null==g)return;if(Array.isArray(g)){const e=g.map(e=>inferRuntimeSerializedParamTypeHint(e)).find(e=>null!=e);return{type:V.Array,...null!=e&&e.type!==V.Array?{element:e.type}:{},...null!=e?.struct?{elementStruct:e.struct}:{}}}switch(typeof g){case"number":return{type:V.Number};case"boolean":return{type:V.Boolean};case"string":return{type:V.String}}const S=function(e){const r=e;if(e instanceof s||"function"==typeof r?.isFloat||!0===r?.isFloat)return V.FloatNode;if(e instanceof i||"function"==typeof r?.isBool||!0===r?.isBool)return V.BooleanNode;if(e instanceof f||"function"==typeof r?.isRgb||!0===r?.isRgb)return V.RgbNode;if(e instanceof m||"function"==typeof r?.isVec2||!0===r?.isVec2)return V.Vec2Node;if(e instanceof d||"function"==typeof r?.isVec3||!0===r?.isVec3)return V.Vec3Node;if(e instanceof b||"function"==typeof r?.isVec4||!0===r?.isVec4)return V.Vec4Node;if(e instanceof y||e instanceof p||"function"==typeof r?.isSampler2D||!0===r?.isSampler2D)return V.Sampler2DNode;return}(g);if(null!=S)return{type:S};if(g instanceof o)return{type:V.Vector2};if(g instanceof a)return{type:V.Vector3};if(g instanceof c)return{type:V.Vector4};if(g instanceof e)return{type:V.Color};if(g instanceof r)return{type:V.Euler};if(g instanceof u)return{type:V.Texture};if(g instanceof t)return{type:V.Material};if(g instanceof n)return{type:V.Object3D};if("undefined"!=typeof AudioBuffer&&g instanceof AudioBuffer)return{type:V.AudioBuffer};if(W(g,"VisualEffect"))return{type:V.VisualEffect};if(W(g,"PrefabOf"))return{type:V.PrefabActor};if(W(g,"Prefab"))return{type:V.Prefab};if(W(g,"DataAssetRef"))return{type:V.DataAsset};if(g instanceof N)return{type:V.Curve};if(W(g,"ColorLayer"))return{type:V.ColorLayer};if(W(g,"MaskLayer"))return{type:V.MaskLayer};if(g instanceof l)return{type:V.AnimationClip};if(W(g,"Sequence"))return{type:V.Sequence};const v=A(g.constructor);return null!=v?{type:V.Struct,struct:v}:void 0}export function convertConfiguredParamValueToRuntimeType(e,r){if(null==e||null==r)return e;if(e.type===V.Array||r.type===V.Array)return function(e,r){if(r.type===V.Array){const t=B(e),n=r.element??(t?e.element:e.type);if(null==n)return t?e:null;const u=t?e.element:e.type,o=(t?Array.isArray(e.value)?e.value:[]:[e.value]).map(e=>M(e,u,n));return o.some(e=>e===D)?null:{...e,type:V.Array,element:n,...k(e,r),value:o}}if(!B(e))return null;const t=Array.isArray(e.value)?e.value[0]:void 0;if(null==t)return null;const n=M(t,e.element,r.type);if(n===D)return null;return{...e,type:r.type,...j(e,r),value:n}}(e,r);const t=M(e.value,e.type,r.type);return t===D?null:{...e,type:r.type,...j(e,r),value:t}}function B(e){return e.type===V.Array}function j(e,r){if(r.type!==V.Struct&&e.type!==V.Struct)return{};const t=function(e,r){if(null==r)return e;if(null==e)return r;if(e===r||S(e,r))return e;const t=g(e),n=g(r);if(null==t||null==n)return e;return r}(e.type===V.Struct?e.struct:void 0,r.struct);return null!=t?{struct:t}:{}}function k(e,r){if(r.type!==V.Array)return{};const t=B(e)?e.elementStruct:void 0,n=r.elementStruct??t;return null!=n?{elementStruct:n}:{}}const D=Symbol("skippedParamValue");function M(e,r,t){if(function(e,r){if(e===r)return!0;const t=F(e);return null!=t&&t===F(r)}(r,t)&&function(e,r){switch(r){case V.Number:case V.FloatNode:return"number"==typeof e||"string"==typeof e&&Number.isFinite(parseFloat(e));case V.Boolean:case V.BooleanNode:return"boolean"==typeof e;case V.Vector2:case V.Vec2Node:return z(e,2);case V.Vector3:case V.Vec3Node:return z(e,3);case V.Vector4:case V.Vec4Node:return z(e,4);case V.Euler:return Array.isArray(e)&&e.length>=3&&null!=E(e,3);case V.Color:case V.RgbNode:return null!=q(e);case V.String:return"string"==typeof e;case V.Array:return Array.isArray(e);case V.Texture:case V.Sampler2DNode:case V.BaseActor:case V.Object3D:case V.Material:case V.AudioBuffer:case V.VisualEffect:case V.Prefab:case V.PrefabActor:case V.DataAsset:case V.AnimationClip:case V.Sequence:return null==e||"string"==typeof e||"object"==typeof e;case V.Struct:return null!=e&&"object"==typeof e&&!Array.isArray(e);case V.Curve:case V.ColorLayer:case V.MaskLayer:return null!=e}return!0}(e,t))return e;switch(t){case V.Number:case V.FloatNode:{const r=L(e);return null!=r?r:D}case V.Boolean:case V.BooleanNode:{const r=function(e){if("boolean"==typeof e)return e;if("number"==typeof e)return 0!==e;if("string"==typeof e){const r=e.trim().toLowerCase();if(["true","1","yes","on"].includes(r))return!0;if(["false","0","no","off"].includes(r))return!1}return null}(e);return null!=r?r:D}case V.Vector2:case V.Vec2Node:return H(e,2,r)??D;case V.Vector3:case V.Vec3Node:return H(e,3,r)??D;case V.Vector4:case V.Vec4Node:return H(e,4,r)??D;case V.Color:case V.RgbNode:return function(e,r){if(r===V.Color||r===V.RgbNode)return"string"==typeof e||"number"==typeof e?e:O(e);return O(e)}(e,r)??D;case V.Euler:return function(e,r){if(Array.isArray(e)){const r=E(e,3);if(null==r)return null;const t="string"==typeof e[3]?e[3]:"XYZ";return[r[0],r[1],r[2],t]}const t=H(e,3,r);return null!=t?[t[0],t[1],t[2],"XYZ"]:null}(e,r)??D;case V.String:return"string"==typeof e?e:String(e);case V.Texture:case V.Sampler2DNode:case V.BaseActor:case V.Object3D:case V.Material:case V.AudioBuffer:case V.VisualEffect:case V.Curve:case V.ColorLayer:case V.MaskLayer:case V.Prefab:case V.PrefabActor:case V.DataAsset:case V.AnimationClip:case V.Sequence:case V.Struct:return D}return D}function z(e,r){if(Array.isArray(e))return e.length>=r&&null!=E(e,r);if(null!=e&&"object"==typeof e){const t=e;return["x","y","z","w"].slice(0,r).every(e=>null!=L(t[e]))}return!1}function F(e){switch(e){case V.Number:case V.FloatNode:return"number";case V.Boolean:case V.BooleanNode:return"boolean";case V.Vector2:case V.Vec2Node:return"vector2";case V.Vector3:case V.Vec3Node:return"vector3";case V.Vector4:case V.Vec4Node:return"vector4";case V.Color:case V.RgbNode:return"color";case V.Texture:case V.Sampler2DNode:return"texture";case V.Prefab:case V.PrefabActor:return"prefab";case V.DataAsset:return"dataAsset";case V.Struct:return"struct"}}function L(e){if("number"==typeof e)return Number.isFinite(e)?e:null;if("string"==typeof e){const r=parseFloat(e);return Number.isFinite(r)?r:null}if("boolean"==typeof e)return e?1:0;if(Array.isArray(e))return L(e[0]);if(null!=e&&"object"==typeof e){const r=e;return L(r.x??r.r??r.value)}return null}function H(e,r,t){if(t===V.Color||t===V.RgbNode){const t=q(e);if(null!=t)return E(t.toArray(),r,4===r?1:0)}if(Array.isArray(e))return E(e,r);if("number"==typeof e||"string"==typeof e||"boolean"==typeof e){const t=L(e);return null!=t?new Array(r).fill(t):null}if(null!=e&&"object"==typeof e){const t=e,n=["x","y","z","w"].slice(0,r).map(e=>t[e]);if(n.some(e=>null!=e))return E(n,r);const u=["r","g","b","a"].slice(0,r).map(e=>t[e]);if(u.some(e=>null!=e))return E(u,r,4===r?1:0)}return null}function E(e,r,t=0){const n=[];for(let u=0;u<r;u++){const r=L(e[u]??t);if(null==r)return null;n.push(r)}return n}function O(e){const r=q(e);return null!=r?"#"+r.getHexString():null}function q(r){try{if(r instanceof e)return r.clone();if("string"==typeof r)return function(e){return/^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(e.trim())||/^(rgb|hsl)a?\(/i.test(e.trim())}(r)?new e(r):null;if("number"==typeof r)return Number.isInteger(r)&&r>=0?new e(r):null;if(Array.isArray(r)){const t=E(r,3);return null!=t?(new e).fromArray(t):null}if(null!=r&&"object"==typeof r){const t=r;if(null!=t.r||null!=t.g||null!=t.b){const r=E([t.r,t.g,t.b],3);return null!=r?(new e).fromArray(r):null}if(null!=t.x||null!=t.y||null!=t.z){const r=E([t.x,t.y,t.z],3);return null!=r?(new e).fromArray(r):null}}}catch{return null}return null}function W(e,r){return null!=e&&"object"==typeof e&&e.constructor?.name===r}/*
|
|
1
|
+
import{Color as e,Euler as r,Material as t,Object3D as n,Texture as u,Vector2 as o,Vector3 as a,Vector4 as c,AnimationClip as l}from"three";import{BooleanNode as i,FloatNode as s,RgbNode as f,Sampler2DNode as y,Texture2dLookupNode as p,Vec2Node as m,Vec3Node as d,Vec4Node as b}from"three-shader-graph";import{getParameterDefinitionId as A,getParameterDefinitionType as g,isParameterDefinitionStructAssignableTo as S}from"../shader/parameter.js";import{Curve2 as N}from"../utils/curve.js";import{SerializedParamType as V}from"./model.js";export const applyRuntimeParamTypeInference=!0;export function convertConfiguredParamsToRuntimeTypes(e,r={}){const t={},n=[],u=Object.entries(e),o=r.applyRuntimeParamTypeInference??true;if(0===u.length||!o)return o?{params:t,skipped:n}:{params:e,skipped:n};const a=getRuntimeParameterTypeHints(e,r);for(const[e,r]of u){if(!1===r.override){t[e]=r;continue}const u=a.get(e),o=null!=u?convertConfiguredParamValueToRuntimeType(r,u):r;null!=o?t[e]=o:n.push({key:e,sourceType:r.type,targetType:u.type})}return{params:t,skipped:n}}export function getRuntimeParameterTypeHints(e,r={}){const t=new Map,n=Object.keys(e).filter(r=>!1!==e[r]?.override);if(0===n.length)return t;const u=new Set(n),o=r.parameterTarget??function(e){if(null==e)return null;try{return new e}catch{return null}}(r.parameterType),a=function(e,r){if(null!=r.propertyParams)return r.propertyParams;if(null==r.extractPropertyParameters)return[];if(null!=r.parameterType)return h(r.parameterType,r.extractPropertyParameters);if(null!=e)return h(e.constructor,r.extractPropertyParameters);return[]}(o,r);for(const e of a){if(!u.has(e.name))continue;const n=R(e,r.toSerializedParamType);null!=n&&t.set(e.name,n);const a=inferRuntimeSerializedParamTypeHint(C(o,e.name))??inferRuntimeSerializedParamTypeHint(e.options.defaultValue);null!=a&&t.set(e.name,x(a,n))}if(null!=o)for(const e of n){const r=inferRuntimeSerializedParamTypeHint(C(o,e));if(null!=r){const n=t.get(e);t.set(e,x(r,n))}}return t}const v=new WeakMap,P=new WeakMap,T=Symbol("noCachedSerializedParamType");function h(e,r){let t=v.get(r);null==t&&(t=new WeakMap,v.set(r,t));const n=t.get(e);if(null!=n)return n;const u=function(e,r){try{return r(e)}catch{return[]}}(e,r);return t.set(e,u),u}function C(e,r){return null!=e?e[r]:void 0}function R(e,r){const t=function(e,r){if(null==e||null==r)return;const t=function(e,r){const t=P.get(r);if(null==t||!t.has(e))return T;const n=t.get(e);return null===n?void 0:n}(e,r);if(t!==T)return t;try{const t=r(e);return w(e,r,t),t}catch{return void w(e,r,void 0)}}(e.type,r),n=t===V.Struct?A(e.type):void 0;return!0===e.options.array?{type:V.Array,...null!=t?{element:t}:{},...null!=n?{elementStruct:n}:{}}:null!=t?{type:t,...null!=n?{struct:n}:{}}:void 0}function w(e,r,t){let n=P.get(r);null==n&&(n=new WeakMap,P.set(r,n)),n.set(e,t??null)}function x(e,r){return e.type!==V.Array?e:{type:V.Array,element:e.element??r?.element,elementStruct:e.elementStruct??r?.elementStruct}}export function inferRuntimeSerializedParamTypeHint(g){if(null==g)return;if(Array.isArray(g)){const e=g.map(e=>inferRuntimeSerializedParamTypeHint(e)).find(e=>null!=e);return{type:V.Array,...null!=e&&e.type!==V.Array?{element:e.type}:{},...null!=e?.struct?{elementStruct:e.struct}:{}}}switch(typeof g){case"number":return{type:V.Number};case"boolean":return{type:V.Boolean};case"string":return{type:V.String}}const S=function(e){const r=e;if(e instanceof s||"function"==typeof r?.isFloat||!0===r?.isFloat)return V.FloatNode;if(e instanceof i||"function"==typeof r?.isBool||!0===r?.isBool)return V.BooleanNode;if(e instanceof f||"function"==typeof r?.isRgb||!0===r?.isRgb)return V.RgbNode;if(e instanceof m||"function"==typeof r?.isVec2||!0===r?.isVec2)return V.Vec2Node;if(e instanceof d||"function"==typeof r?.isVec3||!0===r?.isVec3)return V.Vec3Node;if(e instanceof b||"function"==typeof r?.isVec4||!0===r?.isVec4)return V.Vec4Node;if(e instanceof y||e instanceof p||"function"==typeof r?.isSampler2D||!0===r?.isSampler2D)return V.Sampler2DNode;return}(g);if(null!=S)return{type:S};if(g instanceof o)return{type:V.Vector2};if(g instanceof a)return{type:V.Vector3};if(g instanceof c)return{type:V.Vector4};if(g instanceof e)return{type:V.Color};if(g instanceof r)return{type:V.Euler};if(g instanceof u)return{type:V.Texture};if(g instanceof t)return{type:V.Material};if(g instanceof n)return{type:V.Object3D};if("undefined"!=typeof AudioBuffer&&g instanceof AudioBuffer)return{type:V.AudioBuffer};if(W(g,"VisualEffect"))return{type:V.VisualEffect};if(W(g,"PrefabOf"))return{type:V.PrefabActor};if(W(g,"Prefab"))return{type:V.Prefab};if(W(g,"DataAssetRef"))return{type:V.DataAsset};if(g instanceof N)return{type:V.Curve};if(W(g,"ColorLayer"))return{type:V.ColorLayer};if(W(g,"MaskLayer"))return{type:V.MaskLayer};if(g instanceof l)return{type:V.AnimationClip};if(W(g,"Sequence"))return{type:V.Sequence};const v=A(g.constructor);return null!=v?{type:V.Struct,struct:v}:void 0}export function convertConfiguredParamValueToRuntimeType(e,r){if(null==e||null==r)return e;if(e.type===V.Array||r.type===V.Array)return function(e,r){if(r.type===V.Array){const t=B(e),n=r.element??(t?e.element:e.type);if(null==n)return t?e:null;const u=t?e.element:e.type,o=(t?Array.isArray(e.value)?e.value:[]:[e.value]).map(e=>F(e,u,n));return o.some(e=>e===D)?null:{...e,type:V.Array,element:n,...k(e,r),value:o}}if(!B(e))return null;const t=Array.isArray(e.value)?e.value[0]:void 0;if(null==t)return null;const n=F(t,e.element,r.type);if(n===D)return null;return{...e,type:r.type,...j(e,r),value:n}}(e,r);const t=F(e.value,e.type,r.type);return t===D?null:{...e,type:r.type,...j(e,r),value:t}}function B(e){return e.type===V.Array}function j(e,r){if(r.type!==V.Struct&&e.type!==V.Struct)return{};const t=function(e,r){if(null==r)return e;if(null==e)return r;if(e===r||S(e,r))return e;const t=g(e),n=g(r);if(null==t||null==n)return e;return r}(e.type===V.Struct?e.struct:void 0,r.struct);return null!=t?{struct:t}:{}}function k(e,r){if(r.type!==V.Array)return{};const t=B(e)?e.elementStruct:void 0,n=r.elementStruct??t;return null!=n?{elementStruct:n}:{}}const D=Symbol("skippedParamValue");function F(e,r,t){if(function(e,r){if(e===r)return!0;const t=z(e);return null!=t&&t===z(r)}(r,t)&&function(e,r){switch(r){case V.Number:return"number"==typeof e||"string"==typeof e&&Number.isFinite(parseFloat(e));case V.FloatNode:return"number"==typeof e||"string"==typeof e&&Number.isFinite(parseFloat(e))||function(e){if(null==e||"object"!=typeof e||Array.isArray(e))return!1;const r=e;return"particle"===r.time&&"string"==typeof r.easing&&null!=L(r.a)&&null!=L(r.b)}(e);case V.Boolean:case V.BooleanNode:return"boolean"==typeof e;case V.Vector2:case V.Vec2Node:return M(e,2);case V.Vector3:case V.Vec3Node:return M(e,3);case V.Vector4:case V.Vec4Node:return M(e,4);case V.Euler:return Array.isArray(e)&&e.length>=3&&null!=E(e,3);case V.Color:case V.RgbNode:return null!=q(e);case V.String:return"string"==typeof e;case V.Array:return Array.isArray(e);case V.Texture:case V.Sampler2DNode:case V.BaseActor:case V.Object3D:case V.Material:case V.AudioBuffer:case V.VisualEffect:case V.Prefab:case V.PrefabActor:case V.DataAsset:case V.AnimationClip:case V.Sequence:return null==e||"string"==typeof e||"object"==typeof e;case V.Struct:return null!=e&&"object"==typeof e&&!Array.isArray(e);case V.Curve:case V.ColorLayer:case V.MaskLayer:return null!=e}return!0}(e,t))return e;switch(t){case V.Number:case V.FloatNode:{const r=L(e);return null!=r?r:D}case V.Boolean:case V.BooleanNode:{const r=function(e){if("boolean"==typeof e)return e;if("number"==typeof e)return 0!==e;if("string"==typeof e){const r=e.trim().toLowerCase();if(["true","1","yes","on"].includes(r))return!0;if(["false","0","no","off"].includes(r))return!1}return null}(e);return null!=r?r:D}case V.Vector2:case V.Vec2Node:return H(e,2,r)??D;case V.Vector3:case V.Vec3Node:return H(e,3,r)??D;case V.Vector4:case V.Vec4Node:return H(e,4,r)??D;case V.Color:case V.RgbNode:return function(e,r){if(r===V.Color||r===V.RgbNode)return"string"==typeof e||"number"==typeof e?e:O(e);return O(e)}(e,r)??D;case V.Euler:return function(e,r){if(Array.isArray(e)){const r=E(e,3);if(null==r)return null;const t="string"==typeof e[3]?e[3]:"XYZ";return[r[0],r[1],r[2],t]}const t=H(e,3,r);return null!=t?[t[0],t[1],t[2],"XYZ"]:null}(e,r)??D;case V.String:return"string"==typeof e?e:String(e);case V.Texture:case V.Sampler2DNode:case V.BaseActor:case V.Object3D:case V.Material:case V.AudioBuffer:case V.VisualEffect:case V.Curve:case V.ColorLayer:case V.MaskLayer:case V.Prefab:case V.PrefabActor:case V.DataAsset:case V.AnimationClip:case V.Sequence:case V.Struct:return D}return D}function M(e,r){if(Array.isArray(e))return e.length>=r&&null!=E(e,r);if(null!=e&&"object"==typeof e){const t=e;return["x","y","z","w"].slice(0,r).every(e=>null!=L(t[e]))}return!1}function z(e){switch(e){case V.Number:case V.FloatNode:return"number";case V.Boolean:case V.BooleanNode:return"boolean";case V.Vector2:case V.Vec2Node:return"vector2";case V.Vector3:case V.Vec3Node:return"vector3";case V.Vector4:case V.Vec4Node:return"vector4";case V.Color:case V.RgbNode:return"color";case V.Texture:case V.Sampler2DNode:return"texture";case V.Prefab:case V.PrefabActor:return"prefab";case V.DataAsset:return"dataAsset";case V.Struct:return"struct"}}function L(e){if("number"==typeof e)return Number.isFinite(e)?e:null;if("string"==typeof e){const r=parseFloat(e);return Number.isFinite(r)?r:null}if("boolean"==typeof e)return e?1:0;if(Array.isArray(e))return L(e[0]);if(null!=e&&"object"==typeof e){const r=e;return L(r.x??r.r??r.value)}return null}function H(e,r,t){if(t===V.Color||t===V.RgbNode){const t=q(e);if(null!=t)return E(t.toArray(),r,4===r?1:0)}if(Array.isArray(e))return E(e,r);if("number"==typeof e||"string"==typeof e||"boolean"==typeof e){const t=L(e);return null!=t?new Array(r).fill(t):null}if(null!=e&&"object"==typeof e){const t=e,n=["x","y","z","w"].slice(0,r).map(e=>t[e]);if(n.some(e=>null!=e))return E(n,r);const u=["r","g","b","a"].slice(0,r).map(e=>t[e]);if(u.some(e=>null!=e))return E(u,r,4===r?1:0)}return null}function E(e,r,t=0){const n=[];for(let u=0;u<r;u++){const r=L(e[u]??t);if(null==r)return null;n.push(r)}return n}function O(e){const r=q(e);return null!=r?"#"+r.getHexString():null}function q(r){try{if(r instanceof e)return r.clone();if("string"==typeof r)return function(e){return/^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(e.trim())||/^(rgb|hsl)a?\(/i.test(e.trim())}(r)?new e(r):null;if("number"==typeof r)return Number.isInteger(r)&&r>=0?new e(r):null;if(Array.isArray(r)){const t=E(r,3);return null!=t?(new e).fromArray(t):null}if(null!=r&&"object"==typeof r){const t=r;if(null!=t.r||null!=t.g||null!=t.b){const r=E([t.r,t.g,t.b],3);return null!=r?(new e).fromArray(r):null}if(null!=t.x||null!=t.y||null!=t.z){const r=E([t.x,t.y,t.z],3);return null!=r?(new e).fromArray(r):null}}}catch{return null}return null}function W(e,r){return null!=e&&"object"==typeof e&&e.constructor?.name===r}/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -5,7 +5,8 @@ import { SceneObject } from '../../scene/materializer.js';
|
|
|
5
5
|
import { ShaderImpl } from '../../shader/shader.js';
|
|
6
6
|
import { AssetResourceLoader } from '../asset-resource-loader.js';
|
|
7
7
|
import { LandscapeGroup } from './landscape.js';
|
|
8
|
-
|
|
8
|
+
import { grassGeometryTriangleLimit } from '../scatter/scatter-limits.js';
|
|
9
|
+
export { grassGeometryTriangleLimit };
|
|
9
10
|
/**
|
|
10
11
|
* Creates landscape with varying level of detail depending on the
|
|
11
12
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{Subject as e,debounceTime as t}from"rxjs";import{Box3 as s,BufferAttribute as n,InstancedMesh as o,MathUtils as a,Matrix4 as i,Mesh as r,MeshStandardMaterial as c,PerspectiveCamera as l,PlaneGeometry as h,ShaderMaterial as u,Triangle as f,Vector2 as m,Vector3 as p}from"three";import{materialFromAsset as d}from"../../scene/materializer.js";import{getMaterialAttribute as w}from"../../scene/materials/utils/material-painting";import{whenIdle as g}from"../../utils/async.js";import{indexBy as y}from"../../utils/collections.js";import{meanVectors3withWeight as M}from"../../utils/math.js";import{LandscapeMesh as b,defaultLandscapeMaterial as x}from"./landscape.js";import{smoothNormalsCrossMeshes as S}from"./utils.js";export const grassGeometryTriangleLimit=400;new p,new p;const A=new p,v=new p,z=new p;export class LandscapeManager{constructor(s,n,o,a,r,c,l){this.view=n,this.landscape=o,this.assetManagerService=a,this.assetService=r,this.shaders=c,this.applyMaterial=l,this.scatterMeshes=new Map,this.loadedScatterSquares=new Set,this.refreshRequests=new e,this.defaultLandscapeMaterial=x.clone(),this.scatterMeshPool=[],this.onLoopHandler=()=>this.update(),this.sectionCache=new Map,this._matrix=new i,this.scatterGeometryCache=new Map,this._lastUpdatePosition=new p,this._cameraPosition=new p,this.source=JSON.parse(JSON.stringify(s)),this.view.onLoop(this.onLoopHandler),this.defaultLandscapeMaterial.name=x.name,this.defaultLandscapeMaterial.color=x.color,this.refreshRequests.pipe(t(500)).subscribe(e=>this.refreshScatter(e.origin,e.force,e.predicate))}updateSource(e){this.source=JSON.parse(JSON.stringify(e))}updateShaders(e){this.shaders=e}async loadGrass(){const e=await this.assetService.getAsset("6ij937n72g");await this.assetManagerService.getMesh(e);this.grassGeometry=new h(2,2,3,3);const t=this.grassGeometry.getAttribute("normal");for(let e=0;e<t.count;e++)t.setXYZ(e,0,1,0);t.needsUpdate=!0,this.grassMaterial=new c({color:3765785})}refreshGeometry(){const e=this.source.landscape.options,t=(new p,new p);this.view.camera.getWorldPosition(t);const s=[];z.fromArray(this.source.position);const n=this.view.camera instanceof l?Math.min(this.view.camera.far,1e3):1e3,o=1.1*n,a=e.sections.y*e.sectionSize/-2,i=e.sections.x*e.sectionSize/-2;for(let r=0;r<e.sections.x;r++)if(A.x=i+r*e.sectionSize,!(Math.abs(t.x-A.x)>o))for(let c=0;c<e.sections.y;c++){A.z=a+c*e.sectionSize,v.copy(z).add(A);const l=v.distanceTo(t),h=`${r},${c}`,u=this.landscape.sections.find(e=>e.x===r&&e.y===c);if(l<=n){if(null==u){this.sectionCache.has(h)||this.sectionCache.set(h,this.createLandscapeMesh(this.source,e,i,a,r,c));const t=this.sectionCache.get(h);this.applyMaterial(t),this.landscape.add(t),s.push(t)}}else l>o&&this.landscape.remove(u)}S(s)}applyHeightMap(e,t,s,n=1){const o=Math.pow(s+1,2),a=e.getAttribute("position");if(1===n)for(const e of t.points)a.setY(e.i,e.y);else{const e=y(t.points??[],e=>e.i);for(let t=0;t<a.count;t++){const s=P(t,a.count,o);let n=0;n=s%1==0?e.get(s)?.y??0:Math.floor(e.get(s)?.y),a.setY(t,n)}}a.needsUpdate=!0,e.computeVertexNormals()}deleteOldScatterMeshes(){const e=new Set;for(const[t,s]of this.source.grass?.layers.entries()??[])for(const[n,o]of s.meshes.entries()){const s=`${t}-${n}`;e.add(s)}for(const t of this.scatterMeshes.keys())if(!e.has(t)){this.scatterMeshes.get(t).forEach(e=>{e.parent?.remove(e),e.dispose()}),this.scatterMeshes.delete(t)}}queueRefreshScatter(e,t=!1,s=()=>!0){this.refreshRequests.next({origin:e,force:t,predicate:s})}async refreshScatter(e,t=!1,s=()=>!0){t&&this.scatterGeometryCache.clear(),this.deleteOldScatterMeshes();for(const[n,i]of this.source.grass?.layers.entries()??[])for(const[c,l]of i.meshes.entries()){const i=`${n}-${c}`;this.scatterMeshes.has(i)||this.scatterMeshes.set(i,new Map);const h=this.scatterMeshes.get(i),u=await this.assetService.getAsset(l.assetId);if(null==u){console.error(`Can not find asset with id ${l.assetId}`);continue}let m;try{m=await this.assetManagerService.getMesh(u)}catch(e){console.error(`Failed to load mesh in landscape manager for asset with name ${u.name}`,e);continue}const w=[];if(m.scene.traverse(e=>{e instanceof r&&w.push(e)}),1!==w.length){console.log(m),console.warn("Dynamic grass only works for meshes with a single geometry.");continue}if(!(w[0]instanceof r)){console.warn("Only meshes can be used for dynamic grass. Found:",m.scene);continue}const b=w[0];let x=b.geometry;if(this.scatterGeometryCache.has(b.geometry.uuid))x=this.scatterGeometryCache.get(b.geometry.uuid);else if(x=b.geometry.clone(),!0===l.normalsUp&&F(x),this.scatterGeometryCache.set(b.geometry.uuid,x),null==x.userData.updatedMatrix){m.scene.updateMatrixWorld(),x.applyMatrix4(b.matrixWorld),x.userData.updatedMatrix=!0;const e=u.mesh?.rescale??1;1!==e&&x.scale(e,e,e)}const S=x.getIndex()??x.getAttribute("position"),A=null!=S?S.count/3:0;if(A>400){console.warn(`The triangle count of ${u.name} is too big ${A}. Keep it below 400`);continue}const v=null!=u.materialAssignments&&u.materialAssignments.length>0?u.materialAssignments[0].materialId:null,z=null!=v&&"null"!==v?await d(await this.assetService.getAsset(v),null,this.assetService,this.assetManagerService,this.shaders,!1):null;let P=null!=z?z:b.material;if(Array.isArray(P))for(const e of P)e.userData.disableAO=!0;else P.userData.disableAO=!0;const L=a.degToRad(l.maxSlope??90),T=Math.cos(L),_=this.landscape.sections,D=_.filter($(e,l.viewDistance)),q=D.filter(e=>!h.has(e.uuid)||t).filter(e=>s(e));_.filter(O(e,2*l.viewDistance)).forEach(e=>{const t=h.get(e.uuid);null!=t&&(t.visible=!1)});for(const e of D){const t=h.get(e.uuid);null!=t&&(t.visible=!0)}performance.now();const I=this.source.landscape.options,U=I.sectionSize,k=l.density??1??1,H=I.density,X=U/H,Y=k,E=X/Math.sqrt(Y),J=Math.pow(H,2),Z=E/X,K=Math.floor(J*Y),V=[0,0,0];for(const e of q)await g(async()=>{e.updateWorldMatrix(!0,!1);const s=this._matrix,a=new p,i=e.geometry.getAttribute("position"),r=e.geometry.getAttribute("normal"),c=(this.source.vertexMaterials??[]).filter(t=>t.m===e.name),u=y(c,e=>e.i);let m=h.get(e.uuid);if(null==m||m.count==K&&!t||(m.parent?.remove(m),this.scatterMeshPool.push(m),h.delete(e.uuid),m=null),null==m){const e=this.scatterMeshPool.findIndex(e=>e.count>=K);e>-1?(m=this.scatterMeshPool[e],m.geometry=x,m.material=P,this.scatterMeshPool.splice(e,1)):m=new o(x,P,K),m.raycast=()=>{},m.receiveShadow=!0}m.visible=!0;const d=new f(new p,new p,new p);let[w,g,b,S]=[new p,new p,new p,new p],[A,v,z]=[[],[],[]],[L,O,$]=[new p,new p,new p,new p];const _=new p,D=new p,q=new p,I=new p,U=new f(new p,new p,new p),k=new f(new p,new p,new p),F=new f(new p,new p,new p),X=new f(new p,new p,new p);let E=0;e:for(let t=0;t<J;t++){const o=Math.floor(t/H);w.fromBufferAttribute(i,t+o),I.copy(w).applyMatrix4(e.matrixWorld),U.a.copy(w),U.b.fromBufferAttribute(i,t+1+o),U.c.fromBufferAttribute(i,t+H+1+o),k.a.copy(U.b),k.b.copy(U.c),k.c.fromBufferAttribute(i,t+H+2+o),F.a.fromBufferAttribute(r,t+o),F.b.fromBufferAttribute(r,t+1+o),F.c.fromBufferAttribute(r,t+H+1+o),X.a.copy(F.b),X.b.copy(F.c),X.c.fromBufferAttribute(r,t+H+2+o);const c=[];c[0]=u.get(t+o)?.w,c[1]=u.get(t+1+o)?.w,c[2]=u.get(t+H+1+o)?.w,c[3]=u.get(t+H+2+o)?.w;let h=0;for(let e=0;e<=1+Z;e+=Z)for(let t=0;t<=1+Z;t+=Z){if(E>K)break e;if(h++,h>Y)continue e;1-e>t?(g=U.a,b=U.b,S=U.c,L=F.a,O=F.b,$=F.c,A=c[0],v=c[1],z=c[2]):(g=k.a,b=k.b,S=k.c,L=X.a,O=X.b,$=X.c,A=c[1],v=c[2],z=c[3]),d.a.copy(g),d.b.copy(b),d.c.copy(S),C(d),_.set(w.x,0,w.z),R(d,_),d.getBarycoord(_,a).toArray(V),G[0]=A,G[1]=v,G[2]=z;if(j(G,V,.2)!==n-1)continue;if(M([g,b,S],V,D),M([L,O,$],V,q),null!=l.maxSlope&&l.maxSlope<90&&q.y<T)continue;const o=D;o.y+=B(l.offsetMin,l.offsetMax);const i=B(l.scaleMin??1,l.scaleMax??1);s.makeScale(i,i,i);const r=s.elements;r[12]=o.x,r[13]=o.y,r[14]=o.z,!1!==l.randomRotation&&N(s,i),l.alignToNormal&&W(s,o,m.matrixWorld,q);const u=m.instanceMatrix.array,f=16*E;u[f]=r[0],u[f+1]=r[1],u[f+2]=r[2],u[f+3]=r[3],u[f+4]=r[4],u[f+5]=r[5],u[f+6]=r[6],u[f+7]=r[7],u[f+8]=r[8],u[f+9]=r[9],u[f+10]=r[10],u[f+11]=r[11],u[f+12]=r[12],u[f+13]=r[13],u[f+14]=r[14],u[f+15]=r[15],E++}}m.count=E,m.instanceMatrix.needsUpdate=!0,m.position.copy(e.position),m.updateMatrix(),h.has(e.uuid)||this.landscape?.add(m),h.set(e.uuid,m),m.userData.meshConfig=l});performance.now()}}stop(){this.view.removeOnLoop(this.onLoopHandler)}update(){this.view.camera&&(this.view.camera.getWorldPosition(this._cameraPosition),this._cameraPosition.distanceTo(this._lastUpdatePosition)>10&&(this._lastUpdatePosition.copy(this._cameraPosition),this.refreshGeometry(),this.refreshScatter(this._cameraPosition)))}clear(){this.scatterMeshes.forEach(e=>e.forEach(e=>e.parent?.remove(e)))}createLandscapeMesh(e,t,s,n,o,a){const i=new h(t.sectionSize,t.sectionSize,t.density,t.density);i.rotateX(Math.PI/-2);const r=this.defaultLandscapeMaterial,c=new b(i,r);c.position.x=s+o*t.sectionSize,c.position.z=n+a*t.sectionSize,c.receiveShadow=!0,c.castShadow=!1,c.userData.landscape={x:o,y:a},c.x=o,c.y=a,c.name=`${o},${a}`,w(c,0,!0),w(c,4,!0);const l=e.landscape.heightMaps.find(e=>e.x===o&&e.y===a);if(null!=l&&this.applyHeightMap(i,l,t.density,1),i.computeTangents(),i.computeBoundsTree(),null!=e.landscape.holes&&e.landscape.holes.length>0){const t=getHoleAttribute(c,!0);for(const s of e.landscape.holes)s.m===c.name&&t.setX(s.i,s.w[0])}return c}}export function getHoleAttribute(e,t=!1){if(!e.geometry.hasAttribute("hole")||t){const t=new Float32Array(e.geometry.getAttribute("position").array.length);e.geometry.setAttribute("hole",new n(t,1))}return e.geometry.getAttribute("hole")}function P(e,t,s){const n=Math.sqrt(t),o=Math.floor(e/n)/(n-1),a=e%n/(n-1),i=Math.sqrt(s);return(s-1)*o-(i-1)*o+(i-1)*a}new Map,new m(0,0),new m(1,0),new m(0,1),new m(1,0),new m(0,1),new m(1,1),new p;const L=new s;function O(e,t){return function(s){return L.setFromObject(s).distanceToPoint(e)>t}}function $(e,t){return function(s){return L.setFromObject(s).distanceToPoint(e)<t}}function C(e){e.a.y=0,e.b.y=0,e.c.y=0}const G=[];function j(e,t,s=.5){const n=G;let o=-1,a=-1;for(let e=0;e<n.length;e++)if(null!=n[e])for(let i=0;i<n[e].length;i++){const r=n[e][i]*t[e];r>s&&r>a&&(a=r,o=i)}return o}function B(e,t){let s=t-e,n=D();return n*=s,n+=e,n}const T=[];let _=1e3;for(;_--;)T.push(Math.random());function D(){return++_>=T.length?T[_=0]:T[_]}const q=[];let I=20;for(;I--;)q.push((new i).makeRotationY(D()*Math.PI/2));function R(e,t){let s=D(),n=D();s+n>1&&(s=1-s,n=1-n);const o=e.a,a=e.b,i=e.c;t.x=o.x+s*(a.x-o.x)+n*(i.x-o.x),t.z=o.z+s*(a.z-o.z)+n*(i.z-o.z)}new p;new p;const U=new p,k=new p(0,1,0),H=(new i).makeRotationX(Math.PI/-2);function W(e,t,s,n){e.lookAt(U,n,k).multiply(H)}new i;function N(e,t=1){const s=(++I>=q.length?q[I=0]:q[I]).elements,n=e.elements;n[0]=s[0]*t,n[4]=s[4]*t,n[8]=s[8]*t,n[1]=s[1]*t,n[5]=s[5]*t,n[9]=s[9]*t,n[2]=s[2]*t,n[6]=s[6]*t,n[10]=s[10]*t}function F(e){const t=e.getAttribute("normal");for(let e=0;e<t.count;e++)t.setXYZ(e,0,1,0);t.normalized=!0,t.needsUpdate=!0}/*
|
|
1
|
+
import{Subject as e,debounceTime as t}from"rxjs";import{Box3 as s,BufferAttribute as n,InstancedMesh as o,MathUtils as a,Matrix4 as i,Mesh as r,MeshStandardMaterial as c,PerspectiveCamera as l,PlaneGeometry as h,ShaderMaterial as u,Triangle as f,Vector2 as m,Vector3 as p}from"three";import{materialFromAsset as d}from"../../scene/materializer.js";import{getMaterialAttribute as w}from"../../scene/materials/utils/material-painting";import{whenIdle as g}from"../../utils/async.js";import{indexBy as y}from"../../utils/collections.js";import{meanVectors3withWeight as M}from"../../utils/math.js";import{LandscapeMesh as b,defaultLandscapeMaterial as x}from"./landscape.js";import{smoothNormalsCrossMeshes as S}from"./utils.js";import{grassGeometryTriangleLimit as A}from"../scatter/scatter-limits.js";export{A as grassGeometryTriangleLimit};new p,new p;const v=new p,z=new p,P=new p;export class LandscapeManager{constructor(s,n,o,a,r,c,l){this.view=n,this.landscape=o,this.assetManagerService=a,this.assetService=r,this.shaders=c,this.applyMaterial=l,this.scatterMeshes=new Map,this.loadedScatterSquares=new Set,this.refreshRequests=new e,this.defaultLandscapeMaterial=x.clone(),this.scatterMeshPool=[],this.onLoopHandler=()=>this.update(),this.sectionCache=new Map,this._matrix=new i,this.scatterGeometryCache=new Map,this._lastUpdatePosition=new p,this._cameraPosition=new p,this.source=JSON.parse(JSON.stringify(s)),this.view.onLoop(this.onLoopHandler),this.defaultLandscapeMaterial.name=x.name,this.defaultLandscapeMaterial.color=x.color,this.refreshRequests.pipe(t(500)).subscribe(e=>this.refreshScatter(e.origin,e.force,e.predicate))}updateSource(e){this.source=JSON.parse(JSON.stringify(e))}updateShaders(e){this.shaders=e}async loadGrass(){const e=await this.assetService.getAsset("6ij937n72g");await this.assetManagerService.getMesh(e);this.grassGeometry=new h(2,2,3,3);const t=this.grassGeometry.getAttribute("normal");for(let e=0;e<t.count;e++)t.setXYZ(e,0,1,0);t.needsUpdate=!0,this.grassMaterial=new c({color:3765785})}refreshGeometry(){const e=this.source.landscape.options,t=(new p,new p);this.view.camera.getWorldPosition(t);const s=[];P.fromArray(this.source.position);const n=this.view.camera instanceof l?Math.min(this.view.camera.far,1e3):1e3,o=1.1*n,a=e.sections.y*e.sectionSize/-2,i=e.sections.x*e.sectionSize/-2;for(let r=0;r<e.sections.x;r++)if(v.x=i+r*e.sectionSize,!(Math.abs(t.x-v.x)>o))for(let c=0;c<e.sections.y;c++){v.z=a+c*e.sectionSize,z.copy(P).add(v);const l=z.distanceTo(t),h=`${r},${c}`,u=this.landscape.sections.find(e=>e.x===r&&e.y===c);if(l<=n){if(null==u){this.sectionCache.has(h)||this.sectionCache.set(h,this.createLandscapeMesh(this.source,e,i,a,r,c));const t=this.sectionCache.get(h);this.applyMaterial(t),this.landscape.add(t),s.push(t)}}else l>o&&this.landscape.remove(u)}S(s)}applyHeightMap(e,t,s,n=1){const o=Math.pow(s+1,2),a=e.getAttribute("position");if(1===n)for(const e of t.points)a.setY(e.i,e.y);else{const e=y(t.points??[],e=>e.i);for(let t=0;t<a.count;t++){const s=$(t,a.count,o);let n=0;n=s%1==0?e.get(s)?.y??0:Math.floor(e.get(s)?.y),a.setY(t,n)}}a.needsUpdate=!0,e.computeVertexNormals()}deleteOldScatterMeshes(){const e=new Set;for(const[t,s]of this.source.grass?.layers.entries()??[])for(const[n,o]of s.meshes.entries()){const s=`${t}-${n}`;e.add(s)}for(const t of this.scatterMeshes.keys())if(!e.has(t)){this.scatterMeshes.get(t).forEach(e=>{e.parent?.remove(e),e.dispose()}),this.scatterMeshes.delete(t)}}queueRefreshScatter(e,t=!1,s=()=>!0){this.refreshRequests.next({origin:e,force:t,predicate:s})}async refreshScatter(e,t=!1,s=()=>!0){t&&this.scatterGeometryCache.clear(),this.deleteOldScatterMeshes();for(const[n,i]of this.source.grass?.layers.entries()??[])for(const[c,l]of i.meshes.entries()){const i=`${n}-${c}`;this.scatterMeshes.has(i)||this.scatterMeshes.set(i,new Map);const h=this.scatterMeshes.get(i),u=await this.assetService.getAsset(l.assetId);if(null==u){console.error(`Can not find asset with id ${l.assetId}`);continue}let m;try{m=await this.assetManagerService.getMesh(u)}catch(e){console.error(`Failed to load mesh in landscape manager for asset with name ${u.name}`,e);continue}const w=[];if(m.scene.traverse(e=>{e instanceof r&&w.push(e)}),1!==w.length){console.log(m),console.warn("Dynamic grass only works for meshes with a single geometry.");continue}if(!(w[0]instanceof r)){console.warn("Only meshes can be used for dynamic grass. Found:",m.scene);continue}const b=w[0];let x=b.geometry;if(this.scatterGeometryCache.has(b.geometry.uuid))x=this.scatterGeometryCache.get(b.geometry.uuid);else if(x=b.geometry.clone(),!0===l.normalsUp&&X(x),this.scatterGeometryCache.set(b.geometry.uuid,x),null==x.userData.updatedMatrix){m.scene.updateMatrixWorld(),x.applyMatrix4(b.matrixWorld),x.userData.updatedMatrix=!0;const e=u.mesh?.rescale??1;1!==e&&x.scale(e,e,e)}const S=x.getIndex()??x.getAttribute("position"),v=null!=S?S.count/3:0;if(v>A){console.warn(`The triangle count of ${u.name} is too big ${v}. Keep it below ${A}`);continue}const z=null!=u.materialAssignments&&u.materialAssignments.length>0?u.materialAssignments[0].materialId:null,P=null!=z&&"null"!==z?await d(await this.assetService.getAsset(z),null,this.assetService,this.assetManagerService,this.shaders,!1):null;let $=null!=P?P:b.material;if(Array.isArray($))for(const e of $)e.userData.disableAO=!0;else $.userData.disableAO=!0;const L=a.degToRad(l.maxSlope??90),D=Math.cos(L),T=this.landscape.sections,q=T.filter(j(e,l.viewDistance)),I=q.filter(e=>!h.has(e.uuid)||t).filter(e=>s(e));T.filter(O(e,2*l.viewDistance)).forEach(e=>{const t=h.get(e.uuid);null!=t&&(t.visible=!1)});for(const e of q){const t=h.get(e.uuid);null!=t&&(t.visible=!0)}performance.now();const R=this.source.landscape.options,k=R.sectionSize,H=l.density??1??1,W=R.density,Y=k/W,E=H,J=Y/Math.sqrt(E),Z=Math.pow(W,2),K=J/Y,V=Math.floor(Z*E),Q=[0,0,0];for(const e of I)await g(async()=>{e.updateWorldMatrix(!0,!1);const s=this._matrix,a=new p,i=e.geometry.getAttribute("position"),r=e.geometry.getAttribute("normal"),c=(this.source.vertexMaterials??[]).filter(t=>t.m===e.name),u=y(c,e=>e.i);let m=h.get(e.uuid);if(null==m||m.count==V&&!t||(m.parent?.remove(m),this.scatterMeshPool.push(m),h.delete(e.uuid),m=null),null==m){const e=this.scatterMeshPool.findIndex(e=>e.count>=V);e>-1?(m=this.scatterMeshPool[e],m.geometry=x,m.material=$,this.scatterMeshPool.splice(e,1)):m=new o(x,$,V),m.raycast=()=>{},m.receiveShadow=!0}m.visible=!0;const d=new f(new p,new p,new p);let[w,g,b,S]=[new p,new p,new p,new p],[A,v,z]=[[],[],[]],[P,L,O]=[new p,new p,new p,new p];const j=new p,T=new p,q=new p,I=new p,R=new f(new p,new p,new p),k=new f(new p,new p,new p),H=new f(new p,new p,new p),X=new f(new p,new p,new p);let Y=0;e:for(let t=0;t<Z;t++){const o=Math.floor(t/W);w.fromBufferAttribute(i,t+o),I.copy(w).applyMatrix4(e.matrixWorld),R.a.copy(w),R.b.fromBufferAttribute(i,t+1+o),R.c.fromBufferAttribute(i,t+W+1+o),k.a.copy(R.b),k.b.copy(R.c),k.c.fromBufferAttribute(i,t+W+2+o),H.a.fromBufferAttribute(r,t+o),H.b.fromBufferAttribute(r,t+1+o),H.c.fromBufferAttribute(r,t+W+1+o),X.a.copy(H.b),X.b.copy(H.c),X.c.fromBufferAttribute(r,t+W+2+o);const c=[];c[0]=u.get(t+o)?.w,c[1]=u.get(t+1+o)?.w,c[2]=u.get(t+W+1+o)?.w,c[3]=u.get(t+W+2+o)?.w;let h=0;for(let e=0;e<=1+K;e+=K)for(let t=0;t<=1+K;t+=K){if(Y>V)break e;if(h++,h>E)continue e;1-e>t?(g=R.a,b=R.b,S=R.c,P=H.a,L=H.b,O=H.c,A=c[0],v=c[1],z=c[2]):(g=k.a,b=k.b,S=k.c,P=X.a,L=X.b,O=X.c,A=c[1],v=c[2],z=c[3]),d.a.copy(g),d.b.copy(b),d.c.copy(S),C(d),j.set(w.x,0,w.z),U(d,j),d.getBarycoord(j,a).toArray(Q),B[0]=A,B[1]=v,B[2]=z;if(G(B,Q,.2)!==n-1)continue;if(M([g,b,S],Q,T),M([P,L,O],Q,q),null!=l.maxSlope&&l.maxSlope<90&&q.y<D)continue;const o=T;o.y+=_(l.offsetMin,l.offsetMax);const i=_(l.scaleMin??1,l.scaleMax??1);s.makeScale(i,i,i);const r=s.elements;r[12]=o.x,r[13]=o.y,r[14]=o.z,!1!==l.randomRotation&&F(s,i),l.alignToNormal&&N(s,o,m.matrixWorld,q);const u=m.instanceMatrix.array,f=16*Y;u[f]=r[0],u[f+1]=r[1],u[f+2]=r[2],u[f+3]=r[3],u[f+4]=r[4],u[f+5]=r[5],u[f+6]=r[6],u[f+7]=r[7],u[f+8]=r[8],u[f+9]=r[9],u[f+10]=r[10],u[f+11]=r[11],u[f+12]=r[12],u[f+13]=r[13],u[f+14]=r[14],u[f+15]=r[15],Y++}}m.count=Y,m.instanceMatrix.needsUpdate=!0,m.position.copy(e.position),m.updateMatrix(),h.has(e.uuid)||this.landscape?.add(m),h.set(e.uuid,m),m.userData.meshConfig=l});performance.now()}}stop(){this.view.removeOnLoop(this.onLoopHandler)}update(){this.view.camera&&(this.view.camera.getWorldPosition(this._cameraPosition),this._cameraPosition.distanceTo(this._lastUpdatePosition)>10&&(this._lastUpdatePosition.copy(this._cameraPosition),this.refreshGeometry(),this.refreshScatter(this._cameraPosition)))}clear(){this.scatterMeshes.forEach(e=>e.forEach(e=>e.parent?.remove(e)))}createLandscapeMesh(e,t,s,n,o,a){const i=new h(t.sectionSize,t.sectionSize,t.density,t.density);i.rotateX(Math.PI/-2);const r=this.defaultLandscapeMaterial,c=new b(i,r);c.position.x=s+o*t.sectionSize,c.position.z=n+a*t.sectionSize,c.receiveShadow=!0,c.castShadow=!1,c.userData.landscape={x:o,y:a},c.x=o,c.y=a,c.name=`${o},${a}`,w(c,0,!0),w(c,4,!0);const l=e.landscape.heightMaps.find(e=>e.x===o&&e.y===a);if(null!=l&&this.applyHeightMap(i,l,t.density,1),i.computeTangents(),i.computeBoundsTree(),null!=e.landscape.holes&&e.landscape.holes.length>0){const t=getHoleAttribute(c,!0);for(const s of e.landscape.holes)s.m===c.name&&t.setX(s.i,s.w[0])}return c}}export function getHoleAttribute(e,t=!1){if(!e.geometry.hasAttribute("hole")||t){const t=new Float32Array(e.geometry.getAttribute("position").array.length);e.geometry.setAttribute("hole",new n(t,1))}return e.geometry.getAttribute("hole")}function $(e,t,s){const n=Math.sqrt(t),o=Math.floor(e/n)/(n-1),a=e%n/(n-1),i=Math.sqrt(s);return(s-1)*o-(i-1)*o+(i-1)*a}new Map,new m(0,0),new m(1,0),new m(0,1),new m(1,0),new m(0,1),new m(1,1),new p;const L=new s;function O(e,t){return function(s){return L.setFromObject(s).distanceToPoint(e)>t}}function j(e,t){return function(s){return L.setFromObject(s).distanceToPoint(e)<t}}function C(e){e.a.y=0,e.b.y=0,e.c.y=0}const B=[];function G(e,t,s=.5){const n=B;let o=-1,a=-1;for(let e=0;e<n.length;e++)if(null!=n[e])for(let i=0;i<n[e].length;i++){const r=n[e][i]*t[e];r>s&&r>a&&(a=r,o=i)}return o}function _(e,t){let s=t-e,n=q();return n*=s,n+=e,n}const D=[];let T=1e3;for(;T--;)D.push(Math.random());function q(){return++T>=D.length?D[T=0]:D[T]}const I=[];let R=20;for(;R--;)I.push((new i).makeRotationY(q()*Math.PI/2));function U(e,t){let s=q(),n=q();s+n>1&&(s=1-s,n=1-n);const o=e.a,a=e.b,i=e.c;t.x=o.x+s*(a.x-o.x)+n*(i.x-o.x),t.z=o.z+s*(a.z-o.z)+n*(i.z-o.z)}new p;new p;const k=new p,H=new p(0,1,0),W=(new i).makeRotationX(Math.PI/-2);function N(e,t,s,n){e.lookAt(k,n,H).multiply(W)}new i;function F(e,t=1){const s=(++R>=I.length?I[R=0]:I[R]).elements,n=e.elements;n[0]=s[0]*t,n[4]=s[4]*t,n[8]=s[8]*t,n[1]=s[1]*t,n[5]=s[5]*t,n[9]=s[9]*t,n[2]=s[2]*t,n[6]=s[6]*t,n[10]=s[10]*t}function X(e){const t=e.getAttribute("normal");for(let e=0;e<t.count;e++)t.setXYZ(e,0,1,0);t.normalized=!0,t.needsUpdate=!0}/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -7,6 +7,7 @@ import { GameComponent } from '../game-component/game-component.js';
|
|
|
7
7
|
import { BaseActor } from '../gameplay/actors/actor.js';
|
|
8
8
|
import { ActorComponent } from '../gameplay/actors/component.js';
|
|
9
9
|
import { PhysicsBodyType } from '../gameplay/services/physics/physics-system.js';
|
|
10
|
+
import { NetMode } from '../gameplay/net/net-session.js';
|
|
10
11
|
import { RenderingView } from '../rendering.js';
|
|
11
12
|
import { ParameterType, PropertyParameter } from '../shader/parameter.js';
|
|
12
13
|
import { ActorImpl, ActorType, ClassImpl, ShaderImpl, ShaderType } from '../shader/shader.js';
|
|
@@ -20,7 +21,7 @@ import type { ShaderGraphDocument } from "../shader/graph/model.js";
|
|
|
20
21
|
export { applyRuntimeParamTypeInference, convertConfiguredParamsToRuntimeTypes, convertConfiguredParamValueToRuntimeType, inferRuntimeSerializedParamTypeHint };
|
|
21
22
|
export type { RuntimeSerializedParamTypeHint } from './custom-param-runtime-types.js';
|
|
22
23
|
export type SceneObjectId = string;
|
|
23
|
-
export type SceneObjectType = "asset_mesh" | "light" | "shape_mesh" | "spline" | "landscape" | "particles" | "global_fog" | "global_light" | "actor" | "group" | "prefab" | "vfx" | "sky" | "world_env";
|
|
24
|
+
export type SceneObjectType = "asset_mesh" | "light" | "shape_mesh" | "spline" | "landscape" | "particles" | "global_fog" | "global_light" | "actor" | "group" | "prefab" | "vfx" | "sky" | "world_env" | "scatter";
|
|
24
25
|
export type LightType = "point" | "spot" | "directional" | "ambient" | "rectArea";
|
|
25
26
|
type DirectionalLightSettings = {
|
|
26
27
|
color: string;
|
|
@@ -122,6 +123,10 @@ export type SceneObject = {
|
|
|
122
123
|
* Surface scatter settings. Only relevant for object type asset_mesh in v1.
|
|
123
124
|
*/
|
|
124
125
|
surfaceScatter?: SurfaceScatterSettings;
|
|
126
|
+
/**
|
|
127
|
+
* Artist-painted scatter settings. Only relevant for object type scatter.
|
|
128
|
+
*/
|
|
129
|
+
paintedScatter?: PaintedScatterSettings;
|
|
125
130
|
/**
|
|
126
131
|
* Actor settings. Only relevant for object type actor
|
|
127
132
|
*/
|
|
@@ -233,6 +238,39 @@ export interface ScatterMeshSettings {
|
|
|
233
238
|
}
|
|
234
239
|
export interface GrassMesh extends ScatterMeshSettings {
|
|
235
240
|
}
|
|
241
|
+
export type PaintedScatterEraseMode = 'enabled' | 'all';
|
|
242
|
+
export interface PaintedScatterSettings {
|
|
243
|
+
palette: PaintedScatterPaletteItem[];
|
|
244
|
+
brush: PaintedScatterBrushSettings;
|
|
245
|
+
cells: PaintedScatterCell[];
|
|
246
|
+
}
|
|
247
|
+
export interface PaintedScatterPaletteItem extends ScatterMeshSettings {
|
|
248
|
+
id: string;
|
|
249
|
+
enabled: boolean;
|
|
250
|
+
weight: number;
|
|
251
|
+
minSpacing: number;
|
|
252
|
+
castShadow: boolean;
|
|
253
|
+
receiveShadow: boolean;
|
|
254
|
+
}
|
|
255
|
+
export interface PaintedScatterBrushSettings {
|
|
256
|
+
radius: number;
|
|
257
|
+
density: number;
|
|
258
|
+
eraseMode?: PaintedScatterEraseMode;
|
|
259
|
+
}
|
|
260
|
+
export interface PaintedScatterCell {
|
|
261
|
+
key: string;
|
|
262
|
+
revision: number;
|
|
263
|
+
instances: PaintedScatterInstance[];
|
|
264
|
+
}
|
|
265
|
+
export interface PaintedScatterInstance {
|
|
266
|
+
id: string;
|
|
267
|
+
paletteId: string;
|
|
268
|
+
position: number[];
|
|
269
|
+
rotation: [number, number, number, THREE.EulerOrder?];
|
|
270
|
+
scale: number[];
|
|
271
|
+
surfaceNormal?: number[];
|
|
272
|
+
sourceObjectId?: string;
|
|
273
|
+
}
|
|
236
274
|
export type FogType = "linear" | "density";
|
|
237
275
|
export interface FogSettings {
|
|
238
276
|
type: FogType;
|
|
@@ -309,10 +347,12 @@ export declare class SceneMaterializer {
|
|
|
309
347
|
private createAssetSubscription;
|
|
310
348
|
readonly components: GameComponent[];
|
|
311
349
|
private readonly landscapeManagers;
|
|
350
|
+
private paintedScatterManager?;
|
|
312
351
|
private surfaceScatterManager?;
|
|
313
352
|
materializedActors: Map<string, BaseActor>;
|
|
314
353
|
idToSceneObject: Map<string, SceneObject>;
|
|
315
354
|
inEditor: boolean;
|
|
355
|
+
netMode: NetMode;
|
|
316
356
|
updated$: Subject<{
|
|
317
357
|
object: Object3D;
|
|
318
358
|
source: SceneObject;
|
|
@@ -382,6 +422,7 @@ export declare class SceneMaterializer {
|
|
|
382
422
|
private shouldBeMaterialized;
|
|
383
423
|
initWithInstancing(): Promise<void>;
|
|
384
424
|
private prepareCollisionShapesForInstanced;
|
|
425
|
+
setScene(scene: Scene): void;
|
|
385
426
|
private testCanBatch;
|
|
386
427
|
private testCanBatchMaterial;
|
|
387
428
|
/**
|
|
@@ -419,6 +460,12 @@ export declare class SceneMaterializer {
|
|
|
419
460
|
* @returns
|
|
420
461
|
*/
|
|
421
462
|
materialize(source: SceneObject, parent?: Object3D, anonymous?: boolean, context?: MaterializeContext): Promise<Object3D>;
|
|
463
|
+
private handlePaintedScatterSceneMutation;
|
|
464
|
+
private refreshPaintedScatterPresence;
|
|
465
|
+
private disposePaintedScatterManager;
|
|
466
|
+
private sceneContainsPaintedScatter;
|
|
467
|
+
private sceneObjectsContainPaintedScatter;
|
|
468
|
+
private sceneObjectContainsPaintedScatter;
|
|
422
469
|
private handleSurfaceScatterSceneMutation;
|
|
423
470
|
private refreshSurfaceScatterPresence;
|
|
424
471
|
private disposeSurfaceScatterManager;
|
|
@@ -427,6 +474,7 @@ export declare class SceneMaterializer {
|
|
|
427
474
|
private sceneObjectContainsSurfaceScatter;
|
|
428
475
|
private sceneReferencesPrefabAsset;
|
|
429
476
|
private prefabAssetContainsSurfaceScatter;
|
|
477
|
+
private prefabAssetContainsPaintedScatter;
|
|
430
478
|
private pmremGenerator?;
|
|
431
479
|
private pmremGeneratorResults;
|
|
432
480
|
private applyTransform;
|
|
@@ -437,6 +485,7 @@ export declare class SceneMaterializer {
|
|
|
437
485
|
private applySkySettings;
|
|
438
486
|
private createComponent;
|
|
439
487
|
private createFromActor;
|
|
488
|
+
private applyInitialMaterializedNetRole;
|
|
440
489
|
/**
|
|
441
490
|
* Each prefab instance is defined by a unique chain if ids.
|
|
442
491
|
* The first element in the chain is
|