I'm trying to create a clouds fly through similar to this, only with more maneuverability:
http://mrdoob.com/lab/javascript/webgl/clouds/
I had no problem creating that using sprites, but I want to improve the performance so I'm trying to use particles with THREE.PointCloud.
The problem is that when I fly toward the particles, instead of "colliding" in the camera there's some weird effect when the particle hangs in front of the camera and then slides to the side, I made an example here: http://jsfiddle.net/6avpd6me/36/
All the particles are moving toward the camera in a straight line, but non of them actually colliding in it, changing the size doesn't help.
Anybody knows what's causing this and maybe how can I fix that?
Thanks
JSFiddle code:
var geometry, renderer, scene, camera, cloud, uniforms, attributes;
init();
animate();
function init() {
// renderer
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
// scene
scene = new THREE.Scene();
//camera
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.z = 600;
var particleMaterial = new THREE.PointCloudMaterial({
color:0xffffff,
size: 100,
transparent:true,
opacity:0.5,
sizeAttenuation:false
});
particleMaterial.depthTest = true;
particleMaterial.depthWrite = false;
// point cloud geometry
geometry = new THREE.PlaneGeometry( 10, 10, 5, 5);
for( var i = 0; i < geometry.vertices.length; i++)
{
geometry.vertices[i].velocity = new THREE.Vector3(0, 0, random(50, 300) / 100);
}
cloud = new THREE.PointCloud(geometry, particleMaterial);
scene.add( cloud );
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
for( var i = 0; i < geometry.vertices.length; i++ )
{
geometry.vertices[i].add(geometry.vertices[i].velocity);
if (geometry.vertices[i].z > 650) geometry.vertices[i].z = 0;
}
geometry.verticesNeedUpdate = true;
renderer.render( scene, camera );
}
function random(min, max)
{
return Math.floor(Math.random() * (max - min + 1)) + min;
}
Related
EDIT: I've decided to not use DragControls or TransformControls as both are not doing what I require them to do. For now I've added a pivot Object3D at the cueball's position and made cue (stick) a child of that, and try to make my own mousehandler to rotate, and to pull back the stick.
I'm creating a Pool game in ThreeJS as a school project (GitHub Source).
I currently have the following meshes:
- a table
- a set of balls on their starting position
- a cue (stick).
To rotate the scene, I am using OrbitControls from ThreeJS.
I also have a raycaster in place with which I can click on the cue (using this question).
Now, I want to keep the OrbitControls ability to rotate the world, but I also want to use the ability to rotate the cue around the white ball to shoot.
What I have in mind:
- use an onDocumentMouseDrag() something to detect if I'm clicking on the cue and if so, to where I'm dragging it (rotated)
- In the same function, see if the cue was dragged backwards and then "hit" the white ball with that vector.
Can you help me achieve this?
See below for my "main".js: GitHub: Poolgame.js
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
var controls = new THREE.OrbitControls( camera );
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0xcee0ff);
document.body.appendChild(renderer.domElement);
var objects = []; //for raycaster
//Table
var pooltable = new PoolTable();
scene.add(pooltable);
//Lighting
scene.add(new BarLighting() );
//ambient light
scene.add( new THREE.AmbientLight( 0x909090 ) ); // soft white light
//Balls
var poolballs = [], ball;
for(var i = 0; i<=15; i++) {
ball = new PoolBall(i);
scene.add(ball);
poolballs.push(ball);
}
var cue = new PoolStick();
cue.position.copy(poolballs[0].position);
cue.rotateZ(- (100 / 90) * Math.PI / 2); //10 degrees above table
scene.add(cue);
objects.push(cue);
var clock = new THREE.Clock();
document.addEventListener( 'mousedown', onDocumentMouseDown );
function onDocumentMouseDown( event ) {
event.preventDefault();
var mouse3D = new THREE.Vector3( ( event.clientX / window.innerWidth ) * 2 - 1,
-( event.clientY / window.innerHeight ) * 2 + 1,
0.5 );
var raycaster = new THREE.Raycaster();
raycaster.setFromCamera( mouse3D, camera );
var intersects = raycaster.intersectObjects( objects );
if ( intersects.length > 0 ) {
console.log(intersects[0]);
//has found intersect, i.e. we clicked something: the stick.
}
} // end of onDocumentMouseDown
function render() {
requestAnimationFrame(render);
controls.target.copy(poolballs[0].position);
// controls.target.copy(pooltable.position);
controls.update();
renderer.render(scene,camera);
}
var mouse = new THREE.Vector2();
document.addEventListener('mousemove', onDocumentMouseMove, false);
function onDocumentMouseMove(event) {
event.preventDefault();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
}
camera.position.x = -150;
camera.position.y = 120;
camera.lookAt(pooltable.position);
controls.update();
render();
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
I have created a javascript script to do something, and mostly it worked. There are two issues I had with the script, so I planned to put a working example here on SO. However, during the 'reduction' of the code to something less complex a third error occurred, which completely made the script stop working. Here is the javascript part of the script:
var container, stats;
var camera, scene, renderer;
var group1, group2;
var mouseX = 0, mouseY = 0;
var map_width = 512;
var map_height = 512;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function createMesh(filename) {
var geometry = new THREE.SphereGeometry( 70, 40, 40 );
var texture = new THREE.TextureLoader(filename);
texture.needsUpdate = true;
var material = new THREE.MeshBasicMaterial( { map: texture, overdraw: 0.5 } );
var mesh = new THREE.Mesh( geometry, material );
return mesh;
}
function init() {
container = document.getElementById( 'container' );
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 2000 );
camera.position.z = 500;
scene = new THREE.Scene();
group1 = new THREE.Group();
var mesh = createMesh("textures/tree1.jpg");
group1.add( mesh );
group1.position.x = 00;
scene.add( group1 );
group2 = new THREE.Group();
var mesh = createMesh("textures/tree2.jpg");
group2.add( mesh );
group2.position.x = 250;
scene.add( group2 );
renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setClearColor( 0xffffff, 0 );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
camera.position.x += ( mouseX - camera.position.x ) * 0.05;
camera.position.y += ( - mouseY - camera.position.y ) * 0.05;
camera.lookAt( scene.position );
group1.rotation.y -= 0.005;
group2.rotation.y -= 0.015;
renderer.render( scene, camera );
}
The idea is to have several spheres with some texture on it; to try just use any image. However, when I call this code within a html I get the error
TypeError: n is undefined
all over again. The error seems to originate in THREE.js. How can I fix this error, so I see two spheres with a 'tree' texture on it...?
The body of the html code is as follows:
<body>
<div id="container"></div>
<script src="js/build/three.min.js"></script>
<script>
>> the code from above <<
</script>
</body>
This problem is caused by the following line:
var texture = new THREE.TextureLoader(filename);
The solution is to use a loader instead:
var loader = new THREE.TextureLoader();
var texture = loader.load( filename );
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.
This site is loading a maya model using three.js.
This model has Below texture pictures
Here is the JS
var SCREEN_WIDTH = window.innerWidth;
var SCREEN_HEIGHT = window.innerHeight;
var container;
var camera, scene;
var canvasRenderer, webglRenderer;
var mesh, zmesh, geometry, materials;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
var meshes = [];
function init() {
container = document.createElement('div');
document.body.appendChild(container);
camera = new THREE.PerspectiveCamera(75, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 100000);
camera.position.x = 400;
camera.position.y = 200;
camera.position.z = 400;
scene = new THREE.Scene();
// LIGHTS
var ambient = new THREE.AmbientLight(0x666666);
scene.add(ambient);
var directionalLight = new THREE.DirectionalLight(0xffeedd);
directionalLight.position.set(0, 70, 100).normalize();
scene.add(directionalLight);
// RENDERER
webglRenderer = new THREE.WebGLRenderer();
webglRenderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
webglRenderer.domElement.style.position = "relative";
container.appendChild(webglRenderer.domElement);
var loader = new THREE.JSONLoader(),
callbackKey = function (geometry, materials) {
createScene(geometry, materials, 0, 0, 0, 6)
};
loader.load("chameleon.js", callbackKey);
window.addEventListener('resize', onWindowResize, false);
}
function createScene(geometry, materials, x, y, z, scale) {
zmesh = new THREE.Mesh(geometry, new THREE.MeshFaceMaterial(materials));
zmesh.position.set(x, y, z);
zmesh.scale.set(scale, scale, scale);
meshes.push(zmesh);
scene.add(zmesh);
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
webglRenderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
for (var i = 0; i < meshes.length; i++) {
meshes[i].rotation.y += .01;
}
requestAnimationFrame(animate);
render();
}
function render() {
camera.lookAt(scene.position);
webglRenderer.render(scene, camera);
}
$(document).ready(function () {
init();
animate();
});
now i want to change the 1st texture picture to some other texture and rest of the texture remains same on runtime! how to do it?
if you'd like to change the texture at runtime. All you need to do is look at the zmesh objects material. Find the appropriate index of the blue dress material and swap it out. Your model is a little tricky in that you have an array of materials but no matter. For a single material object you simply change the mesh.material.map and update it, in your case we need mesh.material.materials[index].map. So try adding this to the bottom of your createScene function. It will replace the dress with the eyeball texture:
zmesh.material.materials[1].map = THREE.ImageUtils.loadTexture( 'c006_10.jpg' );
Of course, replace 'c006_10.jpg' with the appropriate path to your eyeball texture. One added Note, if you hook up the texture swap to an onclick for example you'll want to have an active render loop or call renderer's render function to get it to display.