Table of Contents

Raycasting and Camera Focus

In this tutorial, we will learn how to use raycasting to detect entities in a 3D scene and adjust the camera to focus on them. This technique is useful for games or simulations where you need to interact with objects using the mouse and smoothly transition the camera's focus based on those interactions.

What You'll Learn

  • How to create 3D entities and assign materials to them.
  • How to use raycasting to detect objects in a 3D scene.
  • How to use the camera to smoothly look at the target entity.

Code Walkthrough

using Stride.CommunityToolkit.Bepu;
using Stride.CommunityToolkit.Engine;
using Stride.CommunityToolkit.Rendering.ProceduralModels;
using Stride.Core.Mathematics;
using Stride.Engine;
using Stride.Games;

Entity? target = null;
CameraComponent? camera = null;

using var game = new Game();

game.Run(new SceneSetup3D().UseBepu(), start: Start, update: Update);

void Start(Scene scene)
{
    // Add a gizmo to help visualize the ground plane and axis directions
    game.AddGroundGizmo(showAxisName: true);

    // Create a cube entity with a violet material and position it in the scene
    var cube = game.CreatePrimitive(Primitive3D.Cube(), new()
    {
        Material = game.CreateMaterial(Color.Violet),
    });

    cube.Transform.Position = new Vector3(0, 8, -3);

    // Add cube to the scene
    cube.Scene = scene;

    // Create a sphere entity with a wheat-colored material
    var entity = game.CreatePrimitive(Primitive3D.Sphere(), new()
    {
        Material = game.CreateMaterial(Color.Wheat),
    });

    entity.Transform.Position = new Vector3(-4, 8, 0);

    // Add sphere to the scene
    entity.Scene = scene;

    camera = scene.GetCamera();
}

// Update method called every frame to handle game logic
void Update(Scene scene, GameTime gameTime)
{
    game.DebugTextSystem.Print("Click on a sphere, cube or ground to turn the camera", new Int2(5, 10));

    if (camera is null) return;

    if (game.Input.IsMouseButtonPressed(Stride.Input.MouseButton.Left))
    {
        var hit = camera.Raycast(game.Input.MousePosition, 100, out var hitInfo);

        if (hit)
        {
            target = hitInfo.Collidable.Entity;
        }
        else
        {
            Console.WriteLine("No hit");
        }
    }

    // If a target entity is set, make the camera smoothly look at it
    if (target != null)
    {
        camera.Entity.Transform.LookAt(target.Transform, game.DeltaTime() * 3.0f);
    }
}

Code Breakdown

  • Game Setup: In the Start() method, the scene setup passed to game.Run has already given us lighting, a camera and a ground with Bepu physics. We then create two 3D entities, a cube and a sphere, and position them in the scene with different materials.

  • Raycasting with Mouse Input: In the Update() method, we check if the left mouse button is pressed. If pressed, camera.Raycast() from the Bepu package casts a ray from the mouse position into the 3D world, up to 100 units, and reports the first collidable it hits.

  • Camera Focus: If the ray successfully hits an entity, that entity becomes the target. The camera then uses the LookAt() method to smoothly focus on the target entity, giving the player a clear view of the object they clicked on.

Running the Code

When you run this code, the game will display a 3D scene with a cube and a sphere. Clicking on either object, or on the ground, with the left mouse button makes the camera smoothly rotate to focus on what was clicked.

Summary

This example demonstrates how to use raycasting to detect entities in a scene based on mouse input and how to adjust the camera to focus on those entities. This technique is useful for games that require interactive environments, object selection, or camera-based interactions.

Feel free to extend this concept by adding more entities, adjusting the camera's behavior, or experimenting with different easing functions for camera movement.