Using imageToArray to alter the pixels of a rendered texture, is this possible?

I was experimenting with bge.texture.imageToArray() to retrieve the list of pixels/colors in the render, and it works fine. I am able to get a list of pixels with their RGB values. But it doesn’t seem like there is a way to do this “backwards”. Would it be possible to alter the pixel data and then pass it back into the respective texture?

Here’s what I want to do:
imageToArray(source,'RGB) > gives me a list of numbers > I want to alter these numbers somewhat > pass the data back into the image texture (or if I have to, make a new one?)

The reason I want to figure out how to do this is it would allow for manipulation of the texture coordinates and each pixel’s color using python, which could lead to some interesting results.

Here’s the section of code that I have so far:

def getPixelInfo():
	obj = getObj("render01") #getObj is a function I wrote that calls an object in the scene by its name to make it easier
    #note these props were added in the gamelogic window to more easily change the camera/material while debugging
	matName = obj['matName']
	fromCam = getObj(str(obj['fromCam']))
	fromSce = getSce(str(obj['fromSce'])) 
	#
	src = bge.texture.ImageRender(fromSce,fromCam)	
	src.capsize = [320,240]
	src.background = [0,0,0,0] #world background (set to black)
	imageArray = bge.texture.imageToArray(src,'RGB')  
	charArray = imageArray.to_list()

	print(charArray) #data in 1d array
    
    #alter the numbers in charArray
    # # #
    #then pass them back into the the texture image (or make a new one) - how??

image

This is the resource that I used for loading images from disk and making a texture out of them while the game is running:

The documentation suggests that you can use different sources, one of which is “Buffer”, which I’m pretty sure is what bge.texture.imageToArray is returning.

1 Like

Like TheDave suggested, you can use a buffer as a source, but you must create a Buffer object with the modified array, then set the source to ImageBuff and update the source with said buffer object.

#You must import bgl

#The mode must be RGBA
imageArray = bge.texture.imageToArray(src,'RGBA')
charArray = imageArray.to_list()

#change the first pixel(bottom-left) to red
charArray[0] = 255
charArray[1] = 0
charArray[2] = 0

#create buffer object from charArray
ImgBuffer = bgl.Buffer(bgl.GL_BYTE, [1, len(charArray)], [charArray])

width = src.capsize[0]
height = src.capsize[1]

#set the source to ImageBuff
src = bge.texture.ImageBuff(width, height)

#Update the image buffer with the one we created
src.plot(ImgBuffer, width, height, 0, 0, bge.texture.IMB_BLEND_COPY)
2 Likes

Thank you both! I am going to test this out and I will let you know if it works.

Update - I finally managed to get this working with some tweaking. My code probably isn’t the cleanest, but this worked for me:

import bgl
def pixeltest():#################################################
	capsX=320
	capsY=240
	import VideoTexture
	#
	obj=getObj("#ren")
	matName=obj['matName']
	fromCam=getObj(str(obj['fromCam']))
	fromSce=getSce(str(obj['fromSce']))

	matID=VideoTexture.materialID(obj,"MA"+obj['matName'])

	src=VideoTexture.ImageRender(fromSce,fromCam)
	src.capsize=[capsX,capsY]

	imageArray=bge.texture.imageToArray(src,'RGBA')
	charArray=imageArray.to_list()
	
	charArray[0]=255
	charArray[1]=0
	charArray[2]=0

	ImgBuffer=bgl.Buffer(bgl.GL_BYTE, [1, len(charArray)], [charArray])
	width=src.capsize[0]
	height=src.capsize[1]
	
	newsrc=bge.texture.ImageBuff(width, height)
	newsrc.plot(ImgBuffer, width, height, 0, 0, bge.texture.IMB_BLEND_COPY_RGB)
	renderToTexture=VideoTexture.Texture(obj,matID)
	obj["RenderToTexture"]=renderToTexture
	src.capsize=[capsX,capsY]
	renderToTexture.source=newsrc
	obj["RenderToTexture"].refresh(True)
	
	#turn off mipmaps
	bindcode=obj.meshes[0].materials[0].getTextureBindcode(0)
	glEnable		(GL_TEXTURE_2D)
	glBindTexture   (GL_TEXTURE_2D
					,bindcode)
	glTexParameteri (GL_TEXTURE_2D
					,GL_TEXTURE_MIN_FILTER
					,GL_NEAREST)
	glTexParameteri (GL_TEXTURE_2D
					,GL_TEXTURE_MAG_FILTER
					,GL_NEAREST)
	glBindTexture   (GL_TEXTURE_2D
					,0)
	
pixeltest()

The next step for me is to find some interesting ways to alter these pixels and come up with some visual effects using math…

1 Like

Hmmmm, could definitely be used for some kind of camera effect, or even portals.