【发布时间】:2013-10-17 05:23:55
【问题描述】:
我正在编写一个交互式程序,用户可以在其中更改显示的材质、灯光和对象。我编写所有 HTML 表和 javascript 事件以处理用户交互的部分,我认为效果很好,所以我在这里只发布相关部分,我将添加一个指向整个文件的链接。
在这里我创建了场景、对象、灯光和渲染函数:
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();
那么每当用户通过一个按钮改变一个参数时,我就使用这些函数来改变材质和光线特性:
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;
}
}
在这些函数中,我使用getMaterialParameters() 和getLightParameters() 来获取两个表中传递的所有参数,其中包含一些文本字段来处理值。我已经测试了这些功能并且它们可以工作,因此没有必要查看代码。这些函数返回一个具有这种结构的对象:
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")
一旦获得了材料属性,如果材料类型发生了变化,我会从头开始创建一个新材料,如果只是它的属性发生了变化,我会更新它。对光也一样。
问题是物体似乎对光线变化没有反应:如果我改变光线的位置/颜色,什么也没有发生。我也可以将灯光的 z 设置为 -1000,这样不会有任何变化。 Phong 模型对我来说似乎不正确,物体没有像它应该的那样发光。示例:
参数为:Phong材质,shininess 100,diffuse light 0x00abb1,emissive light 0x006063,specular light 0xa9fcff,shininess light 100。白点光在位置(20,20,200)。如果我将光线转移到 (0,0,0),球体看起来是一样的。这似乎并不现实,我想我做错了什么。
如果我需要添加更多详细信息,请告诉我,完整代码在这里:http://pastebin.com/3uwgwvfE
更新
我发现问题在于场景已经初始化时我无法添加新灯光。我制作了一个新程序,作为如何重现问题的示例:我开始使用聚光灯,然后当用户单击画布时,我从场景中移除灯光并添加新灯光(定向)。但它不起作用:没有照明,我只看到环境成分。代码在这里:http://pastebin.com/BVU0dPi3
【问题讨论】:
-
参见 Wiki 文章 How to Update Things with WebGLRenderer。还要删除所有
needsUpdate标志并仅在需要它们的地方重新添加它们。避免material.color = new THREE.Color();改用material.color.copy( color )。shininess不是THREE.Color。 -
它说“这些变化需要构建新的着色器程序。您需要将 material.needsUpdate 标志设置为 true”。因此,当我移动灯光时,我将 material.needsUpdate 设置为 true,我只需要这样做吗?它不起作用(仍然是同样的问题)。
-
如果您只是移动一盏灯,则不需要设置
material.needsUpdate = true。设置material.emissive = 0x000000。设置material.specular = 0x050505。将material.ambient设置为与material.color相同的值。 -
仍然无事可做:如果我移动灯,什么也不会发生:圆柱体/球体上的闪亮区域不会移动。
-
您检查控制台是否有错误?
<input type="number" value="20" id="light-position-z"> </input>
标签: javascript html three.js light