I am trying to pass image texture to fragment shader and read it back. But it only works if the color of the pixel is set to 0.0 or 1.0. The value returns to the buffer if the value is set to, for example, 0.2, is incorrect. I am using blender 2.8 with python script. I am totally new to Blender, so any suggestions are appreciated. Here is my code so far:
import bpy
import gpu
import bgl
import random
from mathutils import Matrix
from gpu_extras.batch import batch_for_shader
import numpy as np
from math import *
# from gpu_extras.presets import draw_circle_2d
import time
IMAGE_NAME = "Generated Image"
WIDTH = 4
HEIGHT = 4
vertex_shader = '''
in vec2 position;
in vec2 uv;
out vec2 uvInterp;
void main()
{
uvInterp = uv;
gl_Position = vec4(position, 0.0, 1.0);
}
'''
fragment_shader = '''
uniform sampler2D image;
out vec4 color;
in vec2 uvInterp;
void main()
{
vec4 result = texture(image, uvInterp);
color = result;
}
'''
shader = gpu.types.GPUShader(vertex_shader, fragment_shader)
batch = batch_for_shader(
shader, 'TRI_FAN',
{
"position": ((-1, -1), (1, -1), (1, 1), (-1, 1)),
"uv": ((0, 0), (1, 0), (1, 1), (0, 1)),
},
)
# print(buffer)
# push buffer to blender image
if IMAGE_NAME in bpy.data.images:
image = bpy.data.images[IMAGE_NAME]
if image:
bpy.data.images.remove(image)
bpy.data.images.new(IMAGE_NAME, WIDTH, HEIGHT)
else:
bpy.data.images.new(IMAGE_NAME, WIDTH, HEIGHT)
image = bpy.data.images[IMAGE_NAME]
#FIXED: set data
for i in range(0, WIDTH*HEIGHT*4, 4):
image.pixels[i] = 0.2
image.pixels[i+1] = 0.3
image.pixels[i+2] = 0.1
image.pixels[i+3] = 0.4
print(list(image.pixels))
# load to gpu
if image.gl_load():
raise Exception()
offscreen = gpu.types.GPUOffScreen(WIDTH, HEIGHT)
# at the beginning:
start_time = time.time()
with offscreen.bind():
bgl.glClear(bgl.GL_COLOR_BUFFER_BIT)
bgl.glActiveTexture(bgl.GL_TEXTURE0)
bgl.glBindTexture(bgl.GL_TEXTURE_2D, image.bindcode)
shader.bind()
shader.uniform_int("image", 0)
batch.draw(shader)
buffer = bgl.Buffer(bgl.GL_FLOAT, WIDTH * HEIGHT * 4)
bgl.glReadBuffer(bgl.GL_BACK)
bgl.glReadPixels(0, 0, WIDTH, HEIGHT, bgl.GL_RGBA, bgl.GL_FLOAT, buffer)
# at the end of the program:
print("glReadPixels: %f seconds" % (time.time() - start_time))
offscreen.free()
print(buffer)