Skip to content

A PLAY EXPERIENCE MAKER'S WORK LOG FOR FUTURE SELF©2001 – 2023 Kyle Li 李肅綱 All Rights Reserved.

Author: admin

BMP – Rearrange Colormap

Posted on February 16, 2026March 1, 2026 by admin

In my limited experience working with BMP, GIMP UI is more intuitive and easy to use in comparison to Photoshop in this particular task, especially when it comes to rearranging colors in the color palette. Also, the image quality after color reduction and shrinking is better effortlessly in my opinion.

Using GIMP

  1. Open Image: Open your image in GIMP.
  2. Indexed Mode: Go to Image > Mode > Indexed.
  3. Set Colors: Choose “Generate optimum palette” and set the Maximum number of colors to 4.
  4. Reorder Palette: Go to Colors > Map > Rearrange Colormap. Drag and drop the colors into your desired order (Index 0-3).
  5. Force 8-bit Colormap: Open the Colormap dialog (Windows > Dockable Dialogs > Colormap) and click the ‘+’ button to add colors, ensuring the total is greater than 16, which forces an 8-bit (256 color) palette.
    ※This is because the index image is reduced to 4 colors, GIMP automatically create a 4-bit (16 colors) map to save space. This will mess up how BMP is displayed in yyCHR.
  6. Export: Go to File > Export As, select BMP. 
Add 13 more colors in the colormap to force the 8-bit Colormap.
You can see the difference in Bit Depth in Properties/Details. On the left is the correct one with 8 bit depth (>16 colors).
8-bit Colormap
4-bit Colormap

Reset Allow USB Debugging? Notification

Posted on February 16, 2026February 18, 2026 by admin
  1. Go to C:\Users\<YourProfile>\.android and delete both adbkey files, if there are none, skip this step.
  2. Download adb here and extract it somewhere.
  3. Open command prompt and navigate to the folder you’ve just extracted, for example 
    cd C:\path\to\platform-tools
    ※right click on the unzipped folder and select Open in Terminal also work.
  4. With the headset connected and logged in an administrator account, run .\adb kill-server and then .\adb devices.
  5. The notification should appear.

The “Toggle” Fix (Most Common Solution)

The Developer Mode status can sometimes desync between the headset and the mobile app.

  1. Open the Meta Horizon (Quest) App on your phone.
  2. Navigate to Menu > Devices > Headset Settings > Developer Mode.
  3. Toggle the switch OFF, wait about 10 seconds, and then toggle it back ON.
  4. Restart your headset (hold the power button and select Restart).
  5. Plug it back into your PC; the prompt should now appear.

8-bit Notes

Posted on February 8, 2026February 16, 2026 by admin

8 Eyes
Look at that bird animation.

A列車で行こう
There is a whole Locomotive in the CHR for the title screen.

Akira

AT29C256 90PI

Posted on January 31, 2026February 6, 2026 by admin

The differences between various types of the AT29C256 (a 256Kbit [32K x 8] 5-volt only Flash memory chip) primarily relate to speed, packaging, temperature ratings, and manufacturing reliability. While the core memory functionality remains the same, these factors determine the best fit for specific applications. 

Here are the key areas of variation based on part number suffixes:

1. Access Speed (Speed Ratings)

The numbers following the hyphen (e.g., 90, 12, 15) indicate the maximum access time in nanoseconds (ns). 

  • 70/700: 70ns (Fastest)
  • 90/900: 90ns
  • 12/120: 120ns
  • 15/150: 150ns
  • Faster chips can be used in place of slower ones, but not always vice versa. 

2. Package Types

The package affects how the chip is soldered or socketed onto a board. 

  • P (PDIP): 28-pin Plastic Dual Inline Package (ideal for through-hole breadboards).
  • J (PLCC): 32-pin Plastic Leaded Chip Carrier (surface mount or socket).
  • T (TSOP): 28-lead Thin Small Outline Package (smaller surface mount). 

3. Temperature Range and Reliability

Suffixes after the package type indicate the environmental rating. 

  • C: Commercial (0°C to 70°C).
  • I: Industrial (-40°C to +85°C).
  • RoHS Compliance: Some newer versions are RoHS compliant (lead-free), whereas older stock might not be. 

4. Part Number Breakdown Example (AT29C256-90TI)

  • AT29C256: The device type (256Kbit Flash).
  • 90: 90ns access speed.
  • T: TSOP Package.
  • I: Industrial Temperature Range (-40 to +85°C).
  • -T: Tape and Reel packaging. 

Super-Toys Last All Summer Long

Posted on November 15, 2025November 15, 2025 by admin

By Brian Aldiss

The inspiration behind Kubrick’s ongoing AI project, a tale of humanity and of the aching loneliness in an overpopulated future.

Though Brian Aldiss bristles at being pigeonholed as a sci-fi writer, the British author has won every major science fiction award. He has also sparked director Stanley Kubrick’s imagination with the short story “Super-Toys Last All Summer Long.” First published in Harper’s Bazaar in 1969 and later anthologized, this tale of humanity in an age of intelligent machines and of the aching loneliness endemic in an overpopulated future is the inspiration behind Kubrick’s ongoing AI project. Aldiss’s story offers richly suggestive details that one hopes will make the cinematic cut. But just in case they don’t, read the original.

In Mrs. Swinton’s garden, it was always summer. The lovely almond trees stood about it in perpetual leaf. Monica Swinton plucked a saffron-colored rose and showed it to David.

“Isn’t it lovely?” she said.

David looked up at her and grinned without replying. Seizing the flower, he ran with it across the lawn and disappeared behind the kennel where the mowervator crouched, ready to cut or sweep or roll when the moment dictated. She stood alone on her impeccable plastic gravel path.

She had tried to love him.

When she made up her mind to follow the boy, she found him in the courtyard floating the rose in his paddling pool. He stood in the pool engrossed, still wearing his sandals.

“David, darling, do you have to be so awful? Come in at once and change your shoes and socks.”

He went with her without protest into the house, his dark head bobbing at the level of her waist. At the age of three, he showed no fear of the ultrasonic dryer in the kitchen. But before his mother could reach for a pair of slippers, he wriggled away and was gone into the silence of the house.

He would probably be looking for Teddy.

Monica Swinton, twenty-nine, of graceful shape and lambent eye, went and sat in her living room, arranging her limbs with taste. She began by sitting and thinking; soon she was just sitting. Time waited on her shoulder with the maniac slowth it reserves for children, the insane, and wives whose husbands are away improving the world. Almost by reflex, she reached out and changed the wavelength of her windows. The garden faded; in its place, the city center rose by her left hand, full of crowding people, blowboats, and buildings (but she kept the sound down). She remained alone. An overcrowded world is the ideal place in which to be lonely.

The directors of Synthank were eating an enormous luncheon to celebrate the launching of their new product. Some of them wore the plastic face-masks popular at the time. All were elegantly slender, despite the rich food and drink they were putting away. Their wives were elegantly slender, despite the food and drink they too were putting away. An earlier and less sophisti- cated generation would have regarded them as beautiful people, apart from their eyes.

Henry Swinton, Managing Director of Synthank, was about to make a speech.

“I’m sorry your wife couldn’t be with us to hear you,” his neighbor said.

“Monica prefers to stay at home thinking beautiful thoughts,” said Swinton, maintaining a smile.

“One would expect such a beautiful woman to have beautiful thoughts,” said the neighbor.

Take your mind off my wife, you bastard, thought Swinton, still smiling.

He rose to make his speech amid applause.

After a couple of jokes, he said, “Today marks a real breakthrough for the company. It is now almost ten years since we put our first synthetic life-forms on the world market. You all know what a success they have been, particularly the miniature dinosaurs. But none of them had intelligence.

“It seems like a paradox that in this day and age we can create life but not intelligence. Our first selling line, the Crosswell Tape, sells best of all, and is the most stupid of all.” Everyone laughed.

“Though three-quarters of the overcrowded world are starving, we are lucky here to have more than enough, thanks to population control. Obesity’s our problem, not malnutrition. I guess there’s nobody round this table who doesn’t have a Crosswell working for him in the small intestine, a perfectly safe parasite tape-worm that enables its host to eat up to fifty percent more food and still keep his or her figure. Right?” General nods of agreement.

“Our miniature dinosaurs are almost equally stupid. Today, we launch an intelligent synthetic life-form – a full-size serving-man.

“Not only does he have intelligence, he has a controlled amount of intelligence. We believe people would be afraid of a being with a human brain. Our serving-man has a small computer in his cranium.

“There have been mechanicals on the market with mini-computers for brains – plastic things without life, super-toys – but we have at last found a way to link computer circuitry with synthetic flesh.”

David sat by the long window of his nursery, wrestling with paper and pencil. Finally, he stopped writing and began to roll the pencil up and down the slope of the desk-lid.
“Teddy!” he said.

Teddy lay on the bed against the wall, under a book with moving pictures and a giant plastic soldier. The speech-pattern of his master’s voice activated him and he sat up.

“Teddy, I can’t think what to say!”

Climbing off the bed, the bear walked stiffly over to cling to the boy’s leg. David lifted him and set him on the desk.

“What have you said so far?”

“I’ve said -” He picked up his letter and stared hard at it. “I’ve said, ‘Dear Mummy, I hope you’re well just now. I love you….'”

There was a long silence, until the bear said, “That sounds fine. Go downstairs and give it to her.”

Another long silence.

“It isn’t quite right. She won’t understand.”

Inside the bear, a small computer worked through its program of possibilities. “Why not do it again in crayon?”

When David did not answer, the bear repeated his suggestion. “Why not do it again in crayon?”

David was staring out of the window. “Teddy, you know what I was thinking? How do you tell what are real things from what aren’t real things?”

The bear shuffled its alternatives. “Real things are good.”

“I wonder if time is good.

I don’t think Mummy likes time very much. The other day, lots of days ago, she said that time went by her. Is time real, Teddy?”

“Clocks tell the time. Clocks are real. Mummy has clocks so she must like them. She has a clock on her wrist next to her dial.”

David started to draw a jumbo jet on the back of his letter. “You and I are real, Teddy, aren’t we?”

The bear’s eyes regarded the boy unflinchingly. “You and I are real, David.” It specialized in comfort.

Monica walked slowly about the house. It was almost time for the afternoon post to come over the wire. She punched the Post Office number on the dial on her wrist but nothing came through. A few minutes more.

She could take up her painting. Or she could dial her friends. Or she could wait till Henry came home. Or she could go up and play with David….

She walked out into the hall and to the bottom of the stairs.

“David!”

No answer. She called again and a third time.

“Teddy!” she called, in sharper tones.

“Yes, Mummy!” After a moment’s pause, Teddy’s head of golden fur appeared at the top of the stairs.

“Is David in his room, Teddy?”

“David went into the garden, Mummy.”

“Come down here, Teddy!”

She stood impassively, watching the little furry figure as it climbed down from step to step on its stubby limbs. When it reached the bottom, she picked it up and carried it into the living room. It lay unmoving in her arms, staring up at her. She could feel just the slightest vibration from its motor.

“Stand there, Teddy. I want to talk to you.” She set him down on a tabletop, and he stood as she requested, arms set forward and open in the eternal gesture of embrace.

“Teddy, did David tell you to tell me he had gone into the garden?”

The circuits of the bear’s brain were too simple for artifice. “Yes, Mummy.”

“So you lied to me.”

“Yes, Mummy.”

“Stop calling me Mummy! Why is David avoiding me? He’s not afraid of me, is he?”

“No. He loves you.”

“Why can’t we communicate?”

“David’s upstairs.”

The answer stopped her dead. Why waste time talking to this machine? Why not simply go upstairs and scoop David into her arms and talk to him, as a loving mother should to a loving son? She heard the sheer weight of silence in the house, with a different quality of silence pouring out of every room. On the upper landing, something was moving very silently – David, trying to hide away from her….

He was nearing the end of his speech now. The guests were attentive; so was the Press, lining two walls of the banqueting chamber, recording Henry’s words and occasionally photographing him.

“Our serving-man will be, in many senses, a product of the computer. Without computers, we could never have worked through the sophisticated biochemics that go into synthetic flesh. The serving-man will also be an extension of the computer – for he will contain a computer in his own head, a microminiaturized computer capable of dealing with almost any situation he may encounter in the home. With reservations, of course.” Laughter at this; many of those present knew the heated debate that had engulfed the Synthank boardroom before the decision had finally been taken to leave the serving-man neuter under his flawless uniform.

“Amid all the triumphs of our civilization – yes, and amid the crushing problems of overpopulation too – it is sad to reflect how many millions of people suffer from increasing loneliness and isolation. Our serving-man will be a boon to them; he will always answer, and the most vapid conversation cannot bore him.

“For the future, we plan more models, male and female – some of them without the limitations of this first one, I promise you! – of more advanced design, true bio-electronic beings.

“Not only will they possess their own computer, capable of individual programming; they will be linked to the World Data Network. Thus everyone will be able to enjoy the equivalent of an Einstein in their own homes. Personal isolation will then be banished forever!”

He sat down to enthusiastic applause. Even the synthetic serving-man, sitting at the table dressed in an unostentatious suit, applauded with gusto.

Dragging his satchel, David crept round the side of the house. He climbed on to the ornamental seat under the living-room window and peeped cautiously in.

His mother stood in the middle of the room. Her face was blank; its lack of expression scared him. He watched fascinated. He did not move; she did not move. Time might have stopped, as it had stopped in the garden.

At last she turned and left the room. After waiting a moment, David tapped on the window. Teddy looked round, saw him, tumbled off the table, and came over to the window. Fumbling with his paws, he eventually got it open.

They looked at each other.

“I’m no good, Teddy. Let’s run away!”

“You’re a very good boy. Your Mummy loves you.”

Slowly, he shook his head. “If she loved me, then why can’t I talk to her?”

“You’re being silly, David. Mummy’s lonely. That’s why she had you.”

“She’s got Daddy. I’ve got nobody ‘cept you, and I’m lonely.”

Teddy gave him a friendly cuff over the head. “If you feel so bad, you’d better go to the psychiatrist again.”

“I hate that old psychiatrist – he makes me feel I’m not real.” He started to run across the lawn. The bear toppled out of the window and followed as fast as its stubby legs would allow.

Monica Swinton was up in the nursery. She called to her son once and then stood there, undecided. All was silent.

Crayons lay on his desk. Obeying a sudden impulse, she went over to the desk and opened it. Dozens of pieces of paper lay inside. Many of them were written in crayon in David’s clumsy writing, with each letter picked out in a color different from the letter preceding it. None of the messages was finished.

“My dear Mummy, How are you really, do you love me as much -“

“Dear Mummy, I love you and Daddy and the sun is shining -“

“Dear dear Mummy, Teddy’s helping me write to you. I love you and Teddy -“

“Darling Mummy, I’m your one and only son and I love you so much that some times -“

“Dear Mummy, you’re really my Mummy and I hate Teddy -“

“Darling Mummy, guess how much I love -“

“Dear Mummy, I’m your little boy not Teddy and I love you but Teddy -“

“Dear Mummy, this is a letter to you just to say how much how ever so much -“

Monica dropped the pieces of paper and burst out crying. In their gay inaccurate colors, the letters fanned out and settled on the floor.

Henry Swinton caught the express home in high spirits, and occasionally said a word to the synthetic serving-man he was taking home with him. The serving-man answered politely and punctually, although his answers were not always entirely relevant by human standards.

The Swintons lived in one of the ritziest city-blocks, half a kilometer above the ground. Embedded in other apartments, their apartment had no windows to the outside; nobody wanted to see the overcrowded external world. Henry unlocked the door with his retina pattern-scanner and walked in, followed by the serving-man.

At once, Henry was sur-rounded by the friendly illusion of gardens set in eternal summer. It was amazing what Whologram could do to create huge mirages in small spaces. Behind its roses and wisteria stood their house; the deception was complete: a Georgian mansion appeared to welcome him.

“How do you like it?” he asked the serving-man.

“Roses occasionally suffer from black spot.”

“These roses are guaranteed free from any imperfections.”

“It is always advisable to purchase goods with guarantees, even if they cost slightly more.”

“Thanks for the information,” Henry said dryly. Synthetic life-forms were less than ten years old, the old android mechanicals less than sixteen; the faults of their systems were still being ironed out, year by year.

He opened the door and called to Monica.

She came out of the sitting-room immediately and flung her arms round him, kissing him ardently on cheek and lips. Henry was amazed.

Pulling back to look at her face, he saw how she seemed to generate light and beauty. It was months since he had seen her so excited. Instinctively, he clasped her tighter.

“Darling, what’s happened?”

“Henry, Henry – oh, my darling, I was in despair … but I’ve just dialed the afternoon post and – you’ll never believe it! Oh, it’s wonderful!”

“For heaven’s sake, woman, what’s wonderful?”

He caught a glimpse of the heading on the photostat in her hand, still moist from the wall-receiver: Ministry of Population. He felt the color drain from his face in sudden shock and hope.

“Monica … oh … Don’t tell me our number’s come up!”

“Yes, my darling, yes, we’ve won this week’s parenthood lottery! We can go ahead and conceive a child at once!”

He let out a yell of joy. They danced round the room. Pressure of population was such that reproduction had to be strict, controlled. Childbirth required government permission. For this moment, they had waited four years. Incoherently they cried their delight.

They paused at last, gasping, and stood in the middle of the room to laugh at each other’s happiness. When she had come down from the nursery, Monica had de-opaqued the windows, so that they now revealed the vista of garden beyond. Artificial sunlight was growing long and golden across the lawn – and David and Teddy were staring through the window at them.

Seeing their faces, Henry and his wife grew serious.

“What do we do about them?” Henry asked.

“Teddy’s no trouble. He works well.”

“Is David malfunctioning?”

“His verbal communication-center is still giving trouble. I think he’ll have to go back to the factory again.”

“Okay. We’ll see how he does before the baby’s born. Which reminds me – I have a surprise for you: help just when help is needed! Come into the hall and see what I’ve got.”

As the two adults disappeared from the room, boy and bear sat down beneath the standard roses.

“Teddy – I suppose Mummy and Daddy are real, aren’t they?”

Teddy said, “You ask such silly questions, David. Nobody knows what ‘real’ really means. Let’s go indoors.”

“First I’m going to have another rose!” Plucking a bright pink flower, he carried it with him into the house. It could lie on the pillow as he went to sleep. Its beauty and softness reminded him of Mummy.

1993-2004 The Condé Nast Publications Inc. All rights reserved.

Creative Coding Exercise

Posted on October 21, 2025October 21, 2025 by admin

Stage 1: draw a ball and assign behaviors to it — in this case, bounce around the edges
https://editor.p5js.org/megagpxp/sketches/hwRM3G0aQ

let posx;
let posy;
let xSpeed;
let ySpeed;

function setup() {
  createCanvas(400, 400);
  posx = width/2;
  posy = height/2;
  xSpeed = random(-5, 5);
  ySpeed = random(-5, 5);
}

function draw() {
  background(220);
  posx += xSpeed;
  if (posx > width || posx < 0) {
    xSpeed *= -1;
  }
  posy += ySpeed;
  if (posy > height || posy < 0) {
    ySpeed *= -1;
  }
  ellipse(posx, posy, 10);
}

Stage 2: make the ball into a class
https://editor.p5js.org/megagpxp/sketches/FAVtr2ZsG

let oneBall;

function setup() {
  createCanvas(400, 400);
  oneBall = new ball(random(0, width), random(0, height), random(-3, 3), random(-3, 3));
}

function draw() {
  background(220);
  oneBall.update();
  oneBall.display();
}

class ball {
  constructor(px, py, sx, sy) {
    this.px = px;
    this.py = py;
    this.sx = sx;
    this.sy = sy;
  }

  update() {
    this.px += this.sx;
    if (this.px > width || this.px < 0) {
      this.sx *= -1;
    }
    this.py += this.sy;
    if (this.py > height || this.py < 0) {
      this.sy *= -1;
    }
  }

  display() {
    ellipse(this.px, this.py, 50);
  }
}

Stage 3: bounce 100 balls
https://editor.p5js.org/megagpxp/sketches/v3DmiOK-B

let manyBalls = [];
function setup() {
  createCanvas(400, 400);
  for (let i = 0; i < 100; i ++) {
    manyBalls[i] = new ball(
      random(0, width),
      random(0, height),
      random(-3, 3),
      random(-3, 3)
    );
  }
}

function draw() {
  background(220);
  for (let i = 0; i < 100; i ++) {
  manyBalls[i].update();
  manyBalls[i].display();
  }
}

class ball {
  constructor(px, py, sx, sy) {
    this.px = px;
    this.py = py;
    this.sx = sx;
    this.sy = sy;
  }

  update() {
    this.px += this.sx;
    if (this.px > width || this.px < 0) {
      this.sx *= -1;
    }
    this.py += this.sy;
    if (this.py > height || this.py < 0) {
      this.sy *= -1;
    }
  }

  display() {
    ellipse(this.px, this.py, 50);
  }
}

Stage 4: define the relationship between bouncing balls
https://editor.p5js.org/megagpxp/sketches/YYVsvsTkf

let manyBalls = [];
function setup() {
  createCanvas(400, 400);
  for (let i = 0; i < 100; i++) {
    manyBalls[i] = new ball(
      random(0, width),
      random(0, height),
      random(-3, 3),
      random(-3, 3)
    );
  }
}

function draw() {
  background(220);
  for (let i = 0; i < 100; i++) {
    manyBalls[i].update();
    //manyBalls[i].display();
    for (let n = 0; n < 100; n++) {
      let d = dist(manyBalls[i].px, manyBalls[i].py, manyBalls[n].px, manyBalls[n].py);
      if (d < 60) {
        let w = ((60-d)/60)*3;
        strokeWeight(w);
        line(manyBalls[i].px, manyBalls[i].py, manyBalls[n].px, manyBalls[n].py);
      }
    }
  }
}

class ball {
  constructor(px, py, sx, sy) {
    this.px = px;
    this.py = py;
    this.sx = sx;
    this.sy = sy;
  }

  update() {
    this.px += this.sx;
    if (this.px > width || this.px < 0) {
      this.sx *= -1;
    }
    this.py += this.sy;
    if (this.py > height || this.py < 0) {
      this.sy *= -1;
    }
  }

  display() {
    ellipse(this.px, this.py, 50);
  }
}

Casey Reas’s Process

Gen.AI Exploration

Posted on October 20, 2025 by admin

Trellis AI: https://trellis3d.co/
Anything World: https://app.anything.world/
ElevenLabs: https://elevenlabs.io/
Typecast: https://typecast.ai/
Suno: https://suno.com/
Soundraw: https://soundraw.io/

Passthrough relighting (Mixed Reality)

Posted on October 20, 2025 by admin

Passthrough relighting (for mixed reality) 

  • MRUK: Use the Mixed Reality Utility Kit (MRUK) to achieve passthrough relighting.
  • Import the sample package: Import the necessary passthrough relighting sample package into your project to access the required components.
  • Replace OVR: The MRUK component replaces the OVR scene manager and includes an effect mesh component that applies a material to your room models, handling highlights and shadows correctly. 

This video explains how to use passthrough relighting in Quest 3 with Unity:

Mixed reality (MR) passthrough lighting

Quest 3 passthrough applications must solve the complex problem of blending virtual and real-world lighting. This requires using the Meta SDK to create virtual lights and shadows that interact with your actual physical environment. 

1. Enable passthrough relighting

  • Add the OVR components: Begin by setting up passthrough in your scene with the OVR Manager and OVR Passthrough Layer components. You will need to set the Passthrough Support to Supported.
  • Import the Meta XR Interaction SDK: Passthrough relighting capabilities are part of the Meta XR Interaction SDK (MRUK package). Import this into your Unity project to gain access to the necessary components and prefabs.
  • Add the MRUK prefab: Add the MRUK prefab to your scene hierarchy. The MRUK handles the generation of the real-world meshes that your virtual lights and shadows can interact with. 

2. Configure shadows and occlusion

  • Enable occlusion meshes: The Meta SDK generates a virtual mesh of your room. This “scene mesh” is required for shadows and occlusion to work correctly.
  • Cast shadows on the real world: With the scene mesh in place, you can configure your virtual lights to cast shadows onto the real-world environment. This adds depth and realism to your mixed-reality experience.
    • Virtual lights will cast shadows onto the generated scene mesh, and objects marked as casting shadows will appear to block real-world light. 

3. Estimate real-world lighting for reflections

To make virtual objects reflect real-world light, you can leverage the headset’s cameras to generate a real-time reflection probe. 

  • Create a real-time reflection probe: Add a reflection probe to your scene.
  • Map to a cubemap: Map the passthrough camera feed to a cubemap and project this onto the reflection probe. This allows the probe to capture the surrounding real-world lighting environment.
  • Improve PBR material plausibility: When used on physically based rendering (PBR) materials, this technique allows virtual objects to realistically reflect the real-world environment, dramatically improving visual plausibility. 

Realtime Lighting Estimation on Quest 3
This video demonstrates the unlocked potential of Meta Quest 3 Camera Access via the Media Projection API. When mapped to a cubemap and projected onto a real-time reflection probe in Unity, you can finally use the environment to light your PBR materials. This dramatically improves the plausibility of the 3D Model in the environment – especially of course when you are in Mixed Reality. The video shows how this approach allows to adopt to different lighting conditions in “Real Time”.

VR Lighting

Posted on October 20, 2025October 20, 2025 by admin

For Meta Quest 3 and Unity, use mixed lighting with a combination of baked lighting for static objects and real-time lighting for dynamic objects to balance performance and visual quality. Key optimization techniques include using the Lightmap parameter for baked lighting, leveraging light probes for dynamic objects, and for passthrough AR, using the passthrough relighting features for realistic blending with the real world.

This video explains the basics of lighting in Unity, including real-time, baked, and mixed lighting:

Lighting types and performance

  • Baked Lighting: Pre-calculates how light bounces off static objects and stores this information in lightmaps. This is highly performant, but dynamic objects can appear flat or lack proper shadows.
  • Real-time Lighting: Calculates lighting and shadows dynamically as the scene changes. This is very expensive and generally not suitable for Quest 3 due to performance limitations.
  • Mixed Lighting: A combination of both baked and real-time lighting. Static objects use baked lighting, while dynamic objects use real-time lighting and cast their own shadows. This is the recommended approach for Quest 3. 

Key considerations for Quest 3 lighting link1, link2

  • Use the Universal Render Pipeline (URP): All modern VR projects for Quest should be built using URP. It is optimized for mobile hardware and offers the best performance for Quest devices.
  • Manage shadow quality: Real-time shadows can be very costly. If you use them, configure the URP settings to balance shadow quality with performance.
  • Profile your project: Use the Unity Profiler and Oculus Debug Tool to monitor your application’s performance. Watch for performance drops related to lighting, as real-time lighting can quickly overwhelm the Quest’s mobile processor.

Optimization and setup

You can watch this video to learn how to optimize lighting in Unity for VR on Quest:

  1. Set up lighting:
    • Go to Window > Rendering > Lighting to open the Lighting window.
    • For best performance, enable “Baked Global Illumination” under the “Mixed” lighting setting. Leave the lightmapper settings at their defaults for now. For a powerful GPU, you can try “GPU Processing”.
  2. Bake static lighting:
    • Ensure your static objects are marked as “Static” in the inspector.
    • Press the “Generate Lighting” button to bake the lightmaps for your scene.
  3. Illuminate dynamic objects:
    • Place Light Probes strategically around your scene to capture baked lighting information. This will allow dynamic objects (like the player’s hands) to receive a more realistic lighting response without needing expensive real-time calculations for static elements.
  4. AR and passthrough relighting:
    • For AR projects, use Passthrough Relighting to make virtual objects blend more realistically with the real world. This feature allows virtual lights and shadows to interact with real-world surfaces like floors and walls. 

Optimizations for Quest 3

  • Pixel Light Count: In your project’s Quality settings (for URP), ensure the Additional Lights setting is set to “Per Pixel” and increase the Per Object Limit to allow more light sources to affect objects.
  • Light Probes: Use light probes to add lighting to dynamic objects, which is crucial for a more immersive experience. Place probes strategically in areas with significant lighting changes, ensuring they don’t intersect with other objects to avoid issues.
  • Baked vs. Realtime: For scenes with many static objects, bake the lighting to reduce performance costs. If you need dynamic shadows, use the mixed lighting mode, which allows dynamic objects to cast shadows while static objects use baked shadows.
  • Lighting Settings: Access and adjust lighting settings by navigating to Window > Rendering > Lighting in the Unity editor. You can adjust scene lighting and optimize your precomputed lighting data here. 

This video explains how to use light probes to optimize lighting in VR:

Optimizing Universal Render Pipeline (URP) shadow settings for the Quest 3 requires balancing visual fidelity with performance. The goal is to achieve realistic-looking shadows that don’t cause frame rate drops, which are particularly jarring and disorienting in VR. 

Most shadow settings are found in your URP Asset, which you can locate in your project’s Assets > Settings folder. The settings should be configured differently for your directional “main light” versus additional lights like spots and points. 

Shadow performance fundamentals

Before adjusting settings, remember these key concepts:

  • Shadowmaps are expensive: Rendering shadows requires generating separate texture maps (shadowmaps) from the perspective of each light source. A point light, for instance, requires six shadowmaps for its cube mapping, making it extremely costly.
  • Draw calls are critical: The number of objects casting shadows can be a major performance bottleneck. Minimizing draw calls is a top priority for mobile VR development.
  • Bake what you can: Whenever possible, use baked shadows for static objects. This eliminates the runtime performance cost entirely and generally produces higher-quality, more stable results. 

URP Asset shadow settings

Access your URP Asset and navigate to the Shadows section to adjust these settings: 

Main light shadows

The settings for your directional light are crucial, as it typically illuminates the largest area.

  • Max Distance: This is the most important setting for a directional light’s shadows.
    • Action: Set the value as low as artistically acceptable. The shadowmap is stretched across this distance, so a shorter distance results in a denser, higher-quality shadow near the player.
    • Reason: By limiting the range of rendered shadows, you reduce the area that must be calculated, freeing up significant GPU resources. You can use fog to hide where the shadows are culled.
  • Shadow Resolution: Choose the smallest resolution that still provides an acceptable visual result.
    • Action: Start with a low resolution, like 512, and increase it only if the shadows are too blurry.
    • Reason: High shadowmap resolutions have a direct impact on performance.
  • Cascade Count: For VR, you should only use a single cascade.
    • Action: Set the cascade count to 1.
    • Reason: Shadow cascades, which divide the shadow frustum into multiple maps, are a performance drain and often unnecessary for VR given the close-up, immediate nature of the experience.
  • Soft Shadows: Soft shadows generally look better, but they are more expensive to render.
    • Action: Leave soft shadows disabled. If you must have them for aesthetic reasons, set them to the lowest quality and profile for performance impact. 

Additional lights (point and spot)

  • Shadow Atlas Resolution: Control the maximum size of the texture atlas for all additional light shadows.
    • Action: Set this to a low value, such as 512 or 1024, to limit video memory usage.
  • Shadow Resolution Tiers: Reduce the resolution for lights farther away from the camera.
    • Action: Set tiers to low or medium. This ensures that only the most important, nearby additional lights get higher-resolution shadows. 

Optimizing shadow casters

In addition to the global URP settings, you can optimize shadows on a per-object basis. 

  • Reduce shadow-casting objects: Avoid having every object cast a shadow.
    • Action: For static objects, mark them as static and bake their shadows. For dynamic objects, go to the Mesh Renderer component and set Cast Shadows to Off for non-essential items.
  • Use simplified shadow meshes: For complex dynamic characters, you can create a simplified, invisible mesh to cast the shadow.
    • Action: Create a low-polygon version of the mesh. On the original mesh’s Mesh Renderer, set Cast Shadows to Off. On the simplified mesh, set Cast Shadows to Shadows Only.
  • Disable shadows for small objects: For small items like pebbles or debris, disable their shadow casting.
    • Action: Use a script or manually set the Cast Shadows property to Off on their Mesh Renderer components.
  • Disable shadows based on distance: For dynamic lights, use a script to disable shadows when the light source is far from the camera. 

Shadow artifacts and profiling

  • Shadow Acne and Peter Panning: These are common shadow artifacts. You can adjust the Depth Bias and Normal Bias settings in your URP Asset or on individual lights to fix them. Start with small changes and observe the results.
  • Profile your application: When unsure about the performance impact of a setting, use the Unity Profiler and the Oculus Debug Tool to measure frame rates and draw calls directly on the Quest 3. This is the most reliable way to confirm if a change is an improvement or a detriment. 

Other ways to optimize shadows in Unity for VR

Beyond scripts and URP settings, several other techniques can dramatically optimize shadows for VR, especially on mobile VR devices like the Quest 3. These methods often trade a small amount of visual quality for a significant gain in performance. 

1. The Shadowmask lighting mode

This is a hybrid approach that provides high-quality static shadows while also allowing for real-time shadows from dynamic objects.

  • How it works: Static geometry has its shadows pre-calculated and stored in a lightmap (the “shadow mask”), which is very cheap to render. Dynamic objects then cast real-time shadows on top of the static baked lightmap.
  • Best for: Scenes with a mix of static and moving objects, where you want high-quality shadows from your environment without the runtime cost.
  • Implementation:
    1. Go to Project Settings > Quality and set the Shadowmask Mode to Shadowmask.
    2. For static objects, ensure the Mesh Renderer has Contribute Global Illumination enabled and Cast Shadows set to On.
    3. Generate your lighting in the Lighting Window (Window > Rendering > Lighting). 

2. Simplified shadow meshes

For complex or high-poly models, rendering the full mesh into the shadow map is computationally expensive. Using a low-poly proxy mesh for shadow casting can save significant GPU time.

  • How it works: You create a simplified, low-poly version of a complex model (e.g., a character) that is only visible to the light source. The original model is configured to not cast shadows, and the simplified model casts “Shadows Only.”.
  • Best for: Characters, complex props, or vehicles that are constantly moving and must cast real-time shadows.
  • Implementation:
    1. Duplicate your high-poly mesh.
    2. Use a 3D modeling tool to simplify the new mesh, or create one manually.
    3. On the original mesh’s Mesh Renderer, set Cast Shadows to Off.
    4. On the new, simplified mesh, set Cast Shadows to Shadows Only. 

3. Blob shadows

For less realistic art styles, blob shadows are a classic performance optimization trick. Instead of rendering a complex shadow map, you project a simple, circular, or custom-textured decal onto the ground below a character.

  • How it works: A simple plane with a transparent texture is placed under a dynamic object. It follows the object’s movement but has no real-time lighting calculation, making it extremely fast.
  • Best for: Cartoonish or stylized games where realism is not the main goal. It’s a very cheap way to provide a sense of depth and contact with the ground.
  • Implementation:
    1. Create a transparent texture of a faded circle or blob.
    2. Create a simple quad or plane and assign a transparent, unlit material with the blob texture to it.
    3. Parent this quad to your character and ensure it always stays just above the ground.
    4. Adjust the color and transparency of the quad to create the shadow effect. 

4. Occlusion culling

While not a shadow-specific technique, occlusion culling can indirectly boost shadow performance by reducing the number of objects rendered.

  • How it works: Occlusion culling prevents rendering objects that are blocked from the camera’s view by other objects. Since objects that are not rendered cannot cast shadows, this automatically reduces the workload for the shadow pass.
  • Best for: Large, indoor environments with many rooms, corridors, or structures that can occlude geometry from view.
  • Implementation:
    1. Mark your static environment geometry as Occluder Static in the Inspector.
    2. In the Window > Rendering > Occlusion Culling window, bake the occlusion data.
    3. Ensure your VR camera is set up to use occlusion culling. 

5. Level of Detail (LOD) for shadows

For objects with LOD groups, you can configure their lower-detail levels to not cast shadows or to use a simplified shadow.

  • How it works: As an object gets farther away and switches to a lower LOD, you can set the Mesh Renderer on that LOD level to disable shadow casting. This saves rendering time for shadows that would be imperceptible at a distance.
  • Best for: Large, complex models like buildings, trees, or characters that are part of a LOD group.
  • Implementation:
    1. Select the GameObject with the LOD Group component.
    2. For each LOD level, click the small box next to the mesh renderer.
    3. In the Mesh Renderer component for the farther LOD levels, set the Cast Shadows property to Off. 

Examples of scripts that disable shadows based on distance

For VR development, you should generally rely on the URP Shadow Distance setting to manage shadow visibility based on distance for all objects. For more specific needs, like disabling shadows for a single moving object that is far away, you can use scripts.

1. Script for a single dynamic object

This script is attached to a specific GameObject to manage its shadow-casting behavior. The script compares the object’s distance from the main camera to a predefined threshold.

using UnityEngine;

[RequireComponent(typeof(MeshRenderer))]
public class DistanceBasedShadows : MonoBehaviour
{
    // The main camera in the scene. In VR, this is the camera that renders the player's view.
    private Transform mainCameraTransform;

    // The MeshRenderer component of this object.
    private MeshRenderer meshRenderer;

    // The maximum distance at which the object should cast shadows.
    public float maxShadowDistance = 20f;

    // A small buffer distance to prevent constant flickering at the threshold.
    public float distanceHysteresis = 2f;

    // The initial shadow casting mode.
    private UnityEngine.Rendering.ShadowCastingMode initialShadowCastingMode;

    void Start()
    {
        // Find the main camera.
        mainCameraTransform = Camera.main.transform;

        // Get the MeshRenderer component.
        meshRenderer = GetComponent<MeshRenderer>();

        // Store the initial shadow casting mode to restore later.
        initialShadowCastingMode = meshRenderer.shadowCastingMode;
    }

    void Update()
    {
        // If the main camera is not set, exit to prevent errors.
        if (mainCameraTransform == null)
        {
            return;
        }

        // Calculate the distance from the camera to this object.
        float distance = Vector3.Distance(transform.position, mainCameraTransform.position);

        // Toggle shadows based on the distance.
        if (distance > maxShadowDistance)
        {
            // Disable shadows if they are not already off.
            if (meshRenderer.shadowCastingMode != UnityEngine.Rendering.ShadowCastingMode.Off)
            {
                meshRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
            }
        }
        else if (distance < maxShadowDistance - distanceHysteresis)
        {
            // Re-enable shadows if they are not already on and the object is close enough.
            if (meshRenderer.shadowCastingMode != initialShadowCastingMode)
            {
                meshRenderer.shadowCastingMode = initialShadowCastingMode;
            }
        }
    }
}

2. Script for managing multiple objects

For a cleaner approach, you can create a single “manager” script that controls multiple shadow-casting objects. This avoids the overhead of having an Update loop running on many individual game objects.

using System.Collections.Generic;
using UnityEngine;

public class ShadowDistanceManager : MonoBehaviour
{
    // A list of all the MeshRenderers that this script will manage.
    public List<MeshRenderer> managedRenderers;

    // The main camera in the scene.
    private Transform mainCameraTransform;

    // The maximum distance for shadows.
    public float maxShadowDistance = 20f;

    // A small buffer to prevent flickering at the threshold.
    public float distanceHysteresis = 2f;

    // Storage for the initial shadow casting mode of each renderer.
    private Dictionary<MeshRenderer, UnityEngine.Rendering.ShadowCastingMode> initialModes = new Dictionary<MeshRenderer, UnityEngine.Rendering.ShadowCastingMode>();

    void Start()
    {
        mainCameraTransform = Camera.main.transform;

        // Store the initial state of each renderer.
        foreach (var renderer in managedRenderers)
        {
            if (renderer != null)
            {
                initialModes[renderer] = renderer.shadowCastingMode;
            }
        }
    }

    void Update()
    {
        if (mainCameraTransform == null)
        {
            return;
        }

        // Iterate through all managed renderers.
        foreach (var renderer in managedRenderers)
        {
            if (renderer == null) continue;

            float distance = Vector3.Distance(renderer.transform.position, mainCameraTransform.position);

            // Toggle shadows based on distance.
            if (distance > maxShadowDistance)
            {
                if (renderer.shadowCastingMode != UnityEngine.Rendering.ShadowCastingMode.Off)
                {
                    renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
                }
            }
            else if (distance < maxShadowDistance - distanceHysteresis)
            {
                if (renderer.shadowCastingMode != initialModes[renderer])
                {
                    renderer.shadowCastingMode = initialModes[renderer];
                }
            }
        }
    }
}

3. Script for a single point or spot light

This script manages the shadows of a specific light source, such as a torch or lamp, disabling them when the light is far from the player.

using UnityEngine;

[RequireComponent(typeof(Light))]
public class LightShadowToggler : MonoBehaviour
{
    private Transform mainCameraTransform;
    private Light lightComponent;

    public float maxShadowDistance = 15f;
    public float distanceHysteresis = 1f;

    private LightShadows initialShadowsSetting;

    void Start()
    {
        mainCameraTransform = Camera.main.transform;
        lightComponent = GetComponent<Light>();
        initialShadowsSetting = lightComponent.shadows;
    }

    void Update()
    {
        if (mainCameraTransform == null)
        {
            return;
        }

        float distance = Vector3.Distance(transform.position, mainCameraTransform.position);

        if (distance > maxShadowDistance)
        {
            if (lightComponent.shadows != LightShadows.None)
            {
                lightComponent.shadows = LightShadows.None;
            }
        }
        else if (distance < maxShadowDistance - distanceHysteresis)
        {
            if (lightComponent.shadows != initialShadowsSetting)
            {
                lightComponent.shadows = initialShadowsSetting;
            }
        }
    }
}

ウォーゲームエレクトロニクス

Posted on September 23, 2025 by admin

Posts navigation

Older posts

Recent Posts

  • BMP – Rearrange Colormap
  • Reset Allow USB Debugging? Notification
  • 8-bit Notes
  • AT29C256 90PI
  • Super-Toys Last All Summer Long

Archives

Proudly powered by WordPress | Theme: MiniZen by Martin Stehle.