upatde(fabrik): zone + herbe
🔍 Lint / 🪄 Check lint (pull_request) Has been cancelled
🔍 Lint / 🎨 Check format (pull_request) Has been cancelled
🔍 Lint / 🔎 Typecheck (pull_request) Has been cancelled
📊 Quality / 🔒 Security Audit (pull_request) Has been cancelled
📊 Quality / 📋 Dependency Freshness (pull_request) Has been cancelled
📊 Quality / 📦 Bundle Size (pull_request) Has been cancelled
🔍 Lint / 🏗 Build (pull_request) Has been cancelled
🔍 Lint / 🪄 Check lint (pull_request) Has been cancelled
🔍 Lint / 🎨 Check format (pull_request) Has been cancelled
🔍 Lint / 🔎 Typecheck (pull_request) Has been cancelled
📊 Quality / 🔒 Security Audit (pull_request) Has been cancelled
📊 Quality / 📋 Dependency Freshness (pull_request) Has been cancelled
📊 Quality / 📦 Bundle Size (pull_request) Has been cancelled
🔍 Lint / 🏗 Build (pull_request) Has been cancelled
This commit is contained in:
@@ -18,6 +18,7 @@ import {
|
||||
useTerrainHeightSampler,
|
||||
} from "@/hooks/three/useTerrainHeight";
|
||||
import { WorldBoundsCollision } from "@/world/collision/WorldBoundsCollision";
|
||||
import { flattenLaFabrikTerrainFootprint } from "@/data/world/laFabrikConfig";
|
||||
import type { MapNode } from "@/types/map/mapScene";
|
||||
import type { OctreeReadyHandler } from "@/types/three/three";
|
||||
import type { SceneLoadingChangeHandler } from "@/types/world/sceneLoading";
|
||||
@@ -213,7 +214,7 @@ function CollisionModelInstance({
|
||||
modelUrl: string;
|
||||
onLoaded: () => void;
|
||||
terrainHeight: TerrainHeightSampler;
|
||||
}): React.JSX.Element {
|
||||
}): React.JSX.Element | null {
|
||||
const { position, rotation, scale } = node;
|
||||
const normalizedScale = normalizeMapScale(scale);
|
||||
const { scene } = useLoggedGLTF(modelUrl, {
|
||||
@@ -223,22 +224,46 @@ function CollisionModelInstance({
|
||||
scale: normalizedScale,
|
||||
});
|
||||
const sceneInstance = useClonedObject(scene);
|
||||
const collisionSceneInstance = useMemo(() => {
|
||||
if (node.name === "terrain") {
|
||||
flattenLaFabrikTerrainFootprint(
|
||||
sceneInstance,
|
||||
position,
|
||||
rotation,
|
||||
normalizedScale,
|
||||
);
|
||||
}
|
||||
return sceneInstance;
|
||||
}, [node.name, normalizedScale, position, rotation, sceneInstance]);
|
||||
const collisionPosition = useMemo(() => {
|
||||
if (node.name === "terrain") return position;
|
||||
|
||||
const [x, y, z] = position;
|
||||
const height = terrainHeight.getHeight(x, z);
|
||||
const bottomOffset = getObjectBottomOffset(sceneInstance, normalizedScale);
|
||||
const bottomOffset = getObjectBottomOffset(
|
||||
collisionSceneInstance,
|
||||
normalizedScale,
|
||||
);
|
||||
return [x, height !== null ? height + bottomOffset : y, z] as const;
|
||||
}, [node.name, normalizedScale, position, sceneInstance, terrainHeight]);
|
||||
}, [
|
||||
node.name,
|
||||
normalizedScale,
|
||||
position,
|
||||
collisionSceneInstance,
|
||||
terrainHeight,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
onLoaded();
|
||||
}, [onLoaded]);
|
||||
|
||||
if (node.name === "lafabrik") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<primitive
|
||||
object={sceneInstance}
|
||||
object={collisionSceneInstance}
|
||||
position={collisionPosition}
|
||||
rotation={rotation}
|
||||
scale={normalizedScale}
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
SUN_Z_MIN,
|
||||
SUN_Z_STEP,
|
||||
} from "@/data/world/lightingConfig";
|
||||
import { LA_FABRIK_INTERIOR_LIGHT_POSITION } from "@/data/world/laFabrikConfig";
|
||||
import { useDebugFolder } from "@/hooks/debug/useDebugFolder";
|
||||
import { LIGHTING_STATE } from "@/world/lightingState";
|
||||
|
||||
@@ -121,6 +122,13 @@ export function Lighting(): React.JSX.Element {
|
||||
castShadow
|
||||
/>
|
||||
<object3D ref={sunTarget} />
|
||||
<pointLight
|
||||
position={LA_FABRIK_INTERIOR_LIGHT_POSITION}
|
||||
color="#dbeafe"
|
||||
intensity={1.2}
|
||||
distance={14}
|
||||
decay={1.6}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,15 +3,18 @@ import { AnimatedModel } from "@/components/three/models/AnimatedModel";
|
||||
import {
|
||||
CHARACTER_CONFIGS,
|
||||
CHARACTER_IDS,
|
||||
type CharacterConfig,
|
||||
type CharacterId,
|
||||
} from "@/data/world/characters/characterConfig";
|
||||
import { useTerrainSnappedPosition } from "@/hooks/three/useTerrainHeight";
|
||||
import { useCharacterDebugStore } from "@/managers/stores/useCharacterDebugStore";
|
||||
|
||||
function CharacterModel({ id }: { id: CharacterId }): React.JSX.Element {
|
||||
const config = CHARACTER_CONFIGS[id];
|
||||
const config: CharacterConfig = CHARACTER_CONFIGS[id];
|
||||
const state = useCharacterDebugStore((store) => store.characters[id]);
|
||||
const position = useTerrainSnappedPosition(state.position);
|
||||
const snappedPosition = useTerrainSnappedPosition(state.position);
|
||||
const position =
|
||||
config.snapToTerrain === false ? state.position : snappedPosition;
|
||||
|
||||
return (
|
||||
<AnimatedModel
|
||||
|
||||
@@ -8,6 +8,11 @@ import {
|
||||
GRASS_COLORS,
|
||||
GRASS_CONFIG,
|
||||
} from "@/data/world/grassConfig";
|
||||
import {
|
||||
LA_FABRIK_CENTER,
|
||||
LA_FABRIK_HALF_EXTENTS,
|
||||
LA_FABRIK_ROTATION_Y,
|
||||
} from "@/data/world/laFabrikConfig";
|
||||
import {
|
||||
grassFragmentShader,
|
||||
grassVertexShader,
|
||||
@@ -169,6 +174,17 @@ function createGrassMaterial(
|
||||
uMaxBladeHeight: { value: GRASS_CONFIG.maxBladeHeight },
|
||||
uRandomHeightAmount: { value: GRASS_CONFIG.randomHeightAmount },
|
||||
uSurfaceOffset: { value: GRASS_CONFIG.surfaceOffset },
|
||||
uLaFabrikCenter: {
|
||||
value: new THREE.Vector2(LA_FABRIK_CENTER[0], LA_FABRIK_CENTER[2]),
|
||||
},
|
||||
uLaFabrikHalfExtents: {
|
||||
value: new THREE.Vector2(
|
||||
LA_FABRIK_HALF_EXTENTS.x,
|
||||
LA_FABRIK_HALF_EXTENTS.z,
|
||||
),
|
||||
},
|
||||
uLaFabrikRotation: { value: LA_FABRIK_ROTATION_Y },
|
||||
uLaFabrikNoGrassFeather: { value: 1.4 },
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -43,6 +43,10 @@ export const grassVertexShader = /* glsl */ `
|
||||
uniform float uMaxBladeHeight;
|
||||
uniform float uRandomHeightAmount;
|
||||
uniform float uSurfaceOffset;
|
||||
uniform vec2 uLaFabrikCenter;
|
||||
uniform vec2 uLaFabrikHalfExtents;
|
||||
uniform float uLaFabrikRotation;
|
||||
uniform float uLaFabrikNoGrassFeather;
|
||||
|
||||
float random(vec2 st) {
|
||||
return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);
|
||||
@@ -132,6 +136,18 @@ export const grassVertexShader = /* glsl */ `
|
||||
smoothstep(uBoundingBoxMax.z, uBoundingBoxMax.z - 2.0, worldPos.z);
|
||||
heightModifier *= edgeFade * mix(0.45, 1.0, clumpMask);
|
||||
|
||||
vec2 laFabrikDelta = worldPos.xz - uLaFabrikCenter;
|
||||
float laFabrikCos = cos(-uLaFabrikRotation);
|
||||
float laFabrikSin = sin(-uLaFabrikRotation);
|
||||
vec2 laFabrikLocal = vec2(
|
||||
laFabrikDelta.x * laFabrikCos - laFabrikDelta.y * laFabrikSin,
|
||||
laFabrikDelta.x * laFabrikSin + laFabrikDelta.y * laFabrikCos
|
||||
);
|
||||
vec2 laFabrikDistance = abs(laFabrikLocal) - uLaFabrikHalfExtents;
|
||||
float laFabrikOutsideDistance = max(laFabrikDistance.x, laFabrikDistance.y);
|
||||
float laFabrikGrassMask = smoothstep(0.0, uLaFabrikNoGrassFeather, laFabrikOutsideDistance);
|
||||
heightModifier *= laFabrikGrassMask;
|
||||
|
||||
float sideFactor = (color.r == 0.1) ? 1.0 : (color.b == 0.1) ? -1.0 : 0.0;
|
||||
float tipFactor = color.g;
|
||||
float width = smoothstep(0.02, uMaxBladeHeight * 0.85, heightModifier) * uBladeWidth * bladeVisibility;
|
||||
|
||||
@@ -17,7 +17,8 @@ export function GeneratedMapNodeInstance({
|
||||
node,
|
||||
onLoaded,
|
||||
}: GeneratedMapNodeInstanceProps): React.JSX.Element | null {
|
||||
const position = useTerrainSnappedPosition(node.position);
|
||||
const snappedPosition = useTerrainSnappedPosition(node.position);
|
||||
const position = node.name === "lafabrik" ? node.position : snappedPosition;
|
||||
const scale = normalizeMapScale(node.scale);
|
||||
|
||||
if (node.name === "ecole") {
|
||||
|
||||
Reference in New Issue
Block a user