Skip to content

Commit

Permalink
CELE-20 feat: Add outlines example
Browse files Browse the repository at this point in the history
  • Loading branch information
afonsobspinto committed Apr 26, 2024
1 parent 395337f commit b00849b
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 45 deletions.
5 changes: 4 additions & 1 deletion applications/visualizer/frontend/settings/threeDSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@ export const LIGHT_1_COLOR = 0x404040
export const LIGHT_2_COLOR = 0xccccff
export const LIGHT_2_POSITION = [-1, 0.75, -0.5]

export const SCENE_BACKGROUND = '0xd9d8d4'
export const SCENE_BACKGROUND = '0xd9d8d4'

export const OUTLINE_THICKNESS = 0.05
export const OUTLINE_COLOR = 'hotpink'
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import {CameraControls, PerspectiveCamera} from "@react-three/drei";
import {
CAMERA_FAR,
CAMERA_FOV,
CAMERA_NEAR,
CAMERA_POSITION,
LIGHT_1_COLOR, LIGHT_2_COLOR, LIGHT_2_POSITION
} from "../../../../settings/threeDSettings.ts";

function BaseScene() {
return <>
<PerspectiveCamera
makeDefault
fov={CAMERA_FOV}
aspect={window.innerWidth / window.innerHeight}
position={CAMERA_POSITION}
near={CAMERA_NEAR}
far={CAMERA_FAR}
/>
<CameraControls makeDefault/>
<ambientLight color={LIGHT_1_COLOR}/>
<directionalLight color={LIGHT_2_COLOR} position={LIGHT_2_POSITION}/>
</>;
}

export default BaseScene;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {GizmoHelper, GizmoViewport} from "@react-three/drei";

function Gizmo() {
return <GizmoHelper
alignment="bottom-right"
margin={[80, 80]}
>
<GizmoViewport axisColors={["red", "green", "blue"]} hideNegativeAxes hideAxisHeads/>
</GizmoHelper>;
}

export default Gizmo;
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import React, {FC} from "react";
import {Outlines} from '@react-three/drei';
import {useGlobalContext} from "../../../contexts/GlobalContext.tsx";
import {useSelector} from "react-redux";
import {Workspace} from "../../../models/workspace.ts";
import {RootState} from "../../../layout-manager/layoutManagerFactory.ts";
import {DoubleSide, NormalBlending} from "three";
import {getClosestIntersectedObject, getFurthestIntersectedObject} from "../../../helpers/threeDHelpers.ts";
import {OUTLINE_COLOR, OUTLINE_THICKNESS} from "../../../../settings/threeDSettings.ts";

interface Props {
stl: any;
Expand All @@ -15,17 +18,20 @@ interface Props {

const STLMesh: FC<Props> = ({id, color, opacity, renderOrder, stl}) => {
const {workspaces} = useGlobalContext();
const workspaceId = useSelector((state:RootState) => state.workspaceId);
const workspaceId = useSelector((state: RootState) => state.workspaceId);
const workspace: Workspace = workspaces[workspaceId];
const onClick = (event) => {
const clicked = getClosestIntersectedObject(event)
const clicked = getFurthestIntersectedObject(event)
if (clicked) {
workspace.highlightNeuron(clicked.userData.id)
}
}

const isSelected = id == workspace.highlightedNeuron
// TODO: Add outlines for selected
// TODO: Test wireframe
return (

<mesh userData={{id}} onClick={onClick} frustumCulled={false} renderOrder={renderOrder}>
<primitive attach="geometry" object={stl}/>
<meshStandardMaterial color={color}
Expand All @@ -35,20 +41,10 @@ const STLMesh: FC<Props> = ({id, color, opacity, renderOrder, stl}) => {
depthTest={false}
blending={NormalBlending}
transparent/>
{isSelected && <Outlines thickness={OUTLINE_THICKNESS} color={OUTLINE_COLOR}/>}
</mesh>
);
};

function getClosestIntersectedObject(event) {
if (!event.intersections || event.intersections.length === 0) {
return null;
}

// Sort the intersections array by the 'distance' property
const sortedIntersections = event.intersections.sort((a, b) => a.distance - b.distance);

// Return the first object in the sorted array
return sortedIntersections[0].object;
}

export default STLMesh;
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,15 @@ const STLViewer: FC<Props> = ({instances}) => {
// Todo: Fix typescript warning
// Check if useLoader caches or do we need to do it ourselves
const stlObjects = useLoader<STLLoader, BufferGeometry[]>(STLLoader, instances.map(i => i.url));
const {scene} = useThree();
window.myScene = scene;

return (
<Center>
<group frustumCulled={false}>
{stlObjects.map((stl, idx) => (
<STLMesh
key={idx}
stl={stl}
key={instances[idx].id}
id={instances[idx].id}
stl={stl}
opacity={instances[idx].opacity}
color={instances[idx].color}
renderOrder={idx}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
import {Suspense, useEffect, useState} from "react";
import {CameraControls, GizmoHelper, GizmoViewport, PerspectiveCamera} from "@react-three/drei";
import {
CAMERA_FAR,
CAMERA_FOV,
CAMERA_NEAR,
CAMERA_POSITION, LIGHT_1_COLOR, LIGHT_1_POSITION, LIGHT_2_COLOR, LIGHT_2_POSITION,
SCENE_BACKGROUND
} from "../../../../settings/threeDSettings.ts";
import {SCENE_BACKGROUND} from "../../../../settings/threeDSettings.ts";

import STLViewer from "./STLViewer.tsx";
import {Canvas} from "@react-three/fiber";
import Loader from "./Loader.tsx";
import BaseScene from "./BaseScene.tsx";
import Gizmo from "./Gizmo.tsx";

export interface Instance {
id: string;
Expand All @@ -19,14 +14,16 @@ export interface Instance {
opacity: number;
}




function ThreeDViewer() {

const [showNeurons, setShowNeurons] = useState<boolean>(true);
const [showSynapses, setShowSynapses] = useState<boolean>(true);
const [instances, setInstances] = useState<Instance[]>([])



useEffect(() => {
if (showNeurons) {
setInstances([
Expand All @@ -49,25 +46,9 @@ function ThreeDViewer() {
return (
<Canvas style={{backgroundColor: SCENE_BACKGROUND}}>
<Suspense fallback={<Loader/>}>
<PerspectiveCamera
makeDefault
fov={CAMERA_FOV}
aspect={window.innerWidth / window.innerHeight}
position={CAMERA_POSITION}
near={CAMERA_NEAR}
far={CAMERA_FAR}
/>
<CameraControls makeDefault/>
<ambientLight color={LIGHT_1_COLOR}/>
<directionalLight color={LIGHT_2_COLOR} position={LIGHT_2_POSITION}/>
<BaseScene/>
<STLViewer instances={instances}/>
<GizmoHelper
alignment="bottom-right"
margin={[80, 80]}
>
<GizmoViewport axisColors={['red', 'green', 'blue']} labels={['Posterior', 'Dorsal', 'Left']}
labelColor="white" hideNegativeAxes hideAxisHeads/>
</GizmoHelper>
<Gizmo/>
</Suspense>
</Canvas>
);
Expand Down
12 changes: 12 additions & 0 deletions applications/visualizer/frontend/src/helpers/threeDHelpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export function getFurthestIntersectedObject(event) {
if (!event.intersections || event.intersections.length === 0) {
return null;
}

// TODO: Replace the following with the concept of raycasting layers
const validIntersections = event.intersections.filter(intersection => intersection.object.userData.id !== undefined);

const sortedIntersections = validIntersections.sort((a, b) => b.distance - a.distance);

return sortedIntersections[0].object;
}

0 comments on commit b00849b

Please sign in to comment.