I try to apply texture on ground (a THREE.BoxBufferGeometry) , with shadow of a sphere (sphere is animated by Ammo.js)
The presence of shadow seems to depends of two parameters:
the shadow.camera settings of the THREE.DirectionalLight :
thObject.shadow.camera.left = -d;
thObject.shadow.camera.right = d;
thObject.shadow.camera.top = d;
thObject.shadow.camera.bottom = -d;
the shadow.camera.far setting :
thObject.shadow.camera.far = 110;
(it seems to depend of light position regarding shadow projection on ground).
But "playing" with these two settings create the following situation :
ripples on texture
shadow or not shadow (see after a part of shadow).
How to set these parameters but not by trial-and-error ?
(This depends of light position too): for exemple if light is not pointing in vertical axle:
pos: { x: -20, y: 35, z: -20 },
lookAt: { x: 0, y: 0, z: 0 },
The method applyMatrix4 seems like it does nothing...
Why can I not apply this transformation matrix to my vector?
const vec = new THREE.Vector3(1,1,1)
const geometry = new THREE.BoxGeometry(1,1,1)
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 })
const mesh = new THREE.Mesh(geometry, material)
mesh.rotateX(Math.PI)
const rotatedVec = vec.applyMatrix4(mesh.matrix)
console.log(rotatedVec)
Expectation (taking the cross product):
{x: 1, y: -1, z: -1}
Reality (the vector is unchanged)
{x: 1, y: 1, z: 1}
My mesh's matrix has changed - it is not the identity matrix.
[
[1, 0, 0, 0],
[0, -1, 0, 0],
[0, 0, -1, 0],
[0, 0, 0, 1],
]
Object3D.rotateX() only affects the object's quaternion property. It does not update its local matrix. If you say your matrix has changed, I assume you have checked it at a later point when other engine logic triggers a recalculation.
You can solve this issue by adding mesh.updateMatrix(); after you have called Object3D.rotateX().
Or even better use Vector3.applyQuaternion(). In this way, you don't have to recompute the matrix because you don't need it anyway.
const rotatedVec = vec.applyQuaternion(mesh.quaternion)
I want to implement an animation.
The animation should be a line move to another line. There will be some deformation in the process of the line moving
There is a correspondence between the points of the two lines.
How to implements it with three.js?
I try to use the tween.js.It works.
const material = new THREE.LineBasicMaterial({ color: 0x0000ff })
const geometry = new THREE.BufferGeometry().setAttribute('position',
new THREE.Float32BufferAttribute([-2, 0, 0, -0.5, 0, -0.5, 0, 0, -2], 3))
const line = new THREE.Line(geometry, material)
var position2 = new Float32Array([5, 0, 0, 1, 1, 1, 0, 0, 5])
setupObjectPositionTween(line, geometry.attributes.position.array, position2,
10000, 0, TWEEN.Easing.Linear.None) // duration, delay, easing
scene.add(line)
function setupObjectPositionTween(object, source, target, duration, delay, easing) {
new TWEEN.Tween(source)
.to(target, duration)
.delay(delay)
.easing(easing)
.onUpdate(function () {
// console.log(object,source,target)
object.geometry.attributes.position.array = source
object.geometry.attributes.position.needsUpdate=true
})
.start()
}
and in the render function
TWEEN.update()
I suggest you implement the animation of the green line with morph targets. Meaning the green line represents your default geometry whereas the blue line represents a morph target (also known as blend shape). You can then animate the transformation from green to blue by modulating the morphTargetInfluences parameter from 0 to 1.
Morph targets are part of the geometry data and defined in the BufferGeometry.morphAttributes property. Since multiple meshes can share the same geometry, the morphTargetInfluences property belongs to 3D objects like a mesh.
I suggest you study how the official example webgl_morphtargets is implemented. You can apply the same principles on lines.
I want to animate these two things at the same time, and not one by one.
t1.fromTo(searchForm, { scaleX: 0 }, { duration: 1, autoAlpha: 1, scaleX: 1 });
t1.fromTo(loupe, {x: '-=0'}, {duration: 1, x: '+=265'})
I want to move them together; how can I do that?
Just use the position parameter to position your tween(s) wherever you want in the timeline.
t1.fromTo(searchForm, { scaleX: 0 }, { duration: 1, autoAlpha: 1, scaleX: 1 });
t1.fromTo(loupe, {x: '-=0'}, {duration: 1, x: '+=265'}, 0);
There's more info about the position parameter at https://greensock.com/position-parameter.
Also, there's no reason to use a .fromTo() in the second case because x: "-=0" does absolutely nothing, so you can just to a normal .to() tween and omit that whole object.
Happy tweening!
The general problem I'm trying to solve is to find out what face of a cube faces upwards. The cube can be rolled 90° at a time and in any direction. If a certain face faces up, the cube disappears. I'm working with tweens to rotate the cube and change the position of it.
I'm currently trying to solve this by creating a new ray, with its origin set just above the cube and its direction going downwards for a short distance, so it intersects with the upper face of the cube only.
violet thingy on top of die is ray cast downward into the cube
So far so good. I get my cube as the object of intersection when I check per console.log(), but as soon as I try to access the face of intersection by faceIntersect.face it seems to be undefined.
Function in question:
function checkUpperFace(posX, posZ) {
// get position from passed x- and z-values (y is always above cube)
// and set direction and length of ray
var position = new THREE.Vector3( posX, 3, posZ );
var direction = new THREE.Vector3(0, -1, 0);
var far = 2;
// create ray, that goes downwards from above the cube
var cubeRaycaster = new THREE.Raycaster( position, direction, 0, far );
// get intersection with upper face of rolled cube
var faceIntersect = cubeRaycaster.intersectObject( currentCube );
// add a helper to see the ray
var arrowHelper = new THREE.ArrowHelper( direction, position, far, 0x770077 );
scene.add( arrowHelper );
console.log(faceIntersect); // object is shown with everything I want to know
console.log(faceIntersect.face); // is shown to be undefined
}
In the end I did it in a way #unx recommended but I really wanted to avoid the huge if-else statement, so I did it with an array rotationLibrary that has all possible rotations with the corresponding top face of the die. But because of the tween I use to rotate and move the die its rotation values are not really on point and therefore hard to compare to fixed rotation values as I use them in the array.
So I "normalize" the rotation values of the die to values I can use to compare them to my values in rotationLibrary. The last step is to store/update the result on what face is on top in the cube object itself, so I can get it whenever I want.
// spawn condition:
// 1 on top, 2 facing camera, 3 facing right (seen from camera),
// 4 facing left (see 3), 5 facing away from camera, 6 facing down
var rotationLibrary = [
{x: 0, y: 0, z: 0, face: 1},
{x: 0, y: 90, z: 0, face: 1},
{x: 180, y: 0, z: 180, face: 1},
{x: 0, y: -90, z: 0, face: 1},
{x: -90, y: 0, z: 0, face: 2},
{x: -90, y: 0, z: 90, face: 2},
{x: -90, y: 0, z: 180, face: 2},
{x: -90, y: 0, z: -90, face: 2},
{x: 0, y: 0, z: 90, face: 3},
{x: 90, y: 90, z: 0, face: 3},
{x: -90, y: -90, z: 0, face: 3},
{x: -90, y: 90, z: 180, face: 3},
{x: 180, y: 0, z: -90, face: 3},
{x: 0, y: 0, z: -90, face: 4},
{x: 90, y: -90, z: 0, face: 4},
{x: -90, y: 90, z: 0, face: 4},
{x: 180, y: 0, z: 90, face: 4},
{x: 90, y: 0, z: 0, face: 5},
{x: 90, y: 0, z: -90, face: 5},
{x: 90, y: 0, z: 180, face: 5},
{x: 90, y: 0, z: 90, face: 5},
{x: 90, y: 90, z: 90, face: 5},
{x: 0, y: 0, z: 180, face: 6},
{x: 180, y: -90, z: 0, face: 6},
{x: 180, y: 90, z: 0, face: 6},
{x: 180, y: 0, z: 0, face: 6}
];
function checkRotationsToGetUpperFace(cube) {
// create object with "normalized" (brought to quarter-circle-degree-values) degrees
var normalizedRotation = {
x: 0,
y: 0,
z: 0
};
normalizedRotation.x = getNormalizedDegree(cube.rotation._x);
normalizedRotation.y = getNormalizedDegree(cube.rotation._y);
normalizedRotation.z = getNormalizedDegree(cube.rotation._z);
// go through the library that has all the degrees with the corresponding upper face
for (var i = 0; i < rotationLibrary.length; i++) {
// check if the objects match, then get the face
if (rotationLibrary[i].x == normalizedRotation.x &&
rotationLibrary[i].y == normalizedRotation.y &&
rotationLibrary[i].z == normalizedRotation.z) {
cube.face = rotationLibrary[i].face;
}
}
// reattach cube for correct movement later
THREE.SceneUtils.attach(cube, scene, pivot);
}
function getNormalizedDegree(rotationValue) {
// transform rotation value into degree value
var rotValue = rotationValue / (Math.PI / 180);
// default value is 0, so only check if it should be 90°, 180° or -90°
var normalizedDegree = 0;
// x between 45° and 135° ( ~ 90)
if (rotValue > 45 && rotValue < 135) {
normalizedDegree = 90;
}
// x between -45° and -135° ( ~ -90)
else if (rotValue < -45 && rotValue > -135) {
normalizedDegree = -90;
}
// x between 135° and 215° or x between -135° and -215° ( ~ 180)
else if ((rotValue > 135 && rotValue < 215) || (rotValue < -135 && rotValue > -215)) {
normalizedDegree = 180;
}
return normalizedDegree;
}
(http://jsfiddle.net/b2an3pq7/3/)
Might not be the solution to your raycast problem but another approach: Why don't you simply detect the upper face by comparing the rotation euler angles? E.g. (pseudo code):
if(cube.rotation.x % 360 == 0)
{
// upper face upwards
}
else if(cube.rotation.x % 360 == 90)
{
// left face upwards
}
You would have to deal with value tolerance (85° - 95°) negative rotation values and values out of the range of PI*2 but other than that, isn't that much easier?