I am writing an interactive program, where the user can change the material, the light and the object that is displayed. The part where I write all the HTML tables and javascript events to handle user interactions, I think that works fine, so I am posting here just the relevant parts, I'll add a link to the whole file.
Here I create the scene, the object, the light and the rendering function:
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);
camera.position.z=5;
var geometry= new THREE.SphereGeometry(1,15,15);
var material= new THREE.MeshLambertMaterial({color:0xffffff, ambient:0xffffff, emissive:0xffffff});
var object= new THREE.Mesh(geometry,material);
material.name= "lambert";
object.name= "sphere";
scene.add(object);
var light= new THREE.PointLight(0xffffff);
light.position.set(0,0,20);
light.name= "point";
scene.add(light);
var render= function() {
requestAnimationFrame(render);
renderer.render(scene,camera);
}
render();
Then every time that the user, through a button, changes a parameter, I use these functions to change the material and light characteristics:
function changeLightParameters() {
var lightParameters= getLightParameters();
if(lightParameters== null) {
alert("Invalid values");
return;
}
if(light.name!= lightParameters.type) {
scene.remove(light);
if(lightParameters.type== "spot") {
light= new THREE.SpotLight(lightParameters.color);
}
else if(lightParameters.type== "point") {
light= new THREE.PointLight(lightParameters.color);
}
else if(lightParameters.type== "ambient") {
light= new THREE.AmbientLight(lightParameters.color);
}
else if(lightParameters.type== "area") {
light= new THREE.AreaLight(lightParameters.color);
}
else if(lightParameters.type== "directional") {
light= new THREE.DirectionalLight(lightParameters.color);
}
light.position.set(lightParameters.position.x, lightParameters.position.y, lightParameters.position.z);
light.name= lightParameters.name;
scene.add(light);
}
else {
light.position= lightParameters.position;
light.color= new THREE.Color(lightParameters.color);
}
}
function changeMaterialParameters() {
var materialParameters= getMaterialParameters();
if(materialParameters== null) {
alert("Invalid values");
return;
}
if(materialParameters.type!= material.name) {
scene.remove(object);
if(materialParameters.type== "lambert") {
material= new THREE.MeshLambertMaterial({
color:materialParameters.diffuse,
ambient:materialParameters.ambient,
emissive:materialParameters.emissive });
}
else if(materialParameters.type== "normal") {
material= new THREE.MeshNormalMaterial();
}
else if(materialParameters.type== "phong") {
material= new THREE.MeshPhongMaterial({
color:materialParameters.diffuse,
ambient:materialParameters.ambient,
emissive:materialParameters.emissive,
specular:materialParameters.specular,
shininess:materialParameters.shininess });
}
material.name= materialParameters.type;
object= new THREE.Mesh(geometry,material);
scene.add(object);
}
else {
material.color= new THREE.Color(materialParameters.diffuse);
material.ambient= new THREE.Color(materialParameters.ambient);
material.emissive= new THREE.Color(materialParameters.emissive);
material.specular= new THREE.Color(materialParameters.specular);
material.shininess= new THREE.Color(materialParameters.shininess);
material.needsUpdate= true;
}
}
In these functions I use getMaterialParameters()
and getLightParameters()
to get all the parameters passed in two tables containing some text fields to handle the values. I already tested these functions and they work, so it's not necessary to see the code. These functions return an object with this structure:
Light : color (number)
position (THREE.Vector3)
type (string, possibile values "ambient", "point", "spot", "point", "directional")
Material: diffuse (number)
ambient (number)
emissive (number)
specular (number)
shininess (number)
type (string, possible values "phong", "normal", "lambert")
Once got the material properties if the material type has changed, I create a new material from scratch, if instead just it's properties are changed I update it. Same for the light.
The problem is that the object seems irresponsive to light changes: if I change the light position/color nothing happens. I may also set the light's z to be -1000 that nothing changes. The Phong model doesn't seem correct to me, the object doesn't shine like it should. Example:
The parameters are: Phong material, shininess 100, diffuse light 0x00abb1, emissive light 0x006063, specular light 0xa9fcff, shininess light 100. White point light in position (20,20,200). If I displace the light to (0,0,0) the sphere looks the same. It doesn't seem realistic like it should, I think I'm doing something wrong.
Please tell me if I need to add more details, the full code is here: http://pastebin.com/3uwgwvfE
Update
I discover that the problem consists in the fact that I am not able to add a new light when the scene is already initialized. I've made a new program that is an example of how reproducing the problem: I start using a spot light, then when the user clicks on the canvas, I remove the light from the scene and I add a new light (directional). But it doesn't work: there is no lighting, I just see the ambient component. Code is here: http://pastebin.com/BVU0dPi3
needsUpdate
flags and add them back in only where they are needed. Avoidmaterial.color = new THREE.Color()
; usematerial.color.copy( color )
instead.shininess
is not aTHREE.Color
. – WestLangleymaterial.needsUpdate = true
if you are only moving a light. Setmaterial.emissive = 0x000000
. Setmaterial.specular = 0x050505
. Setmaterial.ambient
to the same value asmaterial.color
. – WestLangley<input type="number" value="20" id="light-position-z"> </input>
– WestLangley