Giter Club home page Giter Club logo

babylonjs-editcontrol's Introduction

BabylonJS-EditControl

An edit control for use in BabylonJS (a 3D HTML Webgl framework) applications.

About

Many 3d editors provide, what is called, a widget/gizmo/transform control, to help translate, rotate or scale 3d objects in the editor.
This EditControl is just that.
You can embed this in your Babylonjs application to provide those same capabilities.
It currently supports

  • Translate
  • Translate Snap
  • Rotate
  • Rotate Snap
  • Scale
  • Scale Snap
  • Local or Global Translation and Rotation. (Scaling only in local axis)
  • Create multiple instances in the same scene with each instance attached to a different mesh
  • Scale size of control
  • undo, redo

For a demo, head on over to https://ssatguru.github.io/BabylonJS-EditControl-Samples/demo/Demo.html

Limitations/Issues

This currently does not handle properly, a right handed mesh in a left handed system (example gltf mesh in lhs babylon) or a left handed mesh in a right handed system.
A right handed mesh in a right handed system or a left handed mesh in a left handed system is handled properly.
A gltf mesh in a right handed babylon is handled properly.
I would address this in a future release.

For a list of other know issues, shortcomings and planned enhancements see https://github.com/ssatguru/BabylonJS-EditControl/issues

3.3.0 Major changes

Moved the EditControl to the Babylonjs DefaultUtilityLayer scene.
Because this scene is different from the main scene there is less interference with the main scene. Also makes it a bit faster.
This is similar to how the native gizmos of Babylonjs work.

Upgraded to latest version of Babylons js - 5.41.
Replaced deprecated methods with new ones. Upgraded other dev dependenices to latest version - typescript, webpack etc.

3.20 Major and Breaking changes

Version 3.2.0 converts the project from a plain vanilla JavaScript project to a module based JavaScript project.
With this change, the way to load the application has changed.
In JavaScript, instead of

var EditControl = org.ssatguru.babylonjs.component.EditControl;
editControl = new EditControl(box,camera, canvas, 0.75);

now do

var editControl = new EditControl(box,camera, canvas, 0.75);

In TypeScript, instead of

import EditControl = org.ssatguru.babylonjs.component.EditControl;

now do

import {EditControl} from "babaylonjs-editcontrol";

See below for more details.

Quick start

  1. add the following dependencies
<script src="https://code.jquery.com/pep/0.4.2/pep.js"></script>
<script src="https://cdn.babylonjs.com/babylon.js"></script>
<script src="EditControl.js"></script>

See INSTALL below to find where you can get "EditControl.js".

  1. a small javascript code snippet to get you up and running
//------------------EDIT CONTROL -------------------------------------------------
//create edit control (mesh to attach to, active camera, canvas, scale of editcontrol)
var editControl = new EditControl(box,camera, canvas, 0.75);
//to show translation controls
editControl.enableTranslation();
//set transalation snap value in meters
editControl.setTransSnapValue(0.5

see sample project here https://github.com/ssatguru/BabylonJS-EditControl-Samples/tree/master/sample-global

INSTALL

You can find the "EditControl.js" from its git repository "dist" folder or "releases" section
https://github.com/ssatguru/BabylonJS-EditControl/tree/master/dist
https://github.com/ssatguru/BabylonJS-EditControl/releases

You can also install this from npm

npm install babylonjs-editcontrol

USAGE

This has been built as an UMD module which means you can use it as a CommonJS/NodeJS module, AMD module or as a global object loaded using the script tag.

Project "BabylonJS-EditControl-Samples" https://github.com/ssatguru/BabylonJS-EditControl-Samples has a collection of sample projects to show how to use this from TypeScript, NodeJs, AMD or plain vanilla JavaScript applications.

Below is a quick summary of how you can use this as different module types.

CommonJS/NodeJS Module

let BABYLON = require("babylonjs");
let EditControl = require("babylonjs-editcontrol").EditControl;
let engine = new BABYLON.Engine(canvas, true);
...
let editControl = new EditControl(box,camera, canvas, 0.75);
...

AMD Module

<script src="./lib/require.js"></script>
<script>
	require.config({
		baseUrl: ".",
		paths: {
			"babylonjs": "./lib/babylon",
			"ec": "./lib/EditControl"
		}
	});

	require(['babylonjs', 'ec'], function (BABYLON, ec) {
		let EditControl = ec.EditControl;
		let engine = new BABYLON.Engine(canvas, true);
		...
		let editControl = new EditControl(box,camera, canvas, 0.75);
		...
	});
</script>

Global Module

<script src="./lib/babylon.js"></script>
<script src="./lib/EditControl.js"></script>
<script>
	let engine = new BABYLON.Engine(canvas, true);
	...
	let editControl = new EditControl(box,camera, canvas, 0.75);
	...
</script>

DEPENDENCIES

  • pepjs
  • babylonjs

The two can be installed from npm

npm install babylonjs pepjs

or via cdn

<script src="https://code.jquery.com/pep/0.4.2/pep.js"></script>
<script src="https://cdn.babylonjs.com/babylon.js"></script>

API

To Instantiate

// JavaScript
var editControl = new EditControl(mesh,camera, canvas, 0.75, true);
// TypeScript
import {EditControl} from "babaylonjs-editcontrol";
let editControl:EditControl = new EditControl(mesh,camera, canvas, 0.75, true,0.02);

This positions the edit control at the mesh pivot position and displays x,y,z axis.
Takes five parms

  • mesh - the mesh to control using the editcontrol
  • camera - active camera
  • canvas - the mesh canvas
  • scale - number. Optional. Default 1. Determines how small or large the editcontrol should appear.
  • eulerian - true/false. Optional. Default false. True indicates that rotation of the mesh is in euler.If rotation is unresponsive then it is possible that the rotation may not have been initialized to either a eulerian or quaternion value.
  • pickWidth - number. Optional. Default 0.02. Determines how close to an axis should the pointer get before we can pick it

To show Translation, Rotation or Scaling controls

editControl.enableTranslation();

editControl.enableRotation();
editControl.setRotGuideFull(true/false) //This makes the rotation guides 360 degree(true) or 90 degree(false) .90 degree  looks less cluttered.
editControl.returnEuler(true); // Optional. This will return rotation in euler instead of quaternion. Quaternion is the default.

editControl.enableScaling();

To hide Translation, Rotation or Scaling controls (just displays x,y,z axis)

editControl.disableTranslation();
editControl.disableRotation();
editControl.disableScaling();

To check if Translation, Rotation or Scaling is enabled

editControl.isTranslationEnabled();
editControl.isRotationEnabled();
editControl.isScalingEnabled();

To turn on/off local/ global mode

editControl.setLocal(boolean true/false);

To check if local/ global mode

editControl.isLocal();

To turn on/off translation, rotation or scale snapping

editControl.setTransSnap(boolean true/false);
editControl.setRotSnap(boolean true/false);
editControl.setScaleSnap(boolean true/false);

editControl.isTransSnap();
editControl.isRotSnap();
editControl.isScaleSnap();

To set/get translation, rotation or scale snap values

editControl.setTransSnapValue(number n in meters);
editControl.setRotSnapValue(number n in radians);
editControl.setScaleSnapValue(number n a factor by which scale should increase);

editControl.getTransSnapValue();
editControl.getRotSnapValue();
editControl.getScaleSnapValue();

To bound translation, rotation or scaling

This restricts tranlation, rotation,scaling between a minimum and maximum values

setTransBounds(min?: Vector3,max?: Vector3) ;
setRotBounds(min?: Vector3,max?: Vector3);
setScaleBounds(min?: Vector3,max?: Vector3);
removeTransBounds();
removeRotBounds();
removeScaleBounds();

Note: rotation bounds has not been implemented. This is on TODO list.

To undo or redo

editControl.undo();
editControl.redo();

To set undo count

By default does upto 10 undos

editControl.setUndoCount(number count);

To check if user editing (moving,translating or scaling object)

editControl.isEditing();

returns true if the use is in the process of editing

To check if the pointer is over the edit control

editControl.isPointeOver();

returns true if the pointer is over the edit control

To be called back whenever the user starts, takes or ends an action

editControl.addActionStartListener(function(number actionType));
editControl.addActionListener(function(number actionType));
editControl.addActionEndListener(function(number actionType));

Each of these take a function as a parameter.
The ActionStartListener would be called when the user starts translating,rotating or scaling a mesh
The ActionListener would be called when the user is translating,rotating or scaling a mesh
The ActionEndListener would be called when the user ends translating,rotating or scaling a mesh

When called, these listeners would be passed a number which would indicate the action being taken by the user.
This number would have one of the following values
0 - ActionType.TRANS, Translation
1 - ActioneType.ROT, Rotation
2 - ActioneType.SCALE, Scaling

To remove the listeners

editControl.removeActionStartListener();
editControl.removeActionListener();
editControl.removeActionEndListener();
editControl.removeAllActionListeners() // to remove all;

To refresh mesh Bounding Info.

EditControl uses mesh bounding info to provide the same smooth scaling experience for both small and large mesh. The bounding info changes when a mesh is baked. Use this method to refresh the bounding info if you baked the transform of the mesh.

editControl.refreshBoundingInfo();

To get position and rotaion of EditControl

editControl.getPosition();//returns Vector3
editControl.getRotationQuaternion(): //returns rotation in quaternion

The postion and rotation of EditControl would be the same as that of the mesh to which it is attached

To show/hide EditControl

editControl.hide();
editControl.isHidden(); //turns true or false
editControl.show();

To set visibililty (transparency)

editControl.setVisibility(v:number);

By default the visibility is set to 0.75

To switch camera

editControl.switchCamera(camera:Camera);

The edit control uses the camera specified during instantiation to control how it is scaled or picked.
Use this to swicth to a different camera after instantiation.
You might want to use this for example when the active camera in your scene changes and you want to use the new one for the editcontrol.

To switch edit control to another mesh

editControl.switchTo(Mesh mesh, optional boolean isEuler );

This quickly removes the edit control from one mesh and attaches it to another mesh.

The translation, rotation, scaling mode is maintained.

mesh : the mesh to which the control should switch to
isEuler : true/false, optional, default false, true indicates that rotation of the mesh is in euler

To detach from the mesh and clean up resources.

editControl.detach();

Build and Test

If not already installed, install node js.
Switch to the project folder.
Run "npm install", once, to install all the dependencies.

Build

Run "npm run build" - this will compile the files in "src" and create a development module in the "dist" folder.
Run "npm run build-prod" - this will compile and create a minified production module in the "dist" folder.

To test

Two ways to test.

  1. using the webpack-dev-server.
    Start the development server
    "npm run start"
    This will start the live dev server on port 8080 (could be different if this port is already in use) and open the browser with the file http://localhost:8080/tst/test.html.
    The dev server will live compile your code any time you make changes.
    Note: The dev server does not write the build to disk, instead it serves it from memory. In our case the build, "EditControl.max.js", is served from location http://localhost:8080/dist. (see publicPath in wepack.config.js file).

  2. using any other http server.
    Start the server , say http-server, from the project root folder (not from within "/tst " folder).
    Goto http://localhost:8080/tst/test.html (assuming the server was started on port 8080).
    Everytime you make changes you will have to build using "npm start build-dev".

Note:

The original version was written in Java and then transpiled to TypeScript/JavaScript using JSweet.
It was originally written in Java, as at that time I wasn't very comfortable with the TypeScript language and its ecosystem.
Over time I have become more comfortable with it.
The new version is thus written in TypeScript.
It is based on the initial TypeScript code generated by JSweet.
Porting to Typescript was easy, as JSweet generates good human readable TypeScript which allows one to switch to TypeScript at any time.
For those interested, the old java version is still available at https://github.com/ssatguru/BabylonJS-EditControl.java

babylonjs-editcontrol's People

Contributors

pryme8 avatar ssatguru avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

babylonjs-editcontrol's Issues

Scale and Trans bounds

There's one more addition to the API that I'd need to make this work in my current project which is to add something like a setScaleBounds() and setTransBounds() methods that take a BABYLON.BoundingBox and limit how far you can scale and translate to that box. (I suppose you could do the same with rotationBounds, but it will be harder to specify the limits.)

@ssatguru Is this something you'd like to do or should I give it a shot?

Getting "Error: Eulerian is set to false but the mesh's rotationQuaternion is not set" on creation

Hi,

I'm getting the error "Error: Eulerian is set to false but the mesh's rotationQuaternion is not set." when I instantiate the editControl with the useEuler set to false (or null):

this.editControl = new EditControl(this.scene.meshes[0],this.camera, this.canvas, 1, false);

If I set it to true, the control works except when rotated with snaps on, in which case I get "Cannot read property 'toEulerAngels' of null" in doRotation() (around line 680).

This only seems to happen when I use webpack to build everything. I can't reproduce it in the playground.

Any thoughts?

James

ends remain white when switching mode

to reproduce
go to a mode say translate
hover over an axis say x
axis x will become white
without moving cursor switch to rotate
switch back to trans
the x axis arrow remain white

Update during transform

Currently the actionListener is only called on pointer up. It would be very helpful to have it get called while the user was actively manipulating the control (so we can show the user how much they've moved/rotated/scaled the object, for example). It's important that the API distinguish between the two types of actions.

I can see three ways to handle this.

  1. Add an "updateOnMove" flag - when set, the control calls the action listener on every move
  2. Add a new type of listener - to distinguish from the current action
  3. Add new action types - eg: ActionType.TRANS_MOVE, .ROT_MOVE, SCALE_MOVE

My vote would be option 3 because it clearly distinguishes between the types of action and doesn't add the confusion of different types of listeners. We could also think of adding a ActionType.TRANS_START, .ROT_START and .SCALE_START incase people want to do something else while the user is manipulating the control (like open up a 'stats' window).

Once we decide on an option, I'm happy to add this myself (once I figure out the compiling issue).

Thanks,

James

npm / webpack

Hi,

I'm looking at using the EditControl for a project that is built with webpack, which means we can't import the dependencies in a script tag.

Is there an easy way to package this up as an npm package? Or some other way I can cleanly export it for import?

Thanks

Adjust scale "speed"

Is it possible to adjust the scale "speed"? That is, change how much a mesh scales given the size of the mouse move? I think this has to do with the scale of the objects in my project, but right now, a tiny move makes the scale shoot out to the horizon.

Thanks,

James

Editor tools interfering with bounding box + re-sizing when camera moves

Hey there. I'm not sure if this library is still being supported but thought I'd log an issue just in case. Not sure if this is due to my implementation or not but I'm noticing two issues that are leaving me scratching my head.

  1. The size/scale of the editor tools themselves seems to change based on the position of my camera.
  2. My bounding box implementation (which i will leave the code for below) is being broken whenever the editor tools are active. It seems to react to the changes made by the tools but gets completely separated from the mesh itself. The scale tool ends up controlling its location so perhaps something is wrong there?

Here is a video showing the irregular behaviour:

editor-tool-bugs.mp4

Here is my bounding box code (its pretty much ripped straight from the docs):

let childMeshes = parent.getChildMeshes();

    let min = childMeshes[0].getBoundingInfo().boundingBox.minimumWorld;
    let max = childMeshes[0].getBoundingInfo().boundingBox.maximumWorld;

    for(let i=0; i<childMeshes.length; i++){
        let meshMin = childMeshes[i].getBoundingInfo().boundingBox.minimumWorld;
        let meshMax = childMeshes[i].getBoundingInfo().boundingBox.maximumWorld;

        min = BABYLON.Vector3.Minimize(min, meshMin);
        max = BABYLON.Vector3.Maximize(max, meshMax);
    }

    parent.setBoundingInfo(new BABYLON.BoundingInfo(min, max));
    
    parent.showBoundingBox = true;

Trouble compiling from typescript

I created my own fork (to try to help figure out the npm stuff), but can't get the typescript to compile.

npm install works, but when I run npm run compile I get a ton of "Cannot find namespace 'BABYLON'." errors.

editControl.setTransSnapValue doesn't work in sample-global

I'm trying to enable snapping by giving editControl.setTransSnapValue a value but nothing happens.

I've just put it in the index.js at the transButton, but when I click it, nothing happens ( still no snapping)

transButton.onclick = function () {
       editControl.enableTranslation();
       editControl.setTransSnap = true;
       editControl.setTransSnapValue = 10;
   };

parent/child issue

if mesh is a child of another mesh then editcontrol doe snot work as expected

Scale bounds behaves erratically when min bound is set to zero

Scale bounds works fine in all cases except that if the min vector of any of the scale axes is set to exactly 0, the object will flicker between 0 and some random small size as the mouse moves. It looks as if the diff values being sent to doScaling() are bouncing around. This only happens if the min vectors values are set to exactly 0. Any other arbitrarily small number works fine.

Error when rotating while looking directly at axis

My project starts with the camera looking directly at the object. If you try to rotate the x by dragging on the red ring (which is essentially a straight line from this angle), you get a "Cannot read property 'x' of null' error on this line:

var diff = newPos.subtract(this.prevPos);
if (diff.x == 0 && diff.y == 0 && diff.z == 0)

in onPointerMove()

scaling along plane not intuitive

depending on which co-ordinate axes quadrant the camera is in, the scaling along plane behaves differently
In some quadrant moving the pointer towards camera scales up whereas in others it scales down
the behavior should be the same in all quadrants

How can I get the scaling values?

Sorry if I missed it, I noticed you can use getPosition and getRotationQuaternion to get the position and rotation information, but how can I get the scaling ones?
What I want is to know the changed values in registered action listeners, since the only argument for the listener is the action type, so I have to get the values by other functions, am I right?

handle mesh with non uniformed scaled parent

We have an issue when the mesh has a parent and the parent scaling is not uniform, that is the scaling in x y and z are not the same.
In such cases the axes are no longer at right angle to each other.
To handle this we would have to change how axes are drawn
For now if the scaling of parent is not uniform we prevent any transforms.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.