Realtime Texture Switching


(SolarLune) #1

This is a simple example of texture switching. Most people want to do material switching, as do I, but that feature isn’t in Blender. So, there are 3 ways around it.

  1. Make multiple meshes and use the Replace Mesh actuator (is there a replaceMesh Python function? I don’t recall). Pros: You have control over the materials and textures present on the mesh (right?). Cons: You have to make a duplicate mesh for each outfit; if you want to change something later, like change the way his elbow moves, you have to do so for all duplicated meshes.

  2. Use 1 material and 1 texture, but use multiple UV-maps on that texture (i.e. 3 outfits on the same texture) and switch between them by moving the UV-maps around. Pros: It should work fine. Cons: It would quickly require a huge texture - if one outfit is 512x512 and you want five for the player, that would quickly become a problem.

The third way is the way that’s outlined here. Basically, you use the VideoTexture module to load an outside image, and the UV-maps stick with the mesh, meaning that you could have a hundred different player outfits, and load them each when necessary. It works very well, though there are some downsides.

The only real problem is that the textures present MUST be in an external directory - they can’t be packed in with the blend, because the VideoTexture module only loads outside files. If someone knows a way to load internal blend textures, then that would be ideal, but this method still works fine. Anyway, here’s the zip file (it includes two textures that I’m giving away to the public, free of charge, for any use, including commercial use. I know it’s simple, but hey, it’s free.)

Press A or S to switch textures. It will only update when you change texture, and that’s indicated by the obj[‘change’] variable. This works in Blender 2.5, not 2.49.


Realtime Texture Switching


(heijulien) #2

VideoTexture.Texture has a textureObj option, that can be used to reference internal textures.


(SolarLune) #3

EDIT: Just tried it out, but textureObj for the Texture constructor in the VideoTexture module only works for other VideoTexture.Texture objects, not internal Blender textures. This method still works well as you don’t need to manually open each texture for external files - you could even make a game in which the player can design a character or texture for an object in-game…


(Smoking_mirror) #4

There always seems to be a catch with whatever system I’ve tried.
Only mesh replace works consistently.

UV scroll won’t work on a rigged character- as far as Ive found.
And the video texture module… I heard that it is not included with the blender player. I.e. you can’t use it in
saved runtimes. Is it true?


(SolarLune) #5

I haven’t heard that… It’s used specifically for the GE, so I don’t really see why not. I’ll have to test it out.


(SolarLune) #6

Tested it out - the VideoTexture module worked fine in the standalone executable.


(Smoking_mirror) #7

Good news^^


(Olm-Z) #8

actually you can switch any texture channel you want so you can replace also the specular channel :

# if you have more than 1 material on the mesh and you want to 
# modify a texture of one particular material, get its ID
matID=VideoTexture.materialID(gameobj,"MAmat.001")
# GLSL material can have more than 1 texture channel, identify 
# the texture by the texture slot where it is defined, here 2
tex=VideoTexture.Texture(gameobj, matID, 2)

(SolarLune) #9

Oh, wow. Thanks for that information - I’ll update the first post.


(nweissberg) #10

I hope you dont mind but I modefied you code to work with blender 2.49b
But with this one you will need two key sensors…
And btw AWESOME CODE!!!


import GameLogic as logic
import VideoTexture

cont = logic.getCurrentController()
obj = cont.owner

a = cont.sensors["AKey"]
s = cont.sensors["SKey"]

if not 'texture' in obj:
    mat = VideoTexture.materialID(obj, 'MAFace')
    obj['texture'] = VideoTexture.Texture(obj, mat)
    obj['file'] = 'Sad.png'
    obj['changed'] = 0
else:
    if obj['changed']:
        path = logic.expandPath('//'+obj['file'])
        obj['texture'].source = VideoTexture.ImageFFmpeg(path)
        obj['changed'] = 0
        obj['texture'].refresh(True)

if a.positive:
    obj['file'] = 'Happy.png'
    obj['changed'] = 1
elif s.positive:
    obj['file'] = "Sad.png"
    obj['changed'] = 1


(TrinityGamer) #11

I love just about everything about it, but i’m having trouble trying to get the script to work for other objects, even though i have my objects with all the same settings, can you please tell me how the texture was applied or anything else that might change the way the script behaves?


(SolarLune) #12

Thanks. Is the problem that the texture’s aren’t showing up at all? Do you see any errors in the console?

EDIT: Line 36 of the script specifies that it uses the material named “MAFace”. Blender cuts off the ‘MA’ part in the game engine, which you can see by the fact that the material for the red cube character in the example blend has a material named “Face”. You need to change that name to the name of your object’s material.

EDIT 2:You can change it to the name of the image with ‘IM’ in front of it, if that helps matters.


(TrinityGamer) #13

thank you, that was the problem (i didn’t know about the MA-originalimagenamehere- thing, so it just said MAFace in the data still, but item001 for the material, XD) thanks or the help


(TrinityGamer) #14

ug, i’m not having a slightly different problem. i edited the code so that it got the material id from a variable on the object that the controler is on so that i could use the script for multiple items, but it still changes ALL of the objects materials.


(SolarLune) #15

Yeah, that’s the way it works - it replaces the image for the material. There’s not really a fix for it - if you want to load different materials on different objects (especially duplicated ones), I would recommend making the meshes that you need and using replaceMesh() or the Replace Mesh actuator.


(TrinityGamer) #16

ok, thanks you :slight_smile:


(haidme) #17

Actually this code can be optimized quite a bit, like this(for 2.49b):

import GameLogic as g

import VideoTexture

cont = g.getCurrentController()
obj = cont.owner

if not 'texture' in obj:
	mat = VideoTexture.materialID(obj, 'IMEmptyText.png')
	obj['texture'] = VideoTexture.Texture(obj, mat)
	obj['files'] = ['Img1.png','Img2.png']
	obj['DFrame']=0

path = g.expandPath('//'+obj['files'][obj['DFrame']])
obj['texture'].source = VideoTexture.ImageFFmpeg(path)
obj['texture'].refresh(True)

It is using two key sensors to switch a list of textures and the always sensor pulse mode is off which makes the script runs faster.
Here is the example

Good job Solar!


(cdo1955) #18

Do you have a sample of the entire code that will work with Version 2.62.


(SolarLune) #19

Here’s a sample of the code. It’s the same that’s in the blend file at the top, as it works fine in Blender 2.61


##############################
#                            #
# Realtime Texture Switching #
#                            #
# Author: SolarLune          #
# Date: 11/16/10             #
#                            #
# You may use this script    #
# however you wish for free, #
# including commercial,      #
# educational, personal, etc.#
#                            #
##############################

# Use A and S to switch textures.
# This method works very well, except
# for the fact that the textures can't
# be included in the blend file; they have
# to be in an external directory

import bge
from bge import logic
from bge import events

import VideoTexture

cont = logic.getCurrentController()
obj = cont.owner

k = logic.keyboard

a = k.events[events.AKEY]
s = k.events[events.SKEY]

if not 'texture' in obj:
    mat = VideoTexture.materialID(obj, 'MAFace')
    obj['texture'] = VideoTexture.Texture(obj, mat)
    obj['file'] = 'Sad.png'
    obj['changed'] = 0
else:
    if obj['changed']:
        path = logic.expandPath('//'+obj['file'])
        obj['texture'].source = VideoTexture.ImageFFmpeg(path)
        obj['changed'] = 0
        obj['texture'].refresh(True)

if a == 1:
    obj['file'] = 'Happy.png'
    obj['changed'] = 1
elif s == 1:
    obj['file'] = "Sad.png"
    obj['changed'] = 1

.


(mrn) #20

could you just use replace mesh or is this something different?