In Three.js, lights don't work - webgl

I've been fooling around with Three.js for a while, and I don't seem to be able to get any sort of lights to work. The scene renders normally with the 0xFFFFFF ambient lighting, but adding lights doesn't have any effect. I've copied the code directly from the examples and the lights are listed in the children of scene, only not showing up...
var camera;
var scene;
var renderer;
$(document).ready(function() {
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.z = 600;
scene = new THREE.Scene();
scene.add(new THREE.PointLight(0xFF0000, 3.0, 1000));
renderer = new THREE.WebGLRenderer();
//renderer = new THREE.CanvasRenderer();
renderer.domElement.id = "canvas";
renderer.setSize(window.innerWidth, window.innerHeight);
$(window).resize(function() {
renderer.setSize(window.innerWidth, window.innerHeight);
});
$("#container").get(0).appendChild(renderer.domElement);
function Animate() {
requestAnimationFrame(Animate);
renderer.render(scene, camera);
}
Animate();
});

Your code does not give much to work with, but one thing to check is that your materials support lights. That means you should be using MeshLambertMaterial or MeshPhongMaterial. Also note that if you are using a custom ShaderMaterial, it does not magically get scene lighting.

Related

In A-Frame (AR.js), Want to make 3D object appear to come out of the floor, i.e. clip/mask below marker somehow

I am looking for a way to clip a 3D object below a certain point in A-Frame with Ar.js. The clipping point would be 0,0,0 I suppose, the marker location. My idea is to have an object appear to come out of the marker from below, so below that point you wouldn't see it. Hopefully my diagram will explain what I mean.
I have tried using a C4D compositing tag but as expected that doesn't export as a gltf object.
There is a neat technique used to create an invisible cloak - disabling the colorWrite property of a material.
Lets say you want to hide your object within a box. You need to create a box, slightly bigger than your object, and set its material as described:
AFRAME.registerComponent('cloak', {
init: function() {
var geometry = new THREE.BoxGeometry( 1.1, 1.1, 1.1 );
var material = new THREE.MeshBasicMaterial( {colorWrite: false} );
var cube = new THREE.Mesh( geometry, material );
this.el.object3D.add( cube );
}
})
Then just make sure its rendered before the cloaked objects:
<a-marker>
<a-entity cloak></a-entity>
<a-box animation="property: position; to: 0 1.2 0; dur: 1500;
easing: linear; loop: true; dir: alternate"> </a-box>
</a-marker>
check it out in this glitch.

Drawing Text to the canvas using three.js

To start, I am not the most advanced javascript developer. I have only now started to undertake a more serious study of the subject.
So one of my first forays in this subject is to draw some text to the canvas using the three.js library.But for the life of me, I can't get this sucker to work. I have looked on google and even through the three.js documentation. When I inspect the page in chrome, the page doesn't show any errors either. Here is my code for reference:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth /
window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setClearColor(0xdddddd);
var spotlight = new THREE.SpotLight(0xffffff,);
spotlight.castShadow = true;
spotlight.position.set(30,60,60);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var loader = new THREE.FontLoader();
loader.load( 'fonts/helvetiker_regular.typeface.json', function ( font ) {
var textGeo = new THREE.TextGeometry( 'Hello three.js!', {
font: font,
size: 80,
height: 5,
curveSegments: 12,
bevelEnabled: true,
bevelThickness: 10,
bevelSize: 8,
bevelSegments: 5
} );
var color = new THREE.Color();
color.setRGB(255, 250, 250);
textGeo.computeBoundingBox();
textGeo.computeVertexNormals();
var textMaterial = new THREE.MeshBasicMaterial({ color: color });
var mesh = new THREE.Mesh(textGeo, textMaterial);
mesh.position.x = textGeo.boundingBox.max.x / 2;
mesh.position.y = textGeo.boundingBox.max.y / 2;
mesh.castShadow = true;
scene.add(mesh);
} );
var render = function (){
requestAnimationFrame(render);
renderer.render(scene, camera);
}
camera.lookAt(scene.position);
render();
Also, for some background if it's needed, I am running this in debug mode in an asp.net application.
Thanks everyone.
I had my camera directly on the scene, so I couldn't see anything. Thanks prisoner for comment.

mapping texture to a sphere in ThreeJS

When mapping texture to a sphere in ThreeJS with I am loosing the sphere. Instead I am getting consol errors that read --
Uncaught TypeError: Cannot call method 'add' of undefined index.html:28
and
Cross-origin image load denied by Cross-Origin Resource Sharing policy.
The image is the correct size and resolution since it works in another instance where I was attempting texture mapping, however it is not working here. It must be a problem with how I am applying the map. I am new to both javascript and ThreeJS, so bear with me. Thank you.
<body>
<div id="container"></div>
<script src="javascript/mrdoob-three.js-ad419d4/build/three.js"></script>
<script defer="defer">
// renderer
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// camera
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 500;
// material
var material = new THREE.MeshLambertMaterial({
map: THREE.ImageUtils.loadTexture('images/physicalworldmapcolor.jpg')
});
// add subtle ambient lighting
var ambientLight = new THREE.AmbientLight(0x000044);
scene.add(ambientLight);
// directional lighting
var directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(1, 1, 1).normalize();
scene.add(directionalLight);
// scene
var scene = new THREE.Scene();
// sphere
// the first argument of THREE.SphereGeometry is the radius,
// the second argument is the segmentsWidth
// the third argument is the segmentsHeight.
var sphere = new THREE.Mesh(new THREE.SphereGeometry(150, 70, 50),
new THREE.MeshNormalMaterial(material));
sphere.overdraw = true;
scene.add(sphere);
renderer.render(scene, camera);
</script>
There are MANY errors with the code you provided.
Just check a basic example at:
https://github.com/mrdoob/three.js/
your script is missing a render loop, your camera is not added to the scene, the Three.Scene() constructor is called after already adding objects to "scene". Then you have MeshNormalMaterial() and wrapped in there another material. This won't work , just do Three.Mesh(SphereGeometry(...), material). "overdraw" is a material propery so you will have to do sphere.material.overdraw. But i think overdraw only affects stuff for the CSS canvas renderer and i am not sure if it has any meaning if you use WebGLRenderer
Concerning the error with cross-origin, read up here:
https://github.com/mrdoob/three.js/wiki/How-to-run-things-locally

THREE.JS Shadow on opposite side of light

I used THREE.js r49 create 2 cube geometry with a directional light to cast shadow on them and got result as in the following picture.
I noticed that the shadow in the green circle should not be appeared, since the directional light is behind both of the cube. I guess that this is the material issue, I've tried changing various material parameters as well as change the material type itself, but the result still the same. I also tested the same code with r50 and r51 and got the same result.
Could anybody please give me some hint how to get rid of that shadow.
Both cube are creating using CubeGeometry and MeshLambertMaterial as following code.
The code:
// ambient
var light = new THREE.AmbientLight( 0xcccccc );
scene.add( light );
// the large cube
var p_geometry = new THREE.CubeGeometry(10, 10, 10);
var p_material = new THREE.MeshLambertMaterial({ambient: 0x808080, color: 0xcccccc});
var p_mesh = new THREE.Mesh( p_geometry, p_material );
p_mesh.position.set(0, -5, 0);
p_mesh.castShadow = true;
p_mesh.receiveShadow = true;
scene.add(p_mesh);
// the small cube
var geometry = new THREE.CubeGeometry( 2, 2, 2 );
var material = new THREE.MeshLambertMaterial({ambient: 0x808080, color: Math.random() * 0xffffff});
var mesh = new THREE.Mesh( geometry, material );
mesh.position.set(0, 6, 3);
mesh.castShadow = true;
mesh.receiveShadow = true;
// add small cube as the child of large cube
p_mesh.add(mesh);
p_mesh.quaternion.setFromAxisAngle(new THREE.Vector3(0, 1, 0), 0.25 * Math.PI );
// the light source
var light = new THREE.DirectionalLight( 0xffffff );
light.castShadow = true;
light.position.set(0, 10, -8); // set it light source to top-behind the cubes
light.target = p_mesh // target the light to the large cube
light.shadowCameraNear = 5;
light.shadowCameraFar = 25;
light.shadowCameraRight = 10;
light.shadowCameraLeft = -10;
light.shadowCameraTop = 10;
light.shadowCameraBottom = -10;
light.shadowCameraVisible = true;
scene.add( light );
Yes, this is a known, and long-standing, WebGLRenderer issue.
The problem is that the dot product of the face normal and the light direction is not taken into consideration in the shadow calculation. As a consequence, "shadows show through from the back".
As a work-around, you could have a different material for each face, with only certain materials receiving shadows.
three.js r.71

Multiple collada scenes

I have two collada files (two different scenes: "01.dae" and "02.dae").
I want to display 01.dae first and right after the animation finishes I want to load and display 02.dae on the same canvas.
(I'm trying to modify "webgl_loader_collada_keyframe.html" to do this but no results so far.)
How could I handle more than one animated collada scenes? A source code or any tips or tricks would be appreciated!
Thank you for your answer. I modified my code based on your idae but unfortunately it's not working.
Could you take a look at my code please?
Here is my code:
loader.load( 'pump.dae', function ( collada ) {
model = collada.scene;
animations = collada.animations;
kfAnimationsLength = animations.length;
model.scale.x = model.scale.y = model.scale.z = 0.125; // 1/8 scale, modeled in cm
init();
start();
animate( lastTimestamp );
setTimeout(loadSecond,3000);
} );
function loadSecond()
{
loader2.load( 'pump2.dae', function ( collada2 )
{
scene.remove( model );
model2 = collada2.scene;
animations2 = collada2.animations;
kfAnimationsLength2 = animations2.length;
model2.scale.x = model2.scale.y = model2.scale.z = 0.125; // 1/8 scale, modeled in cm
init2();
start2();
animate2( lastTimestamp2 );
//alert("second loaded");
} );
}
...
As you can see I extended your code with
scene.remove( model );
to remove the previous scene.
The first scene displays and then disapears properly however the new secene does not load. Do you have an idae why?
(Note: I don't know how long my first scene realy is.)
If you know how long the animation is, you could use a setTimeout to load the second model.
var loader = new THREE.ColladaLoader();
loader.options.convertUpAxis = true;
loader.load('PATH TO MODEL', function colladaReady( collada){
dae = collada.scene;
skin = collada.skins[ 0 ];
dae.scale.x = dae.scale.y = dae.scale.z = 1;
dae.updateMatrix();
scene.add(dae);
render();
setTimeout(loadSecond,3000);
});
function loadSecond(){
var loader = new THREE.ColladaLoader();
loader.options.convertUpAxis = true;
loader.load('PATH TO MODEL', function colladaReady( collada){
///repeat model loading logic
}
Where the time interval in the setTimeout is equal to the length of your animation.

Resources