[SOLVED] I am using playcanvas version 1.73.5 and I am facing issue while raycasting

I am importing playcanvas through minified script tag (script src=“https://code.playcanvas.com/playcanvas-1.73.5.min.js”>) and i am facing this issue

DEBUG] ERROR: Unexpected error in onMouseDown TypeError: ex is undefined
raycastFirst playcanvas-1.73.5.min.js:9
onMouseDown MaterialController.js:81
fire playcanvas-1.73.5.min.js:9
_handleDown playcanvas-1.73.5.min.js:9
attach playcanvas-1.73.5.min.js:9
e playcanvas-1.73.5.min.js:9
Application Application.js:17
main.js:122
EventListener.handleEvent* main.js:107

use the debug engine build https://code.playcanvas.com/playcanvas-1.73.5.dbg.js

and inspect what the problem is in the debugger

okay

Hi martin,

I have switched the implentation from using script tag to directly using npm package as defined in the docs of using engine standalone. Now i am getting the following error

[DEBUG] ERROR: Unexpected error in onMouseDown TypeError: Cannot read properties of undefined (reading ‘setValue’)
at RigidBodyComponentSystem.raycastFirst (playcanvas.js?v=cb4b0323:60491:18)
at MaterialController.onMouseDown (MaterialController.js:83:53)
at Mouse.fire (playcanvas.js?v=cb4b0323:179:20)
at Mouse._handleDown (playcanvas.js?v=cb4b0323:14177:10)

how do i exactly use the debug build to debug this problem.

Looks like the error is in your code. If you open the browser console and click on the source file link top of the callstack, what code does it go to? Yours or PlayCanvas’ engine?

Can you share your code?

yes the top link goes to playcanvas.js more precisely this line ammoRayStart.setValue(start.x, start.y, start.z);

following is my code

import { debugLog } from '../utils/DebugLogger.js';
import { StandardMaterial, Texture, Vec3, BoundingBox, Color, Entity, Mat4 } from 'playcanvas';

export class MaterialController {
    constructor(app, uiManager) {
        this.app = app;
        this.uiManager = uiManager;
        this.selectedEntity = null;
        this.materialCatalog = {};
        this.isSelectionActive = false;
        this.selectionMarker = null;
        this.setupEventListeners();
        
    }

    setupEventListeners() {
        this.app.mouse.on('mousedown', this.onMouseDown, this);
    }

    toggleMaterialSelection() {
        this.isSelectionActive = !this.isSelectionActive;
        debugLog("Material selection active:", this.isSelectionActive);
    }

    setSelectionFalse() {
        this.isSelectionActive = false;
    }

    // createSelectionMarker(position) {
    //     this.removeSelectionMarker();

    //     // Create a sphere entity
    //     this.selectionMarker = new Entity('SelectionMarker');
    //     this.app.root.addChild(this.selectionMarker);

    //     // Add a sphere model
    //     this.selectionMarker.addComponent('model', {
    //         type: 'sphere'
    //     });

    //     // Set the position
    //     this.selectionMarker.setPosition(position);

    //     // Set the scale to make it visible but not too large
    //     this.selectionMarker.setLocalScale(0.1, 0.1, 0.1);

    //     // Create a material for the marker
    //     const material = new StandardMaterial();
    //     material.emissive = new Color(1, 0, 0); // Red color
    //     material.update();

    //     // Assign the material to the model
    //     this.selectionMarker.model.material = material;

    //     debugLog("Created selection marker at", position);
    // }

    // removeSelectionMarker() {
    //     if (this.selectionMarker) {
    //         this.selectionMarker.destroy();
    //         this.selectionMarker = null;
    //         debugLog("Removed selection marker");
    //     }
    // }

    onMouseDown(event) {
        if (!this.isSelectionActive) return;

        try {
            debugLog("Mouse down event triggered");
            debugLog("Mouse coordinates:", event.x, event.y);

            const camera = this.app.root.findComponent('camera');
            if (!camera) {
                debugLog('ERROR: Camera component not found');
                return;
            }
            // this.logSceneEntities();
            const from = camera.screenToWorld(event.x, event.y, camera.nearClip);
            const to = camera.screenToWorld(event.x, event.y, camera.farClip);
            debugLog("app.system ",this.app.systems);
            // debugLog(this.app.system.rigidbody);
            var result = this.app.systems.rigidbody.raycastFirst(from, to);
            debugLog(from, to, result);
            
            
            if (result) {
                this.selectedEntity = result.entity;
                debugLog("Picked entity:", this.selectedEntity.name);
                // this.createSelectionMarker(result.point);
                this.openMaterialSelection();
            } else {
                debugLog("No entity picked");
                this.removeSelectionMarker();
            }
        } catch (error) {
            debugLog("ERROR: Unexpected error in onMouseDown", error);
            console.error(error);
        }
    }

    

    logSceneEntities() {
        debugLog("Logging all entities in the scene:");
        this.app.root.forEach(entity => {
            const hasRigidbody = !!entity.rigidbody;
            const hasCollisionComponent = !!entity.collision;
            debugLog(`Entity: ${entity.name}`);
            debugLog(`  Position: ${entity.getPosition()}`);
            debugLog(`  Has Rigidbody: ${hasRigidbody}`);
            debugLog(`  Has Collision: ${hasCollisionComponent}`);
            if (hasCollisionComponent) {
                debugLog(`  Collision type: ${entity.collision.type}`);
            }
        });
    }


    openMaterialSelection() {
        this.setSelectionFalse();
        this.uiManager.openMaterialModal(this.materialCatalog, (material) => {
            this.applyMaterial(material);
            this.uiManager.selectMaterialButton.classList.remove('active');
        });
    }

    applyMaterial(material) {
        debugLog("Attempting to apply material:", material);
        if (this.selectedEntity) {
            debugLog("Selected entity:", this.selectedEntity.name);

            if (this.selectedEntity.model) {
                this.selectedEntity.model.material = material;
                debugLog(`Applied material to model component of ${this.selectedEntity.name}`);
            } else if (this.selectedEntity.render) {
                this.selectedEntity.render.material = material;
                debugLog(`Applied material to render component of ${this.selectedEntity.name}`);
            } else {
                this.selectedEntity.addComponent('render', {
                    type: 'box',
                    material: material
                });
            }

            // Force the engine to update the material
            this.app.scene.updateShaders = true;
        } else {
            debugLog("No entity selected");
        }
    }

    addMaterialToCatalog(name, material) {
        this.materialCatalog[name] = material;
        this.uiManager.onMaterialCatalogUpdated(this.materialCatalog);
    }

    handleTextureUpload(files) {
        let uploadedCount = 0;
        const totalFiles = files.length;

        for (let file of files) {
            const reader = new FileReader();
            reader.onload = (e) => {
                const img = new Image();
                img.onload = () => {
                    const texture = new Texture(this.app.graphicsDevice);
                    texture.setSource(img);

                    const material = new StandardMaterial();
                    material.diffuseMap = texture;
                    material.update();

                    const materialName = file.name.split('.')[0];
                    this.addMaterialToCatalog(materialName, material);
                    debugLog(`Added new material: ${materialName}`);

                    uploadedCount++;
                    if (uploadedCount === totalFiles) {
                        this.uiManager.onAllMaterialsUploaded();
                    }
                };
                img.src = e.target.result;
            };
            reader.readAsDataURL(file);
        }
    }
}

line number 83 above

start and to have proper values.

Looks like you’ve not loaded Ammo WASM library which is needed for all physics based functionality

You can see examples of the Ammo WASM loading here https://playcanvas.vercel.app/#/physics/raycast

There is a problem while loading ammo wasm while using standalone engine right now, if i add it through script tag in index html it shows me either 403 or 404.

where can I download it statically or load it?

Download the files and self host it. Load the WASM like how the examples have shown

Files can be found here: https://github.com/playcanvas/engine/tree/main/examples/src/lib/ammo

hey @yaustar

I have loaded ammo.wasm and js file yet i am seeing the same issue.

import { 
    Application as PcApplication, 
    RESOLUTION_AUTO, 
    FILLMODE_FILL_WINDOW,
    Entity, 
    Color, 
    Vec3,
    Mouse,
    Keyboard,
    RigidBodyComponentSystem,
    WasmModule

} from 'playcanvas';
import { AssetLoader } from './AssetLoader.js';
import { debugLog } from '../utils/DebugLogger.js';

export class Application {
    constructor() {
        this.canvas = document.getElementById('application');
        if (!this.canvas) {
            debugLog('ERROR: Canvas element not found!');
            throw new Error('Canvas element not found');
        }

        // Ensure canvas has non-zero size
        this.resizeCanvas();
        window.addEventListener('resize', () => this.resizeCanvas());

        WasmModule.setConfig('Ammo', {
            glueUrl: '/src/lib/ammo/ammo.wasm.js',
            wasmUrl: '/src/lib/ammo/ammo.wasm.wasm',
            fallbackUrl: '/src/lib/ammo/ammo.js'
        });
        WasmModule.getInstance('Ammo', () => {
            console.log("Ammo.js loaded and ready to use.");
        });

        this.app = new PcApplication(this.canvas, {
            mouse: new Mouse(this.canvas),
            keyboard: new Keyboard(window)
        });
        this.app.setCanvasResolution(RESOLUTION_AUTO);
        this.app.setCanvasFillMode(FILLMODE_FILL_WINDOW);
        this.app.systems.add(RigidBodyComponentSystem);
        this.app.systems.rigidbody.gravity.set(0, -9.81, 0);
        this.assetLoader = new AssetLoader(this.app);
        this.setupLights();
    }

    resizeCanvas() {
        this.canvas.width = window.innerWidth;
        this.canvas.height = window.innerHeight;
    }

    start() {
        this.app.start();
    }

    setupLights() {
        this.createLight('directional', 0.6, new Vec3(0, 10, 0), new Vec3(45, 45, 0));
        this.createLight('point', 0.7, new Vec3(0, 5, 0));
        this.createLight('point', 0.7, new Vec3(5, 5, 5));
        this.createLight('point', 0.7, new Vec3(-5, 5, -5));
    }

    createLight(type, intensity, position, rotation) {
        const light = new Entity();
        light.addComponent('light', {
            type: type,
            color: new Color(1, 1, 1),
            intensity: intensity,
            range: 20,
            shadowDistance: 30,
            shadowResolution: 1024,
            shadowBias: 0.2,
            normalOffsetBias: 0.05
        });
        light.setPosition(position.x, position.y, position.z);
        if (rotation) {
            light.setEulerAngles(rotation.x, rotation.y, rotation.z);
        }
        this.app.root.addChild(light);
        return light;
    }

    getCanvas() {
        return this.canvas;
    }
}

Am I doing something wrong ?

I don’t see where you are actually waiting for Ammo to load before creating the app instance like in the examples

Currently you are creating the app immediately after trying to get the instance of Ammo but you should waiting for that to resolve first

1 Like

yes that was it. Thanks alot.