Part I: Week 12: Temple Of Fortune (Part I)

Part II: Week 13: Temple Of Fortune (Part II)

Partners: Queenie Hsiao and Michelle Xu

Figjam: https://www.figma.com/board/JhTdafrliIsiqcVVy4lKKL/The-Temple-of-Fortune-(Work-in-Progress-Title)?node-id=0-1&t=kri01edzRn2pq4ns-1

ITP Finals (F24')_ Temple of Fortune.png

🔦 Lighting with TouchDesigner: Projection Mapping via OSC Integration

IMG_6305.jpeg

IMG_6306.jpeg

IMG_6307.jpeg

We relocated to a dimly-lit room to ensure accurate projection mapping on the cabinets using TouchDesigner. Last week, we confirmed that TouchDesigner successfully received the correct cabinet value from Unity. This week, we learned to utilize the OSC library to activate the corresponding components with the TouchDesigner interface and basic Python scripting.

The video below demonstrates the complete user interaction flow — starting from the activation of seat pressure sensors, followed by the user selecting and placing their chosen offering on the RFID reader, and concluding with the projector illuminating the cabinet containing the user’s fortune.

image.png

IMG_6310.mov

We discovered a specific edge case where, if the system selects the same cabinet value as the previous interaction, the onValueChange() function in TouchDesigner would fail to trigger because the stored value doesn't change. This is due to TouchDesigner’s behavior of only responding to actual value changes.

To resolve this, I refactored the code to include a step where, during the reset process, a null value (e.g., -1) is sent to TouchDesigner — osc.SendInteger(-1);. This effectively clears the previously stored value. Consequently, when the next cabinet value is sent—even if it matches the previous value—the onValueChange() function still triggers, ensuring consistent behavior for all interactions.

🧑🏻‍💻 Code

## 
# TouchDesigner Script that receives the cabinet value (index) and switches the alpha value of that cabinet to 1, hence turning the light "on".
##

# constant12 will always be empty/ 0
# This is the only cabinet that is not associated with any offering/ fortune
constantsArr = ['constant1','constant2','constant3','constant4','constant5','constant6','constant7','constant8','constant9','constant10','constant11','constant12','constant13','constant14','constant15','constant16']

def onValueChange(channel, sampleIndex, val, prev):
    index = int(op('oscin1')['switch/toggle'])
    timer = op('timer2')
    if index == -1:
        pass
    else:
        for constant in constantsArr:
            constantNum = int(constant[8:len(constant)])
            op(constant).par.alpha.val = 0
            if constantNum == index:
                op(constant).par.alpha.val = 1
                timer.par.start.pulse()
                break

💗 Creating Anticipation

With the necessary components successfully communicating, we shifted our focus to evaluating the feasibility and overall quality of the user experience from the perspective of a potential user. What does this mean?

  1. We wanted the cabinet light to illuminate the cabinet only after the dragon finishes its 21-second speech about Chinese fortune-telling and the symbolism behind the chosen offering.
  2. We aim for the cabinet light to turn off at the end of the user experience, resetting the system and preparing it for the next participant.

🐉 Illuminate the Cabinet After the Dragon's Speech

I chose to delay sending the cabinet value to TouchDesigner, thus postponing the light trigger. This was the simplest approach with minimal code.