Skip to content
1 change: 1 addition & 0 deletions bundledAssets/Robot_FRCKitBot/config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"name": "KitBot",
"isFTC": false,
"dynamicColoring": true,
"rotations": [
{
"axis": "z",
Expand Down
Binary file modified bundledAssets/Robot_FRCKitBot/model.glb
Binary file not shown.
4 changes: 3 additions & 1 deletion src/hub/controllers/Field3dController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,9 @@ export default class Field3dController implements TabController {
yz: mechanismYZ
},
visionTargets: visionTargets,
swerveStates: swerveStates
swerveStates: swerveStates,
bumperColor:
source.options.bumper === "auto" ? (isRedAlliance ? "#ff0000" : "#0000ff") : source.options.bumper
});
break;
case "ghost":
Expand Down
36 changes: 32 additions & 4 deletions src/hub/controllers/Field3dController_Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ const Field3dController_Config: SourceListConfig = {
display: "Robot",
symbol: "location.fill",
showInTypeName: false,
color: "#000000",
darkColor: "#ffffff",
color: "bumper",
sourceTypes: [
"Pose2d",
"Pose3d",
Expand All @@ -39,6 +38,21 @@ const Field3dController_Config: SourceListConfig = {
display: "Model",
showInTypeName: true,
values: []
},
{
key: "bumper",
display: "Bumper",
showInTypeName: false,
values: NeonColors_RedStart.toReversed()
.concat({
// Puts these options at the top
key: "#000000",
display: "Black"
}, {
key: "auto",
display: "Auto"
})
.toReversed()
}
],
initialSelectionOption: "model",
Expand All @@ -50,8 +64,7 @@ const Field3dController_Config: SourceListConfig = {
display: "Robot",
symbol: "location.fill",
showInTypeName: false,
color: "#000000",
darkColor: "#ffffff",
color: "bumper",
sourceTypes: ["NumberArray"],
showDocs: false,
options: [
Expand Down Expand Up @@ -80,6 +93,21 @@ const Field3dController_Config: SourceListConfig = {
{ key: "radians", display: "Radians" },
{ key: "degrees", display: "Degrees" }
]
},
{
key: "bumper",
display: "Bumper",
showInTypeName: false,
values: NeonColors_RedStart.toReversed()
.concat({
// Puts these options at the top
key: "#000000",
display: "Black"
}, {
key: "auto",
display: "Auto"
})
.toReversed()
}
],
initialSelectionOption: "model",
Expand Down
7 changes: 6 additions & 1 deletion src/main/assetUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,8 @@ export function parseRobot(configRaw: unknown): Config3dRobot | "invalid" {
position: [0, 0, 0],
cameras: [],
components: [],
disableSimplification: false
disableSimplification: false,
dynamicColoring: false
};
if ("name" in configRaw && typeof configRaw.name === "string") {
config.name = configRaw.name;
Expand All @@ -309,6 +310,10 @@ export function parseRobot(configRaw: unknown): Config3dRobot | "invalid" {
if ("disableSimplification" in configRaw && typeof configRaw.disableSimplification === "boolean") {
config.disableSimplification = configRaw.disableSimplification;
}
if ("dynamicColoring" in configRaw && typeof configRaw.dynamicColoring === "boolean"
) {
config.dynamicColoring = configRaw.dynamicColoring;
}
if (
"rotations" in configRaw &&
Array.isArray(configRaw.rotations) &&
Expand Down
1 change: 1 addition & 0 deletions src/shared/AdvantageScopeAssets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export interface Config3dRobot {

isFTC: boolean;
disableSimplification: boolean;
dynamicColoring: boolean;
rotations: Config3d_Rotation[];
position: [number, number, number];
cameras: Config3dRobot_Camera[];
Expand Down
1 change: 1 addition & 0 deletions src/shared/renderers/Field3dRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ export type Field3dRendererCommand_GenericRobotObj = {

export type Field3dRendererCommand_RobotObj = Field3dRendererCommand_GenericRobotObj & {
type: "robot";
bumperColor: string;
};

export type Field3dRendererCommand_GhostObj = Field3dRendererCommand_GenericRobotObj & {
Expand Down
3 changes: 2 additions & 1 deletion src/shared/renderers/Field3dRendererImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -824,7 +824,8 @@ export default class Field3dRendererImpl implements TabRenderer {
components: [],
mechanisms: { xz: null, yz: null },
visionTargets: [],
swerveStates: []
swerveStates: [],
bumperColor: "#000000"
});
}
}
Expand Down
44 changes: 41 additions & 3 deletions src/shared/renderers/field3d/OptimizeGeometries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,16 @@ export default async function optimizeGeometries(
normal: THREE.Mesh[];
transparent: THREE.Mesh[];
carpet: THREE.Mesh[];
bumper: THREE.Mesh[];
}> {
return new Promise(async (resolve) => {
let geometries = getGeometries(object, mode, enableSimplification, isFTC, slicingSize);

let normalMeshes: THREE.Mesh[] = [];
let transparentMeshes: THREE.Mesh[] = [];
let carpetMeshes: THREE.Mesh[] = [];
let bumperMeshes: THREE.Mesh[] = [];

geometries.normal.forEach((group) => {
if (group.length > 0) {
let geometry = BufferGeometryUtils.mergeGeometries(group, false);
Expand Down Expand Up @@ -104,11 +107,34 @@ export default async function optimizeGeometries(
}
}
});
geometries.bumper.forEach((group) => {
if (group.length > 0) {
let geometry = BufferGeometryUtils.mergeGeometries(group, false);
if (geometry !== null) {
let mesh = new THREE.Mesh(
geometry,
new THREE.MeshPhongMaterial({
vertexColors: true,
side: THREE.DoubleSide,
specular: materialSpecular,
shininess: materialShininess
})
);
bumperMeshes.push(mesh);
if (mode === "cinematic") {
mesh.castShadow = true;
mesh.receiveShadow = false;
}
mesh.name = "bumper";
}
}
});
disposeObject(object);
resolve({
normal: normalMeshes,
transparent: transparentMeshes,
carpet: carpetMeshes
carpet: carpetMeshes,
bumper: bumperMeshes
});
});
}
Expand All @@ -119,10 +145,16 @@ function getGeometries(
enableSimplification: boolean,
isFTC: boolean,
slicingSize?: number
): { normal: THREE.BufferGeometry[][]; transparent: THREE.BufferGeometry[][]; carpet: THREE.BufferGeometry[][] } {
): {
normal: THREE.BufferGeometry[][];
transparent: THREE.BufferGeometry[][];
carpet: THREE.BufferGeometry[][];
bumper: THREE.BufferGeometry[][];
} {
let normal: THREE.BufferGeometry[][] = [];
let transparent: THREE.BufferGeometry[][] = [];
let carpet: THREE.BufferGeometry[][] = [];
let bumper: THREE.BufferGeometry[][] = [];

let totalCount = 0;
object.traverse((object) => {
Expand Down Expand Up @@ -215,6 +247,11 @@ function getGeometries(
transparent.push([]);
}
transparent[outputIndex].push(geometry);
} else if (mesh.name.includes("BUMPERCOLOR")) {
while (bumper.length < outputIndex + 1) {
bumper.push([]);
}
bumper[outputIndex].push(geometry);
} else {
while (normal.length < outputIndex + 1) {
normal.push([]);
Expand All @@ -228,6 +265,7 @@ function getGeometries(
return {
normal: normal,
transparent: transparent,
carpet: carpet
carpet: carpet,
bumper: bumper
};
}
29 changes: 29 additions & 0 deletions src/shared/renderers/field3d/objectManagers/RobotManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export default class RobotManager extends ObjectManager<
shininess: this.materialShininess,
depthWrite: false
});
private bumperMaterial = new THREE.MeshStandardMaterial();
private visionLines: Line2[] = [];
private mechanismLinesXZ: MechanismLineData[] = [];
private mechanismLinesYZ: MechanismLineData[] = [];
Expand All @@ -69,6 +70,7 @@ export default class RobotManager extends ObjectManager<
private hasNewAssets = false;
private lastModel = "";
private lastColor = "";
private lastBumperColor = "";
private lastHadSwerveStates = false;
private lastHideRobotModels = false;

Expand Down Expand Up @@ -248,6 +250,13 @@ export default class RobotManager extends ObjectManager<
}
}

if (mesh.name.includes("BUMPERCOLOR") && robotConfig.dynamicColoring) {
if (!Array.isArray(mesh.material)) {
mesh.material.dispose();
}
mesh.material = this.bumperMaterial;
}

if (object.type === "ghost") {
if (!Array.isArray(mesh.material)) {
mesh.material.dispose();
Expand Down Expand Up @@ -298,6 +307,13 @@ export default class RobotManager extends ObjectManager<
}
}

if (mesh.name === "bumper" && robotConfig.dynamicColoring) {
if (!Array.isArray(mesh.material)) {
mesh.material.dispose();
}
mesh.material = this.bumperMaterial;
}

if (object.type === "ghost") {
if (!Array.isArray(mesh.material)) {
mesh.material.dispose();
Expand Down Expand Up @@ -346,6 +362,19 @@ export default class RobotManager extends ObjectManager<
this.meshes[0].setPoses(object.poses.map((x) => x.pose));
}

// Update bumper color
if (object.type === "robot" && object.bumperColor !== this.lastBumperColor) {
this.lastBumperColor = object.bumperColor;
this.bumperMaterial.color = new THREE.Color(object.bumperColor).offsetHSL(0.0, -0.1, 0.0);

if (!robotConfig?.dynamicColoring) {
window.sendMainMessage("error", {
title: "Cannot display dynamic color.",
content: "This robot model is not configured for displaying dynamic colors and your selection will not have any effect. See the documentation for details."
});
}
}

// Update components
for (let i = 1; i < this.meshes.length; i++) {
this.meshes[i].setPoses(
Expand Down
1 change: 1 addition & 0 deletions src/shared/renderers/field3d/workers/loadRobot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ self.onmessage = (event) => {
let sceneMeshes: THREE.Mesh[] = [];
if (optimized.normal.length > 0) sceneMeshes.push(optimized.normal[0]);
if (optimized.transparent.length > 0) sceneMeshes.push(optimized.transparent[0]);
if (optimized.bumper.length > 0) sceneMeshes.push(optimized.bumper[0]);
meshes.push(sceneMeshes.map((mesh) => mesh.toJSON()));
}

Expand Down
3 changes: 2 additions & 1 deletion src/xrClient/XRRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,8 @@ export default class XRRenderer {
components: [],
mechanisms: { xz: null, yz: null },
visionTargets: [],
swerveStates: []
swerveStates: [],
bumperColor: "#000000"
});
}
}
Expand Down