Feature: Implement wind simulation for foliage rendering across renderer, runtime, and viewport hosts
This commit is contained in:
@@ -473,6 +473,8 @@ export class FoliageInstancedRenderer {
|
||||
private scatter: FoliageScatterResult | null = null;
|
||||
private prototypeRegistry: FoliagePrototypeRegistry = {};
|
||||
private quality: FoliageQualitySettings = resolveFoliageQualitySettings(null);
|
||||
private windTime = 0;
|
||||
private windUniforms: FoliageWindUniformSet[] = [];
|
||||
private currentView: FoliageRenderView | null = null;
|
||||
private viewSignature: string | null = null;
|
||||
private renderResourceSignature: string | null = null;
|
||||
@@ -498,6 +500,18 @@ export class FoliageInstancedRenderer {
|
||||
this.group.userData.nonPickable = true;
|
||||
}
|
||||
|
||||
updateWind(deltaSeconds: number) {
|
||||
if (!this.shouldApplyWindShader()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Number.isFinite(deltaSeconds) && deltaSeconds > 0) {
|
||||
this.windTime += deltaSeconds;
|
||||
}
|
||||
|
||||
this.writeWindUniforms();
|
||||
}
|
||||
|
||||
sync(input: FoliageInstancedRendererSyncInput) {
|
||||
const terrains = normalizeTerrainRegistry(input.terrains);
|
||||
const quality = resolveFoliageQualitySettings(input.quality);
|
||||
@@ -536,6 +550,7 @@ export class FoliageInstancedRenderer {
|
||||
renderResourceSignature === this.renderResourceSignature &&
|
||||
this.scatter !== null
|
||||
) {
|
||||
this.writeWindUniforms();
|
||||
this.applyCurrentViewToRenderResources();
|
||||
return;
|
||||
}
|
||||
@@ -668,6 +683,7 @@ export class FoliageInstancedRenderer {
|
||||
this.currentView = null;
|
||||
this.viewSignature = null;
|
||||
this.renderResourceSignature = null;
|
||||
this.windUniforms = [];
|
||||
this.sourceMeshPromisesByBundledPath.clear();
|
||||
this.clearActiveBatches();
|
||||
}
|
||||
@@ -677,6 +693,7 @@ export class FoliageInstancedRenderer {
|
||||
this.activeBatchKeyByChunkKey.clear();
|
||||
this.activeLodLevelByChunkKey.clear();
|
||||
this.renderChunks = [];
|
||||
this.windUniforms = [];
|
||||
|
||||
if (this.activeBatchGroup === null) {
|
||||
return;
|
||||
@@ -696,6 +713,41 @@ export class FoliageInstancedRenderer {
|
||||
console.warn(message);
|
||||
}
|
||||
|
||||
private shouldApplyWindShader(): boolean {
|
||||
return (
|
||||
this.quality.enabled &&
|
||||
this.quality.densityMultiplier > 0 &&
|
||||
this.quality.windEnabled
|
||||
);
|
||||
}
|
||||
|
||||
private registerWindUniforms = (uniforms: FoliageWindUniformSet) => {
|
||||
writeFoliageWindUniformValues(uniforms, this.quality, this.windTime);
|
||||
this.windUniforms.push(uniforms);
|
||||
};
|
||||
|
||||
private writeWindUniforms() {
|
||||
if (!this.shouldApplyWindShader()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const uniforms of this.windUniforms) {
|
||||
writeFoliageWindUniformValues(uniforms, this.quality, this.windTime);
|
||||
}
|
||||
}
|
||||
|
||||
private getWindMaterialOptions(): FoliageWindMaterialOptions | undefined {
|
||||
if (!this.shouldApplyWindShader()) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
getSettings: () => this.quality,
|
||||
getTime: () => this.windTime,
|
||||
registerUniforms: this.registerWindUniforms
|
||||
};
|
||||
}
|
||||
|
||||
private loadTemplateSourceMeshes(
|
||||
bundledPath: string
|
||||
): Promise<FoliageTemplateSourceMesh[]> {
|
||||
@@ -761,8 +813,12 @@ export class FoliageInstancedRenderer {
|
||||
batchGroup.userData.foliageLayerId = batch.layerId;
|
||||
batchGroup.userData.foliageTerrainId = batch.terrainId;
|
||||
|
||||
const windOptions = this.getWindMaterialOptions();
|
||||
|
||||
for (const sourceMesh of sourceMeshes) {
|
||||
batchGroup.add(createInstancedMeshForSource(batch, sourceMesh));
|
||||
batchGroup.add(
|
||||
createInstancedMeshForSource(batch, sourceMesh, windOptions)
|
||||
);
|
||||
}
|
||||
|
||||
applyRendererRenderCategoryFromMaterial(batchGroup);
|
||||
|
||||
@@ -5704,6 +5704,7 @@ export class RuntimeHost {
|
||||
|
||||
this.updateTerrainLodVisibility();
|
||||
this.foliageRenderer.updateView(this.camera);
|
||||
this.foliageRenderer.updateWind(simulationDt);
|
||||
this.updateUnderwaterSceneFog();
|
||||
this.syncCelestialShadowState();
|
||||
|
||||
|
||||
@@ -14188,6 +14188,7 @@ export class ViewportHost {
|
||||
this.updateTransformGizmoPose();
|
||||
this.updateTerrainLodVisibility();
|
||||
this.foliageRenderer.updateView(this.getActiveCamera());
|
||||
this.foliageRenderer.updateWind(dt);
|
||||
this.volumeTime += dt;
|
||||
|
||||
for (const uniform of this.volumeAnimatedUniforms) {
|
||||
|
||||
@@ -341,7 +341,11 @@ describe("foliage render batch helpers", () => {
|
||||
enabled: false,
|
||||
densityMultiplier: 1,
|
||||
maxDistanceMultiplier: 1,
|
||||
shadows: "near"
|
||||
shadows: "near",
|
||||
windEnabled: true,
|
||||
windStrength: 1,
|
||||
windSpeed: 1,
|
||||
windDirectionDegrees: 35
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -373,7 +377,11 @@ describe("foliage render batch helpers", () => {
|
||||
enabled: true,
|
||||
densityMultiplier: 1,
|
||||
maxDistanceMultiplier: 1,
|
||||
shadows: "near"
|
||||
shadows: "near",
|
||||
windEnabled: true,
|
||||
windStrength: 1,
|
||||
windSpeed: 1,
|
||||
windDirectionDegrees: 35
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user