I'm currently working on my first three js project, and getting quite an education. But, I've hit a wall, and am seeking a generalized outline of what to do.
I have three images that I want to use as background images. I want them to crossfade at a specified interval... let's say every 5 seconds, the background crossfades to the next one. After the last background is displayed, crossfade into the first one, and so forth in a loop.
I've found a few examples where there's crossfading between two objects, like this fiddle, but that seems to depend on having two cameras. I've taken other examples I've found as far as I could, nothing worthy of posting.
I don't understand enough about three, which is why I'm seeking help. If someone could help me define my approach, that would be fantastic. Should I be altering the opacity of my meshes? Doing something with shaders? Something else?
Here, at least, is how I'm adding one background:
camera = new THREE.PerspectiveCamera( 75, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 10000 );
camera.position.z = 450;
scene = new THREE.Scene();
// Load the background texture
var summerTexture = THREE.ImageUtils.loadTexture( 'tree-animation/images/summer.png' );
summerMesh = new THREE.Mesh(
new THREE.PlaneGeometry(2, 2, 0),
new THREE.MeshBasicMaterial({
map: summerTexture,
}));
summerMesh.material.depthTest = false;
summerMesh.material.depthWrite = false;
backgroundCamera = new THREE.Camera();
summerScene = new THREE.Scene();
summerScene.add(backgroundCamera);
summerScene.add(summerMesh);
Any direction would be most appreciated!
This can be achieved by writing a custom shader and using the mix() or smooth-step() function between the images and add a clock to your render loop to update the shader uniforms to manipulate the transition in your shader over time.
Here is an example of a static blend of textures but can easily intergrated into your own project:
http://stemkoski.github.io/Three.js/Shader-Heightmap-Textures.html
check the frag shader
Related
I'm working on an app where I visualize ATV trails in a 3d perspective (NAIP imagery draped over elevation data). I am using three.js for the rendering engine.
In the above image, the white line you see is just a THREE.Line instance, where I convert a trails gps coordinates into threejs coordinates. I'd like to add more of 3d perspective to this line. I tried implementing a THREE.TubeGeometry where the path was a THREE.CatmullRomCurve3 using the same Vector3 points as how I built the line you see in the image above. That did not produce a desirable result...
From the many, many THREE examples I have looked at, I really think an extruded geometry would achieve the look I am after... But I cant for the life of me figure out how to extrude a geometry for the line. Any suggestions/thoughts?
UPDATE 1:
Here is my desired look (same trail - no imagery). This image was produced in QGIS using the Q2Threejs plugin
UPDATE 2: Here is a code of how I have attempted to create a tubegeometry. Maybe I am messing something up in there...
// trailVectors are an array of Vector3 - same as ones used to create line
var trailCurve = new THREE.CatmullRomCurve3(trailVectors);
var tubeGeometry = new THREE.TubeGeometry(trailCurve,80,1,15,false);
var material = new THREE.MeshBasicMaterial({color:0x00ff00});
var tubeMesh = new THREE.Mesh(tubeGeometry,material);
var wireframeMaterial = new THREE.LineBasicMaterial({color:0xffffff,lineWidth:2});
var wireframe = new THREE.Mesh(tubeGeometry,wireframeMaterial);
tubeMesh.add(wireframe);
scene.add(tubeMesh);
UPDATE 3
THREE.TubeGeometry(trailCurve,80,4,2,false) per mzartman request
I think that you should be able to achieve what you want with a TubeGeometry. I think the big thing is that your example (from the picture shown) has more than 2 radius segments. That gives it the tubular shape and makes it look sort of like a blob. If you set the radial segment count to 2 (as it's shown below) then I think it would look a lot better.
tubeGeometry = new THREE.TubeBufferGeometry(
[YOUR_PATH_HERE],
params.extrusionSegments, // <--- Edit this for higher resolution on the spline
3, // <--- This defines the height
2, // <--- This 2 keeps 2D (i.e. not a tube!!!!)
true );
var mesh = new THREE.Mesh( geometry, material );
var wireframe = new THREE.Mesh( geometry, wireframeMaterial );
mesh.add( wireframe );
scene.add( mesh );
Update:
I think that you might do better with a material that shows some shadow like the MeshPhong. Also, to do the wireframe you want to add it as an option in the material initialization. Give it a show with the following:
var tubeGeometry = new THREE.TubeGeometry(curve,80,1,2,false);
var material = new THREE.MeshPhongMaterial({color:0x00ff00, wireframe: true});
var tubeMesh = new THREE.Mesh(tubeGeometry,material);
scene.add(tubeMesh);
I am a newbie in Three js. In my project, I need draw a ground with a lot of texture. The ground has many layers, every layer has 4 textures and textures in different layers are different size. Below picture describe the ground:
Ground is one mesh has multiple material:
this.mesh = new THREE.Mesh(geometry, new THREE.MultiMaterial(materials));
Suppose I have a car it always at center of ground, in other word, center of all layers. When it move, the ground will translate to make sure the car always at center. So everytime ground translate, I need to update texture in new position.
The picture draw 3 layers for illustration, but in my project is 6 layers. So everytime all texture change, that means need to change 6 * 4 = 24 textures, and that cause low fps in my program.
This is my function to load texture from indexed DB every time a texture change:
Ground.prototype.loadTextureFromIndexedDB = function (url, materialIndex) {
var loader = new THREE.TextureLoader();
loader.crossOrigin = '';
loader.load(url,
function (texture) {
var groundMaterial = ground.mesh.material.materials[materialIndex];
groundMaterial.map.dispose();
groundMaterial.map = texture;
groundMaterial.map.anisotropy = ground.maxAnisotropy;
groundMaterial.map.minFilter = THREE.LinearFilter;
groundMaterial.map.needsUpdate = true;
img = null;
window.URL.revokeObjectURL(url);
});
}
I have tried many solutions. One of them is make a mesh with a BufferGeometry and MultiMaterial with array of ShaderMaterial. As what I known, it is the best for performance in THREE JS, isn't it? If it is then maybe THREE JS is not powerful as I thinked. Should I change to another API for my project?
Anyone suggest me any solution to make higher performance in my program? Thanks a lot!
I have some code similar to the following...
this.texture = new THREE.ImageUtils.loadTexture( 'spritesheet.png' );
this.material = new THREE.MeshBasicMaterial( { map: this.texture, side:THREE.DoubleSide } );
this.geometry = new THREE.PlaneGeometry(32, 32, 1, 1);
this.sprite = new THREE.Mesh( this.geometry, this.material );
game.scene.add( this.sprite );
I've also tried along the lines of...
this.material = new THREE.SpriteMaterial( {
map: image,
useScreenCoordinates: true,
alignment: THREE.SpriteAlignment.center
} );
this.sprite = new THREE.Sprite( this.material );
These display the full spritesheet (sort of), as I would expect without further settings.
How do I align the sprite so it only displays say 32x32px starting at offset 50,60 for example ? The three.js documentation doesn't seem have much information, and the examples I've seen tend to use one image per sprite (which may be preferable, or only way possible ?)
Edit: I've spotted a material uvOffset and uvScale that I suspect is related to alignment in a Sprite object if anyone knows how these work. Will dig further.
Well, there is a "uvOffset" and "uvScale" parameter in spriteMaterial , i think you could use those but I cannot present any source code to you.
What you can of course do is using PlaneGeometry and calculate UV Coordinates for the 2 triangles (the plane). For example top-left is your offset and bottom right is calculated from a given offset and size (32x32) but using the whole image size in pixels to get the UV coordinates between 0 and 1
for example topleft is (50/imageSize, 60/imagesize) and bottom right is ( (50+32)/imgSize, (60+32)/imgSize). I think this should work, although i am not quite sure if you would get the result you want as OpenGL treats images "up side down". But you can try and go on from here. Hope this helps.
I use CubeCamera to build a simple reflection model. The setup can be seen on the picture below.
If the camera is close enough to the cube - the reflection looks fine. However, if i move away from the objects - the reflection just gets bigger. See the picture below.
This is not the way i want it. I'd like the reflection to proportionally get smaller. I tried to play with different settings, then I thought this could be achieved using a proper shader program (just squish the cube texture, kind of), so i've tried to mess with the existing PhongShader, but no luck there, i'm too newbie to this.
Also, i've noticed that if i change the width and height of the cubeCamera.renderTarget, i.e.
cubeCamera.renderTarget.width = cubeCamera.renderTarget.height = 150;
i can get the proper dimensions of the reflection, but its position on the surface is wrong. It's visible from the angle presented on the picture below, but not visible if i place the camera straight. Looks like the texture needs to be centered.
The actual code is pretty straightforward:
var cubeCamera = new THREE.CubeCamera(1, 520, 512);
cubeCamera.position.set(0, 1, 0);
cubeCamera.renderTarget.format = THREE.RGBAFormat;
scene.add(cubeCamera);
var reflectorObj = new THREE.Mesh(
new THREE.CubeGeometry(20, 20, 20),
new THREE.MeshPhongMaterial({
envMap: cubeCamera.renderTarget,
reflectivity: 0.3
})
);
reflectorObj.position.set(0, 0, 0);
scene.add(reflectorObj);
var reflectionObj = new THREE.Mesh(
new THREE.SphereGeometry(5),
new THREE.MeshBasicMaterial({
color: 0x00ff00
})
);
reflectionObj.position.set(0, -5, 20);
scene.add(reflectionObj);
function animate () {
reflectorObj.visible = false;
cubeCamera.updateCubeMap(renderer, scene);
reflectorObj.visible = true;
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
Appreciate any help!
Environment mapping in three.js is based on the assumption that the object being reflected is "infinitely" far away from the reflective surface.
The reflected ray used in the environment map look-up does not emanate from the surface of the reflective material, but from the CubeCamera's center. This approximation is OK, as long as the reflected object is sufficiently far away. In your case it is not.
You can read more about this topic in this tutorial.
three.js r.58
I would like somebody to explain me how I can achieve the blue semi-transparent intermittent sphere of this example: (the one next to the intermittent red sphere)
http://threejs.org/examples/webgl_materials.html
I believe in first place that this is a matter of using the right material with the right settings (specially because the example is about materials) but not sure anyway.
Hopefully you do not feel my question does not deserve to be made here. I was trying to analyze it but definitely it is written in a non-friendly way for newbies, and I've not been able to separate this part from the rest, not I find an explanation anywhere else.
To create, for example, a partially transparent blue sphere, you could try:
var sphereGeom = new THREE.SphereGeometry( 40, 32, 16 );
var blueMaterial = new THREE.MeshBasicMaterial( { color: 0x0000ff, transparent: true, opacity: 0.5 } );
var sphere = new THREE.Mesh( sphereGeom, blueMaterial );
For more examples of creating semi-transparent materials, check out
http://stemkoski.github.io/Three.js/Translucence.html
If you want the sphere to fade in and out, you can change the transparency in your update or render function -- make the sphere a global object, also create a (global) clock object to keep track of the time in your initialization, for example, with
clock = new THREE.Clock();
and then in your update, you could, for example, write
sphere.material.opacity = 0.5 * (1 + Math.sin( clock.getElapsedTime() ) );