geometry materials in THREE.js - javascript

I am creating a geometry in THREE.js:
var dotGeometry = new THREE.Geometry();
dotGeometry.dynamic = true;
var createDot = function (group, x, y, z){
group.vertices.push(new THREE.Vector3( x, y, z));
}
var width = 300;
var height = 300;
var gap = 0.1;
for(var i = 0; i < width; i++){
for(var j = 0; j < height; j++){
createDot(dotGeometry, i*gap, j*gap, 0);
}
}
as long as I use the points material, everything works fine - I can see my geometry:
var dotMaterial = new THREE.PointsMaterial( { size: 1, color: 0xffffff, sizeAttenuation: false } );
var dot = new THREE.Points( dotGeometry, dotMaterial );
scene.add( dot );
but as soon as I want to use any other material to see something like a "solid" surface, I can't see anything, for example:
var dotMaterial = new THREE.MeshPhongMaterial( { color: 0xffffff } );
var dot = new THREE.Points( dotGeometry, dotMaterial );
scene.add( dot );
does geometry only work together with PointsMaterial or what am I doing wrong?
Example 1: Working
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
var renderer = new THREE.WebGLRenderer();
var light = new THREE.PointLight(0xffffff, 1);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var dotGeometry = new THREE.Geometry();
dotGeometry.dynamic = true;
var createDot = function (group, x, y, z){
group.vertices.push(new THREE.Vector3( x, y, z));
}
var width = 300;
var height = 300;
var gap = 0.1;
for(var i = 0; i < width; i++){
for(var j = 0; j < height; j++){
createDot(dotGeometry, i*gap, j*gap, 0);
}
}
var dotMaterial = new THREE.PointsMaterial( { size: 1, color: 0xffffff, sizeAttenuation: false } );
var dot = new THREE.Points( dotGeometry, dotMaterial );
scene.add( dot );
scene.add(light);
camera.position.z = 5;
light.position.y = 2;
light.position.z = 5;
light.position.x = 0;
var render = function() {
requestAnimationFrame(render);
dot.rotation.x += 0.01;
dot.rotation.y += 0.01;
renderer.render(scene, camera);
};
render();
body {
margin: 0;
}
canvas {
width: 100%;
height: 100%
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/87/three.min.js"></script>
Example 2: Not working
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
var renderer = new THREE.WebGLRenderer();
var light = new THREE.PointLight(0xffffff, 1);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var dotGeometry = new THREE.Geometry();
dotGeometry.dynamic = true;
var createDot = function (group, x, y, z){
group.vertices.push(new THREE.Vector3( x, y, z));
}
var width = 300;
var height = 300;
var gap = 0.1;
for(var i = 0; i < width; i++){
for(var j = 0; j < height; j++){
createDot(dotGeometry, i*gap, j*gap, 0);
}
}
var dotMaterial = new THREE.MeshPhongMaterial( { color: 0xffffff } );
var dot = new THREE.Points( dotGeometry, dotMaterial );
scene.add( dot );
scene.add(light);
camera.position.z = 5;
light.position.y = 2;
light.position.z = 5;
light.position.x = 0;
var render = function() {
requestAnimationFrame(render);
dot.rotation.x += 0.01;
dot.rotation.y += 0.01;
renderer.render(scene, camera);
};
render();
body {
margin: 0;
}
canvas {
width: 100%;
height: 100%
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/87/three.min.js"></script>
Thanks for any help!

Something you could do is use your geometry.vertices to populate a ConvexGeometry (you will need to link to ConvexGeometry.js and QuickHull.js).
You create your geometry as you did before
dotGeometry.vertices.push(new THREE.Vector3(0, 0, 0));
Then you will need to pass that onto your ConvexGeometry like so:
var geometry = new THREE.ConvexGeometry(dotGeometry.vertices);
After that, you apply your material as usual.
var material = new THREE.MeshPhongMaterial({
color: 0xffffff
});
var mesh = new THREE.Mesh(geometry, material);
Here's an example in CodePen;
This is assuming you need a convex shape. If you just need a plane, use a PlaneGeometry.
r87

Related

WireFrame of Json formated geometry in Three.js

I would like to display the wireframe of a parallelepiped defined by vertexes in a Json format using the following Three.js code
var testCube ={
"metadata":{
"version":json['version'],
"type":json['type'],
"uvs":json['n_uvs'],
"normals":json['n_normals'],
"faces":json['n_faces'],
"generator":"io_three",
"vertices":json['n_vertices'],
},
"faces":json['faces'],
"vertices":json['vertices'],
"normals":json['normals'],
"uvs":[],
"name":json['name']}
var loader = new THREE.JSONLoader();
var model = loader.parse( testCube );
meshBox = new THREE.Mesh( model.geometry, model.materials[ 0 ] );
var geo = new THREE.EdgesGeometry( meshBox.geometry );
var mat = new THREE.LineBasicMaterial( { color: 0xffffff, linewidth: 2 });
var wireframe = new THREE.LineSegments( geo, mat );
scene.add( wireframe );
however, the above code produce this kind of visualization:
while I would like to produce a visualization where also the internal wireframe is visible as the following:
Question: do you know how I can modify the above Three.js code to produce a full wireframe as displayed in the second picture?
Upadate: using the function WireframeGeometry you have the following plot:
Diagonals appear on each face of the mesh. Do yo know a function that does not produce diagonals?
Thank you very much for your help!
The solution is rough and imperfect, and it's a huge field for improvement and optimization.
You create one geometry and share it between two instances of THREE.LineSegments() for opposing sides of a box.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(-15, 10, 10);
var renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
scene.add(new THREE.AmbientLight(0xffffff, .5));
var light = new THREE.DirectionalLight(0xffffff, .5);
light.position.setScalar(10);
scene.add(light);
var box = new THREE.Mesh(new THREE.BoxGeometry(10, 5, 5, 5, 5, 5), new THREE.MeshLambertMaterial({color:"gray"}));
scene.add(box);
var material = new THREE.LineBasicMaterial({
vertexColors: THREE.VertexColors
});
var params = box.geometry.parameters;
var geometryGridXY = Grid(params.width, params.height, params.widthSegments, params.heightSegments, "yellow");
var gridXYFront = new THREE.LineSegments(geometryGridXY, material);
gridXYFront.position.z = params.depth / 2 + 0.001;
box.add(gridXYFront);
var gridXYBack = new THREE.LineSegments(geometryGridXY, material);
gridXYBack.position.z = -params.depth / 2 - 0.001;
box.add(gridXYBack);
var geometryGridYZ = Grid(params.height, params.depth, params.heightSegments, params.depthSegments, "aqua");
var gridYZLeft = new THREE.LineSegments(geometryGridYZ, material);
gridYZLeft.position.x = -params.width / 2 - 0.001;
gridYZLeft.rotation.y = -Math.PI * .5;
box.add(gridYZLeft);
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script>
function Grid(width, height, widthSegments, heightSegments, color) {
width = width || 1;
height = height || 1;
widthSegments = widthSegments || 1;
heightSegments = heightSegments || 1;
color = new THREE.Color(color !== undefined ? color : 0x444444);
var stepWidth = width / widthSegments;
var stepHeight = height / heightSegments;
var halfWidth = width / 2;
var halfHeight = height / 2;
var vertices = [],
colors = [], j = 0;
for (let i = 0, k = -halfHeight; i <= heightSegments; i++, k += stepHeight) {
vertices.push(-halfWidth, k, 0, halfWidth, k, 0);
color.toArray(colors, j); j += 3;
color.toArray(colors, j); j += 3;
}
for (let i = 0, k = -halfWidth; i <= widthSegments; i++, k += stepWidth) {
vertices.push(k, halfHeight, 0, k, -halfHeight, 0);
color.toArray(colors, j); j += 3;
color.toArray(colors, j); j += 3;
}
var geometry = new THREE.BufferGeometry();
geometry.addAttribute('position', new THREE.BufferAttribute(new Float32Array(vertices), 3));
geometry.addAttribute('color', new THREE.BufferAttribute(new Float32Array(colors), 3));
return geometry;
}
</script>

How can I use three js to generate terrain using voxel generators

I have seen voxel js, but it seems to be outdated, and it uses node js, which I do not want to use. I want to generate simple terrain using for loops, and my function to create a block.
Here is my function:
function createBlock(block, x, y, z, top, bottom, front, back, left, right) {
var geometry;
var meshFaceMaterial;
var mesh;
var material;
var blockObj = {};
if (top == true) {
geometry = new THREE.PlaneGeometry(1, 1);
material = new THREE.MeshPhongMaterial({map: THREE.ImageUtils.loadTexture(blocks[block].top)});
meshFaceMaterial = new THREE.MeshFaceMaterial(material);
mesh = new THREE.Mesh(geometry, meshFaceMaterial);
mesh.position.z = z;
mesh.position.x = x;
mesh.position.y = y+5;
mesh.rotation.x = (-90 * Math.PI)/180;
blockObj.top = mesh;
}
if (bottom == true) {
geometry = new THREE.PlaneGeometry(1, 1);
material = new THREE.MeshPhongMaterial({map: THREE.ImageUtils.loadTexture(blocks[block].bottom)});
meshFaceMaterial = new THREE.MeshFaceMaterial(material);
mesh = new THREE.Mesh(geometry, meshFaceMaterial);
mesh.position.z = z;
mesh.position.x = x;
mesh.position.y = y-5;
mesh.rotation.x = (90 * Math.PI)/180;
blockObj.bottom = mesh;
}
if (back == true) {
geometry = new THREE.PlaneGeometry(1, 1);
material = new THREE.MeshPhongMaterial({map: THREE.ImageUtils.loadTexture(blocks[block].side)});
meshFaceMaterial = new THREE.MeshFaceMaterial(material);
mesh = new THREE.Mesh(geometry, meshFaceMaterial);
mesh.position.z = z-5;
mesh.position.x = x;
mesh.position.y = y;
mesh.rotation.y = (180 * Math.PI)/180;
blockObj.back = mesh;
}
if (right == true) {
geometry = new THREE.PlaneGeometry(1, 1);
material = new THREE.MeshPhongMaterial({map: THREE.ImageUtils.loadTexture(blocks[block].side)});
meshFaceMaterial = new THREE.MeshFaceMaterial(material);
mesh = new THREE.Mesh(geometry, meshFaceMaterial);
mesh.position.z = z;
mesh.position.x = x+5;
mesh.position.y = y;
mesh.rotation.y = (90 * Math.PI)/180;
blockObj.right = mesh;
}
if (left == true) {
geometry = new THREE.PlaneGeometry(1, 1);
material = new THREE.MeshPhongMaterial({map: THREE.ImageUtils.loadTexture(blocks[block].side)});
meshFaceMaterial = new THREE.MeshFaceMaterial(material);
mesh = new THREE.Mesh(geometry, meshFaceMaterial);
mesh.position.z = z;
mesh.position.x = x-5;
mesh.position.y = y;
mesh.rotation.y = (-90 * Math.PI)/180;
blockObj.left = mesh;
}
if (front == true) {
geometry = new THREE.PlaneGeometry(1, 1);
material = new THREE.MeshPhongMaterial({map: THREE.ImageUtils.loadTexture(blocks[block].side)});
meshFaceMaterial = new THREE.MeshFaceMaterial(material);
mesh = new THREE.Mesh(geometry, meshFaceMaterial);
mesh.position.z = z+5;
mesh.position.x = x;
mesh.position.y = y;
blockObj.front = mesh;
}
blockObjects.push(blockObj);
return blockObj;
}
Any help would be appreciated.
Here is an algorithm that creates cubes and builds a random terrain with them. In this case I have fixed the terrain height change to be at most one cube height higher than the adjacent cubes. I have randomly generated a green color for each cube but you could obviously apply whatever texture you have in mind.
var camera, scene, renderer;
var mesh;
var cubesize = 30;
var landscape_width = 30;
var landscape_length = 30;
var heights = [];
var camera_offset = cubesize * landscape_width *0.7;
var camera_height = cubesize * landscape_width / 2;
function init() {
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set(0,camera_offset,camera_height);
camera.up = new THREE.Vector3(0,0,1);
camera.lookAt(new THREE.Vector3(0,0,0));
scene = new THREE.Scene();
geom = new THREE.CubeGeometry( cubesize, cubesize, cubesize );
cubes = new THREE.Object3D();
scene.add( cubes );
var xoff = landscape_width * cubesize / 2;
var yoff = landscape_length * cubesize / 2;
for(var i=0; i<landscape_width; i++) heights[i,0] = 0;
for(var j=0; j<landscape_length; j++) heights[0,j] = 0;
for(var i=1; i<landscape_width; i++) {
var h = heights[i-1,0];
for(var j=1; j< landscape_length; j++ ) {
var rand = Math.random();
if(heights[i-1,j] == heights[i,j-1]) { // level ground, go up dn or stay
if(rand < 0.33)
heights[i,j] = heights[i-1,j] - cubesize;
else if (rand > 0.66)
heights[i,j] = heights[i-1,j] + cubesize;
else
heights[i,j] = heights[i-1,j];
}
else if(Math.abs(heights[i-1,j] - heights[i,j-1]) > cubesize) { // two edges are wide apart, split the difference
heights[i,j] = (heights[i-1,j] +heights[i,j-1])/2;
}
else {
if(rand > 0.5)
heights[i,j] = heights[i-1,j];
else
heights[i,j] = heights[i,j-1];
}
var grayness = Math.random() * 0.5 + 0.25,
mat = new THREE.MeshBasicMaterial(),
cube = new THREE.Mesh( geom, mat );
mat.color.setRGB( 0, grayness, 0 );
cube.position.set( i*cubesize - xoff, j*cubesize - yoff, heights[i,j] );
cubes.add( cube );
}
}
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
var angle = 0;
function animate() {
angle += 0.5;
var rads = angle * Math.PI /180;
camera.position.set(Math.cos(rads)*camera_offset,Math.sin(rads)*camera_offset,camera_height);
camera.lookAt(scene.position);
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
init();
animate();
body {
margin: 0px;
background-color: #000000;
overflow: hidden;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/85/three.js"></script>
If i understand your question, you're asking for loops that will call you function over 3 axis x, y, z.
You could do something like this:
for (var i = 0; i < SIZEX; i++) {
for (var j = 0; j < SIZEY; j++) {
for (var k = 0; k < SIZEZ; k++) {
createBlock(block, i, j, k, (k == SIZEZ-1), (k == 0), (j == SIZEY-1), (j == 0), (i == SIZEX-1), (i == 0));
}
}
}
This code will navigate in a 3 dimensions.
If (k == SIZEZ-1) is true, then top will be true in your function. Same for all the other.
I don't know what block is.
I hope that what you were looking for.

three.js[83] points vertices update not work [duplicate]

I am using Three.js r83.
I am trying to dynamically add points to a geometry, but the scene never gets updated.
This works :
var tmaterial = new THREE.PointsMaterial({
color: 0xff0000,
size: 5,
opacity: 1
});
var tgeometry = new THREE.Geometry();
var pointCloud = new THREE.Points(tgeometry, tmaterial);
for(var i = 0; i< 1000; i++) {
x = (Math.random() * 200) - 100;
y = (Math.random() * 200) - 100;
z = (Math.random() * 200) - 100;
tgeometry.vertices.push(new THREE.Vector3(x, y, z));
}
tgeometry.verticesNeedUpdate = true;
tgeometry.computeVertexNormals();
scene.add(pointCloud);
This doesn't work:
var tmaterial = new THREE.PointsMaterial({
color: 0xff0000,
size: 5,
opacity: 1
});
var tgeometry = new THREE.Geometry();
var pointCloud = new THREE.Points(tgeometry, tmaterial);
scene.add(pointCloud);
for(var i = 0; i< 1000; i++) {
x = (Math.random() * 200) - 100;
y = (Math.random() * 200) - 100;
z = (Math.random() * 200) - 100;
tgeometry.vertices.push(new THREE.Vector3(x, y, z));
}
tgeometry.verticesNeedUpdate = true;
tgeometry.elementsNeedUpdate = true;
tgeometry.computeVertexNormals();
renderer.render(scene, camera);
As you can see, the only difference is the fact that I add scene.add(pointCloud); before adding vertexes.
What do I miss?
You can find a fiddle Thanks to #hectate
To see what I means, just replace
init();
setPoints();
animate();
by
init();
animate();
setPoints();
I am not sure why the THREE.Geometry object doesn't update Points after initial rendering, but I got it working with a THREE.BufferGeometry instead.
Thanks to #Hectate who got a working fiddle for me and #WestLangley who directed me to the hints, here is the working fiddle
BufferGeometry has a fixed number of Vertices, but you can decide how many of them you want to render. The trick is to make use of geometry.attributes.position.needsUpdate = true; and geometry.setDrawRange( 0, nbPointsYouWantToDisplay );
var MAX_POINTS = 1000000;
var geometry = new THREE.BufferGeometry();
var positions = new Float32Array( MAX_POINTS * 3 );
geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
Then you can create your cloudpoints and add it to the scene:
//material and scene defined in question
pointCloud = new THREE.Points(geometry, material);
scene.add(pointCloud);
Now I want to add and render 500 new points every 10 milliseconds.
var nbPoints = 500;
var INTERVAL_DURATION = 10;
All I have to do is :
var interval = setInterval(function() {
setPoints();
}, INTERVAL_DURATION)
function setPoints() {
var positions = pointCloud.geometry.attributes.position.array;
var x, y, z, index;
var l = currentPoints + nbPoints;
if(l >= MAX_POINTS) {
clearInterval(interval);
}
for ( var i = currentPoints; i < l; i ++ ) {
x = ( Math.random() - 0.5 ) * 300;
y = ( Math.random() - 0.5 ) * 300;
z = ( Math.random() - 0.5 ) * 300;
positions[ currentPointsIndex ++ ] = x;
positions[ currentPointsIndex ++ ] = y;
positions[ currentPointsIndex ++ ] = z;
}
currentPoints = l;
pointCloud.geometry.attributes.position.needsUpdate = true;
pointCloud.geometry.setDrawRange( 0, currentPoints );
controls.update();
renderer.render(scene, camera);
}
Here's a fiddle with your first setup installed: https://jsfiddle.net/87wg5z27/236/
var scene, renderer, camera;
var cube;
var controls;
init();
animate();
function init()
{
renderer = new THREE.WebGLRenderer( {antialias:true} );
var width = window.innerWidth;
var height = window.innerHeight;
renderer.setSize (width, height);
document.body.appendChild (renderer.domElement);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera (45, width/height, 1, 10000);
camera.position.y = 160;
camera.position.z = 400;
camera.lookAt (new THREE.Vector3(0,0,0));
controls = new THREE.OrbitControls (camera, renderer.domElement);
var tmaterial = new THREE.PointsMaterial({
color: 0xff0000,
size: 5,
opacity: 1
});
var tgeometry = new THREE.Geometry();
var pointCloud = new THREE.Points(tgeometry, tmaterial);
for(var i = 0; i< 1000; i++) {
x = (Math.random() * 200) - 100;
y = (Math.random() * 200) - 100;
z = (Math.random() * 200) - 100;
tgeometry.vertices.push(new THREE.Vector3(x, y, z));
}
tgeometry.verticesNeedUpdate = true;
tgeometry.computeVertexNormals();
scene.add(pointCloud);
window.addEventListener ('resize', onWindowResize, false);
}
function onWindowResize ()
{
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize (window.innerWidth, window.innerHeight);
}
function animate()
{
controls.update();
requestAnimationFrame ( animate );
renderer.render (scene, camera);
}
Here's one with your second: https://jsfiddle.net/87wg5z27/237/
var scene, renderer, camera;
var cube;
var controls;
init();
animate();
function init()
{
renderer = new THREE.WebGLRenderer( {antialias:true} );
var width = window.innerWidth;
var height = window.innerHeight;
renderer.setSize (width, height);
document.body.appendChild (renderer.domElement);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera (45, width/height, 1, 10000);
camera.position.y = 160;
camera.position.z = 400;
camera.lookAt (new THREE.Vector3(0,0,0));
controls = new THREE.OrbitControls (camera, renderer.domElement);
var tmaterial = new THREE.PointsMaterial({
color: 0xff0000,
size: 5,
opacity: 1
});
var tgeometry = new THREE.Geometry();
var pointCloud = new THREE.Points(tgeometry, tmaterial);
scene.add(pointCloud);
for(var i = 0; i< 1000; i++) {
x = (Math.random() * 200) - 100;
y = (Math.random() * 200) - 100;
z = (Math.random() * 200) - 100;
tgeometry.vertices.push(new THREE.Vector3(x, y, z));
}
tgeometry.verticesNeedUpdate = true;
tgeometry.elementsNeedUpdate = true;
tgeometry.computeVertexNormals();
renderer.render(scene, camera);
window.addEventListener ('resize', onWindowResize, false);
}
function onWindowResize ()
{
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize (window.innerWidth, window.innerHeight);
}
function animate()
{
controls.update();
requestAnimationFrame ( animate );
renderer.render (scene, camera);
}
In both cases the point cloud shows for me perfectly fine (release 82). Perhaps there is something else missing where you're neglecting to render something? I notice that your first example doesn't show at what step you call render(). I hope this helps!

three.js adding object to scene but not rendering object

I'm creating a function createCylinder(n, len, rad) that is called from function createScene(). I have checked that the vertices and faces are added and I get no errors. However, the geometry is not rendered. I suppose this has to do with the timing of returning the geometry or returning the mesh and adding it to the scene. That being said, I have tried everything I could think of and found no solution. Can someone please help me figure this out? Thanks in advance!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Cylinder</title>
</head>
<script type="text/javascript" src="three.js"></script>
<script type="text/javascript" src="OrbitControls.js"></script>
<style>
body {
/* set margin to 0 and overflow to hidden, to go fullscreen */
margin: 0;
overflow: hidden;
}
</style>
<body>
<div id="container">
</div>
<div id="msg">
</div>
<script type="text/javascript">
var camera, scene, renderer;
var cameraControls;
var clock = new THREE.Clock();
var isCappedBottom = false;
var isCappedTop = false;
function createCylinder(n, len, rad) {
var geometry = new THREE.Geometry();
var radius = rad;
var length = len;
var yUp = length / 2;
var yDown = -length / 2;
var theta = (2.0 * Math.PI) / n;
for (var i = 0; i < n ; i++) { //runs n + 2 times if we allow redundant vertices
var x = radius * Math.cos(i * theta);
var z = radius * Math.sin(i * theta);
//Top to bottom
var originUp = new THREE.Vector3(x, yUp, z);
var originDown = new THREE.Vector3(x, yDown, z);
geometry.vertices.push(originUp); //0
geometry.vertices.push(originDown); //1
console.log("Vertices " + geometry.vertices.length);
}//end of first for loop
// Draw faces
for (var j = 0; j < 2*n; j+= 2) {
var face1 = new THREE.Face3(j, j + 1, j + 2);
var face2 = new THREE.Face3(j + 1, j + 3, j + 2);
geometry.faces.push(face1);
geometry.faces.push(face2);
console.log("faces " + geometry.faces.length);
}
// return geometry;
//scene.add(geometry);
var material = new THREE.MeshLambertMaterial({color: 0xFF0000, side: THREE.DoubleSide});
var mesh = new THREE.Mesh(geometry, material);
return mesh;
scene.add(mesh);
// add subtle ambient lighting
var ambientLight = new THREE.AmbientLight(0x222222);
scene.add(ambientLight);
var light = new THREE.PointLight(0xFFFFFF, 1, 1000);
light.position.set(0, 10, 20);
scene.add(light);
var light2 = new THREE.PointLight(0xFFFFFF, 1, 1000);
light2.position.set(0, -10, -10);
scene.add(light2);
} //End of function
function createScene() {
var cyl = createCylinder(10, 10, 2);
return cyl;
scene.add(cyl);
}
function animate() {
window.requestAnimationFrame(animate);
render();
}
function render() {
var delta = clock.getDelta();
cameraControls.update(delta);
renderer.render(scene, camera);
}
function init() {
var canvasWidth = window.innerWidth;
var canvasHeight = window.innerHeight;
var canvasRatio = canvasWidth / canvasHeight;
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer({antialias: true, preserveDrawingBuffer: true});
renderer.gammaInput = true;
renderer.gammaOutput = true;
renderer.setSize(canvasWidth, canvasHeight);
renderer.setClearColor(0x000000, 1.0);
renderer.shadowMapEnabled = true;
camera = new THREE.PerspectiveCamera( 40, canvasRatio, 1, 1000);
/* camera.position.z = 5;
camera.lookAt(scene.position); */
camera.position.set(0, 0, 12);
camera.lookAt(new THREE.Vector3(0, 0, 0));
cameraControls = new THREE.OrbitControls(camera, renderer.domElement);
}
function addToDOM() {
var container = document.getElementById('container');
var canvas = container.getElementsByTagName('canvas');
if (canvas.length>0) {
container.removeChild(canvas[0]);
}
container.appendChild( renderer.domElement );
}
init();
createScene();
addToDOM();
render();
animate();
</script>
</body>
</html>
In the createCylinder function:
var mesh = new THREE.Mesh(geometry, material);
return mesh; // this line must be the last line in the function
// after return(), the rest of the code is unreacheable
//scene.add(mesh); // this line should be deleted as you add the mesh in the createScene() function
and then the createScene function should be like this:
function createScene() {
var cyl = createCylinder(10, 10, 2);
//return cyl;
scene.add(cyl);
}
jsfiddle example

THREE.js dynamically add points to a Points geometry does not render

I am using Three.js r83.
I am trying to dynamically add points to a geometry, but the scene never gets updated.
This works :
var tmaterial = new THREE.PointsMaterial({
color: 0xff0000,
size: 5,
opacity: 1
});
var tgeometry = new THREE.Geometry();
var pointCloud = new THREE.Points(tgeometry, tmaterial);
for(var i = 0; i< 1000; i++) {
x = (Math.random() * 200) - 100;
y = (Math.random() * 200) - 100;
z = (Math.random() * 200) - 100;
tgeometry.vertices.push(new THREE.Vector3(x, y, z));
}
tgeometry.verticesNeedUpdate = true;
tgeometry.computeVertexNormals();
scene.add(pointCloud);
This doesn't work:
var tmaterial = new THREE.PointsMaterial({
color: 0xff0000,
size: 5,
opacity: 1
});
var tgeometry = new THREE.Geometry();
var pointCloud = new THREE.Points(tgeometry, tmaterial);
scene.add(pointCloud);
for(var i = 0; i< 1000; i++) {
x = (Math.random() * 200) - 100;
y = (Math.random() * 200) - 100;
z = (Math.random() * 200) - 100;
tgeometry.vertices.push(new THREE.Vector3(x, y, z));
}
tgeometry.verticesNeedUpdate = true;
tgeometry.elementsNeedUpdate = true;
tgeometry.computeVertexNormals();
renderer.render(scene, camera);
As you can see, the only difference is the fact that I add scene.add(pointCloud); before adding vertexes.
What do I miss?
You can find a fiddle Thanks to #hectate
To see what I means, just replace
init();
setPoints();
animate();
by
init();
animate();
setPoints();
I am not sure why the THREE.Geometry object doesn't update Points after initial rendering, but I got it working with a THREE.BufferGeometry instead.
Thanks to #Hectate who got a working fiddle for me and #WestLangley who directed me to the hints, here is the working fiddle
BufferGeometry has a fixed number of Vertices, but you can decide how many of them you want to render. The trick is to make use of geometry.attributes.position.needsUpdate = true; and geometry.setDrawRange( 0, nbPointsYouWantToDisplay );
var MAX_POINTS = 1000000;
var geometry = new THREE.BufferGeometry();
var positions = new Float32Array( MAX_POINTS * 3 );
geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
Then you can create your cloudpoints and add it to the scene:
//material and scene defined in question
pointCloud = new THREE.Points(geometry, material);
scene.add(pointCloud);
Now I want to add and render 500 new points every 10 milliseconds.
var nbPoints = 500;
var INTERVAL_DURATION = 10;
All I have to do is :
var interval = setInterval(function() {
setPoints();
}, INTERVAL_DURATION)
function setPoints() {
var positions = pointCloud.geometry.attributes.position.array;
var x, y, z, index;
var l = currentPoints + nbPoints;
if(l >= MAX_POINTS) {
clearInterval(interval);
}
for ( var i = currentPoints; i < l; i ++ ) {
x = ( Math.random() - 0.5 ) * 300;
y = ( Math.random() - 0.5 ) * 300;
z = ( Math.random() - 0.5 ) * 300;
positions[ currentPointsIndex ++ ] = x;
positions[ currentPointsIndex ++ ] = y;
positions[ currentPointsIndex ++ ] = z;
}
currentPoints = l;
pointCloud.geometry.attributes.position.needsUpdate = true;
pointCloud.geometry.setDrawRange( 0, currentPoints );
controls.update();
renderer.render(scene, camera);
}
Here's a fiddle with your first setup installed: https://jsfiddle.net/87wg5z27/236/
var scene, renderer, camera;
var cube;
var controls;
init();
animate();
function init()
{
renderer = new THREE.WebGLRenderer( {antialias:true} );
var width = window.innerWidth;
var height = window.innerHeight;
renderer.setSize (width, height);
document.body.appendChild (renderer.domElement);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera (45, width/height, 1, 10000);
camera.position.y = 160;
camera.position.z = 400;
camera.lookAt (new THREE.Vector3(0,0,0));
controls = new THREE.OrbitControls (camera, renderer.domElement);
var tmaterial = new THREE.PointsMaterial({
color: 0xff0000,
size: 5,
opacity: 1
});
var tgeometry = new THREE.Geometry();
var pointCloud = new THREE.Points(tgeometry, tmaterial);
for(var i = 0; i< 1000; i++) {
x = (Math.random() * 200) - 100;
y = (Math.random() * 200) - 100;
z = (Math.random() * 200) - 100;
tgeometry.vertices.push(new THREE.Vector3(x, y, z));
}
tgeometry.verticesNeedUpdate = true;
tgeometry.computeVertexNormals();
scene.add(pointCloud);
window.addEventListener ('resize', onWindowResize, false);
}
function onWindowResize ()
{
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize (window.innerWidth, window.innerHeight);
}
function animate()
{
controls.update();
requestAnimationFrame ( animate );
renderer.render (scene, camera);
}
Here's one with your second: https://jsfiddle.net/87wg5z27/237/
var scene, renderer, camera;
var cube;
var controls;
init();
animate();
function init()
{
renderer = new THREE.WebGLRenderer( {antialias:true} );
var width = window.innerWidth;
var height = window.innerHeight;
renderer.setSize (width, height);
document.body.appendChild (renderer.domElement);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera (45, width/height, 1, 10000);
camera.position.y = 160;
camera.position.z = 400;
camera.lookAt (new THREE.Vector3(0,0,0));
controls = new THREE.OrbitControls (camera, renderer.domElement);
var tmaterial = new THREE.PointsMaterial({
color: 0xff0000,
size: 5,
opacity: 1
});
var tgeometry = new THREE.Geometry();
var pointCloud = new THREE.Points(tgeometry, tmaterial);
scene.add(pointCloud);
for(var i = 0; i< 1000; i++) {
x = (Math.random() * 200) - 100;
y = (Math.random() * 200) - 100;
z = (Math.random() * 200) - 100;
tgeometry.vertices.push(new THREE.Vector3(x, y, z));
}
tgeometry.verticesNeedUpdate = true;
tgeometry.elementsNeedUpdate = true;
tgeometry.computeVertexNormals();
renderer.render(scene, camera);
window.addEventListener ('resize', onWindowResize, false);
}
function onWindowResize ()
{
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize (window.innerWidth, window.innerHeight);
}
function animate()
{
controls.update();
requestAnimationFrame ( animate );
renderer.render (scene, camera);
}
In both cases the point cloud shows for me perfectly fine (release 82). Perhaps there is something else missing where you're neglecting to render something? I notice that your first example doesn't show at what step you call render(). I hope this helps!

Categories

Resources