How do you enable shading in Three.js?
Various examples have shown it should be as simple as assigning THREE.FlatShading to your material, but when I do this, my shape has no shading at all.
My JS:
CANVAS_WIDTH = 200,
CANVAS_HEIGHT = 200;
var camera, scene, renderer;
var mesh;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 70, CANVAS_WIDTH / CANVAS_HEIGHT, 1, 1000 );
camera.position.z = 400;
scene = new THREE.Scene();
var geometry = new THREE.BoxBufferGeometry( 200, 200, 200 );
var material = new THREE.MeshBasicMaterial( {color: 0xff0000} );
material.shading = THREE.FlatShading;
for(var i=0; i<material.length; i++){
material[i].shading = THREE.FlatShading;
}
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
// light
//scene.add( new THREE.AmbientLight( 0x404040 ) );
light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 400, 400, 400 );
scene.add( light );
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( CANVAS_WIDTH, CANVAS_HEIGHT );
container = document.getElementById( 'accelgyro_canvas' );
container.appendChild( renderer.domElement );
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
console.log('animate')
requestAnimationFrame( animate );
mesh.rotation.x += 0.005;
mesh.rotation.y += 0.01;
renderer.render( scene, camera );
}
And this renders by cube as:
I've tried adjusting the light angles, adding/removing ambient light, changing which object I add the FlatShading to and nothing seems to help.
How do I fix this?
MeshBasicMaterial does not respond to lights. Use MeshLambertMaterial, MeshPhongMaterial, or MeshStandardMaterial.
Also, MeshLambertMaterial does not have a shading property. If you want FlatShading, you need to use MeshPhongMaterial, or MeshStandardMaterial.
three.js r.75
Are your looking for result like this.
Attaching the reference code for same
var camera, scene, renderer;
var mesh;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.z = 400;
scene = new THREE.Scene();
scene.add(new THREE.HemisphereLight(0xffffff,0xffffff,1.0))
var geometry = new THREE.BoxGeometry( 200, 200, 200 );
for ( var i = 0; i < geometry.faces.length; i++ )
{
geometry.faces[ i ].color.setRGB( 1.0 * Math.random()+0.2 , 0, 0 );
}
var material = new THREE.MeshBasicMaterial( { color:0xff0000,vertexColors: THREE.FaceColors } );
mesh = new THREE.Mesh( geometry, material );
//mesh.drawMode =THREE.TriangleStripDrawMode;
scene.add( mesh );
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 );
}
function animate() {
requestAnimationFrame( animate );
mesh.rotation.x += 0.005;
mesh.rotation.y += 0.01;
renderer.render( scene, camera );
}
Related
This is my source code.
I'm trying to make the TextGeometry always look to the camera?It's possible?
Code:
var stats;
var camera, controls, scene, renderer;
init();
render();
function init() {
scene = new THREE.Scene();
var ambient = new THREE.AmbientLight( 0xFFFFFF );
scene.add( ambient );
var container = document.getElementById('container');
renderer = new THREE.WebGLRenderer({antialias: 1 });
renderer.shadowMap.enabled = true;
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight);
renderer.setClearColor(0x013A65);
container.appendChild( renderer.domElement );
camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 5000 );
camera.position.set(0,0,0);
controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.addEventListener( 'change', render );
controls.enableKeys = false;
controls.enableZoom = true;
controls.minDistance = 2000;
controls.maxDistance = 3500;
controls.maxPolarAngle = Math.PI/2;
// world
var onError = function ( xhr ) { };
THREE.Loader.Handlers.add( /\.dds$/i, new THREE.DDSLoader() );
var mtlLoader = new THREE.MTLLoader();
mtlLoader.setPath( './assets/3d/' );
mtlLoader.load( 'A.mtl', function( materials ) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials( materials );
mtlLoader.setPath( './assets/3d/' );
objLoader.load( './assets/3d/A.obj', function ( object ) {
object.position.x = 0;
object.position.y = 0;
object.position.z = 0;
scene.add( object );
}, onError );
});
//Text
var loader = new THREE.FontLoader();
loader.load( './fonts/Open_Sans_Regular.json', function ( font ) {
var textGeometry = new THREE.TextGeometry( "Test", {font: font, size: 22, height: 3, curveSegments: 1});var textMaterial = new THREE.MeshPhongMaterial({ color: 0xFFFFFF, specular: 0xFFFFFF });var mesh1 = new THREE.Mesh( textGeometry, textMaterial );mesh1.position.x = -200;mesh1.position.y = 250;mesh1.position.z = 725;scene.add( mesh1);});
// lights
light = new THREE.DirectionalLight( 0xFFFFFF );
light.position.set( 1, 1, 1 );
scene.add( light );
window.addEventListener( 'resize', onWindowResize, true );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
stats.update();
render();
}
function render() {
renderer.render( scene, camera );
}
I already tried mesh.lookAt(camera.position) inside the render function but no sucess.
Best Regards.
I believe your question is how to make the text appear regardless of where the camera is. Instead of using text geometry you can try to put your text in a div container and make the position absolute using CSS. https://threejs.org/docs/#manual/en/introduction/Creating-text
function ani() {
if (Detector.webgl) {
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).width() - 20, $(window).height() );
document.body.appendChild( renderer.domElement );
var geometry = new THREE.BoxGeometry( 1, 1, 1);
var material = new THREE.MeshBasicMaterial( { color: 0xffffff } );
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );
camera.position.z = 5;
var render = function() {
requestAnimationFrame( render );
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render( scene, camera );
}
render();
} else {
var warning = Detector.getWebGLErrorMessage();
document.getElementById('container').appendChild(warning);
}
};
ani();
$(window).resize(ani);
Description:
The function ani is not being called on window resize to resize the renderer.
How can I fix this?
Thank you in advance!
Hi I currently working with three.js, I would like to create 4 cubes in the 4 parts of the axis. I am able to create one cube that is rotating but how do I create the other three?, I have tried the clone () function and position.set, but I cant seem to create another cube in a different axis. thanks for any help or guidance
Here is my javascript
var camera;
var scene;
var renderer;
var mesh;
init();
animate();
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000);
var light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 0, 1, 1 ).normalize();
scene.add(light);
var geometry = new THREE.CubeGeometry( 10, 10, 10);
var material = new THREE.MeshPhongMaterial( { ambient: 0x050505, color: 0x0033ff, specular: 0x555555, shininess: 30 } );
mesh = new THREE.Mesh(geometry, material );
mesh.position.z = -50;
scene.add( mesh );
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
window.addEventListener( 'resize', onWindowResize, false );
render();
}
function animate() {
mesh.rotation.x += .04;
mesh.rotation.y += .02;
render();
requestAnimationFrame( animate );
}
function render() {
renderer.render( scene, camera );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
render();
}
Have you added the clone to the scene?
var newMesh = mesh.clone();
newMesh.position.x = 50;
scene.add(newMesh);
You can see a working codepen here.
I'm newbie in Three.js, so, I'm trying just to make STATIC cube. So, I've found a rotating cube example. Here it is:
var camera, scene, renderer;
var mesh;
init();
animate();
//renderer.render( scene, camera );
function init() {
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.z = 400;
scene = new THREE.Scene();
var texture = THREE.ImageUtils.loadTexture( '16.jpg' );
var geometry = new THREE.BoxGeometry( 200, 200, 200 );
var material = new THREE.MeshBasicMaterial( { map: texture } );
var axes = new THREE.AxisHelper( 20 );
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
}
function animate() {
requestAnimationFrame( animate );
mesh.rotation.x += 0.005;
mesh.rotation.y += 0.01;
renderer.render( scene, camera );
}
ok, everything work fine. Now I want to make just STATIC cube, I've wrote
var camera, scene, renderer;
var mesh;
init();
renderer.render( scene, camera );
function init() {
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.z = 400;
scene = new THREE.Scene();
var texture = THREE.ImageUtils.loadTexture( '16.jpg' );
var geometry = new THREE.BoxGeometry( 200, 200, 200 );
var material = new THREE.MeshBasicMaterial( { map: texture } );
var axes = new THREE.AxisHelper( 20 );
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
}
The output is just a black screen, what have I done wrong?
The texture loading is asynchronous, and you are rendering the scene before it is done.
Add a callback to the Image Loader and render again:
var texture = THREE.ImageUtils.loadTexture('16.jpg', undefined, function () {
renderer.render(scene, camera);
});
Alternatively render continuosly with requestAnimationFrame:
init();
animate();
//...
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
it looks like when you got rid of animate(), you also got rid of the call to
renderer.render( scene, camera );
so you need to put that back in the code somewhere to render your scene
I have a texture mapped to a plane. Suppose I only want to move particular points in the plane. How would I go about doing so?
For example, I want to move the bottom right corner at a particular speed and the top right corner at a particular speed.
var camera;
var scene;
var renderer;
var mesh;
init();
animate();
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000);
var light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 0, 1, 1 ).normalize();
scene.add(light);
var geometry = new THREE.PlaneGeometry( 50, 50);
var texture = THREE.ImageUtils.loadTexture('images/03032122.png', {}, function() {
renderer.render(scene, camera);
})
var material = new THREE.MeshBasicMaterial({map: texture, transparent: true })
mesh = new THREE.Mesh(geometry, material );
mesh.position.z = -50;
scene.add( mesh );
renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0xffffff, 1);
document.body.appendChild( renderer.domElement );
window.addEventListener( 'resize', onWindowResize, false );
render();
}
function animate() {
//mesh.scale.x+= 0.0003;
render();
requestAnimationFrame( animate );
}
function render() {
renderer.render( scene, camera );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
render();
}
You can modify the geometry after the mesh creation by accessing its vertices array. If you want the vertex of rank 1 to move linearly in the +x direction, you can add in your render function :
mesh.geometry.vertices[1].x+=.01;
mesh.geometry.verticesNeedUpdate=true;
Beware to use PlaneBufferGeometry instead of PlaneGeometry.