Color3 values should support math operations

Continuing the discussion from Color3.fromFull(r, g, b): Moving the discussion of this entirely different feature request to another thread so the one it started in doesn’t turn into a mess of two separate discussions about two separate features. Original request:

47 Likes

I agree. It’s a pain to have to write wrapper functions to perform basic operations on Color3 values.

7 Likes

I wouldn’t be interested in this. I would just use Vector3s and convert it to Color3 whenever I need to show the result to the user. I think this would bloat the API and make the Color3 object unnecessarily complicated for its intended purpose.

The only math function I think would be appropriate for this object that Vector3 also has would be:
Color3:Lerp(Color3 goal, number alpha)

5 Likes

You shouldn’t have to do that. Multiplying by a scalar is definitely something Color3 should be able to do, along with basic operations involving other color3s.

The api wouldn’t take a hit because these are just overrides for the basic operators.

10 Likes

My complaint in general is a total lack of any color operations. However, it’s hard to abstract to a point where it’d fit in with ROBLOX’s general direction. I’d be surprised if many people on ROBLOX knew about the difference between linear and gamma color.

2 Likes

How would it be more complicated? It would only become less complicated if Roblox implemented metafunctions like __add, __sub and __div to Color3 like there is for Vector3.

3 Likes

Can confirm – I don’t know the difference between them. Even in not knowing that though, I’ve still found the need to use basic mathematical operators on Color3 values in the past. Implementing trickier methods may be something that needs a bit of thought put into it, but basic operator support (+,-,*,/) is a great place to start. Anyone using Color3s can take advantage of that.

1 Like

In that case they can also just make a superclass “Triple” or something, and then have Vector3s and Color3s inherit from that, since they will almost have everything in common except from Color3 having some additional properties for construction (if our ideas from the other thread go through) and Vector3 having some extra methods like FromNormalId, FromAxis etc.

In a lot of computer graphics applications outside of ROBLOX, 3D vectors and colors are literally just the same object aliased under different names, and you can use them interchangeably. If this is happening then it might be cool if that were the case, but that’s probably asking a bit too much.

3 Likes

Remember that Color3 and Vector3 aren’t really Instances. Eg they don’t have properties like Name, Classname, Parent, etc. So what difference would it make?
The thing here is just that the Color3 should have metafunctions for normal operations like */±

1 Like

I understand what is requested in the OP, you don’t have to explain that to me. I’m discussing the proposed change and how I think it could be made better, which is one of the purposes of a thread in Feature Requests.

Color3s and Vector3s are classes of their own internally (evidenced by the fact that API functions can distinguish between userdatas), they could be extended or aliased from the same base class. Then we can even perform mathematical operations between Color3s and Vector3s, and functions/properties that expect a Color3 can also accept a Vector3 for example.

1 Like

Well, let’s think of it this way. Mathematical operations on colors in gamma space are incorrect. If I take white (255,255,255) and divide it by 2, I get (127.5,127.5,127.5), right? You might expect this to be half as bright. It’s not, though.

Monitors show you color in gamma space because weird reasons I won’t go into. When you do math with colors in shaders, you must convert to linear space first or everything you do is wrong. Normals won’t look right, lighting and shading will be too dark or too bright. Fortunately, conversion is simple… but keeping track of it isn’t. This issue is compounded by the fact that most image formats are in gamma space, and you need to convert back to gamma space when rendering.

Sure, it might be simple enough to make the distinction in your API. Maybe LinearColor3, for example, with conversion functions in between. But it’s a mindset change; 0-255 makes no sense, you really want 0.0-1.0. Linear colors don’t look like you expect them too, either, and different color gamuts make the problem more complicated.

I’m not really the best at explaining this, so TL;DR: linear color space is good for math, gamma color space is not.

2 Likes

Is this referring to the thread this one was linked from? I ask that because Color3 values are already in terms of 0-1 right now.

1 Like

Not sure. I was just mentioning that 0-255 is really pretty meaningless. You shouldn’t be choosing colors that way anyway. I would use a Color3Value myself; the property editor in Studio will take RRGGBB, #RRGGBB, or RRR, GGG, BBB.

1 Like

I replied to you in the other thread here regarding 0-255 since it’s more related to that thread than this one.

Uhhh I think the major point here was that in a semantic sense, mathematical operations in linear space don’t make sense on colors (i.e. halving each channel does not mean you get the color at half the brightness, speaking in gamma space), so the discussion fits here better. The difference between 0-1 and 0-255 is just notation.

(Sure are lots of color threads today)

As a Roblox developer, it is currently inefficient and ugly to make simple number operations across the red, green, and blue segments of Color3.

Currently, if I want to darken a color, i’d have to do something like this:

  • Color3.new(color.r * 0.8, color.g * 0.8, color.b * 0.8)

When instead I could do:

  • color * 0.8

This gets more annoying when using more complicated number offsets, creating something like this:

  • Color3.new(color.r * 0.8 + 0.1, color.g * 0.8 + 0.1, color.b * 0.8 + 0.1)

When it could be this instead:

  • color * 0.8 + 0.1

The numbers would automatically clamp down if higher than 1 or up if lower than 0.

This suggestion isn’t completely necessary, however it would be a great quality of life improvement. I’m interested in how other developers feel about this, so i’m putting a poll below. Thanks!

How do you feel about this suggestion?

  • Love it
  • Like it
  • Indifferent
  • Don’t like it
  • Hate it

0 voters

9 Likes

This is still an issue.

I can’t multiply a Color3 by a number, I have to write a wrapper to do it manually. This seems like something that should be implemented and would benefit both new & experienced devs.

My use case is similar to a tween, I was trying to take a weighted point between two Color3 values.

5 Likes

As a Roblox developer, I want to perform math directly on Color3 values, because it is more convenient than converting between data types.

If Roblox is able to address this issue, it would improve my development experience because there would be no more need to convert Color3s to Vector3s to do simple math on Color3 values.

Color3s and Vector3s are extremely similar but Color3s lack so many of the features that Vector3s have.

I propose that Vector3 math is applied to Color3s values. Additionally, or in place the above, I propose the following methods be added:
Color3 Color3.fromVector3(Vector3 color)
Vector3 Color3:ToVector3()

These methods simply treat r as x, g as y, and b as z.

Examples:

local color = Color3.fromVector3(Vector3.new(255, 127, 0)/255) -- Orange

color = color + Color3.new(0, -0.5, 1) -- Magenta

-- Possibly?
color = color - Vector3.new(0, -0.5, 1) -- Back to orange?

color = color:ToVector3() -- 1, 0.5, 0

This form of Vector3 math/conversion could be used to visualize values and easily convert between color and position. It also allows Roblox to partially merge the functionality of Vector3s and Color3s which can reduce the amount of work needed to be done when updating Color3s.

This form of math is also much easier to type and to read.

-- Before
local colorAddVector = Color3.new(color.r+vector.x, color.g+vector.y, color.b+vector.z)
-- After
local colorAddVector = color+vector
-- Before
local color = Color3.new(0.65, 0.45, 0.55)
color = Color3.new(color.r/2, color.g/2, color.b/2) -- Half as bright
-- After
local color = Color3.new(0.65, 0.45, 0.55)
color = color/2 -- Half as bright
10 Likes

It’s still a pain trying to change Color values. I would like to see support for math operations on Color3s.

There’s a legitimate request here for sure about better methods to work with colors, but this is an A/B problem. Arithmetic operations are certainly not the best solution to providing effective color handling.

Even taking directly from the above post: color = color/2 -- Half as bright

Sounds great… except that it’s not true! The human eye does not handle color intensity linearly, so to have something appear “half as bright” you actually need to apply a gamma correction to the computations, not just a linear multiplier.