Using three.js is it possible to rotate a panned object about its center. I have created a jsfiddle, http://jsfiddle.net/yKt6h/4/
When I checked the Auto rotate mode in the control panel, i am able to rotate the panned cube about its center. Is it possible to have a similar effect when i try to rotate the cube with mouse movement.
If it is possible please provide me sample code
I am getting an errors in the console when viewing your jsFiddle THREE is not defined However, what you are asking is not difficult. The trackball camera is designed to do exactly what you want it to. If you are rendering your object at the origin you just need to initialize the trackball controls. I created a simple moon demo that uses TrackballControls. You don't need to do any modifcation in TrackballControls.js.
In the above demo I call a function to initialize the trackball controls the function is defined in my ThreeUtil.js file as:
function initTrackball(camera, rotate, zoom, pan, damping) {
var controls = new THREE.TrackballControls(camera);
controls.rotateSpeed = rotate || 1.0;
controls.zoomSpeed = zoom || 1.2;
controls.panSpeed = pan || 0.8;
controls.noZoom = false;
controls.noPan = false;
controls.staticMoving = true;
controls.dynamicDampingFactor = damping || 0.3;
return controls;
}
If you don't want the user to be able to pan or zoom, only to be able to rotate around your object, then simply set controls.noZoom = true and controls.noPan = true in the function above.
Since my moon object is at the origin of my scene all I have to do is set the camera some distance away from the origin. We will put it on the positive z axis so it is already looking at our object at the origin. Then we call the above function to set up the controls. I pass in a custom rotation speed:
controls = initTrackball(camera, 0.8);
Then in each frame all you have to do is call the update function in your anim loop:
controls.update(camera);
Related
I built my scene in three js and everything was working properly when I rendered the scene on the . But now I need the scene to be on a div, 70% of the viewport to be specific, the other 30% being a left side panel with some info. I replaced every window.height and width for the width and height of the div itself, but now the events are all broken. I tried bubbling and capturing but the problem seems to be related with the camera or something in three js, because when I hover on a corner something is happening...but nothing is happening when i hover/click on the 3d globe. I google everything and didn't find an answer or people with similar issues..I'm hopeless, help? Thanks.
Edit: here's a fiddle: https://jsfiddle.net/2L686cnw/
Did you update all for the renderer relevant variables on window resize?
Just like this:
var onWindowResize = function(){
renderWidth = element.offsetWidth;
renderHeight = element.offsetHeight;
camera.aspect = renderWidth/renderHeight;
camera.updateProjectionMatrix();
renderer.setSize(renderWidth, renderHeight);
};
$(window).on('resize', function() {
onWindowResize();
});
The issue sounds like that you get wrong viewport coordinates for your click position. Most three.js examples add event listeners to window or document object and using event.clientX (and clientY) to transform the mouse screen coordinates to viewport coordinates to use it for raycasting.
Having the 3D scene within a separate div covering only part of the page, it should be a bit different:
function onClick(event) {
var mouse = new THREE.Vector2();
mouse.x = (event.offsetX / panelWidth) * 2 - 1;
mouse.y = - (event.offsetY / panelHeight) * 2 + 1;
// do raycasting
}
canvas.addEventListener('click', onClick);
This is my code:
var sprite = new THREE.Sprite(material);
sprite.renderDepth = 10;
The above renderDepth setting is invalid, it does not work for sprites.
How to solve this problem?
You want one sprite to always be on top.
Since SpriteMaterial does not support a user-specified renderDepth, you have to implement a work-around.
Sprites are rendered last when using WebGLRenderer.
The easiest way to do what you want is to have two scenes and two render passes, with one sprite in the second scene like so:
renderer.autoClear = false;
scene2.add( sprite2 );
then in the render loop
renderer.render( scene, camera );
renderer.clearDepth();
renderer.render( scene2, camera );
three.js r.64
I have a GUi.HorizontalSlider in my scene and have a camera with a FreeCamera script attached. This causes the problem that when I slide the HorizontalSlider, the camera also rotates according to the slider mouse movement.
How can I slide the GUI.HorizontalSlider without making the camera rotate?
var vSliderValue = 0.0F;
var R : Transform;
var L : Transform;
function OnGUI () {
vSliderValue = GUI.HorizontalSlider(new Rect(25, 25, 150, 150), vSliderValue, 0.0F, -180.0F);
R.transform.rotation.eulerAngles.y = vSliderValue;
}
Thanks
The code is working fine in C# and javascript as well. Just changed R.transform.rotation.eulerAngles to R.transform.eulerAngles for C# (samething working in JS). There must be some code where you are also transforming the camera in same script.
Using three js is there anyway to define a clipping region for an object? I have for example a parent which contains child objects, I would like to clip the child objects based on the viewport.
Something like...
// Create container and children
var container = new THREE.Object3D();
for(var i = 0; i < 100; i++) {
var geometry = new THREE.PlaneGeometry(i, 0, 0);
var material = new THREE.MeshBasicMaterial({color: 0x00ff00});
var child = new THREE.Mesh(geometry, material);
container.add(child);
}
// Create bounding box which is my viewport
var geom = new THREE.Geometry();
geom.vertices.push(new THREE.Vector3(0, 0, 0));
geom.vertices.push(new THREE.Vector3(10, 0, 0));
geom.vertices.push(new THREE.Vector3(10, 1, 0));
geom.vertices.push(new THREE.Vector3(0, 1, 0));
geom.computeBoundingBox();
// Magic property (THIS DOESNT EXIST)
container.clipRegion = geom.boundingBox;
The final part doesn't exist but is there any way to achieve this with three js? I potentially want to animate the children within the parent and only show the visible region defined by the bounding box.
Update, Added the following image to describe my problem.
The resulting red area is the region I want to make visible, whilst masking anything that lies outside of this region. All other content should be visible.
I have been able to clip an object with another.
See the result here
fiddle
In this fiddle you will see a cube being clip by an sphere. Since this is a demo, there are some things that are not the final code.
You have in the right hand of the screen another camera view, where you see the scene from a high, static point view.
Also, the part of the cube that should be clipped, instead of this is showed green. In the fragment shader, you have to uncomment the discard statement to achieve real clipping.
if (shadowColor.r < 0.9) {
gl_FragColor = vec4 (0.3, 0.9, 0.0, 1.0);
} else {
gl_FragColor = vec4 (0.8, 0.8, 0.8, 1.0);
// discard;
}
It works by creating a spot light that can cast shadows
clippingLight = new THREE.SpotLight ( 0xafafaf, 0.97 );
clippingLight.position.set (100, 200, 1400);
clippingLight.castShadow = true;
scene.add (clippingLight);
The object that has to do the clipping casts shadows, and the object to be clipped receives shadows.
Then, in the animate , we set this light to the camera location
function animate() {
cameraControls.update();
clippingLight.position.x = camera.position.x;
clippingLight.position.y = camera.position.y;
clippingLight.position.z = camera.position.z;
requestAnimationFrame(animate);
}
Now, the parts that have to be visible in the clipped object are the ones at the shadow. We need a shader that handles that. The frag shader code is take from the standard one in the three.js library, just slightly modified.
I am very new working with three.js, so probably there are a lot of thing in the code that can be done better. Just take the idea :-)
I am working on an app in which images are flying on the Screen.
I need to implement:
Hold onto any of the flying images on Tap
Drag the image to certain position of the user's choice by letting the user hold it.
Here is another easy way to do dragging.
Just draw your image (Texture2d) with respect to a Rectangle instead of Vector2.
Your image variables should look like this
Texture2d image;
Rectangle imageRect;
Draw your image with respect to "imageRect" in Draw() method.
spriteBatch.Draw(image,imageRect,Color.White);
Now in Update() method handle your image with single touch input.
//Move your image with your logic
TouchCollection touchLocations = TouchPanel.GetState();
foreach(TouchLocation touchLocation in touchLocations)
{
Rectangle touchRect = new Rectangle
(touchLocation.Position.X,touchLocation.Position.Y,10,10);
if(touchLocation.State == TouchLocationState.Moved
&& imageRect.Intersects(touchRect))
{
imageRect.X = touchRect.X;
imageRect.Y = touchRect.Y;
}
//you can bring more beauty by bringing centre point
//of imageRect instead of initial point by adding width
//and height to X and Y respectively and divide it by 2
There's a drag-and-drag example in XNA here: http://geekswithblogs.net/mikebmcl/archive/2011/03/27/drag-and-drop-in-a-windows-xna-game.aspx
When you load your image in, you'll need a BoundingBox or Rectangle Object to control where it is.
So, in the XNA app on your phone, you should have a couple of objects declared for your texture.
Texture2D texture;
BoundingBox bBox;
Vector2 position;
bool selected;
Then after you load your image content, keep your bounding box updated with the position of your image.
bBox.Min = new Vector3(position, 1.0f);
bBox.Max = new Vector3(position.X + texture.Width, position.Y + texture.Height, 0f);
Then also in your update method, you should have a touch collection initialized to handle input from the screen, get the positions of the touch collection, loop through them and see if they intersect your boundingbox.
foreach (Vector2 pos in touchPositions)
{
BoundingBox bb = new BoundingBox();
bb.Min = new Vector3(pos, 1.0f);
bb.Max = new Vector3(pos, 0f);
if (bb.Intersects(bBox)
{
if (selected)
{
//do something
}
else
{
selected = true;
}
}
}
From there, you have whether your object is selected or not. Then just use the gestures events to determine what you want to do with your texture object.