remove square border from texture (three.js) - javascript

I am using threejs and trying to create a star system by using the following code:
// create the particle variables
//var particleCount = 180000,
var particles = new THREE.Geometry();
var multiplyingFactor = 50;
// now create the individual particles
for (var p = 0; p < array.length; p++) {
//the star from the csv file
star = array[p];
// initialize the particle with the star's information.
particle = new THREE.Vector3(star.x * multiplyingFactor, star.y * multiplyingFactor, star.z * multiplyingFactor);
// add it to the geometry
particles.vertices.push(particle);
}
// var pMaterial = new THREE.PointsMaterial({
// color: 0xFFFFFF,
// size: 20,
// map: THREE.ImageUtils.loadTexture("http://localhost:8080/images/circle.png"),
// blending: THREE.AdditiveBlending,
// transparent: true
// });
// instantiate a loader
var loader = new THREE.TextureLoader();
//allow cross origin loading
loader.crossOrigin = '';
// load a resource
loader.load('http://localhost:8080/images/circle.png',
// Function when resource is loaded
function (texture) {
var pMaterial = new THREE.PointsMaterial({
color: 0xFFFFFF,
size: 20,
map: texture,
blending: THREE.AdditiveBlending,
transparent: true
});
// create the particle system
particleSystem = new THREE.Points(
particles,
pMaterial);
// also update the particle system to
// sort the particles |which enables
// the behaviour we want
particleSystem.sortParticles = true;
scene.add(particleSystem);
}
);
It works correctly, however the texture is loaded as a square even though the image I am using for it is a white circle (not visible here in stack overflow but you can click over it):
However, once it loads, every vector in the system has black edges visible when over imposed:
My question is:
How can I get rid of those black edges? is it possible?

You can use alphaTest to discard unwanted fragments like so:
var pMaterial = new THREE.PointsMaterial( {
color: 0xffffff,
size: 20,
map: texture,
alphaTest: 0.5,
transparent: false // only set to true if it is required for your texture
} );
Also, only set the material blending property if you specifically want to change it from the default.
three.js r.85

Related

Three.js Multiple Materials in Plane Geometry

I am trying to use a single plane to show multiple materials. I am currently using the MultiMaterial with the materials I plan to use inside of (textured).
The issue I am having is that the materials I use seem to get split across the entire plane into little chunks for each face. However I would like to have a material cover a 1 / n amount of the plane/mesh.
My current code (shortened):
var splitX = 2;
var splitY = 2;
var geometry = new THREE.PlaneGeometry(800, 800, splitX, splitY);
var materials = [
new THREE.MeshBasicMaterial({
map: preloaded texture..., side: THREE.DoubleSide
}),
new THREE.MeshBasicMaterial({
color: 0xff0000, side: THREE.DoubleSide
})
];
// set a single square inside the plane to the desired textured material
geometry.faces[0].materialIndex = 0;
geometry.faces[1].materialIndex = 0;
// set the other squares inside the plane to use the coloured material
for(var i = 1; i < geometry.faces.length / 2; i++) {
geometry.faces[i * 2].materialIndex = 1;
geometry.faces[i * 2 + 1].materialIndex = 1;
}
var mesh = new THREE.Mesh(geometry, new THREE.MultiMaterial(materials));
scene.add(mesh);
The output: http://prnt.sc/e8un2a
I marked each corner of the texture to see whether it would show the entire texture in the 2 faces I specified and it did not. Any help would be appreciated to resolve this! :)

Three.js: how to properly apply texture on TorusGeometry

I'm trying to create a three-dimensional compass, that also displays roll and pitch. In order to show the roll (in degrees), I need to apply a texture with numbers to a TorusMaterial. How can I get it on in such a way that the scale is (somewhat) retained?
The black ring in the picture below (around the compass) is the TorusGeometry. The other attached picture is the texture.
Code:
var geometry = new THREE.TorusGeometry(2.41, 0.2, 50, 50);
// var material = new THREE.MeshBasicMaterial({ color: 0x000000, wireframe: false });
var material = new THREE.MeshPhongMaterial();
material.map = THREE.ImageUtils.loadTexture('styles/quarters.png');
var torus = new THREE.Mesh(geometry, material);
scene.add(torus);
Screenshot:
Texture

Three.js removing inner faces

I am merging multiple cubes into different block shapes with three.js using THREE.GeometryUtils.merge. I want to make these block shapes transparent, but when it's transparent you can see that it's multiple cubes stuck together like this:
How do I make my merged cubes transparent without rendering the inside edges? (how do I remove the inner faces?)
My code that merges the cubes:
geometry = new THREE.CubeGeometry(STEP_SIZE, STEP_SIZE, STEP_SIZE);
for (i = 0; i < shape.length; i++) {
tmpGeometry = new THREE.Mesh(new THREE.CubeGeometry(STEP_SIZE, STEP_SIZE, STEP_SIZE));
tmpGeometry.position.x = STEP_SIZE * shape[i].x;
tmpGeometry.position.y = STEP_SIZE * shape[i].y;
THREE.GeometryUtils.merge(geometry, tmpGeometry);
}
block = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({ color: 0x0000ff, opacity: 0.5, transparent: true }));
After some experimenting I finally got what I wanted. Hope this will help other people.
I go through each face of the block and raycast the block itself using the face's centroid and inverted normal (so that the normal points inward). If it intersects with another face that's part of the block, we know that that face is an inner face and we can go ahead and remove it.
// block is a Three.Mesh object
function removeInternalFaces(block) {
var geometry = block.geometry;
var face;
var toDelete = [];
var blockRaycaster = new THREE.Raycaster();
// raycast itself from the center of each face (negated normal), and whichever face gets intersected
// is an inner face
for (i = 0; i < geometry.faces.length; i++) {
face = geometry.faces[i];
if (face) {
normal = face.normal.clone();
normal.negate();
blockRaycaster.set(face.centroid, normal);
intersects = blockRaycaster.intersectObject(block);
for (j = 0; j < intersects.length; j++) {
toDelete.push(intersects[j].faceIndex);
}
}
}
// actually delete them
for (i = 0; i < toDelete.length; i++) {
delete geometry.faces[toDelete[i]];
}
geometry.faces = geometry.faces.filter( function(v) { return v; });
geometry.elementsNeedUpdate = true; // update faces
}
You can actually initialize cube's each face material separately and individually set the opacity of the inner faces to 0. The Code will be something like this.
var materialArray = [];
materialArray.push(new THREE.MeshLambertMaterial({
opacity:0,
color:0x0000FF,
transparent: true
}));// assuming you want this face to be transparent
materialArray.push(new THREE.MeshLambertMaterial({
opacity:0,
color:0x0000FF,
transparent: true
}));// assuming you want this face to be transparent
materialArray.push(new THREE.MeshLambertMaterial({
opacity:0.5,
color:0x0000FF,
transparent: true
}));
materialArray.push(new THREE.MeshLambertMaterial({
opacity:0.5,
color:0x0000FF,
transparent: true
}));
materialArray.push(new THREE.MeshLambertMaterial({
opacity:0.5,
color:0x0000FF,
transparent: true
}));
materialArray.push(new THREE.MeshLambertMaterial({
opacity:0.5,
color:0x0000FF,
transparent: true
}));
var CubeMat = new THREE.MeshFaceMaterial(materialArray);
and pass this to your cube mesh something like this.
block = new THREE.Mesh(geometry,CubeMat )
check this JsFiddle for a demo

Three.js - bind a texture to particle

My question is how can I bind texture to a particle in
use of THREE.ParticleCanvasMaterial ?
I mean what is the syntax to bind texture to particle?
You should try to use a ParticleBasicMaterial and pass in your Texture as the map property of the material:
var material = new THREE.ParticleBasicMaterial( { map: THREE.ImageUtils.loadTexture( 'yourTexture.png' ) } );
Also, have a look at the canvas_particle_sprites example. Notice that it's generating a texture on the fly, but you can load your own texture as described above. From experience, the CanvasRenderer is slow with many/large textures.
Update 2019: ParticleBasicMaterial is deprecated
ParticleBasicMaterial has been renamed to PointsMaterial.
https://threejs.org/docs/#api/en/deprecated/DeprecatedList
You need to use PointsMaterial instead of ParticleBasicMaterial
var snowMaterial = new THREE.PointsMaterial({
size: 7,
blending: THREE.AdditiveBlending,
map: new THREE.TextureLoader().load("./assets/snowflake.png"),
//createCircleTexture("#ffffff", 20),
transparent: true,
depthWrite: false
});
Alternatively you can use canvas to draw Circular shapes for particle texture as suggest by George:
export const createCircleTexture = (color, size) => {
var matCanvas = document.createElement("canvas");
matCanvas.width = matCanvas.height = size;
var matContext = matCanvas.getContext("2d");
// create texture object from canvas.
var texture = new THREE.Texture(matCanvas);
// Draw a circle
var center = size / 2;
matContext.beginPath();
matContext.arc(center, center, size / 2, 0, 2 * Math.PI, false);
matContext.closePath();
matContext.fillStyle = color;
matContext.fill();
// need to set needsUpdate
texture.needsUpdate = true;
// return a texture made from the canvas
return texture;
};
Test Image
Result

How can I bind two shapes together as one in Three.js?

Can I bind two different shapes together as one shape?
For example, binding sphere and cylinder together as one?
Kind of, yes. There are multiple options:
via hierarchy you can simply add one mesh to another using the add() function
via the GeometryUtil's merge() function to merge vertices and meshes of two Geometry objects into one
using a basic 3D editor that supports Boolean operations between meshes and exporting.
Method 1 is pretty straightforward:
var sphere = new THREE.Mesh(new THREE.SphereGeometry(100, 16, 12), new THREE.MeshLambertMaterial({ color: 0x2D303D, wireframe: true, shading: THREE.FlatShading }));
var cylinder = new THREE.Mesh(new THREE.CylinderGeometry(100, 100, 200, 16, 4, false), new THREE.MeshLambertMaterial({ color: 0x2D303D, wireframe: true, shading: THREE.FlatShading } ));
cylinder.position.y = -100;
scene.add(sphere);
scene.add(cylinder);
Notice that 16 is repeated, so the subdivisions level in one mesh matches the other (for a decent look).
Method 2.1 - via GeometryUtils
// Make a sphere
var sg = new THREE.SphereGeometry(100, 16, 12);
// Make a cylinder - ideally the segmentation would be similar to predictable results
var cg = new THREE.CylinderGeometry(100, 100, 200, 16, 4, false);
// Move vertices down for cylinder, so it maches half the sphere - offset pivot
for(var i = 0 ; i < cg.vertices.length; i++)
cg.vertices[i].position.y -= 100;
// Merge meshes
THREE.GeometryUtils.merge(sg, cg);
var mesh = new THREE.Mesh(sg, new THREE.MeshLambertMaterial({ color: 0x2D303D, wireframe: true, shading: THREE.FlatShading }));
scene.add(mesh);
Method 2.2 merging a Lathe half-sphere and a cylinder:
var pts = []; // Points array
var detail = .1; // Half-circle detail - how many angle increments will be used to generate points
var radius = 100; // Radius for half_sphere
var total = Math.PI * .51;
for(var angle = 0.0; angle < total ; angle+= detail) // Loop from 0.0 radians to PI (0 - 180 degrees)
pts.push(new THREE.Vector3(0,Math.cos(angle) * radius,Math.sin(angle) * radius)); // Angle/radius to x,z
var lathe = new THREE.LatheGeometry(pts, 16); // Create the lathe with 12 radial repetitions of the profile
// Rotate vertices in lathe geometry by 90 degrees
var rx90 = new THREE.Matrix4();
rx90.setRotationFromEuler(new THREE.Vector3(-Math.PI * .5, 0, 0));
lathe.applyMatrix(rx90);
// Make cylinder - ideally the segmentation would be similar for predictable results
var cg = new THREE.CylinderGeometry(100, 100, 200, 16, 4, false);
// Move vertices down for cylinder, so it maches half the sphere
for(var i = 0 ; i < cg.vertices.length; i++)
cg.vertices[i].position.y -= 100;
// Merge meshes
THREE.GeometryUtils.merge(lathe, cg);
var mesh = new THREE.Mesh(lathe, new THREE.MeshLambertMaterial({ color: 0x2D303D, wireframe: true, shading: THREE.FlatShading}));
mesh.position.y = 150;
scene.add(mesh);
The one problem I can't address at the moment comes from the faces that are inside the mesh. Ideally, those would have normals flipped, so they wouldn't render, but I haven't found a quick solution for that.
The third is fairly straightforward. Most 3D packages allow Boolean operation on meshes (e.g., merging two meshes together with the ADD operation (meshA + meshB)). Try creating a cylinder and a sphere in Blender (free and opensource), which already has a Three.js exporter. Alternatively you can export an .obj file of the merged meshes from your 3D editor or choice and use the convert_obj_three script.
I've found yet another method, which might be easier/more intuitive. Remember the Boolean operations I've mentioned above?
It turns out there is an awesome JavaScript library just for that: Constructive Solid Geometry:
Chandler Prall wrote some handy functions to connect CSG with three.js. So with the CSG library and the Three.js wrapper for it, you can simply do this:
var cylinder = THREE.CSG.toCSG(new THREE.CylinderGeometry(100, 100, 200, 16, 4, false), new THREE.Vector3(0, -100, 0));
var sphere = THREE.CSG.toCSG(new THREE.SphereGeometry(100, 16, 12));
var geometry = cylinder.union(sphere);
var mesh = new THREE.Mesh(THREE.CSG.fromCSG(geometry), new THREE.MeshNormalMaterial());
Which gives you a nice result (no problems with extra faces/flipping normals, etc.):

Categories