4
$\begingroup$

I am looking for a way to change the texture in the game engine. I have managed to apply 4 textures and enable/disable them usong a python script. The textures change is working, but only becomes visible when the BGE stops.
It seems that textures are not reloaded in realtime. How can I force update the texture in realtime ?

$\endgroup$
1
$\begingroup$

You can use texture bind ID.

Once you have it, you can pass a image buffer into it I think.

$\endgroup$
1
$\begingroup$

You're probably using functions from bpy? Don't use BPY in the game engine! Thankfully, bge.texture provides this functionality. Here's a code snippet that I use quite often:

def show_picture(obj, path, mat_id=0, tex_id=0):
    '''Loads a picture into a texture'''
    # The texture has to be stored in a place associated with other game data
    # so we store it in a game property. This name inlucdes the mat ID's and
    # tex ID's so that a single object with a complex setup does not have the
    # textures overwrite each other.
    # If a bge.texture object already exists for this object/mat_id/tex_id, then
    # we retrieve that.
    prop_name = 'SHOW_PICTURE{}:{}'.format(mat_id, tex_id)
    if prop_name not in obj:
        tex = bge.texture.Texture(obj, mat_id, tex_id)
        obj[prop_name] = tex
    else:
        tex = obj[prop_name]

    # Load the image from the path
    raw = bge.texture.ImageFFmpeg(os.path.join(path))

    # Check to see that it loaded
    if raw.status == bge.texture.SOURCE_ERROR:
        # Error in loading image
        raise ValueError("Unable to load image at {}".format(path))

    # Assign the new image to the texture and update the texture.
    tex.source = raw
    tex.refresh(True)

Pass in an object, a filepath and (optionally) the material slot and texture slot.

Now, this function reloads the image from disk every time you use it, and as a result it is quite slow - don't go calling it each frame. If you want to have something change picture rapidly, you need to keep it loaded in RAM and just point the plane's material at a bunch of different textures. This can be done by using the bind id. I don't have any nice code snippets for this, but maybe this line will help:

material = obj.meshes[0].materials[0]
material.textures[slot_id].bindCode = tex.bindId

where tex is some dynamic texture (ie a bge.texture.Texture object). You may be able to do:

material1.textures[slot_id].bindCode = material2.textures[slot_id].bindCode

But I have not tested that.

$\endgroup$
  • $\begingroup$ Hi, How does one find the material ID and texture ID? $\endgroup$ – nischayn22 Nov 17 '18 at 14:20
  • $\begingroup$ Most objects have a single material, so most of the time you can leave it at zero. If not you can use: docs.blender.org/api/blender_python_api_2_78a_release/… It seems you use the same function for finding materials. Normally I just hard-code the values because they match the location in the material and texture slots. (ie a texture in the first texture slot has ID zero). $\endgroup$ – sdfgeoff Nov 17 '18 at 16:55
  • $\begingroup$ Thanks, I was actually able to find it out: tex_id = bge.texture.materialID(obj, 'filename.jpg') $\endgroup$ – nischayn22 Nov 17 '18 at 17:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.