Bugs with diffuse texture rendering when locking the camera to my car

Hey everyone,

So i have some meteors with a basic diffuse texture and a particle system linked to them, which look like this normally (this is a demo video, here is screenshot).

As soon as i lock my camera to my car ( via camera.parent = Car in index.html line 67), my texture starts to bug out, allowing me seeing throw the meteor like this (this is a demo video, here is a screenshot).

I’m wondering why i have this problem, i’ve already tried searching and googling but couldn’t find an answer :face_with_diagonal_mouth:.

Here is my source code.

Thanks all for your help :pray:.

(This my first post in the forum so i apologize if i got anything wrong :sweat_smile:)

Hello and welcome!

Can you repro your issue in the Playground?
Using External Assets In the Playground | Babylon.js Documentation (babylonjs.com)

Not gonna lie to you, but it’s really really hard for me to make my game project into the plaground, i’ve already tried that before posting this and it was so complicated (at least for me), that’s why i linked a Github repository and made demo videos, all i can for now is showing you the two main file of my project :

index.html :

<html>

<head>
    <title>Calamity Car</title>
    <meta charset="UTF-8">
    <style>
        html, body {
                overflow: hidden;
                width: 100%;
                height: 100%;
                margin: 0;
                padding: 0;
        }

        #renderCanvas {
                width: 100%;
                height: 100%;
                touch-action: none;
        }
    </style>
    <link rel="stylesheet" href="css/default.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
    <script src="https://assets.babylonjs.com/generated/Assets.js"></script>
    <script src="https://preview.babylonjs.com/ammo.js"></script>
    <script src="https://preview.babylonjs.com/cannon.js"></script>
    <script src="https://preview.babylonjs.com/Oimo.js"></script>
    <script src="https://preview.babylonjs.com/earcut.min.js"></script>
    <script src="https://preview.babylonjs.com/babylon.js"></script>
    <script src="https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
    <script src="https://preview.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script>
    <script src="https://preview.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script>
    <script src="https://preview.babylonjs.com/loaders/babylonjs.loaders.js"></script>
    <script src="https://preview.babylonjs.com/serializers/babylonjs.serializers.min.js"></script>
    <script src="https://preview.babylonjs.com/gui/babylon.gui.min.js"></script>
    <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
    <script src="js/main.js"></script>
</head>

<body>
    <canvas id="renderCanvas" touch-action="none"></canvas>
    <script>
        modifySettings();
        const canvas = document.getElementById("renderCanvas");
        const engine = new BABYLON.Engine(canvas, true);
        const createScene = function () {
            const scene = new BABYLON.Scene(engine);
            var physicsPlugin = new BABYLON.CannonJSPlugin();
            scene.collisionsEnabled = true;
            scene.enablePhysics(physicsPlugin);
            SceneLoader(scene);
            light = new BABYLON.HemisphericLight("Light", new BABYLON.Vector3(0, -1, 0), scene);
            camera = new BABYLON.FreeCamera("Camera", new BABYLON.Vector3(0,0,100), scene);
            camera.inputs.clear();
            camera.attachControl(canvas, true);  
            return scene;
        };
        const scene = createScene();
        

        engine.runRenderLoop(function () {
            if(fullyLoaded(scene) && once){
                //CreateGizmo(scene);
                CreateSkyBox(scene);
                CreateCar(scene);  
                CreateGUI(scene); 
                camera.target = Car.position;
                camera.parent  = Car;
                once = false;          
            }
            else if (start) {
                Car.move();
                if (OK) {
                    SpawnMeteor(scene);    
                    OK = false;
                }
            }
            scene.render();
        });
        window.addEventListener("resize", function () {
            engine.resize();
        });
    </script>
</body>

</html>

and my main.js :

let once = true;
let Car;
let camera;
let inputStates = {};
let world;
let start = false;
let OK = true;
let angle = 0.01;
let angle2 = 0.04;
let gizmoManager;
let light;
let json = {"name":"CPU particle system","id":"default system","capacity":10000,"emitter":[0,0,0],"particleEmitterType":{"type":"ConeParticleEmitter","radius":0.1,"angle":0.7853981633974483,"directionRandomizer":0,"radiusRange":1,"heightRange":1,"emitFromSpawnPointOnly":false},"textureName":"https://www.babylonjs.com/assets/Flare.png","invertY":true,"isLocal":false,"animations":[],"beginAnimationOnStart":false,"beginAnimationFrom":0,"beginAnimationTo":60,"beginAnimationLoop":false,"startDelay":0,"renderingGroupId":0,"isBillboardBased":true,"billboardMode":7,"minAngularSpeed":0,"maxAngularSpeed":0,"minSize":0.1,"maxSize":0.2,"minScaleX":1,"maxScaleX":1,"minScaleY":1,"maxScaleY":1,"minEmitPower":2,"maxEmitPower":2,"minLifeTime":1,"maxLifeTime":2,"emitRate":150,"gravity":[0,0,0],"noiseStrength":[10,10,10],"color1":[1,1,1,1],"color2":[0.7647058823529411,0.07450980392156863,0.07450980392156863,1],"colorDead":[0,0,0,0],"updateSpeed":0.016666666666666666,"targetStopDuration":0,"blendMode":0,"preWarmCycles":0,"preWarmStepOffset":1,"minInitialRotation":0,"maxInitialRotation":0,"startSpriteCellID":0,"endSpriteCellID":0,"spriteCellChangeSpeed":1,"spriteCellWidth":0,"spriteCellHeight":0,"spriteRandomStartCell":false,"isAnimationSheetEnabled":false,"textureMask":[1,1,1,1],"customShader":null,"preventAutoStart":false};

function CreateGizmo(scene){
    gizmoManager = new BABYLON.GizmoManager(scene);
    gizmoManager.positionGizmoEnabled = true;
    gizmoManager.rotationGizmoEnabled = true;
    gizmoManager.scaleGizmoEnabled = true;
    gizmoManager.boundingBoxGizmoEnabled = true;
}

function SpawnMeteor(scene){
    var meteor = BABYLON.MeshBuilder.CreateSphere("meteor", {diameter: 5, segments: 32}, scene);
    var meteorMaterial = new BABYLON.StandardMaterial("meteorM", scene);
    meteorMaterial.diffuseTexture = new BABYLON.Texture("/textures/meteor.jpg", scene);
    meteorMaterial.alpha = 1;
    meteor.material = meteorMaterial;
    meteor.physicsImpostor = new BABYLON.PhysicsImpostor(meteor, BABYLON.PhysicsImpostor.SphereImpostor, {mass: 0});
    meteor.position = new BABYLON.Vector3(getRandomArbitrary(),getRandomArbitrary(),getRandomArbitrary());
    var solutions = FindLineSphereIntersections(meteor.position);
    const particleSystem = new BABYLON.ParticleSystem("particles", 500);
    particleSystem.particleTexture = new BABYLON.Texture(json.textureName);
    particleSystem.updateSpeed = json.updateSpeed;
    particleSystem.emitRate = 150; 
    particleSystem.emitter = meteor;
    particleSystem.start();
    BABYLON.Animation.CreateAndStartAnimation("anim", meteor, "position", 30, 60, meteor.position, solutions[0], BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT);
    setTimeout(SpawnMeteor, 2000);
}
function CreateGUI(scene) {
    var advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI(scene);
    var button1 = BABYLON.GUI.Button.CreateSimpleButton("but1", "START");
    button1.width = "150px"
    button1.height = "75px";
    button1.color = "white";
    button1.cornerRadius = 20;
    button1.background = "green";
    button1.top = "200px"
    button1.onPointerUpObservable.add(function() {
        start = true;
        button1._doNotRender = true;
    });
    advancedTexture.addControl(button1);   
}

function CreateWorld(world) {
    world.physicsImpostor = new BABYLON.PhysicsImpostor(world, BABYLON.PhysicsImpostor.MeshImpostor, {mass: 0});
    world.checkCollisions = true;
}
function CreateCar(scene){

    let pivot = new BABYLON.Mesh("pivot", scene);
    pivot.parent = Car;
    const pivotAt = new BABYLON.Vector3(0, 0, 0);
    const relativePosition = pivotAt.subtract(Car.position);
    Car.setPivotPoint(relativePosition);
    Car.move = () => {
        Car.rotate(new BABYLON.Vector3(1, 0, 0), angle, BABYLON.Space.LOCAL);
        
        if(inputStates.left) {
            Car.rotate(new BABYLON.Vector3(0, 0, -1), angle2, BABYLON.Space.LOCAL);    
        }    
        if(inputStates.right) {
            Car.rotate(new BABYLON.Vector3(0, 0, 1), angle2, BABYLON.Space.LOCAL);
        }
    };

}

function CreateSkyBox(scene){

    var skybox = BABYLON.MeshBuilder.CreateBox("skyBox", {size:500.0}, scene);
	var skyboxMaterial = new BABYLON.StandardMaterial("skyBox", scene);
	skyboxMaterial.backFaceCulling = false;
    var files = [
        "textures/bg_left.jpg",
        "textures/bg_up.jpg",
        "textures/bg_front.jpg",
        "textures/bg_right.jpg",
        "textures/bg_down.jpg",
        "textures/bg_back.jpg",
    ];
	skyboxMaterial.reflectionTexture = new BABYLON.CubeTexture.CreateFromImages(files, scene);
	skyboxMaterial.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE;
	skyboxMaterial.diffuseColor = new BABYLON.Color3(0, 0, 0);
	skyboxMaterial.specularColor = new BABYLON.Color3(0, 0, 0);
	skybox.material = skyboxMaterial;	
}

function fullyLoaded(scene) {
    if(scene.getMeshByName("__root__") != null && scene.getMeshByName("planet_3") != null)
    {
        Car = scene.getMeshByName("__root__");
        world = scene.getMeshByName("planet_3");
        
        return true;
    }
     
    else
        return false;
}
function SceneLoader(scene) {
    BABYLON.SceneLoader.Append("scene/car/", "scene.gltf", scene, function (scene) {
    });
    BABYLON.SceneLoader.Append("scene/World/", "world.gltf", scene,function (scene) {
    });
    
}
function modifySettings() {
    /*scene.onPointerDown = () => {
        if(!scene.alreadyLocked) {
            console.log("requesting pointer lock");
            canvas.requestPointerLock();
        } else {
            console.log("Pointer already locked");
        }
    }
    document.addEventListener("pointerlockchange", () => {
        let element = document.pointerLockElement || null;
        if(element) {
            scene.alreadyLocked = true;
        } else {
            scene.alreadyLocked = false;
        }
    })
    */
    inputStates.left = false;
    inputStates.right = false;
    inputStates.up = false;
    inputStates.down = false;
    inputStates.space = false;

    window.addEventListener('keydown', (event) => {
        if ((event.key === "ArrowLeft") || (event.key === "q")|| (event.key === "Q")) {
           inputStates.left = true;
        } else if ((event.key === "ArrowUp") || (event.key === "z")|| (event.key === "Z")){
           inputStates.up = true;
        } else if ((event.key === "ArrowRight") || (event.key === "d")|| (event.key === "D")){
           inputStates.right = true;
        } else if ((event.key === "ArrowDown")|| (event.key === "s")|| (event.key === "S")) {
           inputStates.down = true;
        }  else if (event.key === " ") {
           inputStates.space = true;
        }
    }, false);

    window.addEventListener('keyup', (event) => {
        if ((event.key === "ArrowLeft") || (event.key === "q")|| (event.key === "Q")) {
           inputStates.left = false;
        } else if ((event.key === "ArrowUp") || (event.key === "z")|| (event.key === "Z")){
           inputStates.up = false;
        } else if ((event.key === "ArrowRight") || (event.key === "d")|| (event.key === "D")){
           inputStates.right = false;
        } else if ((event.key === "ArrowDown")|| (event.key === "s")|| (event.key === "S")) {
           inputStates.down = false;
        }  else if (event.key === " ") {
           inputStates.space = false;
        }
    }, false);
}
function getRandomArbitrary() {
    var sign = Math.random() < 0.5 ? -1 : 1;
    var coord = Math.floor(Math.random() * 100) + 50
    return sign * coord;
}

function FindLineSphereIntersections(meteorPosition)
{
        let solutions;
        var circleRadius = 35;
        var cx = 0;
        var cy = 0;
        var cz = 0;

        var px = cx;
        var py = cy;
        var pz = cz;

        var vx = meteorPosition.x;
        var vy = meteorPosition.y;
        var vz = meteorPosition.z;

        var A = vx * vx + vy * vy + vz * vz;
        var B = 2.0 * (px * vx + py * vy + pz * vz - vx * cx - vy * cy - vz * cz);
        var C = px * px - 2 * px * cx + cx * cx + py * py - 2 * py * cy + cy * cy +
                   pz * pz - 2 * pz * cz + cz * cz - circleRadius * circleRadius;

        // discriminant
        var D = B * B - 4 * A * C;

        if ( D < 0 )
        {
            return new BABYLON.Vector3.Zero();
        }

        var t1 = ( -B - Math.sqrt(D) ) / (2.0 *A);

        var solution1 = new BABYLON.Vector3( cx * ( 1 - t1 ) + t1 * meteorPosition.x,
                                         cy * ( 1 - t1 ) + t1 * meteorPosition.y,
                                         cz * ( 1 - t1 ) + t1 * meteorPosition.z );
        if ( D == 0 )
        {
            solutions = [solution1];
            return solutions;
        }

        var t2 = ( -B + Math.sqrt(D) ) / ( 2.0 * A );
        var solution2 = new BABYLON.Vector3( cx * ( 1 - t2 ) + t2 * meteorPosition.x,
                                         cy * ( 1 - t2 ) + t2 * meteorPosition.y,
                                         cz * ( 1 - t2 ) + t2 * meteorPosition.z );

        // prefer a solution that's on the line segment itself
        
        if ( Math.abs( t1 - 0.5 ) < Math.abs( t2 - 0.5 ) )
        {
            solutions = [solution1, solution2];
            return solutions;
        }

        solutions = [solution2, solution1];
        return solutions;
 
}

everything else is just textures and scenes (wich you can find on my github repository set on public.

Sorry for the inconvenience and my incompetence :grimacing: .

Hello, are you still having issues?

1 Like

hello, yes sir

Are you able to provide us with a playground repro? Doesn’t need to be your entire game, just a simple scene where your problem occurs.