My shadowMap is too little,what's the matter?
You probably did not set the shadowmap camera (correctly).
From the docs:
The default is an OrthographicCamera with left and bottom set to -5, right and top set to 5, the near clipping plane at 0.5 and the far clipping plane at 500.
Meaning:
yourLight.shadow.camera.left = -500 //(default is -5)
yourLight.shadow.camera.right = 500 //(default is 5)
yourLight.shadow.camera.top = -500 //(default is -5)
yourLight.shadow.camera.bottom = 500 //(default is 5)
//not sure if this is needed, the docs do not mention it even though they are changing the projection so probably not needed
yourLight.shadow.camera.updateProjectionMatrix()
Related
Im setting the height and width to 100 when setting the PlaneGemoetry. Then I am scaling to the exact same size later using plane.scale(100, 100, 1);. But the scaled plane is much bigger. Why is the exact same dimentions so diffirent? Am I doing something wrong, or is the scale values really completley diffirent?
My expectation is that when I set the scale to 100, 100 it should not change size because thats the same size I created it at.
var geometry = new THREE.PlaneGeometry(100, 100, 2, 2 ); //<--- sets scale here
var plane = new THREE.Mesh( geometry, material );
plane.scale.set( 100, 100, 1 ); //< -- why does 100, 100 suddenly turn into a completley
Heres a codepen for the issue:
https://codepen.io/carelesscourage/pen/zYLbZBv
Scaling is multiplicative. So your original size * scale is the equivalent of doing
100 * 100 = 10000
You’re getting a plane that’s ten thousand units wide. If you want to return to its initial size, just set the scale to 1, since 100 * 1 = 100
I have a three-globe, and lat/long points perfectly go to the correct locations. The base (Earth) map is 1600x800.
However, I also have a RainViewer map (storm radar) which is square (4096x4096). If I scale that to 1600x1600 and overlay the Earth map, it fits perfectly lined up (top 800 and bottom 800 are outside the boundaries, but that is blank anyway, so perfect).
When I use the TextureLoader/SphereBufferGeometry/MeshPhongMaterial/Mesh, and add it to the scene, it locates itself completely in the wrong spot. No amount of rotateX/Y/Z, or phi/theta shifting seems to work to get it to position correctly.
How can one map this correctly on the globe?
Relevant code (url hardcoded to a timestamp for clarity):
this.myGlobe = new ThreeGlobe()
.globeImageUrl(myImageUrl)
.polygonsData(this.polyData)
.pointsData(gData)
.pointColor('color');
const renderer = new THREE.WebGLRenderer();
console.log('width=' + width);
renderer.setSize(width, width / 2);
document.getElementById('globeViz').appendChild(renderer.domElement);
const myScene = new THREE.Scene();
myScene.add(this.myGlobe);
myScene.add(new THREE.AmbientLight(0xbbbbbb));
myScene.add(new THREE.DirectionalLight(0xffffff, 0.6));
const camera = new THREE.PerspectiveCamera();
camera.aspect = 2; //window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
camera.translateZ(300);
const globeMaterial = new THREE.MeshPhongMaterial();
globeMaterial.bumpScale = 10;
new THREE.TextureLoader().load('//unpkg.com/three-globe/example/img/earth-water.png',
texture => {
globeMaterial.specularMap = texture;
globeMaterial.specular = new THREE.Color('grey');
globeMaterial.shininess = 15;
});
this.myGlobe.globeMaterial = globeMaterial;
new THREE.TextureLoader().load('https://tilecache.rainviewer.com/v2/radar/1652860800/4096/2/0_1.png',
cloudsTexture => {
const geo = new THREE.SphereBufferGeometry(this.myGlobe.getGlobeRadius() * (1 + 0.004), 80, 80);
const mesh = new THREE.MeshPhongMaterial({ map: cloudsTexture, transparent: true });
const weather = new THREE.Mesh(geo, mesh);
myScene.add(weather);
});
Correct placement:
In color (harder to see) to show apples-to-apples:
Incorrect placement when Globified:
I believe Marquizzo is correct in the comments, one of the projected images is rotated 90 degrees (plus or minus, but probably minus in your case) compared to the other. Since you said that your earth map is not rotated at all, this means the RainViewer map is.
This is consistent with how other NASA weather maps I recently projected on my own Earth globe had to be dealt with - in my case, the cloud cover simulation movie applied on the globe started with the prime meridian aka 0 degree of longitude to the left side of the image (instead of being positioned in the horizontal middle of the image as its customary in nearly all maps), and I'm guessing something similar is happening here, except for the direction of the angle needed to make it look right.
The assumption is supported by the fact that in your screenshots, the big orange spot that should be positioned close to the North American Great Lakes (i.e. 90 degrees West) is placed precisely on the prime meridian (i.e. 0 degrees of longitude). Yup, I know this thanks to my own globe... :)
To (partially, see below) fix this, you should construct your geometry so that the phiStart parameter of the constructor is set to the correct rotation angle, something like:
const geo = new THREE.SphereBufferGeometry(this.myGlobe.getGlobeRadius() * (1 + 0.004), 80, 80, - Math.PI / 2);
This will project the map starting from 90 degrees to the "left" as its left side, if this makes sense.
That being said, I don't think this is the entire extent of the issue, because that orange spot is also displaced at around 23 degrees of latitude North (i.e. at the Tropic of Cancer in your Globified screenshot) compared to the correct 46 degrees of latitude North (i.e. more or less where the left side of Lake Superior lies). This fits well with the fact that the projected image is a 1600 x 1600 px square, instead of an expected 1600 x 800 px rectangle, as the most probable cause of the latitudinal aka vertical displacement, so you might want to appropriately "crop" the RainViewer map to have the expected 2:1 horizontal to vertical size that's expected from a plane projection on a sphere. You could probably use the thetaStart and thetaLength parameters of the sphere geometry constructor to adjust things here as well, if that yields what you want.
Or, it might just be that both the longitudinal and latitudinal displacements are somehow caused by the usage of a 1600 x 1600 px square image source instead of a 1600 x 800 px one. The cause of the issue shouldn't affect the way it can be fixed though.
(Hello, it's my first ever post here)
here's what I'd like to incorporate in this simple example:
I would like to make the background turn from light to dark gradually when the user is closer to a particular orientation – in this case (example above) the desired orientation is a steep angle so that the foreshortened anamorphic image looks like a regular skull (the value of the background indicating the angle user should aim for – kind of like playing Hot and Cold)
when the user reaches the desired orientation (the background is then accordingly 100% dark) I would like it to lock rotation and trigger a video file in the background or a pop up window.
I assume it has to do with accessing the camera rotation values inside OrbitControls and setting some kind of an Event?? i have no idea how to access it.
Any kind of help, suggestions to edit the thread or explanation would be greatly appreciated, thank you so much in advance!
You could use camera.position to calculate the best vantage point. First, you have to figure out what the desired position is (I'm not sure how the wooden board is being placed, but this position seems to be close to: { x: 6.8, y: 0.6, z: -1.8})
var vantagePoint = new THREE.Vector3(6.8, 0.6, -1.8);
var distance = 100;
var normalized = 1;
var endColor = new THREE.Color(0xff9900);
var startColor = new THREE.Color(0x0099ff);
scene.background = startColor;
animate() {
distance = vantagePoint.distanceTo(camera.position);
normalized = THREE.Math.smoothstep(distance, 5, 100); // Converts [1, 100] => [0, 1]
// Resets the color on each frame
startColor.set(0x0099ff);
startColor.lerp(endColor, normalized);
}
The closer to 0 you are, the closer you are to seeing the skull. You can then use that value to change the color of scene.background. Anything beyond 10 and you're 'cold', and you get hotter as you approach 0.
https://threejs.org/docs/#api/en/math/Vector3.distanceTo
Update:
You can then transform the distance to a normalized value in the range of [0, 1] by using Math.smoothstep(). Then interpolate the value of the colors with this normalized value using Color.lerp
I have some values that I need to plot into a 2D HTML5 <canvas>. All values are in the range [-1, +1] so I decided to set a transformation (scale + displacement) on the canvas 2D-context before drawing:
var scale = Math.min(canvas.width, canvas.height) / 2;
ctx.setTransform(scale, 0, 0, scale, canvas.width / 2, canvas.height / 2);
Each value is drawn using the arc method, but since I want a fixed arc-radius (no matter what scaling is used) I'm dividing the radius with the current scale value:
ctx.arc(value.X, value.Y, 2 / scale, 0, 2 * Math.PI, false);
Now, a canvas of size 200 x 200 will result in scale factor of 100, which in turn results in a arc-radius of 0.02. Unfortunately, it seems that values like 0.2 or 0.02 don't make any difference to the resulting arc-radius, only the stroke thickness is changing.
You can see this behavior in the JsFiddle. Is this a bug or am I doing something wrong?
The issue is that after scaling by a huge factor your lines you now have a lineWidth far too big to be drawn correctly with stroke.
Just adjust the lineWidth to 1/scale before drawing, and all will work fine.
I've created a 3D map and I'm labelling points on this map through Sprites. This in itself works fine, except for the positioning of the sprite labels.
Because I'm creating a map the camera can tilt from 0 to 90 degrees, while ideally the label always stays some distance directly above the item it is labelling on the screen. But unfortunately, as sprites are always centred around their origin and that overlaps the item, I have to move the sprite up on the Y world axis and with that the centre location of the sprite changes as the camera is tilted. This looks weird if the item looked at is off centre, and doesn't work too well when the camera is looking straight down.
No jsfiddle handy, but my application at http://leeft.eu/starcitizen/ should give a good impression of what it looks like.
The code of THREE.SpritePlugin suggests to me it should be possible to use "matrixWorld" to shift the sprite some distance up on the screen's Y axis while rendering, but I can't work out how to use that, nor am I entirely sure that's what I need to use in the first place.
Is it possible to shift the sprites up on the screen while rendering, or perhaps change their origin? Or is there maybe some other way I can achieve the same effect?
Three.js r.67
As suggested by WestLangley, I've created a workable solution by changing the sprite position based on the viewing angle though it took me hours to work out the few lines of code needed to get the math working. I've updated my application too, so see that for a live demo.
With the tilt angle phi and the heading angle theta as computed from the camera in OrbitControls.js the following code computes a sprite offset that does exactly what I want it to:
// Given:
// phi = tilt; 0 = top down view, 1.48 = 85 degrees (almost head on)
// theta = heading; 0 = north, < 0 looking east, > 0 looking west
// Compute an "opposite" angle; note the 'YXZ' axis order is important
var euler = new THREE.Euler( phi + Math.PI / 2, theta, 0, 'YXZ' );
// Labels are positioned 5.5 units up the Y axis relative to its parent
var spriteOffset = new THREE.Vector3( 0, -5.5, 0 );
// Rotate the offset vector to be opposite to the camera
spriteOffset.applyMatrix4( new THREE.Matrix4().makeRotationFromEuler( euler ) );
scene.traverse( function ( object ) {
if ( ( object instanceof THREE.Sprite ) && object.userData.isLabel ) {
object.position.copy( spriteOffset );
}
} );
Note for anyone using this code: that the sprite labels are children of the object group they're referring to, and this only sets a local offset from that parent object.
I had a similar problem, but with flat sprites; I put trees on a map and wanted them to rotate in such a way that they'd rotate around their base, rather than their center. To do that, i simply edited the image files of the trees to be twice as tall, with the bottom as just a transparency:
http://imgur.com/ogFxyFw
if you turn the first image into a sprite, it'll rotate around the tree's center when the camera rotates. The second tree will rotate around it's base when the camera rotates.
For your application, if you resize the textbox in such a way that the center of it would be coincide with the star; perhaps by adding a few newlines or editing the height of the sprite
This is very much a hack, but if you will only use sprites in this way, and could tolerate a global change to how sprites were rendered, you could change the following line in the compiled three.js script:
Find (ctrl+F) THREE.SpritePlugin = function, and you'll see:
this.init = function ( renderer ) {
_gl = renderer.context;
_renderer = renderer;
vertices = new Float32Array( [
- 0.5, - 0.5, 0, 0,
0.5, - 0.5, 1, 0,
0.5, 0.5, 1, 1,
- 0.5, 0.5, 0, 1
] );
I changed the definition of the array to the following:
var vertices = new Float32Array( [
- 0.5, - 0.0, 0, 0,
0.5, - 0.0, 1, 0,
0.5, 1.0, 1, 1,
- 0.5, 1.0, 0, 1
] );
And now all my sprites render with the rotation origin at the bottom.
If you use the minified version, search for THREE.SpritePlugin=function and move the cursor right until you find the Float32Array defined, and make the same changes there.
Note: this changes how things render only when using WebGL. For the canvas renderer you'll have to play a function called renderSprite() in the THREE.CanvasRenderer. I suspect playing with these lines will do it:
var dist = 0.5 * Math.sqrt( scaleX * scaleX + scaleY * scaleY ); // allow for rotated sprite
_elemBox.min.set( v1.x - dist, v1.y - dist );
_elemBox.max.set( v1.x + dist, v1.y + dist );
This function will also be a lot more difficult to find in the minified version, since renderSprite() is not an outward facing function, it'll likely be renamed to something obscure and small.
Note 2: I did try making these modifications with "polyfills" (or rather, redefining the SpritePlugin after Three is defined), but it caused major problems with things not being properly defined for some reason. Scoping is also an issue with the "polyfill" method.
Note 3: My version of three.js is r69. So there may be differences above.