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 var crf, cgf, cbf, caf float32
cr, cg, cb, ca := clr.RGBA() cr, cg, cb, ca := clr.RGBA()
if ca != 0 { crf = float32(cr) / 0xffff
crf = float32(cr) / float32(ca) cgf = float32(cg) / 0xffff
cgf = float32(cg) / float32(ca) cbf = float32(cb) / 0xffff
cbf = float32(cb) / float32(ca)
caf = float32(ca) / 0xffff caf = float32(ca) / 0xffff
}
b := i.Bounds() b := i.Bounds()
x, y := i.adjustPosition(b.Min.X, b.Min.Y) x, y := i.adjustPosition(b.Min.X, b.Min.Y)
i.image.Fill(crf, cgf, cbf, caf, x, y, b.Dx(), b.Dy()) 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) sx, sy := img.adjustPositionF32(v.SrcX, v.SrcY)
vs[i*graphics.VertexFloatCount+2] = sx vs[i*graphics.VertexFloatCount+2] = sx
vs[i*graphics.VertexFloatCount+3] = sy vs[i*graphics.VertexFloatCount+3] = sy
vs[i*graphics.VertexFloatCount+4] = v.ColorR * cr vs[i*graphics.VertexFloatCount+4] = v.ColorR * v.ColorA * cr
vs[i*graphics.VertexFloatCount+5] = v.ColorG * cg vs[i*graphics.VertexFloatCount+5] = v.ColorG * v.ColorA * cg
vs[i*graphics.VertexFloatCount+6] = v.ColorB * cb vs[i*graphics.VertexFloatCount+6] = v.ColorB * v.ColorA * cb
vs[i*graphics.VertexFloatCount+7] = v.ColorA * ca vs[i*graphics.VertexFloatCount+7] = v.ColorA * ca
} }
is := make([]uint16, len(indices)) 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. // 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 // If the given matrix is merely a scaling matrix, colorMToScale returns
// an identity matrix and its scaling factors. This is useful to optimize // an identity matrix and its scaling factors in premultiplied-alpha format.
// the rendering speed by avoiding the use of the color matrix and instead // This is useful to optimize the rendering speed by avoiding the use of the
// multiplying all vertex colors by the scale. // 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.
func colorMToScale(colorm affine.ColorM) (newColorM affine.ColorM, r, g, b, a float32) { func colorMToScale(colorm affine.ColorM) (newColorM affine.ColorM, r, g, b, a float32) {
if colorm.IsIdentity() { if colorm.IsIdentity() {
return colorm, 1, 1, 1, 1 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() { if !colorm.ScaleOnly() {
return colorm, 1, 1, 1, 1 return colorm, 1, 1, 1, 1
} }
r = colorm.At(0, 0) r = colorm.At(0, 0)
g = colorm.At(1, 1) g = colorm.At(1, 1)
b = colorm.At(2, 2) 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 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; PSInput result;
result.position = mul(projectionMatrix, float4(position, 0, 1)); result.position = mul(projectionMatrix, float4(position, 0, 1));
result.texcoord = tex; result.texcoord = tex;
result.color = float4(color.rgb, 1) * color.a; result.color = color;
return result; return result;
} }

View File

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

View File

@ -115,9 +115,7 @@ varying vec4 varying_color_scale;
void main(void) { void main(void) {
varying_tex = A1; varying_tex = A1;
varying_color_scale = A2;
// Fragment shader wants premultiplied alpha.
varying_color_scale = vec4(A2.rgb, 1) * A2.a;
mat4 projection_matrix = mat4( mat4 projection_matrix = mat4(
vec4(2.0 / viewport_size.x, 0, 0, 0), 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 { for p, c := range i.dotsCache {
dx := float32(p[0]) dx := float32(p[0])
dy := float32(p[1]) dy := float32(p[1])
crf := float32(c[0]) / 0xff
var crf, cgf, cbf, caf float32 cgf := float32(c[1]) / 0xff
if c[3] != 0 { cbf := float32(c[2]) / 0xff
crf = float32(c[0]) / float32(c[3]) caf := float32(c[3]) / 0xff
cgf = float32(c[1]) / float32(c[3])
cbf = float32(c[2]) / float32(c[3])
caf = float32(c[3]) / 0xff
}
vs[graphics.VertexFloatCount*4*idx] = dx vs[graphics.VertexFloatCount*4*idx] = dx
vs[graphics.VertexFloatCount*4*idx+1] = dy vs[graphics.VertexFloatCount*4*idx+1] = dy