はじめに
こんにちは!システム開発部のYです。
visionOS 1.xでは、Entityに対してデフォルトのハイライトによるホバーエフェクトのみが利用可能でした。しかし、visionOS 2.0からは、HoverEffectComponentを自由にカスタマイズできるようになりました。本記事では、そのカスタマイズ方法について解説します。
EntityではなくUIのホバー効果のカスタマイズ方法については、別の記事で解説しています。
気になる方は、以下の記事をご覧ください。
【visionOS】HoverEffectをカスタマイズしてみる
環境
- Swift Version: 5.10
- Xcode: 16.1
- visionOS: 2.1
- Reality Composer Pro: 2.0
- macOS: 14.5
実装について
以下の手順で進めていきます。
前準備
シーンの変更
New Projectから作成し、Reality Composerでシーンを編集します。
サンプルモデルを1つ配置したシーンを作成しました。

ImmersiveView.swiftの変更
ImmersiveView.swiftのコードを修正します。
サンプルモデルであるEntity(ToyCar)を取得し、視線検知を行うために、取得したToyCarにInputTargetComponentとCollisionComponentを設定します。
import SwiftUI
import RealityKit
import RealityKitContent
struct ImmersiveView: View {
var body: some View {
RealityView { content in
// Add the initial RealityKit content
if let immersiveContentEntity = try? await Entity(named: "Immersive", in: realityKitContentBundle) {
content.add(immersiveContentEntity)
if let toyCar = immersiveContentEntity.findEntity(named: "ToyCar") {
// InputTargetComponent, CollisionComponent
toyCar.components.set(InputTargetComponent())
toyCar.components.set(CollisionComponent(shapes: [.generateBox(size: [0.1, 0.15, 0.3])]))
}
}
}
}
}デフォルトのHoverEffectComponent
デフォルトのHoverEffectComponentはvisionOS 1.xから利用可能で、白いハイライトが表示されます。
import SwiftUI
import RealityKit
import RealityKitContent
struct ImmersiveView: View {
var body: some View {
RealityView { content in
// Add the initial RealityKit content
if let immersiveContentEntity = try? await Entity(named: "Immersive", in: realityKitContentBundle) {
content.add(immersiveContentEntity)
if let toyCar = immersiveContentEntity.findEntity(named: "ToyCar") {
// InputTargetComponent, CollisionComponent
toyCar.components.set(InputTargetComponent())
toyCar.components.set(CollisionComponent(shapes: [.generateBox(size: [0.1, 0.15, 0.3])]))
// HoverEffectComponent
toyCar.components.set(HoverEffectComponent())
}
}
}
}
}SpotlightHoverEffectStyle
フォーカス時にSpotlightの効果を適用したい場合は、SpotlightHoverEffectStyleを使用します。
フォーカス位置に応じてライトの当たり方が変化する様子が確認できます。
SpotlightHoverEffectStyleのinitでは、効果の色や強度をカスタマイズすることができます。
import SwiftUI
import RealityKit
import RealityKitContent
struct ImmersiveView: View {
var body: some View {
RealityView { content in
// Add the initial RealityKit content
if let immersiveContentEntity = try? await Entity(named: "Immersive", in: realityKitContentBundle) {
content.add(immersiveContentEntity)
if let toyCar = immersiveContentEntity.findEntity(named: "ToyCar") {
// InputTargetComponent, CollisionComponent
toyCar.components.set(InputTargetComponent())
toyCar.components.set(CollisionComponent(shapes: [.generateBox(size: [0.1, 0.15, 0.3])]))
// HoverEffectComponent.SpotlightHoverEffectStyle
let spotlightHoverEffectStyle = HoverEffectComponent.SpotlightHoverEffectStyle(color: .lightYellow, strength: 2.0)
let hoverEffect = HoverEffectComponent(.spotlight(spotlightHoverEffectStyle))
toyCar.components.set(hoverEffect)
}
}
}
}
}
extension UIColor {
static let lightYellow = UIColor(red: 1.0, green: 1.0, blue: 0.0, alpha: 1.0)
}HighlightHoverEffectStyle
フォーカス時にHighlight効果を適用したい場合は、HighlightHoverEffectStyleを使用します。
このスタイルでは、対象が均一に強調表示されます。
HighlightHoverEffectStyleのでは、効果の色や強度をカスタマイズすることが可能です。init
import SwiftUI
import RealityKit
import RealityKitContent
struct ImmersiveView: View {
var body: some View {
RealityView { content in
// Add the initial RealityKit content
if let immersiveContentEntity = try? await Entity(named: "Immersive", in: realityKitContentBundle) {
content.add(immersiveContentEntity)
if let toyCar = immersiveContentEntity.findEntity(named: "ToyCar") {
// InputTargetComponent, CollisionComponent
toyCar.components.set(InputTargetComponent())
toyCar.components.set(CollisionComponent(shapes: [.generateBox(size: [0.1, 0.15, 0.3])]))
// HoverEffectComponent.HighlightHoverEffectStyle
let highlightHoverEffectStyle = HoverEffectComponent.HighlightHoverEffectStyle(color: .lightYellow, strength: 2.0)
let hoverEffect = HoverEffectComponent(.highlight(highlightHoverEffectStyle))
toyCar.components.set(hoverEffect)
}
}
}
}
}
extension UIColor {
static let lightYellow = UIColor(red: 1.0, green: 1.0, blue: 0.0, alpha: 1.0)
}Opacity Function
SpotlightHoverEffectStyleとHighlightHoverEffectStyleには、Opacity Functionという引数があります。これにより、透明素材に対するホバー効果の見え方をカスタマイズできます。
詳細は公式ドキュメントをご参照ください。
https://developer.apple.com/documentation/realitykit/hovereffectcomponent#Opacity-functions
OpacityFunction.full
エンティティのベースマテリアルの不透明度に関係なく、ホバーエフェクトが常に完全な不透明度で描画されます。
OpacityFunction.mask
エンティティのベースマテリアルの不透明度が 0.05以上 の場合、ホバーエフェクトは完全な不透明度で描画されます。
ベースマテリアルの不透明度が 0.05以下 の場合、ホバーエフェクトはベースマテリアルの不透明度に応じてフェードアウトします。
OpacityFunction.blend
ホバーエフェクトの不透明度は、エンティティのベースマテリアルの不透明度とシェーダーの出力値を掛け合わせた結果になります。
ベースマテリアルとシェーダーの出力が両方とも影響を与えます。
ShaderHoverEffectInputs
フォーカス時にShader Graphを利用した演出を適用したい場合、ShaderHoverEffectInputsを使用します。
フォーカス時に黄色に変更し、フォーカスが外れると黒色に戻る動作を実現しています。
Reality Composer Proでホバー用のShader Graph Materialの作成、マテリアルの設定、コードの変更を行う必要があります。
Reality Composer ProでShader Graph Materialを作成
HoverStateNodeが追加されています。
Intensity値は、ユーザーがフォーカスした際に0から1へと変化します。

Intensity値に応じて、フォーカス時にはForegroundColorを黄色に、フォーカスが外れた際にはBackgroundColorを黒に設定するようにしています。

Materialの設定
作成したShader Graph Materialを、ToyCarのマテリアルとして設定します。

ImmersiveView.swift
HighlightHoverEffectStyle の init では、fadeInDuration と fadeOutDuration をカスタマイズできます。
また、defaultの設定では、フェードインとフェードアウトの継続時間が、デフォルトのスポットライトの継続時間に合わせて設定されます。
import SwiftUI
import RealityKit
import RealityKitContent
struct ImmersiveView: View {
var body: some View {
RealityView { content in
// Add the initial RealityKit content
if let immersiveContentEntity = try? await Entity(named: "Immersive", in: realityKitContentBundle) {
content.add(immersiveContentEntity)
if let toyCar = immersiveContentEntity.findEntity(named: "ToyCar") {
// InputTargetComponent, CollisionComponent
toyCar.components.set(InputTargetComponent())
toyCar.components.set(CollisionComponent(shapes: [.generateBox(size: [0.1, 0.15, 0.3])]))
// HoverEffectComponent.ShaderHoverEffectInputs
let shaderHoverEffectInputs = HoverEffectComponent.ShaderHoverEffectInputs(fadeInDuration: 1.0, fadeOutDuration: 1.0)
let hoverEffect = HoverEffectComponent(.shader(shaderHoverEffectInputs))
toyCar.components.set(hoverEffect)
}
}
}
}
}
Hierarchical-behavior
HoverEffectComponentはエンティティ階層全体にエフェクトを適用します。
最上位のエンティティに設定されたエフェクトは、すべての子エンティティにも引き継がれ、同じエフェクトが表示されます。
詳細は公式ドキュメントをご参照ください。
https://developer.apple.com/documentation/realitykit/hovereffectcomponent#Hierarchical-behavior
まとめ
HoverEffectComponentを使用したEntityのホバーエフェクトのカスタマイズ方法をまとめました。
visionOS 2.0からHoverEffectComponentのカスタマイズできるため、フォーカス時の演出を変更することができました。
また、ShaderHoverEffectInputsを使用することで、Shader Graphでの演出作成が可能となったことで多様な表現ができるようになりそうです。
この記事がお役に立てば幸いです。本記事について誤りや改善点があれば、是非ご指摘ください。
参考
- https://developer.apple.com/jp/videos/play/wwdc2024/10103/
- https://developer.apple.com/documentation/realitykit/hovereffectcomponent








