fix: bug on textute vegetation item
🔍 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:
@@ -2,7 +2,7 @@ import { useEffect, useRef } from "react";
|
||||
import { useGLTF } from "@react-three/drei";
|
||||
import { useThree } from "@react-three/fiber";
|
||||
import * as THREE from "three";
|
||||
import { mergeBufferGeometries } from "three-stdlib";
|
||||
import { mergeGeometries } from "three/addons/utils/BufferGeometryUtils.js";
|
||||
import type { Vector3Tuple } from "@/types/three/three";
|
||||
import { optimizeGLTFSceneTextures } from "@/utils/three/optimizeGLTFScene";
|
||||
|
||||
@@ -102,7 +102,7 @@ function createMergedMeshes(scene: THREE.Group): MergedMeshData[] {
|
||||
};
|
||||
}
|
||||
|
||||
const geometry = mergeBufferGeometries(group.geometries, false);
|
||||
const geometry = mergeGeometries(group.geometries, false);
|
||||
|
||||
for (const sourceGeometry of group.geometries) {
|
||||
sourceGeometry.dispose();
|
||||
|
||||
@@ -3,7 +3,7 @@ export const GRASS_CONFIG = {
|
||||
patchSize: 30,
|
||||
bladeCount: 32000,
|
||||
bladeWidth: 0.08,
|
||||
maxBladeHeight: 0.56,
|
||||
maxBladeHeight: 0.67,
|
||||
randomHeightAmount: 0.25,
|
||||
surfaceOffset: 0.025,
|
||||
heightTextureSize: 128,
|
||||
|
||||
@@ -2,7 +2,6 @@ import { useEffect, useMemo, useRef } from "react";
|
||||
import * as THREE from "three";
|
||||
import { useGLTF } from "@react-three/drei";
|
||||
import { useThree } from "@react-three/fiber";
|
||||
import { mergeBufferGeometries } from "three-stdlib";
|
||||
import {
|
||||
normalizeMapScale,
|
||||
useTerrainHeightSampler,
|
||||
@@ -23,11 +22,6 @@ interface MeshData {
|
||||
material: THREE.Material | THREE.Material[];
|
||||
}
|
||||
|
||||
interface MeshMergeGroup {
|
||||
geometries: THREE.BufferGeometry[];
|
||||
material: THREE.Material | THREE.Material[];
|
||||
}
|
||||
|
||||
const meshDataCache = new Map<string, MeshData[]>();
|
||||
|
||||
function cloneMaterial(
|
||||
@@ -38,46 +32,29 @@ function cloneMaterial(
|
||||
: material.clone();
|
||||
}
|
||||
|
||||
function disposeMaterialOnly(
|
||||
material: THREE.Material | THREE.Material[],
|
||||
): void {
|
||||
if (Array.isArray(material)) {
|
||||
for (const item of material) {
|
||||
item.dispose();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
material.dispose();
|
||||
}
|
||||
|
||||
function disposeInstancedMapMesh(mesh: THREE.InstancedMesh): void {
|
||||
mesh.dispose();
|
||||
}
|
||||
|
||||
function createGeometrySignature(geometry: THREE.BufferGeometry): string {
|
||||
const attributes = Object.entries(geometry.attributes)
|
||||
.map(([name, attribute]) => {
|
||||
return `${name}:${attribute.itemSize}:${attribute.normalized}`;
|
||||
})
|
||||
.sort()
|
||||
.join("|");
|
||||
function hasFinitePositions(geometry: THREE.BufferGeometry): boolean {
|
||||
const position = geometry.getAttribute("position");
|
||||
if (!position) return false;
|
||||
|
||||
return `${geometry.index ? "indexed" : "non-indexed"}:${attributes}`;
|
||||
for (let index = 0; index < position.count; index++) {
|
||||
if (
|
||||
!Number.isFinite(position.getX(index)) ||
|
||||
!Number.isFinite(position.getY(index)) ||
|
||||
!Number.isFinite(position.getZ(index))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function createMaterialKey(
|
||||
material: THREE.Material | THREE.Material[],
|
||||
): string {
|
||||
if (Array.isArray(material)) {
|
||||
return material.map((item) => item.uuid).join("|");
|
||||
}
|
||||
|
||||
return material.uuid;
|
||||
return true;
|
||||
}
|
||||
|
||||
function extractMeshes(scene: THREE.Group): MeshData[] {
|
||||
const groups = new Map<string, MeshMergeGroup>();
|
||||
const meshes: MeshData[] = [];
|
||||
|
||||
scene.updateMatrixWorld(true);
|
||||
scene.traverse((child) => {
|
||||
@@ -85,50 +62,18 @@ function extractMeshes(scene: THREE.Group): MeshData[] {
|
||||
|
||||
const geometry = child.geometry.clone();
|
||||
geometry.applyMatrix4(child.matrixWorld);
|
||||
const material = child.material;
|
||||
const key = `${createMaterialKey(material)}:${createGeometrySignature(geometry)}`;
|
||||
const group = groups.get(key);
|
||||
|
||||
if (group) {
|
||||
group.geometries.push(geometry);
|
||||
if (!hasFinitePositions(geometry)) {
|
||||
geometry.dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
groups.set(key, {
|
||||
geometries: [geometry],
|
||||
material: cloneMaterial(material),
|
||||
});
|
||||
});
|
||||
|
||||
return [...groups.values()]
|
||||
.map((group) => {
|
||||
if (group.geometries.length === 1) {
|
||||
const [geometry] = group.geometries;
|
||||
if (!geometry) return null;
|
||||
|
||||
return {
|
||||
meshes.push({
|
||||
geometry,
|
||||
material: group.material,
|
||||
};
|
||||
}
|
||||
material: cloneMaterial(child.material),
|
||||
});
|
||||
});
|
||||
|
||||
const mergedGeometry = mergeBufferGeometries(group.geometries, false);
|
||||
|
||||
for (const geometry of group.geometries) {
|
||||
geometry.dispose();
|
||||
}
|
||||
|
||||
if (!mergedGeometry) {
|
||||
disposeMaterialOnly(group.material);
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
geometry: mergedGeometry,
|
||||
material: group.material,
|
||||
};
|
||||
})
|
||||
.filter((meshData): meshData is MeshData => meshData !== null);
|
||||
return meshes;
|
||||
}
|
||||
|
||||
function setInstanceMatrices(
|
||||
|
||||
@@ -2,7 +2,6 @@ import { useEffect, useMemo, useRef } from "react";
|
||||
import * as THREE from "three";
|
||||
import { useGLTF } from "@react-three/drei";
|
||||
import { useFrame, useThree } from "@react-three/fiber";
|
||||
import { mergeBufferGeometries } from "three-stdlib";
|
||||
import { useTerrainHeightSampler } from "@/hooks/three/useTerrainHeight";
|
||||
import type { VegetationInstance } from "@/types/map/mapScene";
|
||||
import { useWind } from "@/hooks/world/useWind";
|
||||
@@ -38,6 +37,7 @@ interface VegetationWindUniforms {
|
||||
}
|
||||
|
||||
const meshDataCache = new Map<string, MeshData[]>();
|
||||
const VEGETATION_ALPHA_TEST = 0.35;
|
||||
|
||||
function updateVegetationWindUniforms(
|
||||
uniforms: VegetationWindUniforms,
|
||||
@@ -90,6 +90,15 @@ function applyVegetationWindMaterial(
|
||||
};
|
||||
|
||||
windMaterial.userData.windUniforms = windUniforms;
|
||||
windMaterial.alphaTest = Math.max(
|
||||
windMaterial.alphaTest,
|
||||
VEGETATION_ALPHA_TEST,
|
||||
);
|
||||
windMaterial.transparent = false;
|
||||
windMaterial.depthTest = true;
|
||||
windMaterial.depthWrite = true;
|
||||
windMaterial.side = THREE.DoubleSide;
|
||||
windMaterial.needsUpdate = true;
|
||||
|
||||
windMaterial.onBeforeCompile = (shader) => {
|
||||
shader.uniforms.uVegetationWindTime = windUniforms.time;
|
||||
@@ -130,11 +139,25 @@ function applyVegetationWindMaterial(
|
||||
return windMaterial;
|
||||
}
|
||||
|
||||
function hasFinitePositions(geometry: THREE.BufferGeometry): boolean {
|
||||
const position = geometry.getAttribute("position");
|
||||
if (!position) return false;
|
||||
|
||||
for (let index = 0; index < position.count; index++) {
|
||||
if (
|
||||
!Number.isFinite(position.getX(index)) ||
|
||||
!Number.isFinite(position.getY(index)) ||
|
||||
!Number.isFinite(position.getZ(index))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function extractMeshes(scene: THREE.Group): MeshData[] {
|
||||
const meshesByMaterial = new Map<
|
||||
string,
|
||||
{ geometries: THREE.BufferGeometry[]; material: THREE.Material }
|
||||
>();
|
||||
const meshes: MeshData[] = [];
|
||||
scene.updateMatrixWorld(true);
|
||||
|
||||
scene.traverse((child) => {
|
||||
@@ -147,41 +170,19 @@ function extractMeshes(scene: THREE.Group): MeshData[] {
|
||||
|
||||
const geometry = child.geometry.clone();
|
||||
geometry.applyMatrix4(child.matrixWorld);
|
||||
|
||||
const existing = meshesByMaterial.get(material.uuid);
|
||||
if (existing) {
|
||||
existing.geometries.push(geometry);
|
||||
} else {
|
||||
meshesByMaterial.set(material.uuid, {
|
||||
geometries: [geometry],
|
||||
material: material.clone(),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return [...meshesByMaterial.values()]
|
||||
.map(({ geometries, material }) => {
|
||||
const mergedGeometry = mergeBufferGeometries(geometries, false);
|
||||
|
||||
for (const geometry of geometries) {
|
||||
if (geometry !== mergedGeometry) {
|
||||
if (!hasFinitePositions(geometry)) {
|
||||
geometry.dispose();
|
||||
return;
|
||||
}
|
||||
}
|
||||
addWindWeightAttribute(geometry);
|
||||
|
||||
if (!mergedGeometry) {
|
||||
material.dispose();
|
||||
return null;
|
||||
}
|
||||
meshes.push({
|
||||
geometry,
|
||||
material: applyVegetationWindMaterial(material.clone()),
|
||||
});
|
||||
});
|
||||
|
||||
addWindWeightAttribute(mergedGeometry);
|
||||
|
||||
return {
|
||||
geometry: mergedGeometry,
|
||||
material: applyVegetationWindMaterial(material),
|
||||
};
|
||||
})
|
||||
.filter((meshData): meshData is MeshData => meshData !== null);
|
||||
return meshes;
|
||||
}
|
||||
|
||||
function createInstanceMatrices(
|
||||
@@ -194,18 +195,17 @@ function createInstanceMatrices(
|
||||
const position = new THREE.Vector3();
|
||||
const rotation = new THREE.Euler();
|
||||
const quaternion = new THREE.Quaternion();
|
||||
const scale = new THREE.Vector3();
|
||||
const scale = new THREE.Vector3(
|
||||
scaleMultiplier,
|
||||
scaleMultiplier,
|
||||
scaleMultiplier,
|
||||
);
|
||||
|
||||
for (const instance of instances) {
|
||||
const matrix = new THREE.Matrix4();
|
||||
|
||||
position.set(...instance.position);
|
||||
scale.set(
|
||||
instance.scale[0] * scaleMultiplier,
|
||||
instance.scale[1] * scaleMultiplier,
|
||||
instance.scale[2] * scaleMultiplier,
|
||||
);
|
||||
position.y += -geometryBottomY * scale.y;
|
||||
position.y += -geometryBottomY * scaleMultiplier;
|
||||
rotation.set(
|
||||
instance.rotation[0] + rotationOffset[0],
|
||||
instance.rotation[1] + rotationOffset[1],
|
||||
|
||||
Reference in New Issue
Block a user