Three.js - Why is csg.js not working? - javascript

I tried to use csg.js-functions to cut a sphere out of a box, but it is not working? I read the tutorial on http://learningthreejs.com/blog/2011/12/10/constructive-solid-geometry-with-csg-js/ but its still not working.
<html>
<head>
<title>Experiment</title>
</head>
<body>
<script src="three_js\build\three.min.js"></script>
<script src="ThreeCSG.js"></script>
<script src="csg.js"></script>
<script type="text/javascript">
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth-20, window.innerHeight -20);
document.body.appendChild( renderer.domElement );
var geometry1 = new THREE.BoxGeometry( 10, 10, 10);
var material = new THREE.MeshPhongMaterial( {specular: "#fdfb57", color: "#d8d613", emissive: "#6b6a0d", side: THREE.DoubleSide} );
var box = new THREE.Mesh(geometry1, material);
var sphere = new THREE.Mesh(new THREE.SphereGeometry(5, 32, 32), material);
scene.add(box);
scene.add(sphere);
var boxCsg = THREE.CSG.toCSG(box);
var sphereCsg = THREE.CSG.toCSG(sphere);
boxCsg.substract(sphereCsg);
box = THREE.CSG.fromCSG(boxCsg);
camera.position.z = 50;
var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
directionalLight.position.set( 5, 10, 5 );
scene.add( directionalLight );
var render = function () {
requestAnimationFrame( render );
renderer.render(scene, camera);
//Hier wird die Größe des Fensters manipuliert!
renderer.setSize(window.innerWidth - 20, window.innerHeight - 20);
};
render();
</script>
</body>
</html>

The article is outdated, this is the new syntax:
var box = new THREE.Mesh( new THREE.BoxGeometry( 10, 1, 10 ) );
var box_bsp = new ThreeBSP( box );
var cutgeo = new THREE.SphereGeometry( 1, 16, 8 );
var sub = new THREE.Mesh( cutgeo );
var subtract_bsp = new ThreeBSP( sub );
var result_bsp = box_bsp.subtract( substract_bsp );
var result = result_bsp.toMesh();
scene.add( result );
Three.js r107:
http://jsfiddle.net/r7suq1mv/2/

Related

Plotting 3d network in three.js

I am trying to generate a 3d graph using three.js
Code:
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/three#0.119.0/build/three.min.js"></script>
<style>
body { margin: 0; }
canvas { display: block; }
</style>
</head>
<body>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var node1_geometry = new THREE.BoxGeometry( 1, 1, 1 );
var node1_material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
var node1 = new THREE.Mesh( node1_geometry, node1_material );
node1.position.set(-2, 4, 1);
var node2_geometry = new THREE.BoxGeometry( 1, 1, 1 );
var node2_material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
var node2 = new THREE.Mesh( node2_geometry, node2_material );
node2.position.set(2, 4, 1);
var edge_geometry = new THREE.Geometry();
edge_geometry.vertices.push( node1.position, node2.position );
var edge_material = new THREE.LineBasicMaterial( { color: 0xffffff, linewidth: 2 } );
var edge = new THREE.Line( edge_geometry, edge_material );
scene.add( node1 );
scene.add( node2 );
scene.add( edge );
camera.position.z = 5;
var animate = function () {
requestAnimationFrame( animate );
renderer.render( scene, camera );
};
animate();
</script>
</body>
</html>
But this only gives a black window and the graph is not displayed.
Suggestions on how to fix this will be really helpful.
To get the snippet to run you have a small problem with you line
var edge_material = new THREE.LineBasicMaterial( { color: 0xffffff, linewidth: 2 } );
You can change this to:
var edge_material = new THREE.LineDashedMaterial({
color: 0xffffff,
dashSize: 2,
gapSize: 2
});
It should now render, but a black background still shows up. The problem now is that your camera is not angled at the content you have created, so add a line with a camera position below.
camera.position.y = 5;
Now you should be able to see your two boxes, and the line.
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
scene.background = new THREE.Color(0x333333);
var node1_geometry = new THREE.BoxGeometry(1, 1, 1);
var node1_material = new THREE.MeshBasicMaterial({
color: 0x00ff00
});
var node1 = new THREE.Mesh(node1_geometry, node1_material);
node1.position.set(-2, 4, 1);
var node2_geometry = new THREE.BoxGeometry(1, 1, 1);
var node2_material = new THREE.MeshBasicMaterial({
color: 0xff00ff
});
var node2 = new THREE.Mesh(node2_geometry, node2_material);
node2.position.set(2, 4, 1);
var edge_geometry = new THREE.Geometry();
edge_geometry.vertices.push(node1.position, node2.position);
var edge_material = new THREE.LineDashedMaterial({
color: 0xffffff,
dashSize: 2,
gapSize: 2
});
var edge = new THREE.Line(edge_geometry, edge_material);
scene.add(node1);
scene.add(node2);
scene.add(edge);
camera.position.z = 5;
camera.position.y = 5;
var animate = function() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
};
animate();
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/three#0.119.0/build/three.min.js"></script>
<style>
body {
margin: 0;
}
</style>
</head>
<body>
</body>
</html>

How create window, holes or subtract geometry in three.js

I'm new with three.js and I need to create a "room" with doors and windows. This is a simple task but I have found only not up to date answers.
Similar questions are here:
- subtracting-geometry-in-three-js
- is-it-possible-to-cut-parts-of-the-shape-geometry-away-in-three-js
In my case, I have a big box and I want to subtract a smaller one JSFIDDLE example:
var material = new THREE.MeshBasicMaterial({color: 0xffff00});
var faceMaterial_Y = new THREE.MeshLambertMaterial( { color: 0x0087E6 } );
var faceMaterial = new THREE.MeshLambertMaterial( { color: 0x0087E6 } );
var geometry_Y = new THREE.BoxBufferGeometry( 1.5, 1.5, 0.99 );
var faceMaterial_Y = new THREE.MeshLambertMaterial( { color: 0xffff00 } );
var cube_Y = new THREE.Mesh( geometry_Y, faceMaterial_Y);
scene.add(cube_Y);
var geometry_A = new THREE.BoxBufferGeometry( 0.7, 0.7, 0.7 );
material = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
var faceMaterial_A = new THREE.MeshLambertMaterial( { color: 0x00ff00 } );
var cubeA = new THREE.Mesh( geometry_A, material );
cubeA.position.set( 0.5, 0.5, 0 );
// HOW TO SUBTRACT cube_Y - cubeA?
//create a group and add the three cubes
var group = new THREE.Group();
group.add( cubeA );
group.add( cube_Y );
scene.add( group );
Thanks for helping me!
An option is to use ThreeCSG / ThreeBSP to subtract geometries.
Create ThreeBSP objects form the cube geometries:
var geometry_Y = new THREE.BoxBufferGeometry( 1.5, 1.5, 0.99 );
var geometry_A = new THREE.BoxBufferGeometry( 0.7, 0.7, 0.7 );
geometry_A.translate( 0.5, 0.5, 0 );
var bsp_A = new ThreeBSP(geometry_A);
var bsp_Y = new ThreeBSP(geometry_Y);
Subtract the geometry and create a Mesh:
var bsp_YsubA = bsp_Y.subtract(bsp_A);
var bsp_mesh = bsp_YsubA.toMesh();
bsp_mesh.material = new THREE.MeshLambertMaterial( { color: 0x00ff00 } );
scene.add( bsp_mesh );
See the example:
(function onLoad() {
var container, camera, scene, renderer, controls;
init();
animate();
function init() {
container = document.getElementById('container');
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
container.appendChild(renderer.domElement);
scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(3, 1, -1);
scene.add(camera);
window.onresize = function() {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}
var ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);
var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
directionalLight.position.x = 4;
directionalLight.position.y = 1;
directionalLight.position.z = -2;
scene.add( directionalLight );
controls = new THREE.OrbitControls(camera, renderer.domElement);
addGridHelper();
createModel();
}
function createModel() {
var geometry_Y = new THREE.BoxBufferGeometry( 1.5, 1.5, 0.99 );
var geometry_A = new THREE.BoxBufferGeometry( 0.7, 0.7, 0.7 );
geometry_A.translate( 0.5, 0.5, 0 );
var bsp_A = new ThreeBSP(geometry_A);
var bsp_Y = new ThreeBSP(geometry_Y);
var bsp_YsubA = bsp_Y.subtract(bsp_A);
var bsp_mesh = bsp_YsubA.toMesh();
bsp_mesh.material = new THREE.MeshLambertMaterial( { color: 0x00ff00 } );
scene.add( bsp_mesh );
}
function addGridHelper() {
var helper = new THREE.GridHelper(10, 10);
helper.material.opacity = 0.25;
helper.material.transparent = true;
scene.add(helper);
var axis = new THREE.AxesHelper(100);
scene.add(axis);
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
renderer.render(scene, camera);
}
})();
<!--script src="https://threejs.org/build/three.js"></!--script-->
<script src="https://rawcdn.githack.com/mrdoob/three.js/r124/build/three.js"></script>
<script src="https://rawcdn.githack.com/mrdoob/three.js/r124/examples/js/controls/OrbitControls.js"></script>
<script src="https://rawgit.com/Wilt/ThreeCSG/develop/ThreeCSG.js"></script>
<div id="container"></div>
See also
Unexpected result using ThreeCSG
After using the threeBSP method, the created spheres are not smooth
https://github.com/manthrax/THREE-CSGMesh
You could try my CSG library. It is more robust than the other threejs csg solutions.

three.js multiple images on cylinder face

I am trying to display multiple images on the outside (not the top or bottom) of a rotating cylinder using three.js. I am able to display 1 image, but my goal is to display several side by side. I have added 3 textures to my materials array, but only the first is displayed. Any help is appreciated.
<html>
<head>
<title>My first three.js app</title>
<span>Test</span>
<style>
body { margin: 0; }
canvas { width: 100%; height: 100% }
</style>
</head>
<body>
<script src="js/three.js"></script>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 100, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.y = 24;
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var diameter = 20;
var geometry = new THREE.CylinderGeometry( diameter, diameter, 15, 32 );
var texture1 = new THREE.TextureLoader().load( 'images/image1.jpg' );
var texture2 = new THREE.TextureLoader().load( 'images/image2.jpg' );
var texture3 = new THREE.TextureLoader().load( 'images/image3.png' );
texture1.wrapS = THREE.RepeatWrapping;
//texture.wrapT = THREE.RepeatWrapping;
//texture.repeat.set( 1, 4 );
var materials = [];
materials.push(new THREE.MeshBasicMaterial({ map: texture1 }));
materials.push(new THREE.MeshBasicMaterial({ map: texture2 }));
materials.push(new THREE.MeshBasicMaterial({ map: texture3 }));
var cylinder = new THREE.Mesh( geometry, materials );
cylinder.position.y = 25;
scene.add( cylinder);
camera.position.z = 40;
function render() {
requestAnimationFrame(render);
//cylinder.rotation.z += 0.05;
cylinder.rotation.y += 0.005;
renderer.render(scene, camera);
}
render();
</script>
</body>
You want to apply three textures to your cylinder.
If you don't want to merge your textures into a single texture, one easy solution is to render three cylinder wedges, each with its own texture. Use a pattern like the following:
var group = new THREE.Group();
scene.add( group );
var geometry = new THREE.CylinderBufferGeometry( 5, 5, 10, 16, 1, false, 0, 2 * Math.PI / 3 ); // 1/3 cylinder wedge
var endCapMaterial = new THREE.MeshBasicMaterial();
// mesh
mesh = new THREE.Mesh( geometry, [ new THREE.MeshBasicMaterial( { map: texture1 } ), endCapMaterial, endCapMaterial ] );
mesh.rotation.set( 0, 0, 0 );
group.add( mesh );
mesh = new THREE.Mesh( geometry, [ new THREE.MeshBasicMaterial( { map: texture2 } ), endCapMaterial, endCapMaterial ] );
mesh.rotation.set( 0, 2 * Math.PI / 3, 0 );
group.add( mesh );
mesh = new THREE.Mesh( geometry, [ new THREE.MeshBasicMaterial( { map: texture3 } ), endCapMaterial, endCapMaterial ] );
mesh.rotation.set( 0, 4 * Math.PI / 3, 0 );
group.add( mesh );
three.js r.89
Another way is to assign textures to each face of your geometry using geometry.faces[i].materialIndex property. In this case you should use the number of radial segments that is a multiple of three (if you have 3 textures).
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/89/three.min.js"></script>
<html>
<head>
<title>My first three.js app</title>
<style>
body { margin: 0; overflow:hidden;}
canvas { width: 100%; height: 100% }
</style>
</head>
<body>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 100, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.y = 24;
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var diameter = 20;
var radialSegments = 33;
var geometry = new THREE.CylinderGeometry( diameter, diameter, 15, radialSegments );
var img1 = "http://d2gg9evh47fn9z.cloudfront.net/800px_COLOURBOX9108127.jpg";
var img2 = "http://d2gg9evh47fn9z.cloudfront.net/thumb_COLOURBOX8923432.jpg";
var img3 = "http://d2gg9evh47fn9z.cloudfront.net/800px_COLOURBOX19377428.jpg";
var texture1 = new THREE.TextureLoader().load( img1 );
var texture2 = new THREE.TextureLoader().load( img2 );
var texture3 = new THREE.TextureLoader().load( img3 );
THREE.DefaultLoadingManager.onLoad = function () {
var materials = [];
materials.push(new THREE.MeshBasicMaterial({ map: texture1 }));
materials.push(new THREE.MeshBasicMaterial({ map: texture2 }));
materials.push(new THREE.MeshBasicMaterial({ map: texture3 }));
var l = geometry.faces.length;
for (var i = 0; i < l; i++) {
if (geometry.faces[i].normal.y !== 0) {
// these are caps
geometry.faces[i].materialIndex = 0;
} else {
// each segment has 2 faces
geometry.faces[i].materialIndex = Math.floor(i * 3 / (radialSegments * 2));
}
}
var cylinder = new THREE.Mesh( geometry, materials);
cylinder.position.y = 25;
scene.add( cylinder);
camera.position.z = 40;
function render() {
requestAnimationFrame(render);
cylinder.rotation.y += 0.005;
renderer.render(scene, camera);
}
render();
}
</script>
</body>

Three js load Img in Scene

i would like to load a image in my 360 degree Scene but it dosen't work.
My Code:
<script>
var controls, camera, scene, renderer, element;
var container;
var sceneCube;
init();
animate();
function init() {
// CAMERAS
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 100000 );
camera.position.set( 0, 0, 1000 );
cameraCube = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 100000 );
//
renderer = new THREE.WebGLRenderer();
renderer.autoClear = false;
renderer.setSize( window.innerWidth, window.innerHeight );
element = renderer.domElement;
container = document.getElementById('webglviewer');
container.appendChild(element);
//
controls = new THREE.OrbitControls( camera, element );
controls.noPan = true;
controls.noZoom = true;
// SCENE
scene = new THREE.Scene();
sceneCube = new THREE.Scene();
// Textures
var r = "textures/cube/Bridge2/";
var urls = [ r + "face_4_2048.jpg", r + "face_2_2048.jpg",
r + "face_6_2048.jpg", r + "face_5_2048.jpg",
r + "face_1_2048.jpg", r + "face_3_2048.jpg" ];
textureCube = THREE.ImageUtils.loadTextureCube( urls );
textureCube.format = THREE.RGBFormat;
textureCube.mapping = THREE.CubeReflectionMapping;
// Materials
var cubeShader = THREE.ShaderLib[ "cube" ];
var cubeMaterial = new THREE.ShaderMaterial( {
fragmentShader: cubeShader.fragmentShader,
vertexShader: cubeShader.vertexShader,
uniforms: cubeShader.uniforms,
depthWrite: true,
side: THREE.BackSide
} );
cubeMaterial.uniforms[ "tCube" ].value = textureCube;
// Skybox
cubeMesh = new THREE.Mesh( new THREE.BoxGeometry( 100, 100, 100 ), cubeMaterial );
sceneCube.add( cubeMesh );
var materials = THREE.ImageUtils.loadTexture('badge.png');
myImg = new THREE.Mesh(
new THREE.BoxGeometry( 562, 562, 562, 1, 1, 1 ),
new THREE.MeshFaceMaterial( materials ) );
sceneCube.add( myImg );
//INIT END
}
function onWindowResize() {
var width = container.offsetWidth;
var height = container.offsetHeight;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
cameraCube.aspect = window.innerWidth / window.innerHeight;
cameraCube.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
//
function animate() {
requestAnimationFrame( animate );
render();
controls.update();
}
function render() {
var timer = -0.0002 * Date.now();
camera.lookAt( scene.position );
cameraCube.rotation.copy( camera.rotation );
renderer.render( sceneCube, cameraCube );
renderer.render( scene, camera );
}
At this position:
var materials = THREE.ImageUtils.loadTexture('badge.png');
myImg = new THREE.Mesh(
new THREE.BoxGeometry( 562, 562, 562, 1, 1, 1 ),
new THREE.MeshFaceMaterial( materials ) );
sceneCube.add( myImg );
Got this error message:
three.min.js:538 Uncaught TypeError: Cannot read property 'visible' of undefined
Many thanks for help!
Your code and the version of three.js that you are using are not the same. Your code looks like it could be compatible with three.js version r72.

Create a unique sphere geometry from a sphere and a cylinder Three.js

I'm trying to create a bead like object in Three.js, essentially a sphere with a cylinder through it. I can create the two independently, but I'm wondering how to match the height of the sphere and the cylinder and how to merge / intersect them, so that the result will be one geometry.
Any ideas?
Thanks!
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
//material
var material = new THREE.MeshNormalMaterial( {
wireframe: true
} );
//sphere
var sphere = new THREE.SphereGeometry(2,20,20);
var sphereMesh = new THREE.Mesh( sphere, material );
scene.add( sphereMesh );
//cyl
var cylinder = new THREE.CylinderGeometry(0.5, 0.5, 2, 32 );
var cylinderMesh = new THREE.Mesh( cylinder, material );
scene.add( cylinderMesh );
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = 5;
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
render();
http://jsfiddle.net/RqU2v/
#gaitat, totally awesome, thanks.
here's the solution with ThreeCSG:
//sphere
var sphere = new THREE.SphereGeometry(2,20,20);
var sphereMesh = new THREE.Mesh( sphere, material );
var sphereBSP = new ThreeBSP( sphereMesh );
//cyl
var cylinder = new THREE.CylinderGeometry(0.5, 0.5, 5, 32 );
var cylinderMesh = new THREE.Mesh( cylinder, material );
var cylinderBSP = new ThreeBSP( cylinderMesh );
//result
var subtract_bsp = sphereBSP.subtract( cylinderBSP );
var result = subtract_bsp.toMesh( material );
result.geometry.computeVertexNormals();
scene.add( result );

Categories

Resources