Page 1 of 1

How to transparency ?

Posted: Tue Aug 16, 2016 6:35 am
by DeezRamChips
Hi everyone ^_^

I would like how to implement tansparency in my code, I've tried a lot of formulas
but none of them worked :/ can someone show me a formula in C that works ?

Re: How to transparency ?

Posted: Tue Aug 16, 2016 6:53 am
by Octacone

Re: How to transparency ?

Posted: Tue Aug 16, 2016 7:31 am
by DeezRamChips
Ik, thansk, I'll trie them ^^

Re: How to transparency ?

Posted: Tue Aug 16, 2016 8:45 am
by Ch4ozz
You have to access the pixels underneath the new transparent stuff.
Now its pretty simple.

Old code without transparency:

Code: Select all

*(uint32_t*)physbuff = color;
New transparency code:

Code: Select all

physbuff[0] = clamp(color.r + physbuff[0] * (color.a / 255.0f), 0, 255);
physbuff[1] = clamp(color.g + physbuff[1] * (color.a / 255.0f), 0, 255);
physbuff[2] = clamp(color.b + physbuff[2] * (color.a / 255.0f), 0, 255);
physbuff[3] = clamp(physbuff[3] + color.a, 0, 255);
The only problem is that this is hella slow, Im currently thinking about a fast SSE method

Re: How to transparency ?

Posted: Tue Aug 16, 2016 10:25 am
by Boris
If your transparent image is a matrix (T) , the transparency factor also matrix (A) from 0: transparent,1: opaque, and if your background is matrix B, then the resulting image should be B + TxA - BxA. Which means , applying T to a background B does B+=(T-B)xA
SSE helps you doing quick matrix multiplication and additions but you have to do it by parts. ( Google SSE 4x4)

Re: How to transparency ?

Posted: Tue Aug 16, 2016 11:10 am
by DeezRamChips
I don't know anything about matrices :(

Haven't learned that already :( :( :(

Re: How to transparency ?

Posted: Tue Aug 16, 2016 11:57 am
by Octocontrabass
Ch4ozz wrote:New transparency code:
Why are you doing additive blending instead of alpha blending?

Re: How to transparency ?

Posted: Tue Aug 16, 2016 12:54 pm
by onlyonemac
DeezRamChips wrote:I don't know anything about matrices :(

Haven't learned that already :( :( :(
Either implement each step separately, then, or learn about matrices. In most cases, matrices are just a practical and meaningful way of representing data and performing operations on it, but you can implement the same algorithm with each value separately (different types of matrix multiplication can get a little messy if you're working with the values separately, though). Just think of matrices like arrays, and matrix operations as operations on arrays (it might help to implement each of the main matrix operations as functions, and call then as necessary to implement an algorithm that works with matrices, rather than worrying about the details of how those operations work and how the data is transformed to the required end result).

Re: How to transparency ?

Posted: Tue Aug 16, 2016 5:08 pm
by BrightLight
Well, I implemented alpha blending in the simplest way possible with a cost: I only support 4 different transparency levels, numbered from 1 to 4.
Here's how it works; can be easily converted to C code:

Code: Select all

; alpha_blend_colors:
; Blends two colors
; In\	EAX = Foreground
; In\	EBX = Background
; In\	DL = Number of bits to shift foreground color (1 = less transparent, 4 = most transparent, 0 = no change)
; Out\	EAX = New color
align 16
alpha_blend_colors:
	or dl, dl
	jz .no_change

	cmp dl, 4
	jg .no_change

	push rcx		; my tests have shown that PUSH RCX is a few cycles faster than PUSH CX --
				; -- so this probably gives more performance on slow CPUs and maybe Bochs
				; I thought PUSH CX would be faster because it's less data, but oh well..
	and eax, 0xF0F0F0
	and ebx, 0xF0F0F0

	mov cl, dl
	shr eax, cl
	shr ebx, 1
	and eax, 0x7F7F7F
	and ebx, 0x7F7F7F
	lea eax, [eax+ebx]	; probably faster than add eax, ebx
	pop rcx
	ret

.no_change:
	ret

Re: How to transparency ?

Posted: Tue Aug 16, 2016 8:52 pm
by Brendan
Hi,

Just as a reference, the "mathmatically correct" formulas would be:

Code: Select all

resultBlue = (blue1 * alpha + blue2 * (alphaMax - alpha) ) / alphaMax;
resultGreen = (green1 * alpha + green2 * (alphaMax - alpha) ) / alphaMax;
resultRed = (red1 * alpha + red2 * (alphaMax - alpha) ) / alphaMax;
This is only correct for the "no gamma" case. Pixels typically have a gamma of about 2.2, and for that case "correct" becomes:

Code: Select all

resultBlue = pow( (pow(blue1, 1/2.2) * alpha + pow(blue2, 1/2.2) * (alphaMax - alpha)) / alphaMax, 2.2);
Note that (for 8-bit alpha), most people do it wrong, like:

Code: Select all

resultBlue = (blue1 * alpha + blue2 * ~alphaMax) >> 8;
This causes images to be a fraction darker than they should be (because it's dividing by 256 and not dividing by 255, and because of "round towards zero division"); and lack of gamma correction magnifies this error (especially for darker colours); but it's faster than doing "pow()" twice per pixel. ;)


Cheers,

Brendan

Re: How to transparency ?

Posted: Wed Aug 17, 2016 4:26 am
by max
Brendan wrote:This causes images to be a fraction darker than they should be (because it's dividing by 256 and not dividing by 255, and because of "round towards zero division"); and lack of gamma correction magnifies this error (especially for darker colours); but it's faster than doing "pow()" twice per pixel. ;)
I love that you always know some hardcore stuff that seemingly few other people know :P

Re: How to transparency ?

Posted: Wed Aug 17, 2016 5:05 am
by Sik
Brendan wrote:Note that (for 8-bit alpha), most people do it wrong, like:

Code: Select all

resultBlue = (blue1 * alpha + blue2 * ~alphaMax) >> 8;
This causes images to be a fraction darker than they should be (because it's dividing by 256 and not dividing by 255, and because of "round towards zero division"); and lack of gamma correction magnifies this error (especially for darker colours); but it's faster than doing "pow()" twice per pixel. ;)
Just registered to say this:

Code: Select all

dest_a = ~src_a;
result_r = (src_r * src_a + dest_r * dest_a + 0xFF) >> 8;
result_g = (src_g * src_a + dest_g * dest_a + 0xFF) >> 8;
result_b = (src_b * src_a + dest_b * dest_a + 0xFF) >> 8;
Not necessarily the most accurate thing ever but it does prevent the situation of white becoming darker. Essentially all it's doing is mess with the rounding so fully opaque and fully transparent remain intact despite dividing by 256. Remove the * src_a if you want to make it premultiplied alpha instead, and make sure that dest_a is uint8_t (or you'll slam head straight against C's integer promotion rules).

You probably want premultiplied alpha if the image is filtered and scaled upwards anyway (since texture filtering creates values that don't exist and hence has a tendency to make problematic alpha values at the borders)