[SOLVED] Crosshair in 3D space going through wall

This is a video of what is happening. I think in Unity I would usually change a setting in the camera to stop this happen, I think, its been a while since I have done this, but overall my question is, with this cross hair, which I presume in the UI is something I have to change, how do I make it so the crosshair stops going through objects, the wall and the floor as seen in the above linked video?

Hi @jamiecropley and welcome,

There are several ways to approach this, the most common is to use a second camera. Add a second camera as child to your main camera, that way it will get the same transformation.

Next have your second camera render your crosshair layer (e.g. UI or add a custom layer) and the important bit is to:

  • Disable Clear Color Buffer
  • Enable Clear Depth Buffer

That way an object rendered in 3D space (e.g. the Crosshair) will render on top of your scene geometry (depth buffer is cleared).

I think the problem here is that the entity with the UI element is not a child of an entity with a screen element.

Alternatively you can use an entity with a render component. For that you can use a plane and apply a material with your texture. For this material, you can disable depth or change the layer.

1 Like

Good point, thought it was meant to be in 3D space and not in screen space.

If it’s the latter @Albertos fix is recommended.

This is where I am at now, I attached a plane to the camera of the player instead of the image like I did previously, it works but still clips through so I tried to write this code, but I don’t know how to get the forward camera direction, I looked up via google, even tried ChatGPT and it still don’t work.

direction = camera.forward; is the main line having issues.

var Crosshair = pc.createScript('crosshair');

Crosshair.prototype.initialize = function() {
    // Get the camera component
    this.camera = this.entity.camera;
    
    // Set the maximum distance for the raycast
    this.maxDistance = 100;
};

Crosshair.prototype.update = function(dt) {
    // Get the direction that the camera is facing
    direction = camera.forward;

    // Scale the direction vector to a maximum distance
    direction = direction.scale(this.maxDistance);
    
    // Set the start position for the raycast to be the position of the camera
    var start = this.camera.getPosition();
    
    // Set the end position for the raycast to be the position of the camera + the scaled direction vector
    var end = start.add(direction);
    
    // Perform the raycast
    var result = this.app.systems.rigidbody.raycastFirst(start, end);
    
    // If the raycast hits a rigid body
    if (result) {
        // Set the position of the crosshair to be the hit point
        this.entity.setPosition(result.point);
    } else {
        // Set the position of the crosshair to be the end point of the raycast
        this.entity.setPosition(end);
    }
};

Error is:

[crosshair.js?id=116932426&branchId=a79e9932-7eff-4697-bc13-d581f7fd994f:13]: camera is not defined

ReferenceError: camera is not defined
at Crosshair.update (https://launch.playcanvas.com/api/assets/files/scripts/crosshair.js?id=116932426&branchId=a79e9932-7eff-4697-bc13-d581f7fd994f:13:5)
at ScriptComponent._scriptMethod (https://code.playcanvas.com/playcanvas-1.58.2.dbg.js:62820:22)
at ScriptComponent._onUpdate (https://code.playcanvas.com/playcanvas-1.58.2.dbg.js:62853:15)
at ScriptComponentSystem._callComponentMethod (https://code.playcanvas.com/playcanvas-1.58.2.dbg.js:63345:52)
at ScriptComponentSystem._onUpdate (https://code.playcanvas.com/playcanvas-1.58.2.dbg.js:63359:11)
at ComponentSystemRegistry.fire (https://code.playcanvas.com/playcanvas-1.58.2.dbg.js:674:21)
at Application.update (https://code.playcanvas.com/playcanvas-1.58.2.dbg.js:38411:19)
at Application.tick (https://code.playcanvas.com/playcanvas-1.58.2.dbg.js:39020:20)
at Application.start (https://code.playcanvas.com/playcanvas-1.58.2.dbg.js:38383:11)
at https://launch.playcanvas.com/editor/scene/js/launch.js:1:10466

The crosshair.js code above is attached to the plane / crosshair game object as a script

@jamiecropley I think line 13 should be this.camera instead of just camera.

I tried this and got the same / similar error.

@jamiecropley I can’t really see the project hierarchy and how everything is attached. Did you share your project? I don’t know if this helps but this is a function I use for firing a raycast.

/ handle shooting and raycast
GunShoot.prototype.shoot = function(e) {

    // Get center of screen
    var centerScreenX = this.app.graphicsDevice.width / 2;
    var centerScreenY = this.app.graphicsDevice.height / 2;

    //Get start and end point
    var start = this.camera.camera.screenToWorld(centerScreenX, centerScreenY, this.camera.camera.nearClip);
    var end = this.camera.camera.screenToWorld(centerScreenX, centerScreenY, this.camera.camera.farClip);
    
    // raycast between the two points and return the closest hit result
    var result = this.app.systems.rigidbody.raycastFirst(start, end);

    // Play and reset muzzle flash
    this.muzzleFx.particlesystem.play();
    this.muzzleFx.particlesystem.reset();

    if(this.entity.sound != null) {
        // Play this weapons sound
        this.entity.sound.play("fire");
    }

    // We hit something with collision
    if(result) {

        console.log("You Hit: " + result.entity.name);
        this.handleImpact(result.entity,result.point,result.normal);
 
    } else {

        console.log("Nothing Hit");
    }

};

Hi I tried your code but it didn’t help.

https://playcanvas.com/project/1022409/overview/first-person-controller-template

I have now made the project public, my aim is to eventually implement everything e.g. pick up objects, interact with buttons use weapons etc… but for now I just want to fix the cross hair and get that working any further advice much appericiated.

You need to create a new material to disable depth and apply this material to your crosshair. Then you can also apply a crosshair texture to it.

What is your crosshair.js script doing?

Not sure what you mean, the crosshair is a plane at the moment, so would adding a material make any difference? Note project is currently public.

Code is however:

var Crosshair = pc.createScript('crosshair');

Crosshair.prototype.initialize = function() {
    // Get the camera component
    this.camera = this.entity.camera;
    
    // Set the maximum distance for the raycast
    this.maxDistance = 100;
};

Crosshair.prototype.update = function(dt) {
    // Get the direction that the camera is facing
    direction = this.camera.forward;

    // Scale the direction vector to a maximum distance
    direction = direction.scale(this.maxDistance);
    
    // Set the start position for the raycast to be the position of the camera
    var start = this.camera.getPosition();
    
    // Set the end position for the raycast to be the position of the camera + the scaled direction vector
    var end = start.add(direction);
    
    // Perform the raycast
    var result = this.app.systems.rigidbody.raycastFirst(start, end);
    
    // If the raycast hits a rigid body
    if (result) {
        // Set the position of the crosshair to be the hit point
        this.entity.setPosition(result.point);
    } else {
        // Set the position of the crosshair to be the end point of the raycast
        this.entity.setPosition(end);
    }
};

What’s are you trying to achieve with the script?

Honestly, I can’t remember, I think I was trying to make a raycast for the crosshair so it stops going through the walls and such.

If you add a material that has depth disabled, you will see the plane always in front. I think that was your goal?

Then at least try my suggestion and disable the script.

image
These were the only settings I could find on the material itself for depth but unticking them gets rid of the crosshair entirely.

Not sure why, but you have to set the opacity Blend Type to Alpha.

image

1 Like

Thats sorted it many thanks