Pre-failing test for color interpolation during rendering. (#2001)

Before #1996, this failed with:

image_test.go:1997: At(1, 0): got: {64 64 128 255}, want: {0 128 128 255}

The difference is:

- Before, colors were interpolated in straight-color space:
  - Background: {0 0 255 255}
  - Vertex A: {255 0 0 0}
  - Vertex B: {0 255 0 255}
  - Interpolated: {128 128 0 128}
  - Premultiplied: {64 64 0 128}
  - Onto Background: {64 64 128 255}
- After, colors are interpolated in premultiplied space:
  - Background: {0 0 255 255}
  - Vertex A: {255 0 0 0}
  - Vertex A premultiplied: {0 0 0 0}
  - Vertex B: {0 255 0 255}
  - Vertex B premultiplied: {0 255 0 255}
  - Interpolated: {0 128 0 128}
  - Onto Background: {0 128 128 255}

This DIFFERS from the sample fragment shader, which returns the color as is
(Kage allows vertex color values to be used for arbitrary purposes and
interpolates independently):

- Shader sample:
  - Background: {0 0 255 255}
  - Vertex A: {255 0 0 0}
  - Vertex B: {0 255 0 255}
  - Interpolated: {128 128 0 128}
  - Onto Background: {128 128 128 255}

as the blend function is `GL_ONE` / `GL_ONE_MINUS_SRC_ALPHA`. This shader behavior
is unchanged but has been documented by #1996.
This commit is contained in:
divVerent 2022-02-23 13:12:33 -05:00 committed by GitHub
parent f2209a0b51
commit 62229e82a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1928,6 +1928,157 @@ func TestImageDrawTrianglesWithColorM(t *testing.T) {
}
}
func TestImageDrawTrianglesInterpolatesColors(t *testing.T) {
const w, h = 3, 1
src := ebiten.NewImage(w, h)
dst := ebiten.NewImage(w, h)
src.Fill(color.White)
vs := []ebiten.Vertex{
{
DstX: 0,
DstY: 0,
SrcX: 0,
SrcY: 0,
ColorR: 1,
ColorG: 0,
ColorB: 0,
ColorA: 0,
},
{
DstX: w,
DstY: 0,
SrcX: w,
SrcY: 0,
ColorR: 0,
ColorG: 1,
ColorB: 0,
ColorA: 1,
},
{
DstX: 0,
DstY: h,
SrcX: 0,
SrcY: h,
ColorR: 1,
ColorG: 0,
ColorB: 0,
ColorA: 0,
},
{
DstX: w,
DstY: h,
SrcX: w,
SrcY: h,
ColorR: 0,
ColorG: 1,
ColorB: 0,
ColorA: 1,
},
}
dst.Fill(color.RGBA{0x00, 0x00, 0xff, 0xff})
op := &ebiten.DrawTrianglesOptions{}
is := []uint16{0, 1, 2, 1, 2, 3}
dst.DrawTriangles(vs, is, src, op)
got := dst.At(1, 0).(color.RGBA)
// Correct color interpolation uses the alpha channel and notices that colors on the left side of the texture are fully transparent.
want := color.RGBA{0x00, 0x80, 0x80, 0xff}
// Interpolation isn't exactly specified, so a range is accepable.
diff := math.Max(math.Max(math.Max(
math.Abs(float64(got.R)-float64(want.R)),
math.Abs(float64(got.G)-float64(want.G))),
math.Abs(float64(got.B)-float64(want.B))),
math.Abs(float64(got.A)-float64(want.A)))
if diff > 5 {
t.Errorf("At(1, 0): got: %v, want: %v", got, want)
}
}
func TestImageDrawTrianglesShaderInterpolatesValues(t *testing.T) {
const w, h = 3, 1
src := ebiten.NewImage(w, h)
dst := ebiten.NewImage(w, h)
src.Fill(color.White)
vs := []ebiten.Vertex{
{
DstX: 0,
DstY: 0,
SrcX: 0,
SrcY: 0,
ColorR: 1,
ColorG: 0,
ColorB: 0,
ColorA: 0,
},
{
DstX: w,
DstY: 0,
SrcX: w,
SrcY: 0,
ColorR: 0,
ColorG: 1,
ColorB: 0,
ColorA: 1,
},
{
DstX: 0,
DstY: h,
SrcX: 0,
SrcY: h,
ColorR: 1,
ColorG: 0,
ColorB: 0,
ColorA: 0,
},
{
DstX: w,
DstY: h,
SrcX: w,
SrcY: h,
ColorR: 0,
ColorG: 1,
ColorB: 0,
ColorA: 1,
},
}
dst.Fill(color.RGBA{0x00, 0x00, 0xff, 0xff})
op := &ebiten.DrawTrianglesShaderOptions{
Images: [4]*ebiten.Image{src, nil, nil, nil},
}
is := []uint16{0, 1, 2, 1, 2, 3}
shader, err := ebiten.NewShader([]byte(`
package main
func Fragment(position vec4, texCoord vec2, color vec4) vec4 {
return color
}
`))
if err != nil {
t.Fatalf("could not compile shader: %v", err)
}
dst.DrawTrianglesShader(vs, is, shader, op)
got := dst.At(1, 0).(color.RGBA)
// Shaders get each color value interpolated independently.
want := color.RGBA{0x80, 0x80, 0x80, 0xff}
// Interpolation isn't exactly specified, so a range is accepable.
diff := math.Max(math.Max(math.Max(
math.Abs(float64(got.R)-float64(want.R)),
math.Abs(float64(got.G)-float64(want.G))),
math.Abs(float64(got.B)-float64(want.B))),
math.Abs(float64(got.A)-float64(want.A)))
if diff > 5 {
t.Errorf("At(1, 0): got: %v, want: %v", got, want)
}
}
// Issue #1137
func TestImageDrawOver(t *testing.T) {
dst := ebiten.NewImage(320, 240)