Using AFrame and three. Have made an AFrame simple scene, a camera, a renderer, a spotlight, a plane and a cube.
I want the cube to cast shadow into the plane.
I have set, using the reference cube.object3D and spotlight.object3D, the .castShadow in the spotlight, in the cube.
I have set, using the reference plane.object3D, the receiveShadow in the plane.
Have also set the renderer.shadowMapEnabled.
But can not see any shadow casted into the plane.
Any hint ?
Thanks a lot.
Shadows have since been added to A-Frame: https://github.com/aframevr/aframe/pull/2350
https://aframe.io/docs/master/components/light.html#configuring-shadows
<a-scene shadow>
<a-entity light="type: directional; castShadows: true"></a-entity>
<a-box shadow="cast: true; receive: true"></a-box>
</a-scene>
many thanks for your answers.
I am learning A-Frame, Three.js, Javascript, and html just by doing.
It is awesome what you are doing with A-Frame.
Done the following, it is not perfect, but for now it works:
In the registerComponent init:function()
In the meshes to cast shadows:
el.getObject3D('mesh').castShadow = data.shadow; //data.shadow = true
In the meshes to receive shadows:
el.getObject3D('mesh').receiveShadow = data.shadow; //data.shadow = true
In the spotlight:
this.spotlight = new THREE.SpotLight(data.colorm);
el.setObject3D('spotlight', this.spotlight);
el.getObject3D('spotlight').castShadow = data.shadow;
el.getObject3D('spotlight').shadow.camera.near = data.shadowcameranear;
el.getObject3D('spotlight').shadow.camera.far = data.shadowcamerafar;
el.sceneEl.systems.light.registerLight(el);
And then using the scene has loaded event:
function setShadows()
{
aframeRenderer.shadowMap.enabled = true;
aframeRenderer.shadowMap.type = THREE.PCFSoftShadowMap;
aframeRenderer.setClearColor(0x000000, 1.0);
aframeRenderer.setSize(window.innerWidth, window.innerHeight);
aframeRenderer.shadowMap.enabled = true;
threeSpotLight.shadowCameraNear = 0.01;
threeSpotLight.castShadow = true;
threeCube.castShadow = true;
threeCube.receiveShadow = false;
threePlane.castShadow = false;
threePlane.receiveShadow = true;
threeSpotLight.visible = true;
}
Related
Im currently working on my portfolio in A-frame. I'm trying to change the material of the objects to a wireframe material, i'm using the wireframe material (MeshBasicMaterial) of THREE.js to do that. If I put this material on objects like "a-box" or "a-sphere" it works, but i need to put this wireframe material on my 3D gltf model. Is this possible?
This is my script to call the material:
AFRAME.registerComponent('wireframe', {
dependencies: ['material'],
init: function () {
this.el.components.material.material.wireframe = true;
}
});
<a-box position="-1 0.5 -3" rotation="0 45 0" material="color: blue" wireframe></a-box>
It is possible to modify the material on a gltf.
One way to do it is to drill into the THREEjs level of the mesh inside the gltf, and create a new material and assign it a wireframe property.
AFRAME.registerComponent('tree-manager', {
init: function () {
let el = this.el;
let comp = this;
let data = this.data;
comp.scene = el.sceneEl.object3D;
comp.counter = 0;
comp.treeModels = [];
comp.modelLoaded = false;
// After gltf model has loaded, modify it materials.
el.addEventListener('model-loaded', function(ev){
let mesh = el.getObject3D('mesh');
if (!mesh){return;}
//console.log(mesh);
mesh.traverse(function(node){
if (node.isMesh){
let mat = new THREE.MeshStandardMaterial;
let color = new THREE.Color(0xaa5511);
mat.color = color;
mat.wireframe = true;
node.material = mat;
}
});
comp.modelLoaded = true;
});
}
});
<a-entity id="tree" gltf-model="#tree-gltf" scale="5 5 5" tree-manager></a-entity>
Here is a glitch that shows how.
I'm creating a sphere that casts and receives shadows with MeshToonMaterial but this is giving me an irregular shadow at the darkest section.
Sphere with irregular shadow:
Closer look at the sphere:
The light is:
light = new THREE.PointLight(0xffffff, 0.8, 18);
light.position.set(-3,6,-3);
light.castShadow = true;
light.shadow.camera.near = 0.1;
light.shadow.camera.far = 25;
light.shadowBias = 0.0015;
scene.add(light);
The sphere is:
mesh = new THREE.Mesh
(
new THREE.SphereBufferGeometry( 1, 32, 16 ),
new THREE.MeshToonMaterial({color:0xff4444})
);
mesh.position.y += 1;
mesh.receiveShadow = true;
mesh.castShadow = true;
mesh.position.set(-2.5, 3/2, 2.5);
scene.add(mesh);
The renderer:
renderer = new THREE.WebGLRenderer();
renderer.setSize(800,400);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
I've tried with other models and shadow map types with similar results.
If I set:
mesh.castShadow = false;
Then what I get is:
That's pretty much the style I'm looking for, but I'm also needing it to casts shadows.
I would like to avoid using an extra sphere for casting the shadow.
How can I achieve this?
Disabling receiving shadows on the sphere mesh will prevent it from being rendered with the cast shadows, but it will still cast a shadow on the plane.
mesh.receiveShadow = false
However, that means that the sphere won't have any shadows cast on it from other objects, either.
Other than that, it seems like an issue with the way the toon shader handles cast shadows.
I'm using three v0.85.2.
By default, all my objects are configured to cast and receive shadows :
const mesh = new Mesh(geometry, material)
mesh.castShadow = meshConfig.castShadow
mesh.receiveShadow = meshConfig.receiveShadow
shadowMap of the renderer is enabled.
Self shadows seem to be correctly rendered (green squares in the image below).
But shadows casted to other objects are missing (red squares).
The problem seems to occur with all my meshes.
I don't find a way to make them appear.
DirectionalLightShadow, there you can read how to work with shadows when you use THREE.DirectionalLight() in your scene.
Also you can play around with .left, .top, .right and .bottom properties of the shadow camera of your light source.
var light = new THREE.DirectionalLight(0xffffff,1);
light.position.set(50, 500, 22);
light.target.position.set(300, 400, 200);
light.shadow.camera.near = 0.5;
light.shadow.camera.far = 5000;
light.shadow.camera.left = -500;
light.shadow.camera.bottom = -500;
light.shadow.camera.right = 500;
light.shadow.camera.top = 500;
light.castShadow = true;
scene.add(light);
three.js r85
jsfiddle example
I have a plane with a transparent PNG (a world map).
Can I cast shadows from one plane onto another plane?
I am having no success with this code:
plane = new THREE.Mesh(new THREE.PlaneGeometry(200,200), new THREE.MeshLambertMaterial({color: 0xcccccc}));
var mapTexture = new THREE.ImageUtils.loadTexture("img/map_transp2.png");
mapTexture.needsUpdate = true;
var mapMaterial = new THREE.MeshBasicMaterial({
color:0xaaaaaa,
transparent:true,
map:mapTexture,
side:THREE.DoubleSide
});
mapPlane = new THREE.Mesh(new THREE.PlaneGeometry(800/5,370/5), mapMaterial);
plane.receiveShadow = true;
mapPlane.castShadow = true;
Transparent parts of the mesh should be handled differently if they're written in texture.
Take a look at this example: http://threejs.org/examples/webgl_animation_cloth.html
Your two planes are on the same z value. Give them some distance with:
mapPlane.position.z = 100;
// You need also to set this:
renderer.shadowMapEnabled = true;
// and also you need to add a light and enable its shadow, for example,
sLight = new THREE.SpotLight(0xFFF4E5,1);
sLight.position.set( 250, 250, 250);
sLight.castShadow = true;
sLight.shadowMapWidth = 1024;
sLight.shadowMapHeight = 1024;
sLight.shadowCameraNear = 300;
sLight.shadowCameraFar = 600;
sLight.shadowCameraFov = 45;
scene.add(sLight);
I have had a similar problem.
I don't know why this happens, but I solved it changing the planeGeometry to a cubeGeometry (in the plane casting the shadow)
See https://github.com/mrdoob/three.js/issues/9315
Set
renderer.shadowMap.renderReverseSided = false
or/and
renderer.shadowMap.renderSingleSided = false
can solve the problem.
When disabled, an appropriate shadow.bias must be set on the light source for surfaces that can both cast and receive shadows at the same time to render correctly:
let dl = new THREE.DirectionalLight()
dl.shadow.bias = -0.0001
three.js r.85
I'm trying the second approach to use Text in three.js, drawing on a canvas and using the result as a texture. It basically works, except for the following problem -don't know if it's a bug:
I create two texts, with transparent background, and overlap then. They show ok, but when I rotate one of them, the transparency is messed up.
I create the text objects with following (excerpt) function
function createText(text, ...){
var textHolder = document.createElement( 'canvas' );
var ctext = textHolder.getContext('2d');
...
var tex = new THREE.Texture(textHolder);
var mat = new THREE.MeshBasicMaterial( { map: tex, overdraw: true});
mat.transparent = true;
mat.map.needsUpdate = true;
var textBoard = new THREE.Mesh(new THREE.PlaneGeometry(textHolder.width, textHolder.height),mat);
textBoard.dynamic = true;
textBoard.doubleSided = true;
return textBoard;
}
and add them to the scene.
See demonstration with full code in jsfiddle
Transparency is tricky in webGL.
The best solution in your case is to do the following for your transparent text material:
mat.depthTest = false;
updated fiddle: http://jsfiddle.net/SXA8n/4/
three.js r.55