Particles in three.js - javascript

Can someone kindly explain me why there are no particles visible in the following code?
Followed a tutorial and everything seems ok.
(function() {
var camera, scene, renderer;
init();
animate();
function init() {
scene = new THREE.Scene();
var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;
camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
scene.add(camera);
camera.position.set(2,2,10);
camera.lookAt(scene.position);
console.log(scene.position);
var geometry = new THREE.CubeGeometry(1,1,1);
var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );
var pGeometry = new THREE.Geometry();
for (var p = 0; p < 2000; p++) {
var particle = new THREE.Vector3(Math.random() * 50 - 25, Math.random() * 50 - 25, Math.random() * 50 - 25);
pGeometry.vertices.push(particle);
}
var pMaterial = new THREE.ParticleBasicMaterial({ color: 0xfff, size: 1 });
var pSystem = new THREE.ParticleSystem(pGeometry, pMaterial);
scene.add(pSystem);
renderer = new THREE.CanvasRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
})();
fiddle

CanvasRenderer does not support ParticleSystem. You need to use WebGLRenderer.
If you need to use CanvasRenderer, then see http://threejs./examples/canvas_interactive_particles.html for how to use Sprites instead.
three.js r.64

Also, as a side note, as of the time of this answer, IE11's WebGL implementation has an issue with points and sizing them. Particles in Three.js shaders use points to draw the particles and so in IE11, you will see very small squares and if you're not paying attention, you might not see anything at all ;)
I do know that in the next version of IE (updates coming) that this is fixed and allows you not only to change the point size, but use bitmaps with them.

Related

Rotate cubetexture in Three.js

I got this cubetexture in Three.js. Say I want to rotate the cubeTexture itself 180 degrees. I know I can do this by rotating the camera but I want to rotate the texture itself and not the camera. How can I achieve this?
I want to rotate the x axis of the cubeTexture causing it to display the opposite side. Something like texture.flipX = true; would be handy.
https://codepen.io/haangglide/pen/GRZPqaw
var camera, scene, box, renderer;
init();
animate();
function init() {
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
scene = new THREE.Scene();
const texture = new THREE.CubeTextureLoader()
.setCrossOrigin('') .setPath('https://alca.tv/static/codepen/pens/common/SwedishRoyalCastle/').load(['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg']);
scene.background = texture;
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: new THREE.Color('skyblue') });
box = new THREE.Mesh(geometry, material);
scene.add(box);
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
scene.add(camera);
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
Edit:
According to the following discussions it does not seem easy or even possible to do what you ask with ThreeJS, but in the first link it does mention that it may be possible with BabylonJS.
https://discourse.threejs.org/t/rotate-a-scenes-background-skybox-texture/12199
https://discourse.threejs.o9rg/t/rotate-a-scenes-background/3928/15
Original answer:
You didn't say which axis so I will just use the Y axis. I am also using 45 degrees instead of 180 so you can see it is working.
var camera, scene, box, renderer;
init();
animate();
function init() {
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
scene = new THREE.Scene();
const texture = new THREE.CubeTextureLoader()
.setCrossOrigin('') .setPath('https://alca.tv/static/codepen/pens/common/SwedishRoyalCastle/').load(['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg']);
scene.background = texture;
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: new THREE.Color('skyblue') });
box = new THREE.Mesh(geometry, material);
///
///
///
///////////////////////////////
//since threejs uses radians, you will need a function to get radians from degrees
function getRadians(degrees) {
return Math.PI / 180 * degrees;
}
//using rotation.set(x, y, z)
box.rotation.set(0, getRadians(45), 0);
//directly setting the rotations
box.rotation.y = getRadians(45);
///////////////////////////////
///
///
///
scene.add(box);
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
scene.add(camera);
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
<script src="https://threejs.org/build/three.js"></script>

Flat shading with phong material with spot light

I am trying to achieve flat shading with the phong material. As the documentation says we have to set flatShading:true in config when creating the material. I have created a cube with these settings and created a spot light to focus at the center of the cube (not touching the vertices of the cube).
I assume the face of the cube should look same at all pixels but its not looking so. I see a reflection of the light at the center of the face. Indeed, changing the flatShading from true to false, is not affecting the light.
Here is the JS fiddle link to what i tried. https://jsfiddle.net/dj03gktb/.
Below is the code.
var camera, scene, renderer;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 10);
camera.position.z = 4;
scene.add(camera);
scene = new THREE.Scene();
var ambientLight = new THREE.AmbientLight(0xcccccc, 0.2);
scene.add(ambientLight);
var pointLight = new THREE.SpotLight({ color: 0xffffff, angle: Math.PI / 10, intensity: 2 });
scene.add(pointLight);
//pointLight.position.x = 5;
pointLight.position.z = 1.5;
pointLight.position.y = 0;
var geometry = new THREE.BoxGeometry(1, 1, 1);
//geometry.computeFlatVertexNormals();
//geometry.rotateY(0.5);
var material = new THREE.MeshPhongMaterial({ color: 0xff0000, flatShading: true, shininess: 100, specular: 0x00ff00 });
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
May be i have under stood flat shading wrongly or could be bug with the THREE.js or problem with the render engine.
Any help would be great.
Unfortunately, using a cube to demonstrate flat shading is a bad example since you won't see any difference. Try it with a sphere instead:
var camera, scene, renderer;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 10 );
camera.position.z = 4;
scene = new THREE.Scene();
var ambientLight = new THREE.AmbientLight( 0xcccccc, 0.2 );
scene.add( ambientLight );
var spotLight = new THREE.SpotLight({ color: 0xffffff, angle: Math.PI / 10, intensity: 2});
spotLight.position.z = 1.5;
scene.add(spotLight);
var geometry = new THREE.SphereBufferGeometry( 1, 12, 16);
var material = new THREE.MeshPhongMaterial({color: 0xff0000, flatShading: true, shininess: 100, specular: 0x00ff00});
var mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
}
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
body {
margin: 0;
}
canvas {
display: block;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.118.3/build/three.js"></script>
I assume the face of the cube should look same at all pixels but its not looking so.
This is not what flat shading does. Normally vertex normals are interpolated in the fragment shader which produces the typical smooth rendering. Flat shading just ensures that the normals of a face are equal across its (flat) surface. So there is no interpolation of vertex normals. Apart from that, lighting calculations are not affected. Hence, you also see specular highlights.

Plane always black

I want to add a texture to my plane that repeats horizontal and vertical. The thing is, when I try to apply the texture, it is always black. I don't get any errors, and i already tried to add some lights, but the problem is still there; I don't know how to solve it... Here is what I did:
window.onload = function init()
{
scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.x = -30;
camera.position.y = 40;
camera.position.z = 30;
camera.lookAt(scene.position);
var light = new THREE.AmbientLight( 0x404040 ); // soft white light
scene.add( light );
var spotlight = new THREE.SpotLight( 0xffffff);
spotlight.position.set( -50, 40, 0 );
scene.add( spotlight );
var axes = new THREE.AxisHelper( 20 ); scene.add(axes);
var renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0xEEEEEE);
renderer.setSize(window.innerWidth, window.innerHeight);
desenhaMapa();
document.body.appendChild( renderer.domElement );
renderer.render(scene, camera);
}
function desenhaMapa()
{
labirinto = new THREE.Object3D();
var texturaPlano = new THREE.TextureLoader().load("texturaPac.jpg");
geometryPlano = new THREE.PlaneGeometry(50,50);
materialPlano = new THREE.MeshPhongMaterial( {map: texturaPlano} );
var planoPacMan = new THREE.Mesh(geometryPlano,materialPlano);
planoPacMan.rotation.x = -0.5 * Math.PI;
scene.add(planoPacMan);
}
Any suggestions?
TextureLoader.load() is an asynchronous method. That is why it has an onload argument.
You are calling render() before the texture loads. One solution is to call render() in the loader callback.
var loader = new THREE.TextureLoader();
var texture = loader.load( 'myTexture.jpg', function ( texture ) {
renderer.render( scene, camera );
} );
Another solution is to have an animation loop. But that is not required for static scenes.
three.js r.78

Incremental rendering of particals in THREE.js

Newbie to 3D world. Trying to render particles as they are created so that these 2000 particles should render as they are created. But from below code it renders only once all particles are created.
Tried couple of variations but no luck. Any help is appreciated.
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.z = 255;
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild( renderer.domElement );
var particles = new THREE.Geometry;
for (var p = 0; p < 2000; p++) {
var particle = new THREE.Vector3(Math.random() * 500 - 250, Math.random() * 500 - 250, Math.random() * 500 - 250);
particles.vertices.push(particle);
}
var particleMaterial = new THREE.ParticleBasicMaterial({ color: 0xeeeeee, size: 2 });
var particleSystem = new THREE.ParticleSystem(particles, particleMaterial);
scene.add(particleSystem);
function render() {
requestAnimationFrame(render);
particleSystem.rotation.y += 0.01;
renderer.render(scene, camera);
}
render();
</script>
You can render a subset of you particles (now called THREE.Points) by using BufferGeometry and setting the draw range.
var geometry = new THREE.BufferGeometry();
geometry.setDrawRange( startIndex, count );
You can reset the draw range inside your animation loop.
See this answer for information on how to populate the geometry and a live demo.
three.js r.78

How can I print text along an arc using Three.js?

I'm trying to print text along an arc using Three.js. With help from this post, I was able to get the math for the rotation. But, as you'll see, the text is all jumbled on top of itself. How can I get it to correctly space itself out? Codepen is here.
var container, camera, scene, renderer;
function init() {
container = document.getElementById( 'canvas' );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(50, window.innerWidth/window.innerHeight, 1, 100000);
camera.position.z = 500;
scene.add(camera);
var loader = new THREE.FontLoader();
loader.load( 'https://raw.githubusercontent.com/mrdoob/three.js/master/examples/fonts/helvetiker_bold.typeface.json', function ( font ) {
var theText = "This is some text."
var numRadsPerChar = 2*Math.PI/theText.length;
for (var i = 0; i < theText.length; i++){
var char = theText[i]
var geometry = new THREE.TextBufferGeometry( char, {
font: font,
size: 60,
height: 60,
curveSegments: 20
});
var materials = [
new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff, overdraw: 0.5 } ),
new THREE.MeshBasicMaterial( { color: 0x000000, overdraw: 0.5 } )
];
var mesh = new THREE.Mesh( geometry, materials );
mesh.rotation.z = (i * numRadsPerChar);
//mesh.position.x = i * 20;
group = new THREE.Group();
group.add( mesh );
scene.add( group );
};
} );
renderer = new THREE.WebGLRenderer({alpha: true});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
animate();
} init();
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
Had some help figuring this out, but here's the portion that needed to be edited to work:
mesh.rotation.z = (i * numRadsPerChar);
Needed to be:
mesh.position.x = 100 * Math.sin(i * numRadsPerChar);
mesh.position.y = 100 * Math.cos(i * numRadsPerChar);
mesh.rotation.z = Math.PI/2 -(i * numRadsPerChar);
Basically, I needed to add a constant (Math.PI/2) for the rotation. For the x and y positions, I had to take the sin and cosine, respectively, to get the letters to be placed properly around the arc. Here's a working codepen.
Another way to do this would be to draw your text on a canvas and use the canvas in a texture with texture.wrapS and .wrapT set to THREE.RepeatWrapping.. then put that texture on a material.. then make a path with the extruded path geometry and set it's material. The you can move the text by setting the texture.offset.x or y each frame in your render loop.

Categories

Resources