Skip to content

Commit

Permalink
Add exposure and no tone mapping and allow directional lights to auto…
Browse files Browse the repository at this point in the history
…matically follow shadows
  • Loading branch information
AdaRoseCannon committed Mar 18, 2022
1 parent cafb63d commit 81ec901
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 3 deletions.
8 changes: 7 additions & 1 deletion docs/components/light.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,13 @@ creating a child entity it targets. For example, pointing down its -Z axis:
</a-light>
```

Directional lights are the most efficient type for adding realtime shadows to a scene.
Directional lights are the most efficient type for adding realtime shadows to a scene. You can use shadows like so:

```html
<a-light type="directional" light="castShadow:true;" position="1 1 1" intensity="0.5" auto-shadow-cam="#objects"></a-light>
```

The `auto-shadow-cam` configuration maps to `light.shadowCameraAutoTarget` which tells the light to automatically update the shadow camera to be the minimum size and position to encompass the target elements.

### Hemisphere

Expand Down
37 changes: 37 additions & 0 deletions examples/boilerplate/ar-hello-world/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello, World! • A-Frame</title>
<meta name="description" content="Hello, World! • A-Frame">
<script src="../../../dist/aframe-master.js"></script>
<script>
AFRAME.registerComponent('follow-shadow', {
schema: {type: 'selector'},
init() {this.el.object3D.renderOrder = -1;},
tick() {
if (this.data) {
this.el.object3D.position.copy(this.data.object3D.position);
this.el.object3D.position.y-=0.001; // stop z-fighting
}
}
});
</script>
</head>
<body>
<a-scene
reflection="directionalLight:a-light[type=directional]"
ar-hit-test="target:#objects;"
>
<a-light type="directional" light="castShadow:true;" position="1 1 1" intensity="0.5" auto-shadow-cam="#objects"></a-light>
<a-camera position="0 0.4 0" wasd-controls="acceleration:10;"></a-camera>
<a-entity id="objects" scale="0.2 0.2 0.2" position="0 0 -1" shadow>
<a-box position="-1 0.5 1" rotation="0 45 0" color="#4CC3D9"></a-box>
<a-sphere position="0 1.25 -1" radius="1.25" color="#EF2D5E"></a-sphere>
<a-cylinder position="1 0.75 1" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
</a-entity>
<a-plane follow-shadow="#objects" material="shader:shadow" shadow="cast:false;" rotation="-90 0 0" width="2" height="2"></a-plane>
<a-sky color="#ECECEC" hide-on-enter-ar></a-sky>
</a-scene>
</body>
</html>
1 change: 1 addition & 0 deletions examples/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ <h2>Examples</h2>
<li><a href="showcase/spheres-and-fog/">Spheres and Fog</a></li>
<li><a href="showcase/wikipedia/">Wikipedia</a></li>
<li><a href="boilerplate/hello-world/">Hello World</a></li>
<li><a href="boilerplate/ar-hello-world/">AR Hello World</a></li>
<li><a href="boilerplate/panorama/">360&deg; Image</a></li>
<li><a href="boilerplate/360-video/">360&deg; Video</a></li>
<li><a href="boilerplate/3d-model/">3D Model (glTF)</a></li>
Expand Down
66 changes: 66 additions & 0 deletions src/components/light.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,23 @@ var CubeLoader = new THREE.CubeTextureLoader();

var probeCache = {};

function distanceOfPointFromPlane (positionOnPlane, planeNormal, p1) {
// the d value in the plane equation a*x + b*y + c*z=d
var d = planeNormal.dot(positionOnPlane);

// distance of point from plane
return (d - planeNormal.dot(p1)) / planeNormal.length();
}

function nearestPointInPlane (positionOnPlane, planeNormal, p1, out) {
var t = distanceOfPointFromPlane(positionOnPlane, planeNormal, p1);
// closest point on the plane
out.copy(planeNormal);
out.multiplyScalar(t);
out.add(p1);
return out;
}

/**
* Light component.
*/
Expand Down Expand Up @@ -42,6 +59,7 @@ module.exports.Component = registerComponent('light', {
shadowCameraBottom: {default: -5, if: {castShadow: true}},
shadowCameraLeft: {default: -5, if: {castShadow: true}},
shadowCameraVisible: {default: false, if: {castShadow: true}},
shadowCameraAutoTarget: {default: '', if: {type: ['spot', 'directional']}},
shadowMapHeight: {default: 512, if: {castShadow: true}},
shadowMapWidth: {default: 512, if: {castShadow: true}},
shadowRadius: {default: 1, if: {castShadow: true}}
Expand Down Expand Up @@ -141,11 +159,59 @@ module.exports.Component = registerComponent('light', {
return;
}

if (data.shadowCameraAutoTarget) {
this.shadowCameraAutoTargetEls = Array.from(document.querySelectorAll(data.shadowCameraAutoTarget));
}

// No light yet or light type has changed. Create and add light.
this.setLight(this.data);
this.updateShadow();
},

tick: (function tickSetup () {
var bbox = new THREE.Box3();
var normal = new THREE.Vector3();
var cameraWorldPosition = new THREE.Vector3();
var tempMat = new THREE.Matrix4();
var sphere = new THREE.Sphere();
var tempVector = new THREE.Vector3();

return function tick () {
if (
this.data.type === 'directional' &&
this.light.shadow &&
this.light.shadow.camera instanceof THREE.OrthographicCamera &&
this.shadowCameraAutoTargetEls.length
) {
var camera = this.light.shadow.camera;
camera.getWorldDirection(normal);
camera.getWorldPosition(cameraWorldPosition);
tempMat.copy(camera.matrixWorld);
tempMat.invert();

camera.near = 1;
camera.left = 100000;
camera.right = -100000;
camera.top = -100000;
camera.bottom = 100000;
this.shadowCameraAutoTargetEls.forEach(function (el) {
bbox.setFromObject(el.object3D);
bbox.getBoundingSphere(sphere);
var distanceToPlane = distanceOfPointFromPlane(cameraWorldPosition, normal, sphere.center);
var pointOnCameraPlane = nearestPointInPlane(cameraWorldPosition, normal, sphere.center, tempVector);

var pointInXYPlane = pointOnCameraPlane.applyMatrix4(tempMat);
camera.near = Math.min(-distanceToPlane - sphere.radius - 1, camera.near);
camera.left = Math.min(-sphere.radius + pointInXYPlane.x, camera.left);
camera.right = Math.max(sphere.radius + pointInXYPlane.x, camera.right);
camera.top = Math.max(sphere.radius + pointInXYPlane.y, camera.top);
camera.bottom = Math.min(-sphere.radius + pointInXYPlane.y, camera.bottom);
});
camera.updateProjectionMatrix();
}
};
}()),

setLight: function (data) {
var el = this.el;
var newLight = this.getLight(data);
Expand Down
3 changes: 2 additions & 1 deletion src/extras/primitives/primitives/a-light.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ registerPrimitive('a-light', {
penumbra: 'light.penumbra',
type: 'light.type',
target: 'light.target',
envmap: 'light.envMap'
envmap: 'light.envMap',
'auto-shadow-cam': 'light.shadowCameraAutoTarget'
}
});
4 changes: 3 additions & 1 deletion src/shaders/flat.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ module.exports.Shader = registerShader('flat', {
src: {type: 'map'},
width: {default: 512},
wireframe: {default: false},
wireframeLinewidth: {default: 2}
wireframeLinewidth: {default: 2},
toneMapped: {default: true}
},

/**
Expand Down Expand Up @@ -63,6 +64,7 @@ function getMaterialData (data, materialData) {
materialData.color.set(data.color);
materialData.fog = data.fog;
materialData.wireframe = data.wireframe;
materialData.toneMapped = data.toneMapped;
materialData.wireframeLinewidth = data.wireframeLinewidth;
return materialData;
}
10 changes: 10 additions & 0 deletions src/systems/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ module.exports.System = registerSystem('renderer', {
maxCanvasWidth: {default: 1920},
maxCanvasHeight: {default: 1920},
physicallyCorrectLights: {default: false},
exposure: {default: 1, if: {type: ['ACESFilmic', 'Linear', 'Reinhard', 'Cineon']}},
toneMapping: {default: 'No', oneOf: ['No', 'ACESFilmic', 'Linear', 'Reinhard', 'Cineon']},
precision: {default: 'high', oneOf: ['high', 'medium', 'low']},
sortObjects: {default: false},
colorManagement: {default: false},
Expand All @@ -31,6 +33,7 @@ module.exports.System = registerSystem('renderer', {
var renderer = sceneEl.renderer;
renderer.sortObjects = data.sortObjects;
renderer.physicallyCorrectLights = data.physicallyCorrectLights;
renderer.toneMapping = THREE[this.data.toneMapping + 'ToneMapping'];

if (data.colorManagement || data.gammaOutput) {
renderer.outputEncoding = THREE.sRGBEncoding;
Expand All @@ -48,6 +51,13 @@ module.exports.System = registerSystem('renderer', {
}
},

update: function () {
var data = this.data;
var sceneEl = this.el;
var renderer = sceneEl.renderer;
renderer.toneMappingExposure = data.exposure;
},

applyColorCorrection: function (colorOrTexture) {
if (!this.data.colorManagement || !colorOrTexture) {
return;
Expand Down

0 comments on commit 81ec901

Please sign in to comment.