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

Color4 class to complement Color/Color3, how best to centralize conversion code? #2730

Closed
bhouston opened this issue Dec 3, 2012 · 6 comments

Comments

@bhouston
Copy link
Contributor

bhouston commented Dec 3, 2012

In my experience most colors in 3D graphics are 4 channel colors (red, green, blue and alpha.) It is only a subset of situations in 3D graphics where a 3 channel color is sufficient and usually that deals with solid surface shading algorithms.

Many situation, such as windows with varying transparent, volume effects and particle effects often need RGBA-based colors. Also blending algorithms where one engages in post-processing one also often needs 4 channel-based colors.

Thus I propose creating a Color4 class that enables easy usage of 4-channel colors.

NOTE: I am unsure of the best way to share the conversion code that is fairly common (and bulky) between Color4 and the existing Color (which I suggest renaming Color3.)

Here is my proposed Color4 class:

Color4

properties:

  • r as Scalar
  • g as Scalar
  • b as Scalar
  • a as Scalar // a is last so that it matches OpenGL/WebGL style: http://goo.gl/GKuD8

methods:

  • set( value )
  • setRGBA( r, g, b, a )
  • setHSV( h, s, v ) // centralize in helper as HSV doesn't have alpha
  • setStyle( style as string ) // centralize in helper
  • setHex( hex as Integer )
  • copy( color as Color4 )
  • copyGammaToLinear( color as Color4 ) // I think we don't need this on either Color/Color3 or Color4, just use copy(..).convertGammaToLinear()
  • copyLinearToGamma( color as Color4 ) // I think we don't need this on either Color/Color3 or Color4, just use copy(..).convertLinearToGamma()
  • convertGammaToLinear()
  • convertLinearToGamma()
  • getHex() // centralize in helper ?
  • getHexString() // centralize in helper
  • getStyle() // centralize in helper
  • getHSV() // centralize in helper as HSV doesn't include alpha
  • lerpSelf( color as Color4, alpha as Scalar )
  • clone()
  • bool equals( color as Color4 ) // this needs to be added to Color/Color3
@mrdoob
Copy link
Owner

mrdoob commented Dec 3, 2012

So, from my side there is a historical reason why Color only had 3 components:

var color = new THREE.Color( 0xffffff ); // expectation: full opacity white
var color = new THREE.Color( 0x00ffffff ); // expectation: full transparent white

Both would be full transparent. The only way to get it working would be to force writing the alpha component as part of the hex value. So I never figured out how to solve this and I opted for keeping it RGB only.

However, I'm aware that there's people that would be able to have RGBA, specially on vertex colors, but I think @alteredq had another reason but I don't recall what was it exactly.

@bhouston
Copy link
Contributor Author

bhouston commented Dec 3, 2012

I see an argument for Color3 but there is also a need for Color4. ILM's math library, which I will usually reference as the gold standard, has both:

https://github.com/openexr/openexr/blob/master/IlmBase/Imath/ImathColor.h

Unity also only has a Color4 (as does a number of other programs I just examined and generally I tend to only use Color4s):

http://docs.unity3d.com/Documentation/ScriptReference/Color.html

To address the 0xffffff versus 0x00ffffff ambiguity I see two possible solutions:

  • One could parse hex codes as strings via a Color.parse( value ), thus you can see if there is a 00 part and set it appropriately. One could support short 0xFFF and long 0xffffff as well as codes with alpha 0xffffffff this way. Via string-based parsing one can recognize color names, short, long and full hex codes as well as styles -- in fact it would be really nice. For maximum speed one should set the color more explicitly via the below:
  • Alternatively, one can create setters for the various types, setHex3( 0xfff ), setHex6( 0xffffff ), setHex8( 0xffffffff ) or setHex12, setHex24 and setHex32 depending on your preference.

I guess there is the question as to whether you want both a Color4 and a Color3 or just a Color4. I don't have a major preference, I just know that I do need a Color with an alpha channel most of the time. Having only Color4 will lead to a bit more memory usage in some cases (for the alpha channel which isn't always needed), and it may complicate GPU array uploading if you only want to upload 3 channels, but it will reduce the amount of code in the geometric primitives library.

@alteredq
Copy link
Contributor

alteredq commented Dec 4, 2012

However, I'm aware that there's people that would be able to have RGBA, specially on vertex colors, but I think @alteredq had another reason but I don't recall what was it exactly.

Well, we had RGBA colors before and then we changed it to RGB and I think we were happier with this.

RGBA colors were messier, took more memory and complicated things both from API and implementation point of view.

The thing is - transparency in real-time graphics is always a massive pain, so in most cases you do want to avoid using RGBA colors everywhere anyways.

Also semantics would get pretty muddy if RGBA were everywhere - for example what's supposed to mean if light color is transparent.

So we went with a route of RGB colors and separate opacity parameter used in materials. This simplified API, made much more predictably behaved materials and saved a third of all color related memory + data transfers.

About the only place where occasionally pops-up request for RGBA colors is vertex colors where a solution is to use custom Vector4 attribute instead.

Though whoever tries to use vertex colors with varying transparencies would be probably disappointed anyways. As there is no per-triangle sorting, it'll probably just lead to odd looking artefacts.

The way how to get at least so-so looking transparency is to break your object into transparent and opaque parts and render them separately. And once you do this, then again it makes more sense to have RGB + opacity model than just needlessly repeat the same alpha for every vertex.

I don't know, I can imagine it may be beneficial to also have Color4 or ColorAlpha or ColorRGBA but probably not as a primary color class.

@bhouston
Copy link
Contributor Author

bhouston commented Dec 4, 2012

@alteredq I agree with you that RGBA is often not needed for surface rendering and you have a more limited situation with ThreeJS than the general case (real-time with limits to handling arbitrary transparency) reducing its need even further. Thus I agree that keeping a more restricted interface actually increases usability.

I do still see a need for a Color4 type though as a separate type -- for particle systems (I assume you eventually want to handle per-particle varying transparency), specifying texture parameters such as modulation and for extended material specifications (which may not be something that ThreeJS is going to support, but is needed by many other people.)

So maybe I can do this: I could build a very simple Color4 that is as small as possible via utilizes the Color conversion methods instead of duplicating them or refactoring them to a common utility class. Thus I won't change Color and I will minimize duplication. It will mean that Color4 is slightly slower that Color for conversion purposes, but I don't mind that.

@alteredq
Copy link
Contributor

alteredq commented Dec 4, 2012

I do still see a need for a Color4 type though as a separate type -- for particle systems (I assume you eventually want to handle per-particle varying transparency), specifying texture parameters such as modulation and for extended material specifications (which may not be something that ThreeJS is going to support, but is needed by many other people.)

Not sure are you aware of custom attributes?

http://mrdoob.github.com/three.js/examples/webgl_custom_attributes_particles.html
http://mrdoob.github.com/three.js/examples/webgl_custom_attributes_particles2.html
http://mrdoob.github.com/three.js/examples/webgl_custom_attributes_particles3.html

But indeed, particles are something that could benefit from this. Right now Vector4 could be used for this but I could imagine having Color4 could make this neater.

(coincidentally particles are the only thing that we do have an option for per-triangle depth sorting, it does come with a considerable performance penalty though)

@bhouston
Copy link
Contributor Author

bhouston commented Feb 4, 2013

Color3 is good enough for my needs at this time, closing.

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

No branches or pull requests

3 participants