Trying to make a 360 sphere child of a multiplayer instance

I´ve got a network scene, with the following GameObjects :

  1. Networking GameObject holding SyncedRoom and Networking components.
  2. PlayerSpawner GameObject holding PlayerSync component whose Asset field has a reference to my prefab Player.

The Player GameObject prefab holds PlayerState, SyncedTransform, Camera and OrbirtControls components.
The Player GameObject prefab has a Sphere as a child which has its normals flipped. Also, this Sphere holds a VideoPlayer component whose VideoClip field has a reference to a 360 video. Both Player GameObject and Sphere have their Transform.position set in (0,0,0)

What Do I want to achieve?
That each Player instances generated by PlayerSync see the interior of the sphere as it was a 360 skybox. That way, I can enable and disable the Sphere for each player.

What´s wrong?
That when an Player instance is generated by PlayerSync, whe I orbit the scene, the sphere also moves with the camera so is like a dizzy effect.

How Can I achieve that for each player, she/he see the interior of the sphere like a 360 skybox and can orbit the scene without moving the sphere?

Original Post on Discord

by user 632418299711324161

Hello there – we have an experimental AI bot :robot: that might be able to help you with your question. Would you like to try this out?

How it works:
Reply to the messages of the bot that end with a thread_id to interact with it and ask follow-up questions. You can also mention the bot directly in this channel to get help.

Help requested: please wait a moment…

Here is what I found for you :brain: Discord

It sounds like you wish to make the sphere behave like a skybox that doesn’t move with the player camera, while still allowing each player instance to enable or disable their own view of the sphere. The sphere should stay in place as the camera orbits around, giving the effect of being inside a static 360° environment.

Here’s an outline of steps in pseudocode on how to achieve that:

  1. Create a Sphere component that doesn’t move with the camera.
  2. Have the Sphere component be instantiated with each player but ensure it’s not a child of the Camera GameObject.
  3. Set up the Sphere component so that it is always positioned around the user’s camera but doesn’t react to camera rotation or orbit controls.
  4. Provide a method within the PlayerState script to toggle the visibility of the sphere, so each player can enable or disable their own sphere independently.

Now, let’s write the code in TypeScript:

*thread_l3uXTfaM2JrKrrFAodYuB3Tv*

typescript
import { Behaviour, SyncedTransform, Object3D, Camera, SyncedRoom, Networking, VideoPlayer, Sphere, Behaviour } from “@needle-tools/engine”;
import { Vector3, Object3D } from “three”;

// Extend the Behaviour class for the Sphere component
export class FixedSkyboxSphere extends Behaviour {
// Store a reference to the VideoPlayer component in the sphere
@serializable(Object3D)
private videoPlayerSphere: Object3D;

private cameraPositionCache: Vector3 = new Vector3();

awake() {
// Find and cache the main camera component once during the awake phase
const cameraComponent = this.context.mainCameraComponent;
this.cameraPositionCache.copy(cameraComponent.transform.position);
}

update() {
// On update, set the skybox sphere’s position to be centered around the camera
// We update only the position to follow the camera but ignore rotation
this.videoPlayerSphere.position.copy(this.cameraPositionCache);
}
}

// PlayerState component to attach to the Player GameObject
export class PlayerState extends Behaviour {
@serializable(Object3D)
private skyboxSphere: Object3D;

// Method to toggle the skybox sphere visibility
toggleSkyboxVisibility() {
if (this.skyboxSphere) {
this.skyboxSphere.visible = !this.skyboxSphere.visible;
}
}
}

*thread_l3uXTfaM2JrKrrFAodYuB3Tv*

Attach the FixedSkyboxSphere component to the sphere that holds the VideoPlayer. Then, in your PlayerState component, you can call toggleSkyboxVisibility to show or hide the sphere. Ensure the sphere is not a child of the camera or the player-controlled object to prevent it from moving or rotating with the player’s view.

1 messages left GPT 4
thread_l3uXTfaM2JrKrrFAodYuB3Tv
Thanks for your feedback!

The bot’s outline of what to do is pretty accurate I’d say, I second that

Yep, it helped me.

by user 632418299711324161

If I´m in VR and I have a 360 sphere, how can the 360 sphere follow the player in VR when the player in VR moves ?

by user 632418299711324161

To make the 360° sphere follow the player in VR without rotating when the player moves, you can achieve that using the following steps:

  1. Attach the 360° sphere as a child of the VR headset or VR controller to keep it centered.
  2. Track the position of the VR headset or controller and update the position of the 360° sphere to match it without altering its rotation.

Here’s a basic pseudocode to outline the implementation:

// In the VR player script
update() {
    // Get the VR headset or controller position
    const headsetPosition = getVRHeadsetPosition(); // Function to get VR headset position
    // Match the 360° sphere position to the VR headset or controller
    sphereGameObject.position.copy(headsetPosition);
}

This will ensure that the 360° sphere stays centered relative to the VR headset or controller, allowing the player to move around while the environment appears stationary.

0 messages left GPT 3.5
thread_l3uXTfaM2JrKrrFAodYuB3Tv
Thanks for your feedback!

How can I get the VR Headset Position ?

by user 632418299711324161

You have reached your limit of 2 messages… please try again in a few hours

In VR the head position is also just the camera position (so using this.context.mainCamera should work, just get the worldPosition, e.g. via this.context.mainCameraComponent.gameObject.worldPosition)

Thanks marcel : )

by user 632418299711324161

I´m running this script while I´m in VR but the position doesn´t change :

export class ShowVRInfo extends Behaviour{

    private infoText !: Text;
    //private webXR !: WebXR;

    start(): void {
        
        this.infoText = GameObject.findObjectOfType(Text)!; 
        console.log(this.infoText);
        // this.webXR = GameObject.findObjectOfType(WebXR)!;
        // console.log(this.webXR);
    
    }

    update(): void {
        const headPos = this.getVRHeadPosition();
        console.log(headPos );  
        const str =  `${headPos.x}`.concat(", ").concat(`${headPos.y}`).concat(", ").concat(`${headPos.z}`);  

        console.log(str);
        this.infoText.text = str;  
        // if(this.context.isInVR){
        // }
    }

    getVRHeadPosition():Vector3{
        if (this.context.isInVR) {
            return this.context.mainCameraComponent!.gameObject.worldPosition;
        }
        return this.context.mainCameraComponent!.gameObject.worldPosition; 
    }
}

by user 632418299711324161

How Can I know if a VideoPlayer’s Clip has ended ?

by user 632418299711324161

Here is what I found for you :brain: Discord

Hello DiegoEloko,

The VideoPlayer component in Needle Engine does not provide an explicit method for detecting if a video clip has ended directly through the API, according to the extracted documentation section (see the documentation). Instead, you can monitor the currentTime property of the VideoPlayer and compare it against the duration of the video element to determine if the video has finished playing.

Here’s a high-level pseudocode for implementing this:

  1. Access the VideoPlayer component on your game object.
  2. Within the update lifecycle method, check if the VideoPlayer’s currentTime is equal to or greater than the video’s duration.
  3. If the currentTime is equal to or after the video’s duration, the video has ended.

And the following TypeScript code provides an example of how this might be implemented within a component:

*thread_CvD2yBIFfvZOsUBgDDsguQc3*

typescript
import { VideoPlayer } from “@needle-tools/engine”; // Include the correct module path
import { Behaviour } from “@needle-tools/engine”; // Base class

export class VideoEndDetector extends Behaviour {
private videoPlayer: VideoPlayer;

start() {
    // Access the VideoPlayer component from your GameObject
    this.videoPlayer = this.gameObject.getComponent(VideoPlayer);
    if (!this.videoPlayer) {
        console.error("VideoPlayer component not found!");
        return;
    }
    
    // Optional: start the video if not playing
    if (!this.videoPlayer.isPlaying) {
        this.videoPlayer.play();
    }
}

update() {
    // Check if the video is playing and its current time is at the end
    if (this.videoPlayer && this.videoPlayer.isPlaying) {
        const videoDuration = this.videoPlayer.videoElement.duration;
        if (this.videoPlayer.currentTime >= videoDuration) {
            // Video has ended
            console.log("Video has ended");
            // Perform the desired action after the video ends
        }
    }
}

}

*thread_CvD2yBIFfvZOsUBgDDsguQc3*

To ensure that the video duration is always reachable, you may want to add additional checks to confirm the video’s metadata is fully loaded. This approach requires polling during each update call and will allow you to detect when the video has finished playing.

1 messages left GPT 4
thread_CvD2yBIFfvZOsUBgDDsguQc3
Thanks for your feedback!