Change the opacity of a Particle object in Three.js (NOT ParticleSystem)? - three.js

I am using the CanvasRendererand Particlein Three.JS. I am generating some random particles using this approach:
texture = THREE.ImageUtils.loadTexture("img.png");
material = new THREE.ParticleBasicMaterial({
map : texture,
transparent : true,
});
for (var i = 0; i < pointCount; i++) {
var particle = new THREE.Particle(material);
particle.position.x = Math.random() * (max - min) + min;
particle.position.y = Math.random() * (max - min) + min;
particle.position.z = Math.random() * (max - min) + min;
// Set the size of the particle
particle.scale.x = particle.scale.y = particle.scale.z = Math.floor(Math.random() * 6) + 2;
particles.push(particle);
scatterPlot.add(particle);
}
I would like to (if possible) be able to change the opacity of individual Particles, as I am using transparency as a dimension in my plot (i.e., transparency of a particle reflects the magnitude of a variable). I know I can use particle.material.opacity, but that changes the opacity for all particles. I tried particles[i].material.opacitybut got the same result.
One possibility of course would be to have an array of materials with different opacities. But I'm not sure if there's perhaps a simpler way to do this?
Many thanks!

I think I might have figured this out -- and was simpler than I was thinking. It at least seems to be working for me. I moved the material declaration into the for loop. I think this generates a different ParticleBasicMaterial for each Particle, but I suppose that is okay.
I am then able to access the individual Particle'smaterial by using particles[i].material, which allows me to change the opacity of specific particles.
Here is my updated code:
texture = THREE.ImageUtils.loadTexture("img.png");
for (var i = 0; i < pointCount; i++) {
material = new THREE.ParticleBasicMaterial({
map : texture,
transparent : true,
});
var particle = new THREE.Particle(material);
particle.position.x = Math.random() * (max - min) + min;
particle.position.y = Math.random() * (max - min) + min;
particle.position.z = Math.random() * (max - min) + min;
// Set the size of the particle
particle.scale.x = particle.scale.y = particle.scale.z = Math.floor(Math.random() * 6) + 2;
particles.push(particle);
scatterPlot.add(particle);
}
// Example opacity change
particles[0].material.opacity = 0.5;
If anyone has any other suggestions, I'd greatly appreciate them. But at least this seems to be giving me the desired behavior for now.

Related

Moving a line geometry with three.js using GLSL

I have a line geometry made with three.js, which I want to move as a spermatozoid (i.e. the head moves first, then all of the points along the tail move accordingly to the head) using GLSL.
Here is a visual representation of what I want:
So as you can see, point G eases to (follows) H, which in turn follows point E, which in turn follows the head.
I have a working examples, being animated on the CPU. Here is the code:
class Boid {
constructor (position) {
this.position = position
this.speed = 0.0009 + Math.random() * 0.0003
this.pointsNum = 12
this.points = []
this.line = null
this.angle = Math.random() * 360
for (let i = 0; i < this.pointsNum; i += 1) {
this.points.push(new THREE.Vector3(1, 1, 1))
}
this.angle = 0
}
update (target, time) {
if (time) {
this.line.geometry.verticesNeedUpdate = true
this.line.geometry.vertices.forEach((p, i) => {
let nextP = this.line.geometry.vertices[i + 1]
if (nextP) {
// if it's not the HEAD point, follow the next point in the geometry vertices
p.x += (nextP.x - p.x) * (time * 8.0)
p.y += (nextP.y - p.y) * (time * 8.0)
p.z += (nextP.z - p.z) * (time * 8.0)
} else {
// if the point is in fact the head, ease it according to some random moving point in our scene (target)
p.x += (target.x - p.x) * time
p.y += (target.y - p.y) * time
p.z += (target.z - p.z) * time
}
})
}
}
}
And here is a working example.
This technique is working, but would like to accomplish the same stuff with GLSL. My question is how should I approach it? Should I pass the next vertex position to the previous one and ease in my vertex shader? How should I keep track of the next's point position?
Any help is more then appreciated, I have been thinking about this a lot without any success.

how to figure out cursive paths for an enemy to follow

The Problem
I am making a game where enemies appear at some point on the screen then follow a smooth curvy path and disappear at some point. I can make them follow a straight path but can't figure out the way to make them follow the paths depicted in the image.
Attempts
I started with parabolic curve and implemented them successfully. I just used the equation of parabola to calculate the coordinates gradually. I have no clue what is the equation for desired paths supposed to be.
What I want
I am not asking for the code.I just want someone to explain me the general technique.If you still want to show some code then I don't have special preference for programming language for this particular question you can use C,Java or even pseudo-code.
First you need to represent each curve with a set of points over time, For example:
-At T(0) the object should be at (X0, Y0).
-At T(1) the object should be at (X1, Y1).
And the more points you have, the more smooth curve you will get.
Then you will use those set of points to generate two formulas-one for X, and another one for Y-, using any Interpolation method, like The La-grange's Interpolation Formula:
Note that you should replace 'y' with the time T, and replace 'x' with your X for X formula, and Y for Y formula.
I know you hoped for a simple equation, but unfortunately this is will take from you a huge effort to simplify each equation, and my advise DON'T do it unless it's worth it.
If you are seeking for a more simple equation to perform well in each frame in your game you should read about SPline method, In this method is about splitting your curve into a smaller segments, and make a simple equation for every segment, for example:
Linear Spline:
Every segment contains 2 points, this will draw a line between every two points.
The result will be some thing like this:
Or you could use quadratic spline, or cubic spline for more smooth curves, but it will slow your game performance. You can read more about those methods here.
I think linear spline will be great for you with reasonable set of points for each curve.
Please change the question title to be more generic.
If you want to generate a spiral path you need.
Total time
How many full rotations
Largest radius
So, total time T_f = 5sec, rotations R_f = 2.5 * 2 * PI, the final distance from the start D_f = 200px
function SpiralEnemy(spawnX, spawnY, time) {
this.startX = spawnX;
this.startY = spawnY;
this.startTime = time;
// these will change and be used for rendering
this.x = this.startX;
this.y = this.startY;
this.done = false;
// constants we figured out above
var TFinal = 5.0;
var RFinal = -2.6 * 2 * Math.PI;
var RStart = -Math.PI / 2;
var DFinal = 100;
// the update function called every animation tick with the current time
this.update = function(t) {
var delta = t - this.startTime;
if(delta > TFinal) {
this.done = true;
return;
}
// find out how far along you are in the animation
var percent = delta / TFinal;
// what is your current angle of rotation (in radians)
var angle = RStart + RFinal * percent;
// how far from your start point should you be
var dist = DFinal * percent;
// update your coordinates
this.x = this.startX + Math.cos(angle) * dist;
this.y = this.startY + Math.sin(angle) * dist;
};
}
EDIT Here's a jsfiddle to mess with http://jsfiddle.net/pxb3824z/
EDIT 2 Here's a loop (instead of spiral) version http://jsfiddle.net/dpbLxuz7/
The loop code splits the animation into 2 parts the beginning half and the end half.
Beginning half : angle = Math.tan(T_percent) * 2 and dist = Speed + Speed * (1 - T_percent)
End half : angle = -Math.tan(1 - T_percent) * 2 and dist = **Speed + Speed * T_percent
T_percent is normalized to (0, 1.0) for both halfs.
function LoopEnemy(spawnX, spawnY, time) {
this.startX = spawnX;
this.startY = spawnY;
this.startTime = time;
// these will change and be used for rendering
this.x = this.startX;
this.y = this.startY;
this.last = time;
this.done = false;
// constants we figured out above
var TFinal = 5.0;
var RFinal = -2 * Math.PI;
var RStart = 0;
var Speed = 50; // px per second
// the update function called every animation tick with the current time
this.update = function(t) {
var delta = t - this.startTime;
if(delta > TFinal) {
this.done = true;
return;
}
// find out how far along you are in the animation
var percent = delta / TFinal;
var localDelta = t - this.last;
// what is your current angle of rotation (in radians)
var angle = RStart;
var dist = Speed * localDelta;
if(percent <= 0.5) {
percent = percent / 0.5;
angle -= Math.tan(percent) * 2;
dist += dist * (1 - percent);
} else {
percent = (percent - 0.5) / 0.5;
angle -= -Math.tan(1 - percent) * 2;
dist += dist * percent;
}
// update your coordinates
this.last = t;
this.x = this.x + Math.cos(angle) * dist;
this.y = this.y + Math.sin(angle) * dist;
};
}
Deriving the exact distance traveled and the height of the loop for this one is a bit more work. I arbitrarily chose a Speed of 50px / sec, which give a final x offset of ~+145 and a loop height of ~+114 the distance and height will scale from those values linearly (ex: Speed=25 will have final x at ~73 and loop height of ~57)
I don't understand how you give a curve. If you need a curve depicted on the picture, you can find a curve is given analytically and use it. If you have not any curves you can send me here: hedgehogues#bk.ru and I will help find you. I leave e-mail here because I don't get any messages about answers of users from stackoverflow. I don't know why.
If you have some curves in parametric view in [A, B], you can write a code like this:
struct
{
double x, y;
}SPoint;
coord = A;
step = 0.001
eps = 1e-6;
while (coord + step - eps < B)
{
SPoint p1, p2;
p1.x = x(coord);
p1.y = y(coord);
coord += step;
p2.x = x(coord);
p2.y = y(coord);
drawline(p1, p2);
}

Setting color of mapped image for ThreeJS particles

Originally I was using ParticleSystem, but I discovered that Raycaster does not work with it. So I'm now modifying my code to simply use individual Particle objects.
The problem is, I can't seem to set the color of the image I'm mapping to the particles like I was able to with ParticleSystem.
I tried the following:
texture = THREE.ImageUtils.loadTexture("ball.png");
material = new THREE.ParticleBasicMaterial({
size : 10,
color: 0x00C1BF,
map : texture,
transparent : true,
});
// Generate some random points...
for (var i = 0; i < pointCount; i++) {
var particle = new THREE.Particle(material);
particle.position.x = Math.random() * (max - min) + min;
particle.position.y = Math.random() * (max - min) + min;
particle.position.z = Math.random() * (max - min) + min;
particle.scale.x = particle.scale.y = particle.scale.z = 3;
plot.add(particle);
}
But the color of ball.png remains the same. If I comment out the image I'm mapping to the points, the colors are changing. But it's not working with the mapped image. When I was using ParticleSystem, inside the for loop where I generate the points, I was adding this:
colors[i] = new THREE.Color(0xffffff);
colors[i].setHSL((x + 1000 ) / 2000, 1, 0.5);
And then set particleSys.colors = colors; outside the loop. That changed the color of the points, but this doesn't seem to work with Particle.
I hate to keep bugging the community with questions like this, but I really would appreciate any guidance on this. Many thanks, as always! :)
Also, here's a link to ball.png that I'm using: http://threejsdoc.appspot.com/doc/three.js/examples/textures/sprites/ball.png

Three.js 3D Scene, Uncaught Type Error: "Cannot read property 'x' of undefined" Vertex/Particle Position

I'm attempting to create a randomly distributed particle field that exhibits Brownian (random) motion.
Scroll to the bottom of the code to see where the error happens. I'm trying to set the position of a single vertex with position.x.
I'll omit the rest of the code not directly related to rendering the particles in effort to save your time.
//Using WebGL renderer...
var particle, particles = [], particle_system, material, p_x, p_y, p_z;
particles = new THREE.Geometry();
material = new THREE.ParticleBasicMaterial({color: 0xffffff, size: 1});
for(var count = 0; count < 1000; count++){
p_x = Math.random() * 1000 - 500;
p_y = Math.random() * 1000 - 500;
p_z = Math.random() * 1000 - 500;
particle = new THREE.Vector3(p_x, p_y, p_z);
particles.vertices.push(particle);
}
particle_system = new THREE.ParticleSystem(particles, material);
scene.add(particle_system);
particle_system.geometry.dynamic = true;
//All of the code bellow will go into the render loop.
var index = 0;
while(index < 1000){
index++;
particle_system.geometry.verticiesNeedUpdate = true;
//THESE 3 LINES BELLOW CAUSE THE ERROR
particles.vertices[index].position.x += Math.random() * 1000 - 500;
particles.vertices[index].position.y += Math.random() * 1000 - 500;
particles.vertices[index].position.z += Math.random() * 1000 - 500;
}
verticiesNeedUpdate should be spelled verticesNeedUpdate
your while loop is wrongly incrementing the index variable before it is used. So in the last iteration (when index == 999) you try to access particles.vertices[1000] which is not defined

Eliminating off-of-ball roll in Trackball controls (with code/fix)

Is the intent of the TrackballControl to have a "border" outside the trackball that induces roll? I personally dislike it. It is a bit discontinuous, and does't really have a lot of purpose (imho).
If not, the function getMouseProjectionOnBall can be changed similar to the following. This does two things (not necessarily "correctly"):
Normalize the radius to fill both axis
Map z values outside of the ball (ie where z was previously 0)
I find this a lot more natural, personally.
Thoughts?
this.getMouseProjectionOnBall = function(clientX, clientY) {
var xnormalized = (clientX - _this.screen.width * 0.5 - _this.screen.offsetLeft) / (_this.screen.width / 2.0);
var ynormalized = (_this.screen.height * 0.5 + _this.screen.offsetTop - clientY) / (_this.screen.height / 2.0);
var mouseOnBall = new THREE.Vector3(
xnormalized,
ynormalized,
0.0
);
var length = mouseOnBall.length();
var ballRadius = 1.0; // As a fraction of the screen
if (length > ballRadius * 0.70710678118654752440) {
var temp = ballRadius / 1.41421356237309504880;
mouseOnBall.z = temp * temp / length;
// Remove old method.
// This Left z = 0, which meant rotation axis
// becomes z, which is a roll
//mouseOnBall.normalize();
} else {
mouseOnBall.z = Math.sqrt(1.0 - length * length);
}
_eye.copy(_this.object.position).sub(_this.target);
var projection = _this.object.up.clone().setLength(mouseOnBall.y);
projection.add(_this.object.up.clone().cross(_eye).setLength(mouseOnBall.x));
projection.add(_eye.setLength(mouseOnBall.z));
return projection;
};

Resources