I'm quite new to ThreeJS and I have a small issue (probably wrong usage). I'm trying to create a custom geometry and define the faces normals by myself.
I create one normal in one direction and the other one in the opposite direction, as my Mesh is not 2 sided I expect to see only one of the face, however I can see both of them... Any Idea of what I'm doing wrong ?
Thanks!
<body>
<script src="../build/Three.js"></script>
<script src="js/Stats.js"></script>
<script>
var container, stats;
var camera, scene, renderer;
container = document.createElement( 'div' );
document.body.appendChild( container );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 );
camera.up.x = 0;
camera.up.y = 0;
camera.up.z = 1;
camera.position.x = 300;
camera.position.y = -1000;
camera.position.z = 1000;
camera.lookAt(new THREE.Vector3(300, 250, 0));
scene.add( camera );
var light, geometry, material;
scene.add( new THREE.AmbientLight( 0x404040 ) );
light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 0, 1, 0 );
scene.add( light );
material = new THREE.MeshBasicMaterial( { color: 0xFFFF00, wireframe: false, transparent: false, opacity: 1 } );
geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3(0,0,0));
geometry.vertices.push(new THREE.Vector3(600,0,0));
geometry.vertices.push(new THREE.Vector3(0,-500,0));
geometry.vertices.push(new THREE.Vector3(600,-500,0));
var face;
face = new THREE.Face3(0,2,1);
face.normal.set(0,0,-1);
geometry.faces.push(face);
face = new THREE.Face3(2,3,1);
face.normal.set(0,0,1);
geometry.faces.push(face);
geometry.computeCentroids();
//geometry.computeFaceNormals();
//geometry.computeTangents();
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
renderer.render( scene, camera );
</script>
</body>
WebGLRenderer uses the vertex order in which you created the face for defining the orientation instead of the normal. Try doing this:
face = new THREE.Face3(2,1,3);
Related
I need to place a number of objects on the canvas, using three js. I'm getting stuck at the point of trying to change the location of the objects. My code is as below:
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 geometry = new THREE.BoxGeometry( 2, 1, 1 );
//geometry.position.x = 1;
//geometry.position.y = 1;
//geometry.position.z = 1;
var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
//scene.children[1].position.set(0, 0, 0);
var cube = new THREE.Mesh(geometry, material);
scene.add( cube );
camera.position.z = 5;
renderer.render( scene, camera );
I've commented out the two different ways I tried to achieve this (both failed). Can anyone suggest a solution?
You have to set position to a mesh, not a geometry:
var geometry = new THREE.BoxGeometry( 2, 1, 1 );
var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
var cube = new THREE.Mesh(geometry, material);
cube.position.set(1, 1, 1);
scene.add( cube );
I have a problem with CanvasRenderer rendering a Mesh that has multiple materials applied to a BoxBufferGeometry. It renders a Mesh with no materials applied. This is only problem with CanvasRenderer, when I use the same Mesh with WebGLRenderer all works as expected.
Here's an example code:
// three.js: multiple materials on a single mesh
var renderer, scene, camera, mesh;
init();
render();
function init() {
// renderer
renderer = new THREE.CanvasRenderer( { alpha: true } );
renderer.setSize( window.innerWidth / 2, window.innerHeight );
document.body.appendChild( renderer.domElement );
// scene
scene = new THREE.Scene();
// camera
camera = new THREE.PerspectiveCamera( 40, (window.innerWidth / 2) / window.innerHeight, 1, 1000 );
camera.position.set( 15, 20, 30 );
camera.lookAt(scene.position);
scene.add( camera );
// ambient
scene.add( new THREE.AmbientLight( 0xffffff, 0.1 ) );
// light
camera.add( new THREE.PointLight( 0xffffff, 1 ) );
// geometry
var geometry = new THREE.BoxBufferGeometry( 10, 10, 10 );
// materials
var material0 = new THREE.MeshBasicMaterial({ color: 0xff0000 });
var material1 = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
var material2 = new THREE.MeshBasicMaterial({ color: 0x0000ff });
var material3 = new THREE.MeshBasicMaterial({ color: 0xffff00 });
var material4 = new THREE.MeshBasicMaterial({ color: 0x00ffff });
var material5 = new THREE.MeshBasicMaterial({ color: 0xff00ff });
var materials = [ material0, material1, material2, material3, material4, material5 ];
// mesh
mesh = new THREE.Mesh( geometry, materials );
scene.add( mesh );
}
function render() {
requestAnimationFrame(render);
mesh.rotation.x += 0.005;
mesh.rotation.y += 0.01;
renderer.render( scene, camera );
}
I've also made this fiddle
Where you can see exactly what I'm talking about. In the fiddle there's a Mesh(cube) that has all 6 groups(sides) in different material(color), and that same Mesh is rendered with WebGLRenderer(left) and CanvasRenderer(right).
Can someone with more experience help me understand this.
Am I doing something wrong?
Is there some limitation with CanvasRenderer that disables it to render such a Mesh, and if so, how would I achieve this effect in some other way?
Is this a bug, and should I report it as an issue on three.js repository?
Thanks for your help!
Note:
I'm new to Three.js, so I apologize if I made some obvious mistake.
CanvasRenderer is crucial for me as I use phantom.js to capture some screenshots.
Three.js r93
CanvasRenderer does not appear to support BufferGeometry and multi-materials.
A work-around is to use Geometry, instead.
var geometry = new THREE.BoxGeometry( 10, 10, 10 );
three.js r.93
I am a beginner in THREE.js, I want to create a sphere which I will use to create globe with texture but I'm stuck when creating MeshPhongMaterial it appears nothing. Otherwise when I'm using MeshBasicMaterial it appears,
And this is my code
var mainScene, camera, aspect, renderer;
mainScene = new THREE.Scene();
aspect = window.innerWidth / window.innerHeight;
camera = new THREE.PerspectiveCamera(40, aspect, 0.1, 100);
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
var canvasContainer = document.getElementById("canvasContainer");
canvasContainer.appendChild(renderer.domElement);
var mesh = new THREE.Mesh(
new THREE.SphereGeometry(0.5,32,32),
new THREE.MeshPhongMaterial({
color: 0x00ff00,
wireframe: true
})
);
mainScene.add( mesh );
camera.position.z = 5;
var render = function(){
requestAnimationFrame(render);
renderer.render(mainScene, camera);
}
render();
I don't know what's wrong with this code and should I use MeshPhongMaterial to do it?
Thank you
MeshPhongMaterial requires scene lights.
Here is one way, but look at the three.js examples.
// ambient
scene.add( new THREE.AmbientLight( 0xffffff, 0.1 ) );
// light
var light = new THREE.PointLight( 0xffffff, 1 );
camera.add( light );
scene.add( camera ); // required because the camera has a child
three.js r.84
Three.js Version: 82
I'm looking at this example here: https://threejs.org/examples/#webgl_helpers
Notice that there are yellow boxes around the models. I was using version 79 and was using THREE.EdgesHelper to outline my 3D objects I made in Blender, but THREE.EdgesHelper was replaced by THREE.EdgesGeometry. I wanted to see an example of this, and the only one I could find is linked above.
I dove into the line and BoxHelper objects, but I didn't notice anything that would allow me to get rid of those yellow boxes.
JSFiddle: https://jsfiddle.net/4nbjvmpe/
Here is the code from the JSFiddle:
HTML
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
CSS
body {
background-color: #000;
margin: 0px;
overflow: hidden;
}
JavaScript
var mesh, renderer, scene, camera, controls;
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( 40, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set( 20, 20, 20 );
// controls
controls = new THREE.OrbitControls( camera );
// ambient
scene.add( new THREE.AmbientLight( 0x222222 ) );
// light
var light = new THREE.DirectionalLight( 0xffffff, 1 );
light.position.set( 20, 20, 0 );
scene.add( light );
// geometry
var geometry = new THREE.SphereGeometry( 5, 12, 8 );
// material
var material = new THREE.MeshPhongMaterial( {
color: 0x00ffff,
shading: THREE.FlatShading,
transparent: true,
opacity: 0.7,
} );
// mesh
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
// CUSTOM
// This is where I create the outline mesh.
var group = new THREE.Group();
scene.add( group );
group.updateMatrixWorld(true);
var edges = new THREE.EdgesGeometry(geometry);
var line = new THREE.LineSegments(edges);
group.add(line);
line.material.depthTest = true;
line.material.opacity = 0.25;
line.material.transparent = false;
this.outlineMesh = new THREE.BoxHelper(line);
scene.add(this.outlineMesh);
}
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
Simply comment this.outlineMesh = new THREE.BoxHelper(line); and scene.add(this.outlineMesh);. you will get want you want.
I need to hide the edges that are displayed in a box primitive using ThreeJS. These only are drawn when I put a texture on the faces.
I've tried with many options like wireframe=false, but the edges are still drawn.
This is the code:
var container, stats;
var camera, scene, renderer;
var canvasWidth = 500;
var canvasHeight = 500;
var windowHalfX = 100;
var windowHalfY = 100;
container = document.createElement( 'div' );
document.body.appendChild( container );
// Camera
camera = new THREE.OrthographicCamera( canvasWidth / - 2, canvasWidth / 2, canvasHeight / 2, canvasHeight / - 2, - 500, 5000 );
// Scene
scene = new THREE.Scene();
camera.position.x = 200;
camera.position.y = 200;
camera.position.z = 200;
camera.lookAt( scene.position );
// Renderer
renderer = new THREE.CanvasRenderer();
renderer.setClearColor( "#fff" );
renderer.setSize( canvasWidth, canvasHeight );
container.appendChild( renderer.domElement );
var size = 100;
geometry = new THREE.BoxGeometry( size, size, size );
material = new THREE.MeshBasicMaterial({
color: "#0000ff",
side: THREE.DoubleSide,
wireframe: false
});
// Comment this line to paint a single color cube
material = new THREE.MeshLambertMaterial({ map: THREE.ImageUtils.loadTexture("http://upload.wikimedia.org/wikipedia/commons/8/81/Color_icon_black.png") });
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
var draw = function() {
requestAnimationFrame( draw );
renderer.render( scene, camera );
}
draw();
And a link to the example:
http://jsfiddle.net/gyss/qg4x9/
Cheers!
I've solved my problem changing this line
renderer = new THREE.CanvasRenderer();
for this other
renderer = new THREE.WebGLRenderer();
Other possible solution, as WestLangley commented above is to use this line with CanvasRenderer
material.overdraw = 0.5; // or some number between 0 and 1
When using renderer = new THREE.CanvasRenderer();
to remove the edges, a parameter (overdraw:true) needs to be added to the material definition like this:
var material = new THREE.MeshBasicMaterial( { map: texture, overdraw: true } );
Then you can use add the material to the 3D object:
mesh = new THREE.MeshBasicMaterial( geometry, material );