I'm trying to recreate the effect of fading the drawing buffer and leaving trails of the drawn objects, instead of clearing it every frame. It's a pretty simple effect that in 2D would be done like this: http://jsfiddle.net/faRW3/1/
// draw stuff
c.fillStyle = "red";
c.fillRect(Math.sin( time )*50+70, Math.cos( time )*50+70, 20, 20);
// fade background
c.fillStyle = "rgba(255, 255, 255, 0.25)";
c.fillRect(0, 0, canvas.width, canvas.height);
But I haven't found the way to do it in WebGL, especially using Three.js. I tried to do it by setting preserveDrawingBuffer to true and playing with the Effect Composer but haven't been successful.
I would appreciate any advice.
One way is to place a transparent plane behind the scene and set preserveDrawingBuffer = true.
renderer = new THREE.WebGLRenderer( { preserveDrawingBuffer: true } );
renderer.autoClearColor = false;
// background plane
var plane = new THREE.Mesh( new THREE.PlaneGeometry( 100, 100 ), new THREE.MeshBasicMaterial( { transparent: true, opacity: 0.1 } ) );
plane.position.z = -10;
scene.add( plane );
For a live example see: http://vincemckelvie.com/Potluck/Cartwheel/
three.js r.64
The technique described by WestLangley works very well, but if you want more control over your motion trails you can also use WebGLRenderTarget.
You might have noticed for example that setting the opacity of the plane to values lower than 0.1 results in permanent stains on the screen. With render targets it is possible to fix that.
The technique requires three scenes and three textures:
sceneContent contains cube
sceneComp contains quadComp with material (textureNew + textureOld)
sceneScreen contains quadScreen with material (textureComp)
And they should be rendered like this:
render sceneContent, cameraPerspective onto textureNew
render sceneComp, cameraOrto onto textureComp
render sceneScreen, cameraOrto onto textureOld
render sceneScreen, cameraOrto onto screen
There is no need to set autoClear to false or preserveDrawingBuffer to true.
For a live example see: https://codepen.io/brunoimbrizi/pen/MoRJaN
Related
I have been creating a simple Three.js application and so far I have a centered text in the scene that shows "Hello World". I have been copying the code examples to try and understand what is happening and so far Ihave it working but I am failing to completely understand why.
My confusion comes from reading all the Three.js tutorials describing that a Geometry object is responsible for creating the shape of the object in the scene. Therefore I did not think it would not make sense to have a position on something that is describing the shape of the mesh.
/* Create the scene Text */
let loader = new THREE.FontLoader();
loader.load( 'fonts/helvetiker_regular.typeface.json', function (font) {
/* Create the geometry */
let geometry_text = new THREE.TextGeometry( "Hello World", {
font: font,
size: 5,
height: 1,
});
/* Create a bounding box in order to calculate the center position of the created text */
geometry_text.computeBoundingBox();
let x_mid = geometry_text.boundingBox.max.x - geometry_text.boundingBox.min.x;
geometry_text.translate(-0.5 * x_mid, 0, 0); // Center the text by offsetting half the width
/* Currently using basic material because I do not have a light, Phong will be black */
let material_text = new THREE.MeshBasicMaterial({
color: new THREE.Color( 0x006699 )
});
let textMesh = new THREE.Mesh(geometry_text, material_text);
textMesh.position.set(0, 0, -20);
//debugger;
scene.add(textMesh);
console.log('added mesh')
} );
Here is the code that I use to add to shape and my confusion comes from the following steps.
/* Create a bounding box in order to calculate the center position of the created text */
geometry_text.computeBoundingBox();
let x_mid = geometry_text.boundingBox.max.x - geometry_text.boundingBox.min.x;
geometry_text.translate(-0.5 * x_mid, 0, 0); // Center the text by offsetting half the width
First, we translate the geometry to the left to center the text inside the scene.
let textMesh = new THREE.Mesh(geometry_text, material_text);
textMesh.position.set(0, 0, -20);
Secondly, we set the position of the mesh.
My confusion comes from the fact that we need both of these operations to occur to move the mesh backwards and become centered.
However I do not understand why these operations should be done of the geometry, infact what confuses me more is that why does textMesh.position.set(0, 0, -20); not override my previously performed translation and simply move the mesh to (0,0,-20). removing my previous translation. It seems that both are required.
AFAIK it is recommended (in scenegraph) to transform (translate, rotate, scale) the whole mesh (with simple) rather than prepare transformed geometry and use it to create "untransformed" mesh, since the mesh in second case is not transform-friendly. Basically "cumulative" transform will be just illegal, giving wrong, unexpected results. Even simple movement.
But sometimes it is useful to create transformed geometry and use it for some algos/computations or in meshes.
You are getting somehow "expected" results in your "combined transform" case because it is just particular case (for example it can work only if object position is (0, 0, 0) etc)
mesh.position.set doesn't modify geometry: it is only a property of mesh and it is used to compute final mesh triangles. This computation involves geometry and object matrix which is composed from object position, object quaternion (3D-rotation) and object scale. Object's geometry can be modified by "matrix" operations but none of such operations are performed dynamically by mesh.
We want to create a 3d shoe designing tool, where you can design patterns and upload them to the shoe.
I am trying to place an image on a Threejs material. I am able to update the map, but the texture is blurry. I am new to Threejs, so I do not have concepts clear. I don't understand if aspect ratio is the issue or something else.
This how I am loading texture:
var texture_loader = new THREE.TextureLoader();
var texture = texture_loader.load( 'https://ik.imagekit.io/toesmith/pexels-photo-414612_D4wydSedY.jpg', function ( texture ) {
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.offset.set( 0, 0 );
texture.repeat.set( 1, 1 );
vamp.material = new THREE.MeshPhongMaterial({
map: texture,
color: new THREE.Color('#f2f2f2'),
shininess: 20,
});
});
This is what I am getting
But the expected behavior should be
If anyone could help, that would be great. Thanks
Here is the link to the Codepen code
The problem is that your UVs are occupying a very small area in texture coordinates. As they are now, it looks like your UVs are taking up this much room (see red area):
And that's why it gives the impression that your texture is blurry. What you need to do is make your UVs take up more space, like this:
There are 2 ways to achieve this.
Scale UVs up: Import your model into Blender, and change the UV mapping of the mesh to occupy more of the [0, 1] range.
Scale texture down: You could get creative with the texture.repeat property and use it to scale down your texture to match your existing UVs. Then you'd need to offset it so it's centered correctly. Something like:
texture.repeat = new THREE.Vector2(10, 10);
texture.offset = new THREE.Vector2(xx, yy);
I'm trying to use Three.js to generate some points with Three.Points, and then make the points themselves revolve around a single point (or mesh). I've generated the points randomly in a cylinder region as mentioned in this answer and reviewed posts such as this one, which doesn't seem to work as it's rotating a mesh around a mesh.
Here's what I've got so far:
//Mesh that is to be revolved around
const blackHoleGeometry = new THREE.SphereGeometry(10, 64, 64);
const blackHoleMaterial = new THREE.MeshBasicMaterial({
color: 0x000000
});
const blackHole = new THREE.Mesh(blackHoleGeometry, blackHoleMaterial);
scene.add(blackHole);
//Points that are supposed to revolve around the mesh
const particles = new THREE.PointsMaterial({
color: 0xffffff
});
const geometry = new THREE.Geometry();
// [...] code to generate random points
const pointCloud = new THREE.Points(geometry, particles);
pointCloud.rotation.x = Math.PI / 2; //to rotate it 90*
You can see a full demo here. How can I have the points all revolve around the sphere mesh, as in each vertex of the point "cloud"'s geometry revolving around a center point, or the mesh like a planet and a star?
Couple problems with you code, but here is an updated fiddle for you: https://jsfiddle.net/pwwkght0/2/
So when you create your Three.js scene you want to keep all of your code in the init function. So I moved everything in there and then I called init outside of the variable. When you do this, init will create you scene until it reaches the last line and call animate. You want to call animate instead of render because animate will request animation frames and call render on each.
function init() {
//do all the things to make the scene
function animate() {
requestAnimationFrame(animate);
orbit();
controls.update();
render();
}
function render() {
renderer.render(scene, camera);
}
animate();
}
init()
So now that you are requesting animation frames, it's time to make things orbit. I made a very simple function to grab your point cloud and rotate it on its z-axis, to simulate it rotating around the sphere. Notice how orbit is called in animate:
function orbit() {
pointCloud.rotation.z += 0.01;
}
You can take this a step further and have each point rotate at a different speed around the sphere by accessing pointCloud's children property.
I have been following this tutorial, creating a Cube with a texture.
The problem is, the texture repeats on every face of the cube.
I would like to use a single texture that 'wraps' around the cube. Is this possible?
// material
var material = new THREE.MeshLambertMaterial({
map: THREE.ImageUtils.loadTexture('http://www.html5canvastutorials.com/demos/assets/crate.jpg')
});
// this has no effect!
material.wrapAround = true;
// cube
var cube = new THREE.Mesh(new THREE.CubeGeometry(200, 200, 200), material);
cube.overdraw = true;
cube.rotation.x = Math.PI * 0.1;
scene.add(cube);
Typically, with a THREE.CubeGeometry, you can either:
(1) Choose a single texture that repeats on each side of the cube, or
(2) Have a different texture for each of the six sides
You can also use repeat the number of times a texture is displayed on each side.
For examples of each of these, check out the source code of the demos at:
http://stemkoski.github.io/Three.js/Textures.html
and
http://stemkoski.github.io/Three.js/Texture-Repeat.html
Hope this helps!
I'm creating loads of particles (80.000 to be exact) and I have set a transparent map, though, not all particles are transparent.
I'm using a transparent PNG image: (it's barely visible but it's there alright) as the material map, though it shows a black background as seen here:
If you look closely, some particles blend together well (no overlapping black edges) though some do not. Could it be because there are so many overlapping transparent objects or shouldn't this be an issue?
Here's the snippet responsible for the generation of my particles:
// load the texture
var map = THREE.ImageUtils.loadTexture('img/particle.png');
// create temp variables
var geometry, material;
// create an array with ParticleSystems (I need multiple systems because I have different colours, thus different materials)
var systems = [];
// Loop through every colour
for(var i = 0; i < colors.length; i++) {
// Create a new geometry
geometry = new THREE.Geometry();
// create a new material
material = new THREE.ParticleBasicMaterial({
color: colors[i],
size: 20,
map: map, // set the map here
transparent: true // transparency is enabled!!!
});
// create a new particle system
systems[i] = new THREE.ParticleSystem(geometry, material);
// add the system to the scene
scene.add(systems[i]);
}
// vertices are added to the ParticleSystems' geometry here
Why do some of the particles have a black background?
You can set the alphaTest property of the material instead of transparency. For example,
material.alphaTest = 0.5;
material.transparent = false;
three.js no longer sorts particles; they are rendered in the order they appear in the buffer.
three.js r.85
Those particles with black corners are rendered before anything behind them. So GL doesn't know yet there is something behind to blend. In order to make it look right you have to render these particles in the order of their z coordinates from back to front.
Disable the depthWrite attribute on the material.
// create a new material
material = new THREE.ParticleBasicMaterial({
color: colors[i],
size: 20,
map: map,
transparent: true,
depthWrite: false,
});
Try webgl_particles_billboards.html.
If I'm right it does the same thing you expect.