Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[renderer] Add color management option, replacing gammaOutput. #3757

Merged
merged 13 commits into from
Jan 9, 2019
Merged
33 changes: 21 additions & 12 deletions docs/components/renderer.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ source_code: src/components/renderer.js
examples: []
---

The `renderer` component configures a scene's
The `renderer` system configures a scene's
[THREE.WebGLRenderer](https://threejs.org/docs/#api/renderers/WebGLRenderer) instance.

## Example

```html
<a-scene renderer="antialias: true;
gammaOutput: true;
colorManagement: true;
sortObjects: true;
physicallyCorrectLights: true;
maxCanvasWidth: 1920;
Expand All @@ -26,28 +26,32 @@ The `renderer` component configures a scene's
| Property | Description | Default Value |
|-------------------------|---------------------------------------------------------------------------------|---------------|
| antialias | Whether to perform antialiasing. If `auto`, antialiasing is disabled on mobile. | auto |
| gammaOutput | Whether to pre-multiply gamma on textures and colors before rendering. | false |
| colorManagement | Whether to use a color-managed linear workflow. | false |
| sortObjects | Whether to sort objects before rendering. | false |
| physicallyCorrectLights | Whether to use physically-correct light attenuation. | false |
| maxCanvasWidth | Maximum canvas width. Uses the size multiplied by device pixel ratio. Does not limit canvas width if set to -1. | 1920 |
| maxCanvasHeight | Maximum canvas height. Behaves the same as maxCanvasWidth. | 1920 |
| maxCanvasHeight | Maximum canvas height. Behaves the same as maxCanvasWidth. | 1920 |
| logarithmicDepthBuffer | Whether to use a logarithmic depth buffer. | auto |

> **NOTE:** Once the scene is initialized, these properties may no longer be changed.

### antialias

When enabled, smooths jagged edges on curved lines and diagonals at moderate performance cost.
By default, antialiasing is disabled on mobile devices.

> **NOTE:** Once the scene is initialized, `antialias` may no longer be
> changed.
### colorManagement

### gammaOutput
Color management provides more accurate rendering and reduces the likelihood that scenes
will appear overlit or "washed out." Enabling color management is recommended for precisely
matching colors from texturing and modeling tools, but unofficial components may not always
respond to color management properly at this time.

Typically, textures are converted to linear colorspace in the renderer for lighting calculations.
Unless post-processing used after the initial render,
[gamma correction](https://en.wikipedia.org/wiki/Gamma_correction) should be applied with
`renderer="gammaOutput: true;"` for best color reproduction. By default, gamma correction is off
in order to preserve backward-compatibility. When changed, adjustments to lighting may be needed.
Managed and unmanaged color modes are similar to linear and gamma workflows, respectively, in
other engines and tools.

> **NOTE:** In three.js, and previous versions of A-Frame, a `gammaOutput: true` property was
> available. This is applied automatically when color management is enabled.

### sortObjects

Expand All @@ -66,3 +70,8 @@ be adjusted when making this change. Performance is not significantly affected i

> **NOTE:** When glTF models contain lights, use the physically-correct lighting mode to match
> the results in the original modeling tool.

### logarithmicDepthBuffer

A logarithmic depth buffer may provide better sorting and rendering in scenes containing very
large differences of scale and distance.
4 changes: 3 additions & 1 deletion examples/animation/aframe-logo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
<script src="../../../dist/aframe-master.js"></script>
</head>
<body>
<a-scene vr-mode-ui="enabled: false" background="color: #24CAFF">
<a-scene vr-mode-ui="enabled: false;"
background="color: #24CAFF;"
renderer="colorManagement: true;">
<a-assets>
<a-asset-item id="treeModel" src="../../assets/models/tree1/tree1.dae"></a-asset-item>
<a-mixin
Expand Down
6 changes: 3 additions & 3 deletions examples/showcase/anime-UI/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
<script src="../../../dist/aframe-master.js"></script>
</head>
<body>
<a-scene>
<a-scene renderer="colorManagement: true;">
<a-assets>
<a-asset-item id="engine" src="models/engine.dae"></a-asset-item>
<a-asset-item id="engine" src="models/engine.glb"></a-asset-item>
<a-mixin id="image" geometry="height: 2; width: 2"></a-mixin>
<a-mixin id="toggleAnimation" animation="property: visible; from: false; to: true; dur: 1" visible="false"></a-mixin>
<audio id="blip1" src="audio/321103__nsstudios__blip1.wav"></audio>
Expand All @@ -36,7 +36,7 @@
</a-entity>

<a-entity position="0 0 -3">
<a-collada-model src="#engine" rotation="90 0 0" scale="18 18 18"></a-collada-model>
<a-gltf-model src="#engine" rotation="90 0 0" scale="18 18 18"></a-gltf-model>
</a-entity>

<a-entity id="wall-lights" position="-7.25 1.5 2.9" rotation="0 90 0" scale="1.25 1.25 1.25">
Expand Down
113 changes: 0 additions & 113 deletions examples/showcase/anime-UI/models/engine.dae

This file was deleted.

Binary file added examples/showcase/anime-UI/models/engine.glb
Binary file not shown.
10 changes: 10 additions & 0 deletions src/components/collada-model.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,23 @@ module.exports.Component = registerComponent('collada-model', {
var self = this;
var el = this.el;
var src = this.data;
var rendererSystem = this.el.sceneEl.systems.renderer;

if (!src) { return; }

this.remove();

this.loader.load(src, function (colladaModel) {
self.model = colladaModel.scene;
self.model.traverse(function (object) {
if (object.isMesh) {
var material = object.material;
if (material.color) rendererSystem.applyColorCorrection(material.color);
if (material.map) rendererSystem.applyColorCorrection(material.map);
if (material.emissive) rendererSystem.applyColorCorrection(material.emissive);
if (material.emissiveMap) rendererSystem.applyColorCorrection(material.emissiveMap);
}
});
el.setObject3D('mesh', self.model);
el.emit('model-loaded', {format: 'collada', model: self.model});
});
Expand Down
1 change: 0 additions & 1 deletion src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ require('./scene/inspector');
require('./scene/fog');
require('./scene/keyboard-shortcuts');
require('./scene/pool');
require('./scene/renderer');
require('./scene/screenshot');
require('./scene/stats');
require('./scene/vr-mode-ui');
12 changes: 10 additions & 2 deletions src/components/light.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ module.exports.Component = registerComponent('light', {
var el = this.el;
this.light = null;
this.defaultTarget = null;
this.rendererSystem = this.el.sceneEl.systems.renderer;
this.system.registerLight(el);
},

Expand All @@ -59,6 +60,7 @@ module.exports.Component = registerComponent('light', {
var data = this.data;
var diffData = diff(data, oldData);
var light = this.light;
var rendererSystem = this.rendererSystem;
var self = this;

// Existing light.
Expand All @@ -71,11 +73,13 @@ module.exports.Component = registerComponent('light', {
switch (key) {
case 'color': {
light.color.set(value);
rendererSystem.applyColorCorrection(light.color);
break;
}

case 'groundColor': {
light.groundColor.set(value);
rendererSystem.applyColorCorrection(light.groundColor);
break;
}

Expand Down Expand Up @@ -207,10 +211,14 @@ module.exports.Component = registerComponent('light', {
*/
getLight: function (data) {
var angle = data.angle;
var color = new THREE.Color(data.color).getHex();
var color = new THREE.Color(data.color);
this.rendererSystem.applyColorCorrection(color);
color = color.getHex();
var decay = data.decay;
var distance = data.distance;
var groundColor = new THREE.Color(data.groundColor).getHex();
var groundColor = new THREE.Color(data.groundColor);
this.rendererSystem.applyColorCorrection(groundColor);
groundColor = groundColor.getHex();
var intensity = data.intensity;
var type = data.type;
var target = data.target;
Expand Down
3 changes: 3 additions & 0 deletions src/components/line.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ module.exports.Component = registerComponent('line', {
var data = this.data;
var geometry;
var material;
this.rendererSystem = this.el.sceneEl.systems.renderer;
material = this.material = new THREE.LineBasicMaterial({
color: data.color,
opacity: data.opacity,
Expand All @@ -25,6 +26,7 @@ module.exports.Component = registerComponent('line', {
geometry = this.geometry = new THREE.BufferGeometry();
geometry.addAttribute('position', new THREE.BufferAttribute(new Float32Array(2 * 3), 3));

this.rendererSystem.applyColorCorrection(material.color);
this.line = new THREE.Line(geometry, material);
this.el.setObject3D(this.attrName, this.line);
},
Expand Down Expand Up @@ -57,6 +59,7 @@ module.exports.Component = registerComponent('line', {
}

material.color.setStyle(data.color);
this.rendererSystem.applyColorCorrection(material.color);
material.opacity = data.opacity;
material.transparent = data.opacity < 1;
material.visible = data.visible;
Expand Down
10 changes: 10 additions & 0 deletions src/components/obj-model.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ module.exports.Component = registerComponent('obj-model', {
var el = this.el;
var mtlLoader = this.mtlLoader;
var objLoader = this.objLoader;
var rendererSystem = this.el.sceneEl.systems.renderer;

if (mtlUrl) {
// .OBJ with an .MTL.
Expand All @@ -51,6 +52,15 @@ module.exports.Component = registerComponent('obj-model', {
objLoader.setMaterials(materials);
objLoader.load(objUrl, function (objModel) {
self.model = objModel;
self.model.traverse(function (object) {
if (object.isMesh) {
var material = object.material;
if (material.color) rendererSystem.applyColorCorrection(material.color);
if (material.map) rendererSystem.applyColorCorrection(material.map);
if (material.emissive) rendererSystem.applyColorCorrection(material.emissive);
if (material.emissiveMap) rendererSystem.applyColorCorrection(material.emissiveMap);
}
});
el.setObject3D('mesh', objModel);
el.emit('model-loaded', {format: 'obj', model: objModel});
});
Expand Down
6 changes: 5 additions & 1 deletion src/components/oculus-go-controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ module.exports.Component = registerComponent('oculus-go-controls', {
this.onAxisMoved = bind(this.onAxisMoved, this);
this.controllerPresent = false;
this.lastControllerCheck = 0;
this.rendererSystem = this.el.sceneEl.systems.renderer;
this.bindMethods();
this.checkControllerPresentAndSetup = checkControllerPresentAndSetup; // To allow mock.
this.emitIfAxesChanged = emitIfAxesChanged; // To allow mock.
Expand Down Expand Up @@ -155,6 +156,7 @@ module.exports.Component = registerComponent('oculus-go-controls', {
var buttonMeshes = this.buttonMeshes;
if (!buttonMeshes || !buttonMeshes[buttonName]) { return; }
var color;
var button;
switch (state) {
case 'down':
color = this.data.buttonHighlightColor;
Expand All @@ -165,6 +167,8 @@ module.exports.Component = registerComponent('oculus-go-controls', {
default:
color = this.data.buttonColor;
}
buttonMeshes[buttonName].material.color.set(color);
button = buttonMeshes[buttonName];
button.material.color.set(color);
this.rendererSystem.applyColorCorrection(button.material.color);
}
});
6 changes: 5 additions & 1 deletion src/components/oculus-touch-controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ module.exports.Component = registerComponent('oculus-touch-controls', {
this.controllerPresent = false;
this.lastControllerCheck = 0;
this.previousButtonValues = {};
this.rendererSystem = this.el.sceneEl.systems.renderer;
this.bindMethods();

// Allow mock.
Expand Down Expand Up @@ -208,11 +209,14 @@ module.exports.Component = registerComponent('oculus-touch-controls', {
},

updateButtonModel: function (buttonName, state) {
var button;
var color = (state === 'up' || state === 'touchend') ? this.data.buttonColor : state === 'touchstart' ? this.data.buttonTouchColor : this.data.buttonHighlightColor;
var buttonMeshes = this.buttonMeshes;
if (!this.data.model) { return; }
if (buttonMeshes && buttonMeshes[buttonName]) {
buttonMeshes[buttonName].material.color.set(color);
button = buttonMeshes[buttonName];
button.material.color.set(color);
this.rendererSystem.applyColorCorrection(button.material.color);
}
}
});
80 changes: 0 additions & 80 deletions src/components/scene/renderer.js

This file was deleted.

5 changes: 5 additions & 0 deletions src/components/vive-controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ module.exports.Component = registerComponent('vive-controls', {
this.onButtonTouchStart = function (evt) { onButtonEvent(evt.detail.id, 'touchstart', self); };
this.onAxisMoved = bind(this.onAxisMoved, this);
this.previousButtonValues = {};
this.rendererSystem = this.el.sceneEl.systems.renderer;

this.bindMethods();
},
Expand Down Expand Up @@ -214,15 +215,19 @@ module.exports.Component = registerComponent('vive-controls', {

setButtonColor: function (buttonName, color) {
var buttonMeshes = this.buttonMeshes;
var rendererSystem = this.rendererSystem;

if (!buttonMeshes) { return; }

// Need to do both left and right sides for grip.
if (buttonName === 'grip') {
buttonMeshes.grip.left.material.color.set(color);
buttonMeshes.grip.right.material.color.set(color);
rendererSystem.applyColorCorrection(buttonMeshes.grip.left.material.color);
rendererSystem.applyColorCorrection(buttonMeshes.grip.right.material.color);
return;
}
buttonMeshes[buttonName].material.color.set(color);
rendererSystem.applyColorCorrection(buttonMeshes[buttonName].material.color);
}
});
Loading