three.js transparent maps issue - javascript

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.

Related

How to make colorful round particles in Three.js?

I've been trying to render rounded particles using THREE.PointsMaterial and passing canvas texture in map parameter. Works fine, but I don't know how to use vertexColors to make every particle has own color.
In short:
This code renders colorful square particles:
var material = new THREE.PointsMaterial({
vertexColors: THREE.VertexColors,
});
And this renders one-color round particles:
var material = new THREE.PointsMaterial({
vertexColors: THREE.VertexColors,
map: createCanvasTexture(), // returns texture painted on Canvas
});
Is there any way to pass vertexColors to map?
Or should I use vertexShader+fragmentShader?
(Probably good solution when I need to animate position as well).
But how to pass the colors in there?

Threejs - Maintain aspect ratio while adding texture map to threejs object

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);

Three.js: Combine materials on a single face of cube (that uses multiple materials)

I have created a cube (skybox) that uses different materials for each side. There is no problem with that using MeshFaceMaterial:
var imagePrefix = "images-nissan/pano_";
var imageDirections = ["xpos", "xneg", "ypos", "yneg", "zpos", "zneg"];
var imageSuffix = ".png";
var skyGeometry = new THREE.BoxGeometry(1, 1, 1);
var materialArray = [];
for (var i = 0; i < 6; i++) {
materialArray.push(new THREE.MeshBasicMaterial({
map: THREE.ImageUtils.loadTexture(imagePrefix + imageDirections[i] + imageSuffix),
side: THREE.BackSide
}));
}
var skyMaterial = new THREE.MeshFaceMaterial(materialArray);
var skyBox = new THREE.Mesh(skyGeometry, skyMaterial);
skyBox.name = "interiorMesh";
scene.add(skyBox);
However, now I would like to add a material to one of the faces of the cube and combine the materials on this face of the cube.
So basically I would have one material on 5 faces and 2 materials on 1 face of the cube - I want to overlay that 'original' texture with another transparent png so it covers only a specific part of the original image. Both images have the same dimensions, only the new one is partially transparent. Is it even possible to do with CubeGeometry? Or do I need to do it with planes? Any help greatly appreciated!
You can for sure change material of one of faces. You cannot use two materials for one face though.
I would recommend creating additional texture as combination of previous two, making it into separate material and assign it to sixth face of the cube when needed. If it is possible, merge those images beforehand in your graphic editor of choice. If you can only do it in runtime, you will either have to use canvas to merge them or shader as recommended by #beiller.
I wouldn't recommend transparent planes, transparency can be very tricky sometimes and render in a weird way.
something similar is discussed here - Multiple transparent textures on the same mesh face in Three.js

How do you use textures with transparency in three.js?

I would like to assemble a group of meshes like this:
The black outlined rectangles represent how I would like to assemble them. I have 8 pieces, 4 edges, and 4 corners, as textures (with transparency). Then, I have a 9th texture that I would like to have underneath the others, and that one is represented by the purple area. The geometries seem to be good, and the texture images are 16x16 pngs. First, I tried the basic approach with just MeshBasicMaterial, and I get my rectangles, but not my textures. Following some advice seen elsewhere on SO I tried something like this:
material = new THREE.MeshBasicMaterial({
transparent: true,
map: texture
});
material.needsUpdate = true;
var materials = [];
materials.push(material);
materials.push(new THREE.MeshBasicMaterial({
color: 0x000000,
wireframe: true,
transparent: true
}));
mesh = THREE.SceneUtils.createMultiMaterialObject(geom, materials);
But this did not work either. I've also tried using the ShaderMaterial but I guess I do not get GLSL well enough yet to make it work. How in the world do I get transparent png textures to map onto ShapeGeometries?

THREE.js - How to fade the background?

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

Categories