My objects are all coming out black. I think it might have something to do with the light but I'm not sure. Here's an image showing the problem and here is my code:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
var directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);
var geometry = new THREE.Geometry();
var controls = new THREE.TrackballControls(camera);
var antMaterial = new THREE.MeshLambertMaterial({color: 0xff0000});
var material, mesh;
function init()
{
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColorHex(0x0088FF, 1);
document.body.appendChild(renderer.domElement);
camera.position.z += 5;
camera.position.y += 1;
//Controls
controls.rotateSpeed = 1.0;
controls.zoomSpeed = 1.0;
controls.panSpeed = 1.0;
controls.noZoom = false;
controls.noPan = false;
controls.staticMoving = true;
controls.addEventListener('change', render);
scene.add(ant());
directionalLight.position.set(1, 1, 1);
scene.add(directionalLight);
render();
animate();
}
The answer to your problem is most likely that your directional light comes from below the pane. This makes the colors on the other side, visible in your screenshot, black because the light does not reach this faces. Try to use an ambient light first or change the position to:
directionalLight.position.set(0,0,-1); // change these values for the direction of the light source
Related
When I have intersecting objects there is a weird line of light in the shadow where the objects intersect. I’ve tried different types of lights, materials, browsers (MacOS), and render settings. It occurs with one or more lights.
I found that adjusting the shadow bias (spotLight.shadow.bias = 0.0005) and using a relatively large shadowmap helped reduce the lines but did not get rid of them entirely. I'm guessing that this is issue relates to how the shadowmap is rendered.
Does anyone have any ideas for what is causing this, and how to solve it?
Example image showing lines of light in shadow on intersecting objects - Demo code: https://codepen.io/henryegloff/pen/eYyRJpx
import * as THREE from 'three';
import { OrbitControls } from 'https://unpkg.com/three#0.139.0/examples/jsm/controls/OrbitControls.js';
let scene, camera, renderer, controls;
let cube_mesh;
init();
function init() {
scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
camera = new THREE.PerspectiveCamera(25, window.innerWidth / window.innerHeight, 0.1,1000);
camera.position.set(0,1.5,-10);
renderer = new THREE.WebGLRenderer({ antialias:true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
//renderer.shadowMap.type = THREE.PCFShadowMap;
renderer.setAnimationLoop( animation );
renderer.toneMapping = THREE.LinearToneMapping;
renderer.physicallyCorrectLights = true;
document.body.appendChild(renderer.domElement);
window.addEventListener('resize', onWindowResize);
controls = new OrbitControls(camera, renderer.domElement);
controls.target = new THREE.Vector3(0, 1, 0);
// Spotlight
const spotLight = new THREE.SpotLight( 0xffffff, 11 );
spotLight.position.set( 2, 4, -2 );
spotLight.castShadow = true;
// spotLight.shadow.bias = 0.0005;
spotLight.shadow.mapSize.width = 2048;
spotLight.shadow.mapSize.height = 2048;
spotLight.angle = 0.6;
spotLight.penumbra = 1;
// spotLight.decay = 1;
// const spotLightHelper = new THREE.SpotLightHelper( spotLight );
// scene.add( spotLightHelper );
scene.add( spotLight );
// Materials
const material_1 = new THREE.MeshPhongMaterial({color: 0xffffff,});
const material_2 = new THREE.MeshPhongMaterial({color: 0xbbbbbb,});
// Ground Plane
const ground_geometry = new THREE.PlaneGeometry(20, 20);
const ground_mesh = new THREE.Mesh(ground_geometry, material_2);
ground_mesh.receiveShadow = true;
ground_mesh.rotateX(-Math.PI / 2);
scene.add(ground_mesh);
// Cube
const cube_geometry = new THREE.BoxGeometry(1, 1, 1);
cube_mesh = new THREE.Mesh(cube_geometry, material_1);
cube_mesh.castShadow = true;
cube_mesh.position.y = 2;
scene.add(cube_mesh);
// Sphere
const sphere_geometry = new THREE.SphereGeometry( .75, 128,128 );
const sphere = new THREE.Mesh( sphere_geometry, material_1 );
sphere.castShadow = true;
sphere.receiveShadow = true;
sphere.position.set(0,.75,0);
scene.add( sphere );
const sphere_2_geometry = new THREE.SphereGeometry( 1, 128, 128 );
const sphere_2 = new THREE.Mesh( sphere_2_geometry, material_1 );
sphere_2.castShadow = true;
sphere_2.receiveShadow = true;
sphere_2.position.set(-1,1.5,1);
scene.add( sphere_2 );
}
function animation(time) {
cube_mesh.rotation.x += 0.01;
cube_mesh.rotation.y += 0.01;
controls.update();
renderer.render(scene, camera);
}
// Resize Window
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
I want to get shadows in my scene but the shadow doesn't show up or is glitched/not right.
I've tried to get it to work with AmbientLight, PointLight, DirectionalLight but none of them seem to work.
I've set the lights to cast shadows and set all the meshes in the scene to cast and receive shadows.
My renderer
var renderer,
scene,
camera;
//RENDERER
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setClearColor("#e5e5e5");
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.BasicShadowMap;
document.body.appendChild(renderer.domElement);
The light
//LIGHTS
var directionalLight = new THREE.DirectionalLight( 0xffffff );
directionalLight.position.set( 150, 50, 100 );
var d = 5;
directionalLight.castShadow = true;
directionalLight.shadow.camera.left = - d;
directionalLight.shadow.camera.right = d;
directionalLight.shadow.camera.top = d;
directionalLight.shadow.camera.bottom = - d;
directionalLight.shadow.camera.near = 1;
directionalLight.shadow.camera.far = 20;
scene.add( directionalLight );
var light2 = new THREE.PointLight(0xffffff, 0.5);
light2.position.set(0,50,50);
light2.castShadow = true;
scene.add(light2);
How I load my objects and set them to cast and receive shadows
//LOAD OBJECTS
var loader = new THREE.GLTFLoader();
loader.load('landingpagev2.glb', handle_load);
var mesh;
function handle_load(gltf) {
mesh = gltf.scene;
for(var i = 0; i < mesh.children.length; i++){
mesh.children[i].material = new THREE.MeshPhongMaterial();
mesh.children[i].castShadow=true;
mesh.children[i].receiveShadow=true;
}
scene.add( mesh );
mesh.position.set(4,2.3,-10);
mesh.rotation.set(-80,0,0);
}
The shadows keep showing glitched-like or don't show at all when working with different lights.
The whole code is online at ramonhoffman.nl/three so you can see what I'm working with.
Thanks for your time!
Currently I'm making myself familiar with three.js and created a simple panorama viewer:
http://webentwicklung.ulrichbangert.de/threejs-image-on-sphere-inside.html
Unfortunately the vertical edges of the pillars are rippled.
When using the panorama viewer of Panorama Studio everything is fine:
http://ulrichbangert.de/heimat/Halberstadt/2018-06-10_Halberstadt_Dom_Panorama.html
var width = window.innerWidth,
height = window.innerHeight;
var scene = new THREE.Scene();
scene.add(new THREE.AmbientLight(0x333333));
var light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(5, 3, 5);
scene.add(light);
var camera = new THREE.PerspectiveCamera(45, width / height, 0.01, 1000);
camera.position.z = 1;
camera.fov = Math.max(100, Math.min(200, camera.fov));
camera.updateProjectionMatrix();
var renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height);
document.body.appendChild(renderer.domElement);
var loader = new THREE.TextureLoader();
loader.load('images/panorama.jpg', function (texture) {
texture.anisotropy = renderer.getMaxAnisotropy();
var material = new THREE.MeshBasicMaterial({
map: texture
});
var sphere = new THREE.Mesh(
new THREE.SphereGeometry(20, 32, 32),
material
);
sphere.scale.x = -1;
sphere.rotation.x = -0.5;
scene.add(sphere);
var animate = function () {
requestAnimationFrame(animate);
sphere.rotation.y += 0.002;
renderer.render(scene, camera);
};
animate();
});
What's going wrong here?
Try adding more subdivisions to your SphereGeometry. Right now you have 32 lat & long subdivisions, which creates some unsightly straight-line deformations to your texture. If you do something like new THREE.SphereGeometry(20, 100, 100), you'll get better fidelity when texture mapping.
I have a 3D model file 3dbaotang.obj and a material file 3dbaotang.mtl. I've loaded both of them using three.js OBJLoader and MTLLoader. The model has shown up, but not the material, as it's solely covered with black. Can anyone help?
Here is my code:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth /
window.innerHeight, 0.1, 10000);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var keyLight = new THREE.DirectionalLight('hsl(30, 100%, 75%)', 1.0);
var fillLight = new THREE.DirectionalLight('hsl(240, 100%, 75%)', 0.75);
var backLight = new THREE.DirectionalLight(0xffffff, 1.0);
backLight.position.set(100, 0, -100).normalize();
keyLight.position.set(-100, 0, 100);
fillLight.position.set(100, 0, 100);
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.enableZoom = true;
controls.update();
renderer.setSize(window.innerWidth, window.innerHeight, false);
renderer.setClearColor(new THREE.Color(0xf2f2f2), 1);
document.body.appendChild(renderer.domElement);
// LOAD MODEL
var mtlLoader = new THREE.MTLLoader();
mtlLoader.setResourcePath('/models/');
mtlLoader.setPath('/models/');
mtlLoader.load('/3dbaotang.mtl', (materials) => {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials(materials);
objLoader.setPath('/models/');
objLoader.load('3dbaotang.obj', (object) => {
scene.add(object);
});
});
camera.position.z = 200;
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
Result:
Adding to Brother Eye's answer, I'm brand new and and spent quite a lot of time in the dark but this got me on to the solution so I thought I'd elaborate for anyone in the same position.
Adding a light can be some simply as follows;
//Add light
var light = new THREE.AmbientLight(0xffffff);
scene.add(light);
The reference docs are located at https://threejs.org/docs/#api/en/lights/AmbientLight
It was the lack of light that caused this problem, not the material. After adding ambient light to the scene, the object can be seen normally
See this jfiddle: http://jsfiddle.net/blwoodley/5Tr4D/1/
I have a blue spot light that shines on a rotating rotating square. This casts a shadow to the underlying ground. Except that it only casts a shadow on one side of the square.
I saw this discussion: https://github.com/mrdoob/three.js/issues/3544 which indicates that face culling on planar surfaces is the cause. the recommendation is to give my square some depth, i.e. make it a cube.
I can do that with this simple example, but I'm encountering the same problem with a parametric geometry that is a surface. Is there a way to get both sides to cast a shadow without having to give my geometry a depth in doesn't have or need?
Here is the main function in the fiddle that replicates the problem with a plane:
function init() {
container = document.createElement('div');
document.body.appendChild(container);
camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 1, 100000);
camera.position.x = 100;
camera.position.y = 100;
camera.position.z = 100;
camera.lookAt({x: 0,y: 0,z: 0});
scene = new THREE.Scene();
var groundMaterial = new THREE.MeshLambertMaterial({
color: 0xffffff, side:THREE.DoubleSide
});
plane = new THREE.Mesh(new THREE.PlaneGeometry(2000,2000,10,10), groundMaterial);
plane.rotation.x = Math.PI / 2;
plane.position.y = -40;
plane.receiveShadow = true;
scene.add(plane);
var light;
light = new THREE.SpotLight(0x0000ff);
light.position.set(40, 40, 0);
light.castShadow = true;
light.shadowCameraVisible = true;
light.shadowMapWidth = 2048;
light.shadowMapHeight = 2048;
light.position.set(24, 20, 0);
light.lookAt(plane);
light.castShadow = true;
light.angle = .8;
light.intensity = 30;
light.distance=0;
light.shadowCameraNear = 2;
light.shadowCameraFar = 100;
light.shadowCameraFov = 100;
light.shadowDarkness = 1;
light.shadowCameraVisible = true;
scene.add(light);
var planeGeo = new THREE.PlaneGeometry(20,20,20,20)
_planeMesh = new THREE.Mesh(planeGeo, new THREE.MeshLambertMaterial( { color: 0x00ff00, side:THREE.DoubleSide } ) );
_planeMesh.castShadow = true;
scene.add( _planeMesh );
// RENDERER
webglRenderer = new THREE.WebGLRenderer();
webglRenderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
webglRenderer.domElement.style.position = "relative";
webglRenderer.shadowMapEnabled = true;
webglRenderer.shadowMapSoft = true;
container.appendChild(webglRenderer.domElement);
window.addEventListener('resize', onWindowResize, false);
}
Yes, this is a feature.
WebGLRenderer, by default, culls front faces when rendering shadows. This is OK, because it is assumed that objects have depth. You can cull back faces, instead, if you want:
renderer.shadowMapCullFace = THREE.CullFaceBack;
... but culling neither is not an option.
The material.side property is not taken into consideration when casting shadows.
three.js r.63