I need to rotate a sprite object but it seems this is not feasible, if not, is there a way to achieve the rotation effect, maybe through the UV coordinates of the spriteMaterial, or a custom shader? what would be the best way to go?
The rotation of a Sprite is set by its material's rotation parameter. For example, like so:
var material = new THREE.SpriteMaterial( {
color: 0xffffff,
map: texture,
rotation: Math.PI / 4
} );
var sprite = new THREE.Sprite( material );
three.js r.67
It took me forever, but turns out you need to rotate the sprite material and not the sprite itself. Like so:
var scale = 1;
function animate() {
requestAnimationFrame(animate);
// Rotate the sprite:
sprite.material.rotation += 0.01;
// Resize the sprite:
scale += 0.01
sprite.scale.set(scale, scale, 0);
// Move the sprite:
sprite.position.x += 0.01;
renderer.render(scene, camera);
}
Related
I've create a simple PlaneBufferGeomoetry in THREE.js
Geometry
const geometry = new THREE.PlaneBufferGeometry(10, 10, 10, 10);
const material = new THREE.MeshBasicMaterial( { side: THREE.DoubleSide, wireframe: true } );
const mesh = new THREE.Mesh( geometry, material );
const positions = geometry.attributes.position.array;
scene.add(mesh);
I'm then looping through each of the array segments in order to randomly change the z axis position during the render.
function animate() {
render()
requestAnimationFrame( animate );
}
function render() {
mesh.rotateZ(0.001)
const geoArray = geometry.attributes.position;
for (var i = 0; i < geoArray.count; i++) {
geoArray.setZ(i, Math.round(Math.random() * -2));
}
mesh.geometry.attributes.position.needsUpdate = true;
camera.updateProjectionMatrix()
renderer.render(scene, camera)
}
This works fine, however the animation speed is way too fast. How can i slow down the time during render in order for the z axis positions to smoothly change?
I have tried setting a setTimeOut function during the animate function, however this just slows the framerate down and not the animation itslef.
Thankyou
Right now, you are animating with fixed scalar values in your animation which is normally something you don't want to do in production apps. You should always take a time delta value into account so your animation is framerate independent. This makes it also easier to scale the time of your animation. So create an instance of THREE.Clock in your app like so:
const clock = new THREE.Clock();
In your animation loop, retrieve the time delta value for the current frame and use it:
const timeDelta = clock.getDelta();
mesh.rotateZ(timeDelta);
If you want to change the animation speed, multiply the delta value with another scalar representing your time scale value. E.g:
timeDelta *= 0.1; // this will slow down the animation
I'm new to three.js and having trouble finding documentation on how to change rotation direction. The current rotation is set so the sphere looks like it's spinning towards the viewer on a screen but I want it to rotate in a clockwise direction, so it looks like it's spinning from a side view if a viewer is looking at it.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(50, 500 / 400, 1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(500, 400);
document.body.appendChild(renderer.domElement);
var geometry = new THREE.SphereGeometry(3, 50, 50, 0, Math.PI * 2, 0, Math.PI * 2);
var material = new THREE.MeshNormalMaterial();
var cube = new THREE.Mesh(geometry);
scene.add(cube);
camera.position.z = 10;
var render = function () {
requestAnimationFrame(render);
cube.rotation.x -= 0.10;
cube.rotation.y += 0.00;
renderer.render(scene, camera);
};
render();
http://jsfiddle.net/SF9tX/1968/
If I understand your question correctly, then rotation around different directions (or axis') can be achieved by incrementing different components of the objects rotation vector.
So for example, if you want to rotate the cube around the y-axis (ie to create a "spinning globe" effect) you can increment the .y component of the .rotation vector, as follows:
var render = function () {
requestAnimationFrame(render);
// This was casuing rotation around about the x-axis
// cube.rotation.x -= 0.10;
// Add this to cause rotation around the z-axis,
cube.rotation.z += 0.10;
renderer.render(scene, camera);
};
Ah I figured it out. It's as simple as replacing the cube.rotation.x to cube.rotation.z, so:
camera.position.z = 10;
var render = function () {
requestAnimationFrame(render);
cube.rotation.z -= 0.10;
cube.rotation.y += 0.00;
renderer.render(scene, camera);
};
I'm trying to apply a gradient texture to a model using a gradient texture derived from CSS. The idea is that a user could adjust the stops/colors of a gradient and then apply the gradient to a model to match the current camera view as it's rotated around. I've had a very hard time understanding how to implement something like this tutorial.
I've created a very simple example with a hard coded gradient image and Suzanne the monkey, which you can find here:
https://github.com/abogartz/projection-mapping
(To run this, you can use the provided Browser-Sync setup or just run a simple server on index.html)
Right now, the Suzanne model applies the texture as per its own UVs. This results in a gradient that is not linear across the face:
What I would like is to use "projection mapping" instead, where the gradient starts from the leftmost vertex and ends at the rightmost, no matter how the camera is rotated (I'll save the camera matrix on a user action and use that as a uniform later).
The result should be more like this (of course with lighting,etc)
My current shader looks like this:
<script id='fragmentShader' type='x-shader/x-fragment'>
uniform vec2 u_mouse;
uniform vec2 u_resolution;
uniform float u_time;
uniform sampler2D u_gradient_tex;
varying vec2 vUv;
void main() {
gl_FragColor = texture2D(u_gradient_tex,vUv);
}
Obviously, the vUv varying is not what I want, so how do I calculate the projection coordinate instead?
Check this out, I created this for you so you can see the rough idea on how you would implement this:
http://glslsandbox.com/e#37464.0
I've done this with a circle but you could do it with a model as well.
Essentially all you need to do is change gl_FragColor = texture2D(u_gradient_tex,vUv); to something like gl_FragColor = texture2D(u_gradient_tex,gl_FragCoord.xy * some_scaling_factor);
This is changing the texture mapping to be dependant on the FragCoord rather than the model UV.
I don't think there is an "easy" way to do what you want. If you want the gradient to always stretch from the left edge of the model to the right edge of the model regardless of orientation then you need to compute the left most and right most vertex position from that perspective / camera angle. Otherwise the gradient would have no anchor (on the left) and no width (how far to stretch to fit)
Typical projection mapping is somewhat described here
Programatically generate simple UV Mapping for models
You need the position of the projector, then you project from that projector to the points on your mesh to generate UV coordinates. In your case the projector can always be the camera so you can ignore that part. You'd use planar mapping but you'd need to compute the left most vertex's position and the right most so you can align the projection so it matches silhouette of your 3D model.
If all you want is a single model with silhouette you can just set the background to your CSS gradient, clear to black then draw with 0,0,0,0 with model to cut a hole.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, 1, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer({alpha: true});
document.body.appendChild( renderer.domElement );
renderer.setClearColor(0x000000);
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
var material = new THREE.MeshBasicMaterial( {
color: 0x000000,
opacity: 0,
} );
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );
camera.position.z = 2;
function resize() {
var canvas = renderer.domElement;
var width = canvas.clientWidth;
var height = canvas.clientHeight;
if (canvas.width !== width || canvas.height !== height) {
renderer.setSize(width, height, false);
camera.aspect = width / height;
camera.updateProjectionMatrix();
}
}
function render(time) {
time *= 0.001; // convert to seconds;
resize();
cube.position.z = Math.sin(time);
cube.rotation.x = time * 0.817;
cube.rotation.y = time * 0.923;
renderer.render( scene, camera );
requestAnimationFrame( render );
}
requestAnimationFrame( render );
body { margin: 0; }
canvas {
width: 100vw;
height: 100vh;
display: block;
background: linear-gradient(to right, rgba(255,0,0,1) 0%, rgba(255,191,0,1) 23%, rgba(34,255,0,1) 41%, rgba(0,64,255,1) 55%, rgba(170,0,255,1) 75%, rgba(255,0,0,1) 100%);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r83/three.min.js"></script>
I am trying to use THREE.Raycaster to show an html label when the user hover an object. It works fine if I use THREE.Mesh but with THREE.Sprite it looks like that there is a space that increases with the scale of the object.
The creation process is the same for both scenario, I only change the type based on USE_SPRITE variable.
if ( USE_SPRITE ) {
// using SpriteMaterial / Sprite
m = new THREE.SpriteMaterial( { color: 0xff0000 } );
o = new THREE.Sprite( m );
} else {
// using MeshBasicMaterial / Material
m = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
o = new THREE.Mesh(new THREE.PlaneGeometry( 1, 1, 1 ), m );
}
https://plnkr.co/edit/J0HHFMpDB5INYLSCTWHG?p=preview
I am not sure if it is a bug with THREE.Sprite or if I am doing something wrong.
Thanks in advance.
three.js r73
I would consider this a bug in three.js r.75.
Raycasting with meshes in three.js is exact. However, with sprites, it is an approximation.
Sprites always face the camera, can have different x-scale and y-scale applied (be non-square), and can be rotated (sprite.material.rotation = Math.random()).
In THREE.Sprite.prototype.raycast(), make this change:
var guessSizeSq = this.scale.x * this.scale.y / 4;
That should work much better for square sprites. The corners of the sprite will be missed, as the sprite is treated as a disk.
three.js r.75
have a 3d maze with walls and floor.
have an image with a key ( or other object its not important, but all of em are images and not 3d models ).
I want to display it on the floor and if the camera moves around the object needs to look the same without rotating the object. How can i achieve this?
Update1:
I created a plane geometry added the image ( its a transparent png ) and rotating at render. Its working good, but if i turn the camera sometimes the plane lose transparency for about a few milisec and the get a solid black background ( blinking ).
Any idea why?
here is the code:
var texture = new THREE.ImageUtils.loadTexture('assets/images/sign.png');
var material = new THREE.MeshBasicMaterial( {map: texture, transparent: true} );
plane = new THREE.Mesh(new THREE.PlaneGeometry(115, 115,1,1), material );
plane.position.set(500, 0, 1500);
scene.add(plane);
// at render:
plane.rotation.copy( camera.rotation );
This will be achieved by using:
function animate() {
not3dObject.rotation.z = camera.rotation.z;
not3dObject.rotation.x = camera.rotation.x;
not3dObject.rotation.y = camera.rotation.y;
...
render();
}