Skip to content

Commit

Permalink
Adds the complete Camera View feature (#108)
Browse files Browse the repository at this point in the history
See all commit messages below

 Fixes the nested camera view locations for activeCameraSettings (#102)

* Fixes the nested camera view locations for activeCameraSettings

The problem is that the node.transform is not in world coordinates.
To accurately represent this we create the transform from the actualy object3D world position, rotation, and scale

* Clean up based on feedback

* Rebase needed

Fix target calculation for Camera settings (#104)

Have the Camera Preview pull from the selected node rather than using active camera settings (#101)

Adjusting the active Camera settings also affected the main camera's settings and was a bug.
Utilizing the camera component on the selected node allowed for the same render without the issue as the active Camera settings aren't necessarily set to active by editing anyway

Update the camera component inspector editor to match the UX (#99)

Visual restructuring
Bug fixes
Code clean up

Adds a CameraPreview component (#97)

This performs a LateRender to a smaller viewport designated by the tracked div element
When a camera is selected the div and the render of the camera's view will appear when in edit mode

Adds the activeCamera property (#66)

Based on this property we set the active camera unless we have a selected data binding as that should take precedence

Make TopBar always visible and Add Camera list (#64)

Clicking a camera name in the list will set that camera as the active camera in either editing or viewing
Add an incremental count to the Camera object to give unique names since creation

Revert "Add activeCamera Property to Scene Viewer (#56)" (#61)

This reverts commit 98bce138a4bf572b6f25562c458ace8d7ac3f560.

Add activeCamera Property to Scene Viewer (#56)

State setup seems to appear incorrectly in storybook such that the Camera View
is not utlizing the activeCamera unless the store has already been created.
This is something that will need to be looked into further.

Add Set from current view, button to inspector (#52)

Also refactors how we set the object from the current view
Fixes the bug where we only support one parent for rotational transform

Add basic Inspector Editor for the Camera Component (#49)

Change Camera creation mode to View Camera (From current) as in design (#46)

Update the CameraComponent to be creatable and selectable (#45)

This introduces the ability to set a globally stored active camera which can alter the settings and viewing location of the main camera. These are less cameras themselves than editor and data representations
  • Loading branch information
jwills-jdubs authored Sep 14, 2022
1 parent 0762758 commit e8c1886
Show file tree
Hide file tree
Showing 54 changed files with 5,426 additions and 562 deletions.
33 changes: 24 additions & 9 deletions packages/scene-composer/src/common/constants.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import * as THREE from 'three';

import { Component, LightType } from '../models/SceneModels';
import {
InfoIconSvgString,
WarningIconSvgString,
ErrorIconSvgString,
VideoIconSvgString,
} from '../assets/anchors/IconSvgs';
import { IValueDataBindingProviderState, DefaultAnchorStatus, DistanceUnit } from '../interfaces';
import { InfoIconSvgString, WarningIconSvgString, ErrorIconSvgString, VideoIconSvgString } from '../assets';
import { IValueDataBindingProviderState, DefaultAnchorStatus, DistanceUnit, Vector3 } from '../interfaces';
import { CameraControlImpl } from '../store/internalInterfaces';

/******************************************************************************
* Document Constants
Expand Down Expand Up @@ -59,9 +55,10 @@ export const DEFAULT_COLOR_MAPS = [
];

export const DEFAULT_CAMERA_SETTINGS = {
fov: 30.0,
near: 0.5,
fov: 53.13,
near: 0.1,
far: 1000.0,
zoom: 1,
};

const DEFAULT_DIRECTIONAL_LIGHT_SETTINGS: Component.IDirectionalLightSettings = {
Expand Down Expand Up @@ -117,3 +114,21 @@ export enum Layers {
export const SCENE_BODY_CLASS = 'twinmaker_scene_container';

export const DRACO_PATH = 'https://www.gstatic.com/draco/versioned/decoders/1.4.1/';

/******************************************************************************
* Camera Constants
******************************************************************************/
export const DEFAULT_CAMERA_CONTROLS_OPTIONS: Pick<CameraControlImpl, 'dampingFactor' | 'maxDistance' | 'minDistance'> =
{
dampingFactor: 0.2,
maxDistance: Infinity,
minDistance: 0,
};
export const DEFAULT_CAMERA_POSITION: Vector3 = [5, 5, 5];
export const DEFAULT_CAMERA_OPTIONS: Pick<THREE.PerspectiveCamera, 'far' | 'fov' | 'near'> = {
far: 1000,
fov: 53.13,
near: 0.1,
};
export const DEFAULT_CAMERA_TARGET: Vector3 = [0, 0, 0];
export const DEFAULT_TWEEN_DURATION = 500;
23 changes: 22 additions & 1 deletion packages/scene-composer/src/components/StateManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ import {
setMetricRecorder,
} from '../common/GlobalSettings';
import { useSceneComposerId } from '../common/sceneComposerIdContext';
import { IAnchorComponentInternal, SceneComposerOperationTypeMap, useStore } from '../store';
import { IAnchorComponentInternal, ICameraComponentInternal, SceneComposerOperationTypeMap, useStore } from '../store';
import { createStandardUriModifier } from '../utils/uriModifiers';
import sceneDocumentSnapshotCreator from '../utils/sceneDocumentSnapshotCreator';
import { SceneLayout } from '../layouts/SceneLayout';
import { findComponentByType } from '../utils/nodeUtils';
import { applyDataBindingTemplate } from '../utils/dataBindingTemplateUtils';
import { combineTimeSeriesData, convertDataStreamsToDataInput } from '../utils/dataStreamUtils';
import useActiveCamera from '../hooks/useActiveCamera';
import { getCameraSettings } from '../utils/cameraUtils';

import IntlProvider from './IntlProvider';
import { LoadingProgress } from './three-fiber/LoadingProgress';
Expand All @@ -42,6 +44,8 @@ const StateManager: React.FC<SceneComposerInternalProps> = ({
queries,
viewport,
dataBindingTemplate,
activeCamera,
selectedDataBinding,
}: SceneComposerInternalProps) => {
useLifecycleLogging('StateManager');
const sceneComposerId = useSceneComposerId();
Expand All @@ -54,6 +58,7 @@ const StateManager: React.FC<SceneComposerInternalProps> = ({
selectedSceneNodeRef,
setSelectedSceneNodeRef,
getSceneNodeByRef,
getObject3DBySceneNodeRef,
} = useStore(sceneComposerId)((state) => state);
const [sceneContentUri, setSceneContentUri] = useState<string>('');
const [sceneContent, setSceneContent] = useState<string>('');
Expand All @@ -64,6 +69,8 @@ const StateManager: React.FC<SceneComposerInternalProps> = ({

const dataProviderRef = useRef<ProviderWithViewport<TimeSeriesData[]> | undefined>(undefined);

const { setActiveCameraSettings, setActiveCameraName } = useActiveCamera();

const standardUriModifier = useMemo(
() => createStandardUriModifier(sceneContentUri || '', baseUrl),
[sceneContentUri, baseUrl],
Expand Down Expand Up @@ -91,6 +98,12 @@ const StateManager: React.FC<SceneComposerInternalProps> = ({
onSelectionChanged,
]);

useEffect(() => {
if (!selectedDataBinding) {
setActiveCameraName(activeCamera);
}
}, [activeCamera, selectedDataBinding]);

useEffect(() => {
if (onSelectionChanged) {
const node = getSceneNodeByRef(selectedSceneNodeRef);
Expand Down Expand Up @@ -118,6 +131,14 @@ const StateManager: React.FC<SceneComposerInternalProps> = ({
}
}, [selectedSceneNodeRef]);

useEffect(() => {
const node = getSceneNodeByRef(selectedSceneNodeRef);
const cameraComponent = findComponentByType(node, KnownComponentType.Camera) as ICameraComponentInternal;
const object3D = getObject3DBySceneNodeRef(selectedSceneNodeRef);

setActiveCameraSettings(getCameraSettings(object3D, cameraComponent));
}, [selectedSceneNodeRef]);

useEffect(() => {
if (config.dracoDecoder) {
setDracoDecoder(config.dracoDecoder);
Expand Down
6 changes: 3 additions & 3 deletions packages/scene-composer/src/components/WebGLCanvasManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { Layers, ROOT_OBJECT_3D_NAME } from '../common/constants';
import { getGlobalSettings } from '../common/GlobalSettings';
import { ViewCursorWidget } from '../augmentations/components/three-fiber/viewpoint/ViewCursorWidget';
import { getIntersectionTransform } from '../utils/raycastUtils';
import { createNodeWithTransform } from '../utils/nodeUtils';
import { createNodeWithPositionAndNormal } from '../utils/nodeUtils';

import Environment, { presets } from './three-fiber/Environment';
import { StatsWindow } from './three-fiber/StatsWindow';
Expand All @@ -32,7 +32,7 @@ export const WebGLCanvasManager: React.FC = () => {
const { isEditing, addingWidget, setAddingWidget, cameraControlsType } = useEditorState(sceneComposerId);
const { document, getSceneNodeByRef, getSceneProperty } = useSceneDocument(sceneComposerId);
const appendSceneNode = useStore(sceneComposerId)((state) => state.appendSceneNode);
const { gl, size } = useThree((state) => state);
const { gl, size } = useThree();
const domRef = useRef<HTMLElement>(gl.domElement.parentElement);
const environmentPreset = getSceneProperty(KnownSceneProperty.EnvironmentPreset);
const rootNodeRefs = document.rootNodeRefs;
Expand Down Expand Up @@ -92,7 +92,7 @@ export const WebGLCanvasManager: React.FC = () => {
if (startingPointerPosition.distanceTo(currentPosition) <= MAX_CLICK_DISTANCE) {
if (addingWidget && e.intersections.length > 0) {
const { position } = getIntersectionTransform(e.intersections[0]);
const newWidgetNode = createNodeWithTransform(addingWidget, position, new THREE.Vector3());
const newWidgetNode = createNodeWithPositionAndNormal(addingWidget, position, new THREE.Vector3());

appendSceneNode(newWidgetNode);
setAddingWidget(undefined);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ exports[`SceneComposerInternal should render a default error view when loading a
</Provider>
}
>
<WebGLCanvasManager />
<React.Fragment>
<WebGLCanvasManager />
</React.Fragment>
</React.Suspense>
</Unknown>
</Styled(Component)>
Expand All @@ -46,7 +48,7 @@ exports[`SceneComposerInternal should render a default error view when loading a
/>
}
showModal={true}
topBar={false}
topBar={<TopBar />}
/>
`;

Expand Down Expand Up @@ -106,7 +108,9 @@ exports[`SceneComposerInternal should render both valid and invalid scene correc
</Provider>
}
>
<WebGLCanvasManager />
<React.Fragment>
<WebGLCanvasManager />
</React.Fragment>
</React.Suspense>
</Unknown>
</Styled(Component)>
Expand All @@ -120,7 +124,7 @@ exports[`SceneComposerInternal should render both valid and invalid scene correc
/>
}
showModal={true}
topBar={false}
topBar={<TopBar />}
/>
<StaticLayout
header={<MenuBar />}
Expand Down Expand Up @@ -153,7 +157,9 @@ exports[`SceneComposerInternal should render both valid and invalid scene correc
</Provider>
}
>
<WebGLCanvasManager />
<React.Fragment>
<WebGLCanvasManager />
</React.Fragment>
</React.Suspense>
</Unknown>
</Styled(Component)>
Expand Down Expand Up @@ -204,7 +210,9 @@ exports[`SceneComposerInternal should render correctly with a valid scene in edi
</Provider>
}
>
<WebGLCanvasManager />
<React.Fragment>
<WebGLCanvasManager />
</React.Fragment>
</React.Suspense>
</Unknown>
</Styled(Component)>
Expand Down Expand Up @@ -266,7 +274,7 @@ exports[`SceneComposerInternal should render correctly with an empty scene in ed
/>
}
showModal={false}
topBar={false}
topBar={<TopBar />}
/>
`;

Expand Down Expand Up @@ -308,7 +316,7 @@ exports[`SceneComposerInternal should render correctly with an empty scene in vi
modalContent={<MessageModal />}
rightPanel={false}
showModal={false}
topBar={false}
topBar={<TopBar />}
/>
`;

Expand Down Expand Up @@ -344,7 +352,9 @@ exports[`SceneComposerInternal should render error when major version is newer 1
</Provider>
}
>
<WebGLCanvasManager />
<React.Fragment>
<WebGLCanvasManager />
</React.Fragment>
</React.Suspense>
</Unknown>
</Styled(Component)>
Expand All @@ -358,7 +368,7 @@ exports[`SceneComposerInternal should render error when major version is newer 1
/>
}
showModal={true}
topBar={false}
topBar={<TopBar />}
/>
`;

Expand Down Expand Up @@ -394,7 +404,9 @@ exports[`SceneComposerInternal should render error when specVersion is invalid 1
</Provider>
}
>
<WebGLCanvasManager />
<React.Fragment>
<WebGLCanvasManager />
</React.Fragment>
</React.Suspense>
</Unknown>
</Styled(Component)>
Expand All @@ -408,7 +420,7 @@ exports[`SceneComposerInternal should render error when specVersion is invalid 1
/>
}
showModal={true}
topBar={false}
topBar={<TopBar />}
/>
`;

Expand Down Expand Up @@ -444,7 +456,9 @@ exports[`SceneComposerInternal should render warning when minor version is newer
</Provider>
}
>
<WebGLCanvasManager />
<React.Fragment>
<WebGLCanvasManager />
</React.Fragment>
</React.Suspense>
</Unknown>
</Styled(Component)>
Expand All @@ -458,7 +472,7 @@ exports[`SceneComposerInternal should render warning when minor version is newer
/>
}
showModal={true}
topBar={false}
topBar={<TopBar />}
/>
`;

Expand Down Expand Up @@ -495,7 +509,9 @@ exports[`SceneComposerInternal should support rendering multiple valid scenes 1`
</Provider>
}
>
<WebGLCanvasManager />
<React.Fragment>
<WebGLCanvasManager />
</React.Fragment>
</React.Suspense>
</Unknown>
</Styled(Component)>
Expand Down Expand Up @@ -542,7 +558,9 @@ exports[`SceneComposerInternal should support rendering multiple valid scenes 1`
</Provider>
}
>
<WebGLCanvasManager />
<React.Fragment>
<WebGLCanvasManager />
</React.Fragment>
</React.Suspense>
</Unknown>
</Styled(Component)>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
FormField,
Grid,
Input,
Select,
SelectProps,
SpaceBetween,
TextContent,
} from '@awsui/components-react';
Expand Down Expand Up @@ -202,3 +204,36 @@ export const ExpandableInfoSection: React.FC<React.PropsWithChildren<ExpandableI
</ExpandableSectionWithBorder>
);
};

export const DynamicSelect: React.FC<SelectProps> = (props) => {
const [dynamicOptions, setDynamicOptions] = useState(props.options);

useEffect(() => {
const optionLabels = dynamicOptions?.map((option) => option.label);
const selectedOptionLabel = props.selectedOption?.label;
if (!optionLabels?.includes(selectedOptionLabel)) {
// Add it to the options
const updatedOptions = [
...(dynamicOptions ?? []),
{
label: selectedOptionLabel,
value: props.selectedOption?.value,
},
];

setDynamicOptions(
updatedOptions.sort((a, b) => {
if (a.label! < b.label!) {
return -1;
} else if (a.label! === b.label!) {
return 0;
} else {
return 1;
}
}),
);
}
}, [props.selectedOption, props.options]);

return <Select {...props} options={dynamicOptions} />;
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { LightComponentEditor } from './scene-components/LightComponentEditor';
import { ColorOverlayComponentEditor } from './scene-components/ColorOverlayComponentEditor';
import { ModelRefComponentEditor } from './scene-components/ModelRefComponentEditor';
import { MotionIndicatorComponentEditor } from './scene-components/MotionIndicatorComponentEditor';
import { CameraComponentEditor } from './scene-components/CameraComponentEditor';

export interface IComponentEditorProps {
node: ISceneNodeInternal;
Expand Down Expand Up @@ -42,6 +43,8 @@ export const ComponentEditor: React.FC<IComponentEditorProps> = ({ node, compone
return <AnchorComponentEditor node={node} component={component} />;
case KnownComponentType.Light:
return <LightComponentEditor node={node} component={component} />;
case KnownComponentType.Camera:
return <CameraComponentEditor node={node} component={component} />;
case KnownComponentType.ModelShader:
return <ColorOverlayComponentEditor node={node} component={component} />;
case KnownComponentType.ModelRef:
Expand Down
Loading

0 comments on commit e8c1886

Please sign in to comment.