I am using Scrollorama for scroll animations and I am having vertical spacing issues with the element beneath the pinned container
http://patrick.tbfdev.com/about-tahiti.php
As you scroll down you will notice that once the first container pins, the element beneath (blue sky image) descends down the page. This is NOT the desired behavior. The desired behavior is for the element beneath pinned object to remain coupled.
Here is my JS:
$(document).ready(function() {
var controller = $.superscrollorama({
triggerAtCenter: false,
playoutAnimations: true
});
// set duration, in pixels scrolled, for pinned element
var pinDur = 900;
// create animation timeline for pinned element
var pinAnimations = new TimelineLite();
pinAnimations
.append([
TweenMax.to($('#slide-a1'), 1.5, {css:{right:'+=2200px', ease:Bounce.easeOut}, delay:0.2}),
TweenMax.to($('#slide-a2'), 1.2, {css:{right:'+=2400px', ease:Bounce.easeOut}, delay:0}),
TweenMax.to($('#slide-a3'), 1.3, {css:{right:'+=3800px', ease:Bounce.easeOut}, delay:.2}),
TweenMax.to($('#slide-a4'), 1.5, {css:{right:'+=5400px', ease:Bounce.easeOut}, delay:.4}),
TweenMax.to($('#slide-a5'), 1.6, {css:{right:'+=6250px', ease:Bounce.easeOut}, delay:.6})
]
, -1)
.append([
TweenMax.to($('#info-a1'), 1.2, {css:{right:'+=2200px', ease:Bounce.easeOut}, delay:0.1}),
TweenMax.to($('#info-a2'), 1.1, {css:{right:'+=2400px', ease:Bounce.easeOut}, delay:0.5}),
TweenMax.to($('#info-a3'), 1.0, {css:{right:'+=2800px', ease:Bounce.easeOut}, delay:1.1}),
TweenMax.to($('#info-a4'), 1.3, {css:{right:'+=2400px', ease:Bounce.easeOut}, delay:1.4})
]
, -2.4)
// pin element, use onPin and onUnpin to adjust the height of the element
controller.pin($('#pin1'), pinDur, {
anim:pinAnimations,
onPin: function() {
$('#pin1').css('height','100%');
},
onUnpin: function() {
$('#pin1').css('height','808px');
}
});
Related
I found out that I could use dat.gui to control size and color of textGeometry besides changing color and size for every other scene through editing .js file. But probably bad architecture of my code, I am not able to control or even add gui folder to the scene. It probably has something to do with FontLoader that I'm using.
I tried placing dat.gui inside and outside my textGeometry creation function, none of them worked. As far as I understood, every time size or color changes it should dispose and remove the created mesh to create a new one with the new color/size parameters (i also update for every each keydown event to create a new mesh so that's my thought).
textGeometry, textMesh, textMaterial etc. are defined in global
function textCreation() {
const fontLoader = new FontLoader();
fontLoader.load(
"node_modules/three/examples/fonts/droid/droid_sans_bold.typeface.json",
(droidFont) => {
textGeometry = new TextGeometry(initText, { //initText variable gets updated with each keydown
size: 5,
height: 2,
font: droidFont,
parameters: {
size: 5,
height: 2,
},
});
textMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 });
textMesh = new THREE.Mesh(textGeometry, textMaterial);
group = new THREE.Group();
group.add(textMesh);
scene.add(group);
}
And here is the dat.gui controller that I tried to place in and out of this function.
let textFolder = gui.addFolder("Text Controls");
textFolder.add(textGeometry, "size", 10, 20).onChange(function () {
textGeometry.setSize(textGeometry.size);
// Probably dispose and remove old mesh from scene and create mesh with these new parameters
});
textFolder.addColor(textGeometry, "color").onChange(function () {
textGeometry.setColor(textGeometry.color);
I couldn't manage to add ANY dat.gui controller without breaking the scene. By the way I'm kinda new to JavaScript and three.JS so further explanations are welcome if there are any.
textGeometry.setSize(textGeometry.size);
This does not work since there isn't a setSize() method. You have to call dispose() on the existing geometry and then create a new one based on your updated parameters. You then assign the new geometry to your text mesh. So something like:
const params = {
color: '#ffffff',
size: 5
};
textFolder.add(params, "size", 10, 20).onChange(function (value) {
textGeometry.dispose();
textGeometry = new TextGeometry(initText, {
size: value,
height: 2,
font: droidFont
});
textMesh.geometry = textGeometry;
});
The material's color can be changed without creating a new object.
textFolder.addColor(params, 'color').onChange(function (value) {
textMaterial.color.set(value);
});
I need to set the Sprite(Hello) position to stay with the mesh...Now, the Sprite is independent. If I rotate the object, the Sprite should stay with the mesh
LATER EDIT:
Mesh position is always 0..
I tried for couple of hours but nothing worked..
Here is a screenshot of the code:
And the code...
loader.load('/3D_Cars/Dacia_1410_Tuned/components/scene.gltf', function (gltf) {
carModel = gltf.scene.children[0];
gltf.scene.traverse(function (child) {
if (child.isMesh) {
var v = new THREE.Vector3(0, 0, 0);
domEvents.addEventListener(carModel.getObjectByName(child.name), 'click', function (event) {
app.RenameAsCarParts(child.name)
console.log(child.name)
}, false)
if (child.name == 'rim_RSL1_Aluminium_0') {
child.position.set(100, 50, 3); //testing
var spritey = makeTextSpriteNew(" Hello ",
{ fontsize: 15, textColor: { r: 0, g: 0, b: 0, a: 1.0 } });
scene.add(spritey);
}
}
});
carModel.getObjectByName('Body_paint_0').material = bodyMaterial;
carModel.rotation.set(Math.PI / 2, 0, 0);
carModel.rotateY(Math.PI);
scene.add(carModel);
});
Thank you!
Where is this method defined makeTextSpriteNew?
You can refer this three.js example for drawing Text Sprites in three.js
https://stemkoski.github.io/Three.js/Sprite-Text-Labels.html
The idea is, you need to provide a 3d position to this sprite so that it will project that position on screen and display the Sprite.
In your case you need to provide it the mesh's position (bounding box corner/center based on where you need to show the sprite).
spritey.position.set(posX, posY, posZ);
I'm trying to pin a drei Html element to the top left corner. I'm struggeling with getting it to stay in the same location when rotating or moving the camera. This is my current attempt:
const { mouse2D, mouse3D, normal, plane } = useMemo(() => {
return {
mouse2D: new THREE.Vector2(),
mouse3D: new THREE.Vector3(),
normal: new THREE.Vector3(),
plane: new THREE.Plane(),
};
}, []);
const { width, height } = useWindowDimensions();
useFrame(({camera, raycaster, size}) => {
mouse2D.set(((0.02 * width) / size.width) * 2 - 1, ((-0.02 * height) / size.height) * 2 + 1);
raycaster.setFromCamera(mouse2D, camera);
camera.getWorldDirection(normal).negate();
plane.setFromNormalAndCoplanarPoint(normal, mouse3D);
raycaster.ray.intersectPlane(plane, mouse3D);
});
return <Html position={[mouse3D.x, mouse3D.y, mouse3D.z]}>stuff</Html>;
The Html position updates correctly on window resize but it doesn't update on camera rotation or camera moving. Anyone got any idea how to solve this?
If anyone is interested this is my current solution:
const { viewport } = useThree();
const groupRef = useRef<THREE.Group>(null!);
useEffect(() => {
const groupRefCopy = groupRef.current;
camera.add(groupRefCopy);
return () => {
camera.remove(groupRefCopy);
};
}, [camera, groupRef.current]);
return (
<group ref={groupRef} position={[-viewport.width / 3.5, viewport.height / 3.8, -5]} rotation={[0, 0, 0]}>
<Html style={{ opacity: show ? 1 : 0, width: menuWidth, userSelect: "none", pointerEvents: show? "auto" : "none" }}>
{...}
</Html>
</group>
);
3.5 and 3.8 works very well for my scene. If anyone knows how to get these constants dynamically from 3JS, please comment!
I am trying to add animation along y axis to an entity using the animation component and also trying to change it's position along z axis in a custom component. However, the animation component takes the precedence and the position change in z-axis in the custom component does not work.
I would like to change the position along y axis using the animation component and change the position along z-axis using my custom component.
Here is my code -
<a-entity id="orca" position="4 1 -18" gltf-model="#orca1" static-body animation="property: position.y; dir: alternate; dur: 1000; easing: easeInSine; loop: true; to: -1" move></a-entity>
AFRAME.registerComponent('move', {
schema: {
},
init: function() {
this.directionVec3 = new THREE.Vector3(0, 1, 1);
},
tick: function(t, dt) {
var directionVec3 = this.directionVec3;
var currentPosition = this.el.object3D.position;
directionVec3.z = dt/1000;
this.el.setAttribute('position', {
z: currentPosition.z + directionVec3.z
});
if (currentPosition.z > 10) {
this.el.setAttribute('position', {
z: -14
});
}
}
});
Could you please help? The only reason for me to choose the animation component for movement along y-axis is that I get the smooth sine curve movement using easeInSine.
As you’ve seen the animation component overrides your position. In this case you can apply your component to a parent entity to avoid the collision:
<a-entity move>
<a-entity id="orca" position="4 1 -18" gltf-model="#orca1" static-body animation="property: position.y; dir: alternate; dur: 1000; easing: easeInSine; loop: true; to: -1">
</a-entity>
</a-entity>
I have a button that gets bigger and smaller with an animation. How can I make the font get bigger and smaller along with the button. My code is below.
func animate() {
let originalFrame = self.playButton.frame
let originalBackgroundColor = self.playButton.backgroundColor
UIView.animateKeyframes(withDuration: 2, delay: 0, options: UIViewKeyframeAnimationOptions.calculationModeLinear, animations: {
// make the button grow and become dark gray
UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 0.5) {
self.playButton.frame.size.height = self.playButton.frame.size.height * 1.2
self.playButton.frame.size.width = self.playButton.frame.size.width * 1.2
self.playButton.frame.origin.x = self.playButton.frame.origin.x - (self.playButton.frame.size.width / 12)
self.playButton.frame.origin.y = self.playButton.frame.origin.y - (self.playButton.frame.size.height / 12)
}
// restore the button to original size and color
UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5) {
self.playButton.frame = originalFrame
self.playButton.backgroundColor = originalBackgroundColor
}
}, completion: nil)
}
You can store the grab the original font size and scale it similar to how you do it with the frame and background color:
func animate() {
// Original frame and background color
let originalFontSize = self.playButton.titleLabel?.font.pointSize
// First UIView.addKeyframe()
UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 0.5) {
self.playButton.titleLabel?.font = UIFont.systemFont(ofSize: originalFontSize!*1.2)
// Other animations ...
}
// Second UIView.addKeyframe() to return to normal
UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5) {
self.playButton.titleLabel?.font = UIFont.systemFont(ofSize: originalFontSize!)
// Other animations ...
}
Look into animating the transform property instead.
Something like
self.playButton.transform = CGAffineTransform.init(scaleX: 1.2, y: 1.2)