Skip to content

Conversation

@sirrodgepodge
Copy link

@sirrodgepodge sirrodgepodge commented Apr 29, 2020

Hello there!

Attempting to implement orthographic camera (for the purpose of 2D Usage of 3d-force graph for performance benefits) using this SO post:
https://stackoverflow.com/questions/48758959/what-is-required-to-convert-threejs-perspective-camera-to-orthographic

I actually was unable to get a test environment working for this (with the different packages working together for some reason NPM link didn't work), I figure you likely have one readily available to take a quick look.

@RaulPROP
Copy link
Contributor

To test it locally, i did the following:

  1. Clone 3d-force-graph and your fork in the same folder.
  2. Modify the package.json of 3d-force-graph. Change the three-render-objects dependency to file:<relative-route> (probably file:../three-render-objects).
  3. Run npm i in your fork.
  4. Modify your fork as much as you want.
  5. Run npm run build in your fork folder whenever you want to test changes.
  6. Run npm i in 3d-force-graph, then open one file of the example folder (i usually pick basic) and change the import to the one that is local (<script src="../../dist/3d-force-graph.js"></script>).
  7. Open that file in the browser.

And that's it.

Now, when you want to test some changes you need to run npm run build on the fork and npm i on the 3d-force-graph.

PS: In order for your fork to work, you also need to add cameraType to the stateInit in 3d-force-graph/src/3d-force-graph.js.

@sirrodgepodge
Copy link
Author

sirrodgepodge commented Apr 29, 2020

got it, thank you, I figured there had to be something upstream I was missing...

btw you can use npm link in order to avoid needing to modify package.jsons, it overrides a dependency with a local symlink

  1. in the local forked and modified dependency run npm link, this builds and exposes this local code to be symlinked elsewhere.
  2. in your consuming repo npm link <dependency name>, in this case npm link three-render-objects

Here I think why I failed is because as you pointed out I also need to modify the intermediate dependency of 3d-force-graph.


stateInit: () => ({
scene: new three.Scene(),
camera: new three.PerspectiveCamera(),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The camera declaration should remain in stateInit. Otherwise you may run into situations where you try to use it before it's declared, for example by invoking cameraPosition before initialization.

If you need one of the config options you can always get it as input to stateInit:

stateInit: ({ cameraType }) => ({
  camera: /* cameraType logic */
  ...
}) 

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


if (state._cameraType === 'perspective') {
state.camera.aspect = state.width/state.height;
} else {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does all of this code need to be run at initialization? It seems fully duplicated from the component update part so perhaps having it there is sufficient?

state.renderer.setSize(state.width, state.height);
state.camera.aspect = state.width/state.height;

if (state._cameraType === 'perspective') {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it perhaps be cleaner to derive this from the camera object itself, eg:

state.camera.type === 'PerspectiveCamera' ? ...

You would also not need to maintain a spare state._cameraType attribute.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, didn't know this was available, will use

state.camera.right = width_ortho / 2;
state.camera.top = height_ortho / 2;
state.camera.bottom = height_ortho / -2;
state.camera.near = THREE_JS_PERSPECTIVE_CAMERA_NEAR_DEFAULT;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This appears to be the current default near value of orthographic camera, so maybe there's no need to define it. It can always be overridden upstream.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@vasturiano
Copy link
Owner

Interesting, thanks for the PR @sirrodgepodge! 👍

I left a few minor comments. We should be able to merge this after cleaning up the code a bit.

Would you mind adding something to the docs also?

@sirrodgepodge
Copy link
Author

sirrodgepodge commented May 4, 2020

Responded to all the comments.

Have to be honest and say that I still couldn't get a test environment working :( :( :(. Maybe you have and can confirm it works.

I need to link three-forcegraph and 3d-force-graph to get react-force-graph-3d to be using this right?

camera: new three.PerspectiveCamera(),
clock: new three.Clock()
clock: new three.Clock(),
camera: cameraType === 'perspective' ?
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this logic if the user specifies anything else other than perspective it will fall back to orthographic, which is a little dangerous. Let's swap that so that perspective is the default fallback:

camera: new three[cameraType === 'orthographic' ? 'OrthographicCamera' : 'PerspectiveCamera']();


function updateCamera(camera) {
if (camera.type === 'PerspectiveCamera') {
state.camera.aspect = state.width / state.height;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You won't be able to access the encapsulated state in a function outside of the kapsule init or update methods.

@vasturiano
Copy link
Owner

@sirrodgepodge for testing this functionality you can run yarn build or yarn dev which will save the built files in the local /dist directory.
Then you can simply import those into your development example. If you want to try with the built-in example, you just have to modify the script tag target here: https://github.com/vasturiano/three-render-objects/blob/master/example/basic/index.html#L7

state.camera.aspect = state.width / state.height;
} else {
const aspect = state.width / state.height;
const height_ortho = depth * 2 * Math.atan(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

depth is not defined.

@@ -375,7 +375,7 @@ const THREE_JS_PERSPECTIVE_CAMERA_FOV_Y_DEFAULT = 50;

function updateCamera(camera) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to pass state if you want to access it.

@sirrodgepodge
Copy link
Author

whoops, that was super sloppy, apologies, attempted to clean up here:
38305ff

The only thing I'm unclear on is whether state.camera.position.z maps exactly to depth described here:
https://stackoverflow.com/questions/48758959/what-is-required-to-convert-threejs-perspective-camera-to-orthographic

Will give up on fancy npm link and just try getting local orchestration happening through direct imports this weekend.


const THREE_JS_PERSPECTIVE_CAMERA_FOV_Y_DEFAULT = 50;

function updateCamera(camera, width, height, depth) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small nit, depth could be extracted from camera.position.z eliminating the need for the additional argument.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants