diff --git a/image.go b/image.go index 30cd54fce42c..ad099dd5cbaa 100644 --- a/image.go +++ b/image.go @@ -535,6 +535,8 @@ type DrawTrianglesShaderOptions struct { // If the uniform variable type is an array, a vector or a matrix, // you have to specify linearly flattened values as a slice or an array. // For example, if the uniform variable type is [4]vec4, the length will be 16. + // + // If a uniform variable's name doesn't exist in Uniforms, this is treated as if zero values are specified. Uniforms map[string]any // Images is a set of the source images. @@ -710,6 +712,8 @@ type DrawRectShaderOptions struct { // If the uniform variable type is an array, a vector or a matrix, // you have to specify linearly flattened values as a slice or an array. // For example, if the uniform variable type is [4]vec4, the length will be 16. + // + // If a uniform variable's name doesn't exist in Uniforms, this is treated as if zero values are specified. Uniforms map[string]any // Images is a set of the source images. diff --git a/internal/ui/shader.go b/internal/ui/shader.go index d5d7cb473409..ddd2909d4d93 100644 --- a/internal/ui/shader.go +++ b/internal/ui/shader.go @@ -55,6 +55,9 @@ func (s *Shader) AppendUniforms(dst []uint32, uniforms map[string]any) []uint32 origLen := len(dst) if cap(dst)-len(dst) >= s.uniformUint32Count { dst = dst[:len(dst)+s.uniformUint32Count] + for i := origLen; i < len(dst); i++ { + dst[i] = 0 + } } else { dst = append(dst, make([]uint32, s.uniformUint32Count)...) } diff --git a/shader_test.go b/shader_test.go index 7aa9fe30e4c1..b553cb3fdb56 100644 --- a/shader_test.go +++ b/shader_test.go @@ -1960,3 +1960,55 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 { }) } } + +// Issue #2709 +func TestShaderUniformDefaultValue(t *testing.T) { + const w, h = 16, 16 + + dst := ebiten.NewImage(w, h) + s, err := ebiten.NewShader([]byte(`//kage:unit pixel + +package main + +var U vec4 + +func Fragment(position vec4, texCoord vec2, color vec4) vec4 { + return U +} +`)) + if err != nil { + t.Fatal(err) + } + + // Draw with a uniform variable value. + op := &ebiten.DrawRectShaderOptions{} + op.Uniforms = map[string]any{ + "U": [...]float32{1, 1, 1, 1}, + } + dst.DrawRectShader(w, h, s, op) + + for j := 0; j < h; j++ { + for i := 0; i < w; i++ { + got := dst.At(i, j).(color.RGBA) + want := color.RGBA{0xff, 0xff, 0xff, 0xff} + if got != want { + t.Errorf("dst.At(%d, %d): got: %v, want: %v", i, j, got, want) + } + } + } + + // Draw without a uniform variable value. In this case, the uniform variable value should be 0. + dst.Clear() + op.Uniforms = nil + dst.DrawRectShader(w, h, s, op) + + for j := 0; j < h; j++ { + for i := 0; i < w; i++ { + got := dst.At(i, j).(color.RGBA) + want := color.RGBA{0, 0, 0, 0} + if got != want { + t.Errorf("dst.At(%d, %d): got: %v, want: %v", i, j, got, want) + } + } + } +}