Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Quality Configuration #1070

Draft
wants to merge 14 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions fission/src/Synthesis.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import AnalyticsConsent from "./ui/components/AnalyticsConsent.tsx"
import PreferencesSystem from "./systems/preferences/PreferencesSystem.ts"
import APSManagementModal from "./ui/modals/APSManagementModal.tsx"
import ConfigurePanel from "./ui/panels/configuring/assembly-config/ConfigurePanel.tsx"
import GraphicsSettings from "./ui/panels/GraphicsSettingsPanel.tsx"

const worker = new Lazy<Worker>(() => new WPILibWSWorker())

Expand Down Expand Up @@ -228,6 +229,7 @@ const initialPanels: ReactElement[] = [
<WSViewPanel key="ws-view" panelId="ws-view" />,
<DebugPanel key="debug" panelId="debug" />,
<ConfigurePanel key="configure" panelId="configure" />,
<GraphicsSettings key="graphics-settings" panelId="graphics-settings" openLocation="right" sidePadding={8} />,
]

export default Synthesis
23 changes: 20 additions & 3 deletions fission/src/systems/preferences/PreferenceTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Vector3Tuple } from "three"

/** Names of all global preferences. */
export type GlobalPreference =
| "QualitySettings"
| "ZoomSensitivity"
| "PitchSensitivity"
| "YawSensitivity"
Expand All @@ -17,13 +16,13 @@ export type GlobalPreference =

export const RobotPreferencesKey: string = "Robots"
export const FieldPreferencesKey: string = "Fields"
export const GraphicsPreferenceKey: string = "Quality"

/**
* Default values for GlobalPreferences as a fallback if they are not configured by the user.
* Every global preference should have a default value.
*/
export const DefaultGlobalPreferences: { [key: string]: unknown } = {
QualitySettings: "High" as QualitySetting,
ZoomSensitivity: 15,
PitchSensitivity: 10,
YawSensitivity: 3,
Expand All @@ -36,7 +35,25 @@ export const DefaultGlobalPreferences: { [key: string]: unknown } = {
SubsystemGravity: false,
}

export type QualitySetting = "Low" | "Medium" | "High"
export type GraphicsPreferences = {
lightIntensity: number
fancyShadows: boolean
maxFar: number
cascades: number
shadowMapSize: number
antiAliasing: boolean
}

export function DefaultGraphicsPreferences(): GraphicsPreferences {
return {
lightIntensity: 5,
fancyShadows: false,
maxFar: 30,
cascades: 4,
shadowMapSize: 4096,
antiAliasing: false,
}
}

export type IntakePreferences = {
deltaTransformation: number[]
Expand Down
15 changes: 15 additions & 0 deletions fission/src/systems/preferences/PreferencesSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ import {
DefaultFieldPreferences,
DefaultGlobalPreferences,
DefaultRobotPreferences,
DefaultGraphicsPreferences,
FieldPreferences,
FieldPreferencesKey,
GlobalPreference,
RobotPreferences,
RobotPreferencesKey,
GraphicsPreferences,
GraphicsPreferenceKey,
} from "./PreferenceTypes"

/** An event that's triggered when a preference is changed. */
Expand Down Expand Up @@ -133,6 +136,18 @@ class PreferencesSystem {
return allFieldPrefs
}

/** Gets simulation quality preferences */
public static getGraphicsPreferences(): GraphicsPreferences {
let graphicsPrefs = this.getPreference<GraphicsPreferences>(GraphicsPreferenceKey)

if (graphicsPrefs == undefined) {
graphicsPrefs = DefaultGraphicsPreferences()
this._preferences[GraphicsPreferenceKey] = graphicsPrefs
}

return graphicsPrefs
}

/** Loads all preferences from local storage. */
public static loadPreferences() {
const loadedPrefs = window.localStorage.getItem(this._localStorageKey)
Expand Down
128 changes: 84 additions & 44 deletions fission/src/systems/scene/SceneRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Jolt from "@barclah/jolt-physics"
import { PixelSpaceCoord, SceneOverlayEvent, SceneOverlayEventKey } from "@/ui/components/SceneOverlayEvents"
import PreferencesSystem from "../preferences/PreferencesSystem"
import { CSM } from "three/examples/jsm/csm/CSM.js"
import { GraphicsPreferences } from "../preferences/PreferenceTypes"

const CLEAR_COLOR = 0x121212
const GROUND_COLOR = 0x4066c7
Expand All @@ -28,8 +29,6 @@ class SceneRenderer extends WorldSystem {
private _skybox: THREE.Mesh
private _composer: EffectComposer

private _antiAliasPass: EffectPass

private _sceneObjects: Map<number, SceneObject>

private _orbitControls: OrbitControls
Expand Down Expand Up @@ -65,11 +64,11 @@ class SceneRenderer extends WorldSystem {
this._scene = new THREE.Scene()

this._renderer = new THREE.WebGLRenderer({
// Following parameters are used to optimize post-processing
powerPreference: "high-performance",
antialias: false,
stencil: false,
depth: false,
depth: !PreferencesSystem.getGraphicsPreferences().antiAliasing,
// logarithmicDepthBuffer: true,
})
this._renderer.setClearColor(CLEAR_COLOR)
this._renderer.setPixelRatio(window.devicePixelRatio)
Expand All @@ -78,7 +77,7 @@ class SceneRenderer extends WorldSystem {
this._renderer.setSize(window.innerWidth, window.innerHeight)

// Adding the lighting uisng quality preferences
this.ChangeLighting(PreferencesSystem.getGlobalPreference<string>("QualitySettings"))
this.ChangeLighting(PreferencesSystem.getGraphicsPreferences().fancyShadows)

const ambientLight = new THREE.AmbientLight(0xffffff, 0.3)
this._scene.add(ambientLight)
Expand Down Expand Up @@ -111,9 +110,11 @@ class SceneRenderer extends WorldSystem {
this._composer = new EffectComposer(this._renderer)
this._composer.addPass(new RenderPass(this._scene, this._mainCamera))

const antiAliasEffect = new SMAAEffect({ edgeDetectionMode: EdgeDetectionMode.COLOR })
this._antiAliasPass = new EffectPass(this._mainCamera, antiAliasEffect)
this._composer.addPass(this._antiAliasPass)
if (PreferencesSystem.getGraphicsPreferences().antiAliasing) {
const antiAliasEffect = new SMAAEffect({ edgeDetectionMode: EdgeDetectionMode.COLOR })
const antiAliasPass = new EffectPass(this._mainCamera, antiAliasEffect)
this._composer.addPass(antiAliasPass)
}

// Orbit controls
this._orbitControls = new OrbitControls(this._mainCamera, this._renderer.domElement)
Expand All @@ -127,6 +128,7 @@ class SceneRenderer extends WorldSystem {
this._mainCamera.updateProjectionMatrix()
}

/** Function to disable or enable the antiAliasingPass */
public Update(deltaT: number): void {
this._sceneObjects.forEach(obj => {
obj.Update()
Expand Down Expand Up @@ -164,7 +166,7 @@ class SceneRenderer extends WorldSystem {
*
* @param quality: string representing the quality of lighting - "Low", "Medium", "High"
*/
public ChangeLighting(quality: string): void {
public ChangeLighting(fancyShadows: boolean): void {
// removing the previous lighting method
if (this._light instanceof THREE.DirectionalLight) {
this._scene.remove(this._light)
Expand All @@ -174,13 +176,14 @@ class SceneRenderer extends WorldSystem {
}

// setting the shadow map size
const shadowMapSize = Math.min(4096, this._renderer.capabilities.maxTextureSize)
const graphicsSettings = PreferencesSystem.getGraphicsPreferences()
const shadowMapSize = Math.min(graphicsSettings.shadowMapSize, this._renderer.capabilities.maxTextureSize)

// setting the light to a basic directional light
if (quality === "Low" || quality === "Medium") {
if (!fancyShadows) {
const shadowCamSize = 15

this._light = new THREE.DirectionalLight(0xffffff, 5.0)
this._light = new THREE.DirectionalLight(0xffffff, graphicsSettings.lightIntensity)
this._light.position.set(-1.0, 3.0, 2.0)
this._light.castShadow = true
this._light.shadow.camera.top = shadowCamSize
Expand All @@ -192,42 +195,79 @@ class SceneRenderer extends WorldSystem {
this._light.shadow.bias = 0.0
this._light.shadow.normalBias = 0.01
this._scene.add(this._light)
} else if (quality === "High") {
// setting light to cascading shadows
this._light = new CSM({
parent: this._scene,
camera: this._mainCamera,
cascades: 4,
lightDirection: new THREE.Vector3(1.0, -3.0, -2.0).normalize(),
lightIntensity: 5,
shadowMapSize: shadowMapSize,
mode: "custom",
maxFar: 30,
shadowBias: -0.00001,
customSplitsCallback: (cascades: number, near: number, far: number, breaks: number[]) => {
const blend = 0.7
for (let i = 1; i < cascades; i++) {
const uniformFactor = (near + ((far - near) * i) / cascades) / far
const logarithmicFactor = (near * (far / near) ** (i / cascades)) / far
const combinedFactor = uniformFactor * (1 - blend) + logarithmicFactor * blend

breaks.push(combinedFactor)
}

breaks.push(1)
},
})

// setting up the materials for all objects in the scene
this._light.fade = true
this._scene.children.forEach(child => {
if (child instanceof THREE.Mesh) {
if (this._light instanceof CSM) this._light.setupMaterial(child.material)
} else {
// setting the light to a cascading shadow map
this.CreateCSM(graphicsSettings)

// setting up all the materials
this.SetupCSMMaterials()
}
}

public CreateCSM(settings: GraphicsPreferences) {
this._light = new CSM({
parent: this._scene,
camera: this._mainCamera,
cascades: settings.cascades,
lightDirection: new THREE.Vector3(1.0, -3.0, -2.0).normalize(),
lightIntensity: settings.lightIntensity,
shadowMapSize: settings.shadowMapSize,
mode: "custom",
maxFar: settings.maxFar,
shadowBias: -0.00001,
customSplitsCallback: (cascades: number, near: number, far: number, breaks: number[]) => {
const blend = 0.7
for (let i = 1; i < cascades; i++) {
const uniformFactor = (near + ((far - near) * i) / cascades) / far
const logarithmicFactor = (near * (far / near) ** (i / cascades)) / far
const combinedFactor = uniformFactor * (1 - blend) + logarithmicFactor * blend

breaks.push(combinedFactor)
}
})

breaks.push(1)
},
})
this._light.fade = true
}

private SetupCSMMaterials() {
this._scene.children.forEach(child => {
if (child instanceof THREE.Mesh) {
if (this._light instanceof CSM) this._light.setupMaterial(child.material)
}
})
}

/** Sets the light intensity for both directional light and csm */
public setLightIntensity(intensity: number) {
if (this._light instanceof THREE.DirectionalLight) {
this._light.intensity = intensity
} else if (this._light instanceof CSM) {
this._light.lightIntensity = intensity

this._light.createLights()
this._light.injectInclude()
this._light.updateFrustums()
this._light.update()
console.log(this._light.lightIntensity)
}
}

/** Changes the settings of the cascading shadows from the Quality Settings Panel */
public changeCSMSettings(settings: GraphicsPreferences) {
if (!(this._light instanceof CSM)) return

this._light.maxFar = settings.maxFar
this._light.shadowMapSize = Math.min(settings.shadowMapSize, this._renderer.capabilities.maxTextureSize)
this._light.cascades = settings.cascades

this._light.createLights()
this._light.injectInclude()
this._light.updateFrustums()
this._light.update()
}

public RegisterSceneObject<T extends SceneObject>(obj: T): number {
const id = nextSceneObjectId++
obj.id = id
Expand Down
3 changes: 2 additions & 1 deletion fission/src/ui/components/StyledComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Label, { LabelSize } from "./Label"
import Button, { ButtonProps, ButtonSize } from "./Button"
import { IoCheckmark, IoPencil, IoPeople, IoTrashBin } from "react-icons/io5"
import { HiDownload } from "react-icons/hi"
import { AiOutlinePlus } from "react-icons/ai"
import { AiOutlineInfoCircle, AiOutlinePlus } from "react-icons/ai"
import { BiRefresh } from "react-icons/bi"
import { AiFillWarning } from "react-icons/ai"
import { BsCodeSquare } from "react-icons/bs"
Expand Down Expand Up @@ -53,6 +53,7 @@ export class SynthesisIcons {
public static SteeringWheel = (<GiSteeringWheel />)
public static OutlineDoubleRight = (<AiOutlineDoubleRight />)
public static Connect = (<GrConnect />)
public static Info = (<AiOutlineInfoCircle />)
public static Bug = (<FaBug />)

/** Large icons: used for icon buttons */
Expand Down
31 changes: 15 additions & 16 deletions fission/src/ui/modals/configuring/SettingsModal.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import React, { useState } from "react"
import { useModalControlContext } from "@/ui/ModalContext"
import { usePanelControlContext } from "@/ui/PanelContext"
import Modal, { ModalPropsImpl } from "@/components/Modal"
import { FaGear } from "react-icons/fa6"
import Label, { LabelSize } from "@/components/Label"
import Dropdown from "@/components/Dropdown"
import Button from "@/components/Button"
import Slider from "@/components/Slider"
import Checkbox from "@/components/Checkbox"
import PreferencesSystem from "@/systems/preferences/PreferencesSystem"
import { SceneOverlayEvent, SceneOverlayEventKey } from "@/ui/components/SceneOverlayEvents"
import { QualitySetting } from "@/systems/preferences/PreferenceTypes"
import { Box } from "@mui/material"
import { Spacer } from "@/ui/components/StyledComponents"
import World from "@/systems/World"

const SettingsModal: React.FC<ModalPropsImpl> = ({ modalId }) => {
const [qualitySettings, setQualitySettings] = useState<string>(
PreferencesSystem.getGlobalPreference<string>("QualitySettings")
)
const { openModal, closeModal } = useModalControlContext()
const { openPanel } = usePanelControlContext()

const [zoomSensitivity, setZoomSensitivity] = useState<number>(
PreferencesSystem.getGlobalPreference<number>("ZoomSensitivity")
)
Expand Down Expand Up @@ -43,7 +43,6 @@ const SettingsModal: React.FC<ModalPropsImpl> = ({ modalId }) => {
)

const saveSettings = () => {
PreferencesSystem.setGlobalPreference<string>("QualitySettings", qualitySettings)
PreferencesSystem.setGlobalPreference<number>("ZoomSensitivity", zoomSensitivity)
PreferencesSystem.setGlobalPreference<number>("PitchSensitivity", pitchSensitivity)
PreferencesSystem.setGlobalPreference<number>("YawSensitivity", yawSensitivity)
Expand All @@ -68,15 +67,15 @@ const SettingsModal: React.FC<ModalPropsImpl> = ({ modalId }) => {
>
<div className="flex overflow-y-auto flex-col gap-2 bg-background-secondary rounded-md p-2 max-h-[60vh]">
<Label size={LabelSize.Medium}>Screen Settings</Label>
<Dropdown
label="Quality Settings"
options={["Low", "Medium", "High"] as QualitySetting[]}
defaultValue={PreferencesSystem.getGlobalPreference<QualitySetting>("QualitySettings")}
onSelect={selected => {
setQualitySettings(selected)
World.SceneRenderer.ChangeLighting(selected)
}}
/>
<Box alignSelf={"center"}>
<Button
value="Graphics Settings"
onClick={() => {
openPanel("graphics-settings")
closeModal()
}}
/>
</Box>
{Spacer(5)}
<Label size={LabelSize.Medium}>Camera Settings</Label>
<Slider
Expand Down
Loading
Loading