internal/graphicsdriver/opengl, metal, directx: use premultiplied alpha format for color scales

Updates #2365
This commit is contained in:
Hajime Hoshi 2022-10-02 13:26:33 +09:00
parent 8a7d860632
commit 5e459bbe42
5 changed files with 19 additions and 32 deletions

View File

@ -87,12 +87,10 @@ func (i *Image) Fill(clr color.Color) {
var crf, cgf, cbf, caf float32
cr, cg, cb, ca := clr.RGBA()
if ca != 0 {
crf = float32(cr) / float32(ca)
cgf = float32(cg) / float32(ca)
cbf = float32(cb) / float32(ca)
caf = float32(ca) / 0xffff
}
crf = float32(cr) / 0xffff
cgf = float32(cg) / 0xffff
cbf = float32(cb) / 0xffff
caf = float32(ca) / 0xffff
b := i.Bounds()
x, y := i.adjustPosition(b.Min.X, b.Min.Y)
i.image.Fill(crf, cgf, cbf, caf, x, y, b.Dx(), b.Dy())
@ -386,9 +384,9 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o
sx, sy := img.adjustPositionF32(v.SrcX, v.SrcY)
vs[i*graphics.VertexFloatCount+2] = sx
vs[i*graphics.VertexFloatCount+3] = sy
vs[i*graphics.VertexFloatCount+4] = v.ColorR * cr
vs[i*graphics.VertexFloatCount+5] = v.ColorG * cg
vs[i*graphics.VertexFloatCount+6] = v.ColorB * cb
vs[i*graphics.VertexFloatCount+4] = v.ColorR * v.ColorA * cr
vs[i*graphics.VertexFloatCount+5] = v.ColorG * v.ColorA * cg
vs[i*graphics.VertexFloatCount+6] = v.ColorB * v.ColorA * cb
vs[i*graphics.VertexFloatCount+7] = v.ColorA * ca
}
is := make([]uint16, len(indices))
@ -994,14 +992,9 @@ func NewImageFromImageWithOptions(source image.Image, options *NewImageFromImage
// colorMToScale returns a new color matrix and color sclaes that equal to the given matrix in terms of the effect.
//
// If the given matrix is merely a scaling matrix, colorMToScale returns
// an identity matrix and its scaling factors. This is useful to optimize
// the rendering speed by avoiding the use of the color matrix and instead
// multiplying all vertex colors by the scale.
//
// NOTE: this is only safe when not using a custom Kage shader,
// as custom shaders may be using vertex colors for different purposes
// than colorization. However, currently there are no Ebitengine APIs that
// support both shaders and color matrices.
// an identity matrix and its scaling factors in premultiplied-alpha format.
// This is useful to optimize the rendering speed by avoiding the use of the
// color matrix and instead multiplying all vertex colors by the scale.
func colorMToScale(colorm affine.ColorM) (newColorM affine.ColorM, r, g, b, a float32) {
if colorm.IsIdentity() {
return colorm, 1, 1, 1, 1
@ -1010,6 +1003,7 @@ func colorMToScale(colorm affine.ColorM) (newColorM affine.ColorM, r, g, b, a fl
if !colorm.ScaleOnly() {
return colorm, 1, 1, 1, 1
}
r = colorm.At(0, 0)
g = colorm.At(1, 1)
b = colorm.At(2, 2)
@ -1029,5 +1023,5 @@ func colorMToScale(colorm affine.ColorM) (newColorM affine.ColorM, r, g, b, a fl
return colorm, 1, 1, 1, 1
}
return affine.ColorMIdentity{}, r, g, b, a
return affine.ColorMIdentity{}, r * a, g * a, b * a, a
}

View File

@ -125,7 +125,7 @@ PSInput VSMain(float2 position : POSITION, float2 tex : TEXCOORD, float4 color :
PSInput result;
result.position = mul(projectionMatrix, float4(position, 0, 1));
result.texcoord = tex;
result.color = float4(color.rgb, 1) * color.a;
result.color = color;
return result;
}

View File

@ -70,8 +70,7 @@ vertex VertexOut VertexShader(
VertexOut out = {
.position = projectionMatrix * float4(in.position, 0, 1),
.tex = in.tex,
// Fragment shader wants premultiplied alpha.
.color = float4(in.color.rgb, 1) * in.color.a,
.color = in.color,
};
return out;

View File

@ -115,9 +115,7 @@ varying vec4 varying_color_scale;
void main(void) {
varying_tex = A1;
// Fragment shader wants premultiplied alpha.
varying_color_scale = vec4(A2.rgb, 1) * A2.a;
varying_color_scale = A2;
mat4 projection_matrix = mat4(
vec4(2.0 / viewport_size.x, 0, 0, 0),

View File

@ -140,14 +140,10 @@ func (i *Image) resolveDotsCacheIfNeeded() {
for p, c := range i.dotsCache {
dx := float32(p[0])
dy := float32(p[1])
var crf, cgf, cbf, caf float32
if c[3] != 0 {
crf = float32(c[0]) / float32(c[3])
cgf = float32(c[1]) / float32(c[3])
cbf = float32(c[2]) / float32(c[3])
caf = float32(c[3]) / 0xff
}
crf := float32(c[0]) / 0xff
cgf := float32(c[1]) / 0xff
cbf := float32(c[2]) / 0xff
caf := float32(c[3]) / 0xff
vs[graphics.VertexFloatCount*4*idx] = dx
vs[graphics.VertexFloatCount*4*idx+1] = dy