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

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

merged 13 commits into from
Jan 9, 2019

Conversation

donmccurdy
Copy link
Member

For discussion and not ready to merge, see #3509.

@donmccurdy donmccurdy added this to the 0.9.0 milestone Sep 2, 2018
@dmarcos
Copy link
Member

dmarcos commented Sep 4, 2018

It looks good to me. What's pending?

@donmccurdy
Copy link
Member Author

donmccurdy commented Sep 4, 2018

Some questions in #3509 (comment). This code is working, I'm just not sure if this is the right API to give users a colorspace option. I would probably like to create a new example rather than editing the anime-UI one, too.

@ngokevin
Copy link
Member

ngokevin commented Sep 5, 2018

How about a material system because it only applies through the material component? e.g., material="colorSpace: srgb"

@@ -7,9 +7,9 @@
<script src="../../../dist/aframe-master.js"></script>
</head>
<body>
<a-scene>
<a-scene renderer="gammaOutput: true;" color-space="sRGB">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be camel case: colorSpace

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as is, it's an html attribute

@dmarcos
Copy link
Member

dmarcos commented Sep 5, 2018

Yep, probably a property of material makes more sense.

@donmccurdy
Copy link
Member Author

@dmarcos just to clarify — are you OK with this being a material system? I think something at the scene level is preferable to including colorspace on every material component.

@dmarcos
Copy link
Member

dmarcos commented Oct 3, 2018

@donmccurdy Yep, probably a system is better.

@donmccurdy donmccurdy changed the title [WIP] Add scene color-space="sRGB" option. [material] Add "colorSpace: sRGB" option to material system Nov 20, 2018
@donmccurdy
Copy link
Member Author

donmccurdy commented Nov 20, 2018

This is ready for review. On the logo page, note that the result looks the same as before, with the exception of the (COLLADA) trees, which are washed out. That should be fixed with #3866, but this PR should be merged first.

screen shot 2018-11-19 at 11 11 53 pm

@donmccurdy
Copy link
Member Author

At some point I think three.js may deprecate the gammaOutput: true property, at which point maybe the material colorSpace property would do both things. But for now it feels safer to keep them separate, until we have more testing and feedback on this.

@donmccurdy
Copy link
Member Author

I'm thinking of reversing the names on this, actually. The current names indicate what your input values are considered, assuming gammaOutput: true. But Unity handles this differently, per https://docs.unity3d.com/Manual/LinearRendering-LinearOrGammaWorkflow.html. Matching that sounds better to me, with:

  • material="workflow: gamma;" (default, current)
  • material="workflow: linear;" (new)

In the second case, all material.color, material.src, and emissive properties are automatically considered sRGB inputs, and decoded to linear for rendering, then encoded for display with gammaOutput: true. The linear workflow essentially requires gammaOutput: true, except that users might turn that off when using certain aframe-effects shaders.

@donmccurdy donmccurdy changed the title [material] Add "colorSpace: sRGB" option to material system [renderer] Add 'linear' or 'gamma' workflows, replacing gammaOutput. Nov 22, 2018
@donmccurdy
Copy link
Member Author

Ok, I did what I described in the previous post. Two workflows, gamma and linear. Where gamma is what we have today, and linear is preferred. The difference for scenes that just rely on glTF models and the material component should be minor:

gamma (current) linear
gamma linear

The trees are brighter, because they're COLLADA models, but that will be addressed in the other PR. Otherwise things are close. Mainly, lighting changes are less pronounced.

Usage:

<a-scene renderer="workflow: linear | gamma;">
  <!-- ... -->
</a-scene>

The situation where users will see major differences is when they're adding objects and materials directly to the scene graph without using the material component. For example, the environment component needs to be updated to check the workflow. That requirement would go away if three.js had a built-in equivalent to this workflow setting, which may eventually happen.

I've made linear the default in this PR, but would be glad to change it back to gamma. I moved the setting into the renderer system, so that the gammaOutput option can just be removed for simplicity. This makes things pretty similar to Unity.

@ngokevin
Copy link
Member

So the only concern is for previous scenes that had created their materials directly. But going forward, everything will default under linear and be consistent?

For example, the environment component needs to be updated to check the workflow.

Can you describe a tiny bit more what it would do differently? Would it read the workflow and adjust the material colors? Just to understand.

And is "workflow" a term used? Or does it describe "color space"?

@donmccurdy
Copy link
Member Author

So the only concern is for previous scenes that had created their materials directly. But going forward, everything will default under linear and be consistent?

Right. I'm hoping this option will eventually shift up into three.js — then we can rely on that, and THREE.Color should be adjusted automatically so even custom components like environment won't need to worry about it. But getting that right at the three.js level may take a while..

Can you describe a tiny bit more what it would do differently? Would it read the workflow and adjust the material colors?

Right, so for example:

var workflow = sceneEl.systems.material.data.workflow;
if ( workflow === 'linear' ) {
  colorPalette.forEach((color) => color.convertGammaToLinear( 2.2 ));
}

The gist here is that using material="color: #4285f4" will give results that vary dramatically from CSS #4285f4 when using gammaOutput=true today, whereas this workflow=linear option corrects for that so they should match.

And is "workflow" a term used? Or does it describe "color space"?

I think either term could be used. C4D has a "Linear Workflow" checkbox. Unity calls it a workflow in their docs, but the checkbox says "Color Space: Linear". Maya requires you to set a bunch of colorspace and color profile settings, all of which together are documented as a "workflow".

The important thing to know is that this is the colorspace in which renderer calculations are done, and not the color space textures and colors are input as (which is pretty much always sRGB), or the color space output from the renderer. Because that's easy to misunderstand, I think that workflow is a bit clearer than colorSpace.

@donmccurdy
Copy link
Member Author

I'll go through and do a bunch of before/after screenshots to compare here.

@ngokevin
Copy link
Member

ngokevin commented Dec 1, 2018

Thanks, should be good to merge, just slowly absorbing the implications.

What's behind the decision for linear vs gamma for default?

@donmccurdy
Copy link
Member Author

Here's a comparison:

gamma linear
screen shot 2018-12-03 at 10 38 36 pm screen shot 2018-12-03 at 10 38 37 pm
screen shot 2018-12-03 at 10 38 49 pm screen shot 2018-12-03 at 10 38 50 pm
screen shot 2018-12-03 at 10 40 24 pm screen shot 2018-12-03 at 10 40 25 pm
screen shot 2018-12-03 at 10 41 12 pm screen shot 2018-12-03 at 10 41 15 pm
screen shot 2018-12-03 at 10 42 25 pm screen shot 2018-12-03 at 10 42 33 pm
screen shot 2018-12-03 at 10 42 43 pm screen shot 2018-12-03 at 10 42 44 pm

In these examples, I see three effects:

  • glTF models in scenes with gammaOutput disabled, which were previously shown too dark, now look correct.
  • COLLADA models now look too bright. (see [collada-model] Deprecate 'collada-model'. #3817)
  • Lighting is slightly more even. On the A-Frame Logo, note that the darker sides of the shapes are lighter in the linear workflow.

However, the difference when using other components — like environment will be much more noticeable. For that reason, I think it's probably better to start with this change off by default after all. Once we've gotten more testing maybe it can become opt-out, instead.

@ngokevin
Copy link
Member

ngokevin commented Dec 4, 2018

Thanks for the rundown! So I think maybe it's ok to choose whatever is the more sensible default (linear?). Apps upgrading to 0.9.0 have to option to specify gamma. We can update the environment component for 0.9.0 and document it well in changelog.

@donmccurdy
Copy link
Member Author

I think I'd rather stick a toe in the water first on this one, with an opt-in for 0.9. 😅

Linear is a better choice in the long-run, but it will affect existing components badly if they instantiate THREE.Color or THREE.Texture themselves. I'm hoping that we can test this out and get feedback to influence what three.js does in the future. If the same changes I'm making here could be done in three.js instead — treating colors as sRGB by default — there would be no need for components to add convertGammaToLinear(2.2) throughout their code, and we'd have a more seamless API here.

@ngokevin
Copy link
Member

ngokevin commented Dec 4, 2018

OK. Last thing then I guess is document the new properties/defaults in this table also: https://github.com/aframevr/aframe/pull/3757/files#diff-601edc1958f8dda05aaef2c8adf3cf0cL24

Then looks good!

}
}

// TODO: Uncomment these lines and deprecate 'antialias' for v0.9.0.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to uncomment this now?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. ✅

@donmccurdy
Copy link
Member Author

Ok, refactored this a bit. Also added some helpers so e.g. obj-model and (temporarily) collada-model will adjust to the linear workflow.

@donmccurdy
Copy link
Member Author

Getting a single error in Chrome, doesn't seem obviously related:

screen shot 2018-12-06 at 3 11 19 pm

@ngokevin
Copy link
Member

Looking again, looks scary it will affect existing components badly if they instantiate THREE.Color or THREE.Texture. I think that is an extremely frequent operation, would they need/want to call the color correction util each time? Or only need to worry if they are third party components? What would a three.js change look like that does all automatically? Do we override THREE.Color?

@@ -26,28 +26,30 @@ 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 |
| workflow | Whether to use color-managed (`linear`) or legacy (`gamma`) workflow. | gamma |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Term workflow seems generic word. Does colorManagment make more sense?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or maybe colorSpace?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To note: prior explanation:

And is "workflow" a term used? Or does it describe "color space"?

I think either term could be used. C4D has a "Linear Workflow" checkbox. Unity calls it a workflow in their docs, but the checkbox says "Color Space: Linear". Maya requires you to set a bunch of colorspace and color profile settings, all of which together are documented as a "workflow".

The important thing to know is that this is the colorspace in which renderer calculations are done, and not the color space textures and colors are input as (which is pretty much always sRGB), or the color space output from the renderer. Because that's easy to misunderstand, I think that workflow is a bit clearer than colorSpace.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^Per above I think "colorSpace" is too confusing. But colorManagement: true might be easier to understand, I do like that...

@donmccurdy
Copy link
Member Author

Do you think is sensible to monkey patch THREE COLOR / TEXTURE or introduce temporary changes...

Maybe. I'm not sure how large the change will be in threejs. I can take a look at that but also don't want to hold up 0.9.0... will try to get a rough estimation of the work involved tomorrow.

@dmarcos
Copy link
Member

dmarcos commented Jan 8, 2019

@donmcurdy This is almost
readt. Should we change the property name to colorManagment?

},

applyColorCorrection: function (colorOrTexture) {
if (this.data.workflow !== 'linear' || !colorOrTexture) {
Copy link
Member

@dmarcos dmarcos Jan 8, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe simpler:

  if (this.data.workflow !== 'linear' || !colorOrTexture ||
      (!colorOrTexture.isColor && !colorOrTexture.isTexture) { return; }
   if (colorOrTexture.isColor) {
      colorOrTexture.convertSRGBToLinear();
    } else {
      colorOrTexture.encoding = THREE.sRGBEncoding;
   }

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tbh this seems harder to read to me 😇

@dmarcos
Copy link
Member

dmarcos commented Jan 8, 2019

glTF assumes sRGB (gamma) per standard. More and more experiences include glTF models. It makes sense to default to gamma instead of linear?

@donmccurdy
Copy link
Member Author

glTF assumes sRGB (gamma) per standard. More and more experiences include glTF models. It makes sense to default to gamma instead of linear?

Note that the workflows are named for the space in which the renderer works, and 'linear' is actually what we want even for sRGB or gamma inputs. That's definitely confusing, so I think renaming to colorManagement sounds like a good idea.

As for enabling this change by default, I'd prefer to wait on that until we have a way to automatically upgrade third-party components creating THREE.Color and THREE.Texture instances themselves. Otherwise we'll have two non-trivial breaking changes, instead of one minor one. I think it's fairly likely that can be handled within threejs itself, but I haven't reached a good solution there yet. 😕

Are we OK with just adding the colorManagement option for now, off by default?

@dmarcos
Copy link
Member

dmarcos commented Jan 8, 2019

I'm good with colorManagement and adjust later if needed.

@donmccurdy donmccurdy changed the title [renderer] Add 'linear' or 'gamma' workflows, replacing gammaOutput. [renderer] Add color management option, replacing gammaOutput. Jan 9, 2019
@donmccurdy
Copy link
Member Author

Ok, sounds good. I've replaced workflow: linear with colorManagement: true.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants