1
votes

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:

enter image description here

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

1
See the Wiki article How to Update Things with WebGLRenderer. Also remove all needsUpdate flags and add them back in only where they are needed. Avoid material.color = new THREE.Color(); use material.color.copy( color ) instead. shininess is not a THREE.Color.WestLangley
It says "Changes in these require building of new shader program. You'll need to set material.needsUpdate flag to true". So when I move the light I'm setting material.needsUpdate to true, is that all I need to do? It doesn't work (still the same problem).Ramy Al Zuhouri
You do NOT need to set material.needsUpdate = true if you are only moving a light. Set material.emissive = 0x000000. Set material.specular = 0x050505. Set material.ambientto the same value as material.color.WestLangley
Still nothing to do: if I move the light nothing happens: the shiny area on the cylinder/sphere doesn't move.Ramy Al Zuhouri
Did you check the console for errors? <input type="number" value="20" id="light-position-z"> </input>WestLangley

1 Answers

0
votes

The problem was that when I was changing the light type, I had to update the material; The same is not valid for when I move the lights. So the program worked by adding this line:

// Change type of light and add it to the scene
material.needsUpdate= true;