How to remove Camera Movement Jitter

I think that is not convention, and LERPs are the correct way to achieve a camera animation system fo what you are trying to do.

turnSpeed = Math.max((1 - smoothing) * turnSpeed + smoothing * -_accel, -1) is the LERP btw.

And you say boom arm? can you explain? If you just need it to rotate I can help you with that. Sorry its 3AM I just woke up for a second, Ill look at this in the morning after coffee and make sure I read correct.

I am trying to make a playground with a sample race track and car setup. Then you can really see how things are getting used. You should be able to the test car transform from the scene. Then do whatever you gotta do to create some kinda Smooth Car Follow Camera and use the test car transform from the gltf scene at the lockedTarget

But there seems to be an issue with Ammo.JS on the Playgroundā€¦ As soon as @Deltakosh can figure out whats going thereā€¦ i will make a Starter Racing Template Playgroundā€¦ Any and all parties are welcome to try and make smooth follow camera for test carā€¦

Note the Race Track Scene and Test Car All complete with Physics And User Input to drive the car was all prepared using the Unity Exporter to gltf files which the Scene Manager then parses the scene metadataā€¦ In shortā€¦ You dont have to do anything except load the GLTFā€¦ Any script components attached to entities will automatically get instantiated.

All you gotta do is make the FreeCamera follow the car transform :slight_smile:

Well i can seem to LERP but then cant figure out to get decent camera lag for turning left or rightā€¦

Just check out Need For Speed or any other driving gameā€¦ The follow camera stays within its desired follow distanceā€¦ and also lags a bit when turning right or leftā€¦ When lerping the positionā€¦ If you make the lerp ratio large enough to stay like 5 units behind car the lag for turn is too fast and it looks stiffā€¦ If i lower the lerp enough to not look stiff when turningā€¦ it lags too far behind the car and the car can get away from

Unreal Engine uses a USpringArmComponentā€¦ That is what i meant by camera boomā€¦ basically its was going to be a Spring Arm or Camera Boom with the camera attached at the end of the armā€¦ The Spring Arm is a child of the transform and the camera is a child of Spring Armā€¦ The spring can be rotated left and right while being dragged around track by being a child of car transform instead of trying to catch up using its own separate position.

I am trying whatever i can to create a Need For Speed style racing game for BabylonJS. I got ALOT working already for the actual driving mechanics including Gearbox, Engine Pitching, RPMS, Skidding/Driftingā€¦ Even the most koolest BabylonJS implementation of the native UnitySkidmarks system. Where it one big mesh and all the skid marks for all the cars are dynamically rendered whith virtually NO OVERHEAD.

Things i need to work on still:

1ā€¦ Smooth High Speed Follow Camera
2ā€¦ GPU Based Tire Smoke Particles
3ā€¦ Projectors to project a fake shadow on the ground
4ā€¦ Physics Logic for burning rubber, peel outs and doughnuts

I will show you when we get the playground fix for Ammo.JS

If you get me into your scene here, I bet I could script up a follow cam that you would like in a couple hours.

I could prolly help you with a custom Shader to show rubber on the ground after burnouts too.

https://playground.babylonjs.com/#TTSC4C#3

Hopefully you have a controler, If you look here though as you turn the camera swings to catch up. You make that more dramatic with a smaller LERP value.

Iā€™m trying to get Ammo working on da playgroundā€¦ once that is working I can put Babylon Toolkit generated content including script components ā€¦ on da playground too

Yo @Pryme8 ā€¦ You probobly dont know about the SceneManager ā€¦ Input Manager functionalityā€¦

All that Gamepad User input from your last Playground can be simplified like so:

var player = 1;
var horz = BABYLON.SceneManager.GetUserInput(BABYLON.UserInputAxis.Horizontal, player);
var vert = BABYLON.SceneManager.GetUserInput(BABYLON.UserInputAxis.Vertical, player);
var mousex = BABYLON.SceneManager.GetUserInput(BABYLON.UserInputAxis.MouseX, player);
var mousey = BABYLON.SceneManager.GetUserInput(BABYLON.UserInputAxis.MouseY, player);

Example updateVehicleController function that supports all the required Keyboard and or Gamepad usageā€¦ Buttons, triggers etcā€¦

    protected updateVehicleController(): void {
        if (this.m_standardCarController != null) {
            if (this.enableInput === true) {
                this.playerDeltaX = BABYLON.SceneManager.GetUserInput(BABYLON.UserInputAxis.Horizontal, this.playerNumber);
                this.playerDeltaY = BABYLON.SceneManager.GetUserInput(BABYLON.UserInputAxis.Vertical, this.playerNumber);
                this.playerMouseX = BABYLON.SceneManager.GetUserInput(BABYLON.UserInputAxis.MouseX, this.playerNumber);
                this.playerMouseY = BABYLON.SceneManager.GetUserInput(BABYLON.UserInputAxis.MouseY, this.playerNumber);

                if (Math.abs(this.playerDeltaX) <= BABYLON.UserInputOptions.GamepadDeadStickValue) this.playerDeltaX = 0;
                if (Math.abs(this.playerDeltaY) <= BABYLON.UserInputOptions.GamepadDeadStickValue) this.playerDeltaY = 0;
                if (Math.abs(this.playerMouseX) <= BABYLON.UserInputOptions.GamepadDeadStickValue) this.playerMouseX = 0;
                if (Math.abs(this.playerMouseY) <= BABYLON.UserInputOptions.GamepadDeadStickValue) this.playerMouseY = 0;

                const auxForwardKeyboard:boolean = BABYLON.SceneManager.GetKeyboardInput(this.auxKeyboardForawrd); // Player One Only
                const forwardKeyboard:boolean = BABYLON.SceneManager.GetKeyboardInput(this.keyboardForawrd); // Player One Only
                const forwardTrigger:number = BABYLON.SceneManager.GetGamepadTriggerInput(this.triggerForward, this.playerNumber);
                const auxBackwardKeyboard:boolean = BABYLON.SceneManager.GetKeyboardInput(this.auxKeyboardBackwards); // Player One Only
                const backwardKeyboard:boolean = BABYLON.SceneManager.GetKeyboardInput(this.keyboardBackwards); // Player One Only
                const backwardTrigger:number = BABYLON.SceneManager.GetGamepadTriggerInput(this.triggerBackwards, this.playerNumber);
                const handbrakeKeyboard:boolean = BABYLON.SceneManager.GetKeyboardInput(this.keyboardHandbrake); // Player One Only
                const handbrakeButton:boolean = BABYLON.SceneManager.GetGamepadButtonInput(this.buttonHandbrake, this.playerNumber);

                let playerMovement:number = 0;
                let playerSteering:number = 0;
                let playerHandbrake:boolean = false;

                // Primary Accelerattion
                if (forwardTrigger > 0.2) playerMovement = forwardTrigger;
                else if (this.playerNumber === BABYLON.PlayerNumber.One && (forwardKeyboard === true || auxForwardKeyboard === true)) playerMovement = 1;
                // Braking Takes Precedence
                if (backwardTrigger > 0.2) playerMovement = -backwardTrigger;
                else if (this.playerNumber === BABYLON.PlayerNumber.One && (backwardKeyboard === true || auxBackwardKeyboard === true)) playerMovement = -1;
                // Includes AD And Arrow Keys
                playerSteering = this.playerDeltaX; 
                // Pull Hard Hand Brake Lever
                playerHandbrake = (handbrakeKeyboard === true || handbrakeButton === true);
                // Drive Standard Car Controller
                this.m_standardCarController.drive(playerMovement, playerSteering, playerHandbrake);
            }
        }
    }

The Babylon Scene Manager User Input Functions gives you more a Unity Like game mechanicsā€¦

I can call BABYLON.SceneManager.GetUserInput in the update loop directly to get that User Input weather from keyboard and mouse, Virtual Joysticks or GamePadsā€¦ Also support up to 4 Local player User Inputā€¦ Its the heart of all my Local Multi Player Supportā€¦ All built inā€¦ and all on the playground now :slight_smile:

Yo @Pryme8 ā€¦ I wrote the most awesome Skidmark Manager Class (Againā€¦ Using Unity Style Game Mechanicsā€¦ Actually ported from the UnitySkidmarks.cs)

My Babylon Version:
1ā€¦Set up a large EMPTY mesh to hold the skidmarks for all the cars
2ā€¦ Each carā€™s wheel call AddSkidmarkSegment when the wheill it actually skidding
3ā€¦ I update the actual underlying Float32Array directly adding new skid segments
4ā€¦ A global update runs and applies all the Float32Array buffers Directly to mesh vertex buffer

And we end up with a High Performance skidmarks with virtually no addition overheadā€¦ Unless you make REALLY LARGE skidmark meshā€¦ But anything under 65000 vertsā€¦ About 4096 max Skidmark segments, take no additional MS

Check out my SkidmarkManager.ts


/**
 * Babylon skidmark section class (Native Bullet Physics 2.82)
 * @class SkidmarkSection
 */
class SkidmarkSection {
    public Pos:BABYLON.Vector3 = BABYLON.Vector3.Zero();
    public Normal:BABYLON.Vector3 = BABYLON.Vector3.Zero();
    public Tangent:BABYLON.Vector4 = BABYLON.Vector4.Zero();
    public Posl:BABYLON.Vector3 = BABYLON.Vector3.Zero();
    public Posr:BABYLON.Vector3 = BABYLON.Vector3.Zero();
    public Intensity:number = 0.0;
    public LastIndex:number = -1;
}
/**
 * Babylon Script Component
 * @class SkidmarkManager
 */
class SkidmarkManager extends BABYLON.ScriptComponent {
	private static MAX_MARKS:number = 4096;                                 // Max number of marks total for everyone together
    private static GROUND_OFFSET:number = 0.01;                             // Distance above surface in metres
	private static VELOCITY_SCALE:number = 0.02;                            // Velocity offset scale factor
    private static GPU_TRIANGLES:boolean = true;                            // GPU quad triangle indices only
    private static MARK_COLOR:BABYLON.Color3 = BABYLON.Color3.Black();      // Skidmark Color
	private static MARK_WIDTH:number = 0.3;                                 // Width of the Skidmarks. Should match the width of the wheels
	private static MIN_DISTANCE:number = 0.1;                               // Distance between skid texture sections in metres. Bigger = better performance, less smooth
    private static MIN_SQR_DISTANCE = (SkidmarkManager.MIN_DISTANCE * SkidmarkManager.MIN_DISTANCE);
    private static TEXTURE_MARKS:any = null;

    private static SkidBufferPositions:Float32Array = null;
    private static SkidBufferNormals:Float32Array = null;
    private static SkidBufferTangents:Float32Array = null;
    private static SkidBufferColors:Float32Array = null;
    private static SkidBufferUvs:Float32Array = null;
    private static SkidBufferIndices:Int32Array = null;
	private static SkidmarkSections:SkidmarkSection[] = null;
	private static SkidmarkIndex:number = 0;
	private static SkidmarkMesh:BABYLON.Mesh = null;
    private static SkidmarkUpdated:boolean = false;

    private static TempVector3_POS:BABYLON.Vector3 = new BABYLON.Vector3(0,0,0);
    private static TempVector3_DIR:BABYLON.Vector3 = new BABYLON.Vector3(0,0,0);
    private static TempVector3_XDIR:BABYLON.Vector3 = new BABYLON.Vector3(0,0,0);
    private static TempVector3_SDIR:BABYLON.Vector3 = new BABYLON.Vector3(0,0,0);
    public constructor(transform: BABYLON.TransformNode, scene: BABYLON.Scene, properties: any = {}) {
        super(transform, scene, properties);
        SkidmarkManager.MAX_MARKS = this.getEditorProperty("maxSections", SkidmarkManager.MAX_MARKS);
        SkidmarkManager.MARK_COLOR = BABYLON.Utilities.ParseColor3(this.getEditorProperty("textureColor", SkidmarkManager.MARK_COLOR));
        SkidmarkManager.MARK_WIDTH = this.getEditorProperty("textureWidth", SkidmarkManager.MARK_WIDTH);
        SkidmarkManager.GROUND_OFFSET = this.getEditorProperty("groundOffset", SkidmarkManager.GROUND_OFFSET);
        SkidmarkManager.VELOCITY_SCALE = this.getEditorProperty("velocityScale", SkidmarkManager.VELOCITY_SCALE);
        SkidmarkManager.GPU_TRIANGLES = this.getEditorProperty("gpuQuadIndices", SkidmarkManager.GPU_TRIANGLES);
        SkidmarkManager.TEXTURE_MARKS = this.getEditorProperty("textureMarks", SkidmarkManager.TEXTURE_MARKS);
        SkidmarkManager.MIN_DISTANCE = this.getEditorProperty("textureDistance", SkidmarkManager.MIN_DISTANCE);
        SkidmarkManager.MIN_SQR_DISTANCE = (SkidmarkManager.MIN_DISTANCE * SkidmarkManager.MIN_DISTANCE);
    }

    protected start(): void { SkidmarkManager.CreateSkidmarkManager(this.scene); }
    protected update(): void { SkidmarkManager.UpdateSkidmarkManager(); }

    public static GetVelocityScale():number { return SkidmarkManager.VELOCITY_SCALE; }

    public static AddSkidmarkSegment(pos:BABYLON.Vector3, normal:BABYLON.Vector3, intensity:number, lastIndex:number):BABYLON.Nullable<number> {
        if (SkidmarkManager.SkidmarkMesh == null) return null;
        SkidmarkManager.TempVector3_POS.set(0,0,0);
        SkidmarkManager.TempVector3_DIR.set(0,0,0);
        SkidmarkManager.TempVector3_XDIR.set(0,0,0);
        SkidmarkManager.TempVector3_SDIR.set(0,0,0);
        // ..
        if (intensity > 1.0) intensity = 1.0;
        else if (intensity < 0.0) return -1.0;
        // ..
		if (lastIndex > 0) {
            pos.subtractToRef(SkidmarkManager.SkidmarkSections[lastIndex].Pos, SkidmarkManager.TempVector3_POS);
			const sqrDistance:number = SkidmarkManager.TempVector3_POS.lengthSquared();
            if (sqrDistance < SkidmarkManager.MIN_SQR_DISTANCE) return lastIndex;
        }
        // ..
		const curSection:SkidmarkSection = SkidmarkManager.SkidmarkSections[SkidmarkManager.SkidmarkIndex];
        normal.scaleToRef(SkidmarkManager.GROUND_OFFSET, SkidmarkManager.TempVector3_POS);
        pos.addToRef(SkidmarkManager.TempVector3_POS, curSection.Pos);
		curSection.Normal.copyFrom(normal);
		curSection.Intensity = intensity;
        curSection.LastIndex = lastIndex;
        // ..
        if (lastIndex != -1) {
            const lastSection:SkidmarkSection = SkidmarkManager.SkidmarkSections[lastIndex];
            curSection.Pos.subtractToRef(lastSection.Pos, SkidmarkManager.TempVector3_DIR);
            BABYLON.Vector3.CrossToRef(SkidmarkManager.TempVector3_DIR, normal, SkidmarkManager.TempVector3_XDIR);
            SkidmarkManager.TempVector3_XDIR.normalizeToRef(SkidmarkManager.TempVector3_XDIR);
            // ..
            SkidmarkManager.TempVector3_XDIR.scaleToRef(SkidmarkManager.MARK_WIDTH * 0.5, SkidmarkManager.TempVector3_SDIR)
            curSection.Pos.addToRef(SkidmarkManager.TempVector3_SDIR, curSection.Posl);
            curSection.Pos.subtractToRef(SkidmarkManager.TempVector3_SDIR, curSection.Posr);
            curSection.Tangent.set(SkidmarkManager.TempVector3_XDIR.x, SkidmarkManager.TempVector3_XDIR.y, SkidmarkManager.TempVector3_XDIR.z, 1);
            // ..
			if (lastSection.LastIndex === -1) {
                curSection.Pos.addToRef(SkidmarkManager.TempVector3_SDIR, lastSection.Posl);
                curSection.Pos.subtractToRef(SkidmarkManager.TempVector3_SDIR, lastSection.Posr);
                lastSection.Tangent.copyFrom(curSection.Tangent);
			}
        }
        // ..
        SkidmarkManager.AddSkidmarkVertexData();
		const curIndex:number = SkidmarkManager.SkidmarkIndex;
		SkidmarkManager.SkidmarkIndex = ++SkidmarkManager.SkidmarkIndex % SkidmarkManager.MAX_MARKS;
		return curIndex;
    }
    private static CreateSkidmarkManager(scene:BABYLON.Scene):void {
        if (SkidmarkManager.SkidmarkMesh == null) {
            const skidmarkMaterial:BABYLON.StandardMaterial = new BABYLON.StandardMaterial("SkidmarkMaterial", scene);
            skidmarkMaterial.backFaceCulling = false;
            skidmarkMaterial.disableLighting = true;
            skidmarkMaterial.emissiveColor = SkidmarkManager.MARK_COLOR;
            skidmarkMaterial.diffuseColor = SkidmarkManager.MARK_COLOR;
            skidmarkMaterial.diffuseTexture = BABYLON.Utilities.ParseTexture(SkidmarkManager.TEXTURE_MARKS, scene);
            if (skidmarkMaterial.diffuseTexture != null) {
                skidmarkMaterial.diffuseTexture.hasAlpha = true;
                skidmarkMaterial.useAlphaFromDiffuseTexture = true;
            }
            skidmarkMaterial.freeze();
            SkidmarkManager.SkidmarkMesh = new BABYLON.Mesh("SkidmarkMesh", scene);
            SkidmarkManager.SkidmarkMesh.material = skidmarkMaterial;
            SkidmarkManager.SkidmarkMesh.alwaysSelectAsActiveMesh = true;
            SkidmarkManager.SkidmarkMesh.doNotSyncBoundingInfo = true;
            SkidmarkManager.SkidmarkMesh.receiveShadows = false;
            SkidmarkManager.SkidmarkMesh.checkCollisions = false;
            SkidmarkManager.SkidmarkMesh.useVertexColors = true;
            SkidmarkManager.SkidmarkMesh.hasVertexAlpha = true;
            SkidmarkManager.SkidmarkMesh.isPickable = false;
            // ..
            // Setup Skidmark Section Properties
            // ..
            SkidmarkManager.SkidmarkSections = new Array<SkidmarkSection>(SkidmarkManager.MAX_MARKS);
            for (let i = 0; i < SkidmarkManager.SkidmarkSections.length; i++) {
                SkidmarkManager.SkidmarkSections[i] = new SkidmarkSection();
            }
            // ..
            // Setup Raw Mesh Vertex Buffer Data
            // ..
            SkidmarkManager.SkidBufferPositions = new Float32Array(SkidmarkManager.MAX_MARKS * 4 * 3);
            SkidmarkManager.SkidBufferNormals = new Float32Array(SkidmarkManager.MAX_MARKS * 4 * 3);
            SkidmarkManager.SkidBufferTangents = new Float32Array(SkidmarkManager.MAX_MARKS * 4 * 4);
            SkidmarkManager.SkidBufferColors = new Float32Array(SkidmarkManager.MAX_MARKS * 4 * 4);
            SkidmarkManager.SkidBufferUvs = new Float32Array(SkidmarkManager.MAX_MARKS * 4 * 2);
            SkidmarkManager.SkidBufferIndices = new Int32Array(SkidmarkManager.MAX_MARKS * 6);
            // ..
            // Apply Raw Vertex Buffer Data To Mesh
            // ..
            const vertexData = new BABYLON.VertexData();
            vertexData.positions = SkidmarkManager.SkidBufferPositions;
            vertexData.normals = SkidmarkManager.SkidBufferNormals;
            vertexData.tangents = SkidmarkManager.SkidBufferTangents;
            vertexData.colors = SkidmarkManager.SkidBufferColors;
            vertexData.uvs = SkidmarkManager.SkidBufferUvs;            
            vertexData.indices = SkidmarkManager.SkidBufferIndices;
            vertexData.applyToMesh(SkidmarkManager.SkidmarkMesh, true);
            SkidmarkManager.SkidmarkMesh.freezeWorldMatrix();
        }
    }
    private static AddSkidmarkVertexData():void {
		const curr:SkidmarkSection = SkidmarkManager.SkidmarkSections[SkidmarkManager.SkidmarkIndex];
        if (curr.LastIndex === -1) return;
        const last:SkidmarkSection = SkidmarkManager.SkidmarkSections[curr.LastIndex];
		SkidmarkManager.SkidmarkUpdated = true;
        // ..
        // Update Position Buffers Directly
        // ..
        let index:number = SkidmarkManager.SkidmarkIndex * 4 + 0;
        SkidmarkManager.SkidBufferPositions[index * 3] = last.Posl.x;
        SkidmarkManager.SkidBufferPositions[(index * 3) + 1] = last.Posl.y;
        SkidmarkManager.SkidBufferPositions[(index * 3) + 2] = last.Posl.z;
        index = SkidmarkManager.SkidmarkIndex * 4 + 1;
        SkidmarkManager.SkidBufferPositions[index * 3] = last.Posr.x;
        SkidmarkManager.SkidBufferPositions[(index * 3) + 1] = last.Posr.y;
        SkidmarkManager.SkidBufferPositions[(index * 3) + 2] = last.Posr.z;
        index = SkidmarkManager.SkidmarkIndex * 4 + 2;
        SkidmarkManager.SkidBufferPositions[index * 3] = curr.Posl.x;
        SkidmarkManager.SkidBufferPositions[(index * 3) + 1] = curr.Posl.y;
        SkidmarkManager.SkidBufferPositions[(index * 3) + 2] = curr.Posl.z;
        index = SkidmarkManager.SkidmarkIndex * 4 + 3;
        SkidmarkManager.SkidBufferPositions[index * 3] = curr.Posr.x;
        SkidmarkManager.SkidBufferPositions[(index * 3) + 1] = curr.Posr.y;
        SkidmarkManager.SkidBufferPositions[(index * 3) + 2] = curr.Posr.z;
        // ..
        // Update Normal Buffers Directly
        // ..
        index = SkidmarkManager.SkidmarkIndex * 4 + 0;
        SkidmarkManager.SkidBufferNormals[index * 3] = last.Normal.x;
        SkidmarkManager.SkidBufferNormals[(index * 3) + 1] = last.Normal.y;
        SkidmarkManager.SkidBufferNormals[(index * 3) + 2] = last.Normal.z;
        index = SkidmarkManager.SkidmarkIndex * 4 + 1;
        SkidmarkManager.SkidBufferNormals[index * 3] = last.Normal.x;
        SkidmarkManager.SkidBufferNormals[(index * 3) + 1] = last.Normal.y;
        SkidmarkManager.SkidBufferNormals[(index * 3) + 2] = last.Normal.z;
        index = SkidmarkManager.SkidmarkIndex * 4 + 2;
        SkidmarkManager.SkidBufferNormals[index * 3] = curr.Normal.x;
        SkidmarkManager.SkidBufferNormals[(index * 3) + 1] = curr.Normal.y;
        SkidmarkManager.SkidBufferNormals[(index * 3) + 2] = curr.Normal.z;
        index = SkidmarkManager.SkidmarkIndex * 4 + 3;
        SkidmarkManager.SkidBufferNormals[index * 3] = curr.Normal.x;
        SkidmarkManager.SkidBufferNormals[(index * 3) + 1] = curr.Normal.y;
        SkidmarkManager.SkidBufferNormals[(index * 3) + 2] = curr.Normal.z;
        // ..
        // Update Tangent Buffers Directly
        // ..
        index = SkidmarkManager.SkidmarkIndex * 4 + 0;
        SkidmarkManager.SkidBufferTangents[index * 4] = last.Tangent.x;
        SkidmarkManager.SkidBufferTangents[(index * 4) + 1] = last.Tangent.y;
        SkidmarkManager.SkidBufferTangents[(index * 4) + 2] = last.Tangent.z;
        SkidmarkManager.SkidBufferTangents[(index * 4) + 3] = last.Tangent.w;
        index = SkidmarkManager.SkidmarkIndex * 4 + 1;
        SkidmarkManager.SkidBufferTangents[index * 4] = last.Tangent.x;
        SkidmarkManager.SkidBufferTangents[(index * 4) + 1] = last.Tangent.y;
        SkidmarkManager.SkidBufferTangents[(index * 4) + 2] = last.Tangent.z;
        SkidmarkManager.SkidBufferTangents[(index * 4) + 3] = last.Tangent.w;
        index = SkidmarkManager.SkidmarkIndex * 4 + 2;
        SkidmarkManager.SkidBufferTangents[index * 4] = curr.Tangent.x;
        SkidmarkManager.SkidBufferTangents[(index * 4) + 1] = curr.Tangent.y;
        SkidmarkManager.SkidBufferTangents[(index * 4) + 2] = curr.Tangent.z;
        SkidmarkManager.SkidBufferTangents[(index * 4) + 3] = curr.Tangent.w;
        index = SkidmarkManager.SkidmarkIndex * 4 + 3;
        SkidmarkManager.SkidBufferTangents[index * 4] = curr.Tangent.x;
        SkidmarkManager.SkidBufferTangents[(index * 4) + 1] = curr.Tangent.y;
        SkidmarkManager.SkidBufferTangents[(index * 4) + 2] = curr.Tangent.z;
        SkidmarkManager.SkidBufferTangents[(index * 4) + 3] = curr.Tangent.w;
        // ..
        // Update Color Buffers Directly
        // ..
        index = SkidmarkManager.SkidmarkIndex * 4 + 0;
        SkidmarkManager.SkidBufferColors[index * 4] = 1.0;
        SkidmarkManager.SkidBufferColors[(index * 4) + 1] = 1.0;
        SkidmarkManager.SkidBufferColors[(index * 4) + 2] = 1.0;
        SkidmarkManager.SkidBufferColors[(index * 4) + 3] = last.Intensity;
        index = SkidmarkManager.SkidmarkIndex * 4 + 1;
        SkidmarkManager.SkidBufferColors[index * 4] = 1.0;
        SkidmarkManager.SkidBufferColors[(index * 4) + 1] = 1.0;
        SkidmarkManager.SkidBufferColors[(index * 4) + 2] = 1.0;
        SkidmarkManager.SkidBufferColors[(index * 4) + 3] = last.Intensity;
        index = SkidmarkManager.SkidmarkIndex * 4 + 2;
        SkidmarkManager.SkidBufferColors[index * 4] = 1.0;
        SkidmarkManager.SkidBufferColors[(index * 4) + 1] = 1.0;
        SkidmarkManager.SkidBufferColors[(index * 4) + 2] = 1.0;
        SkidmarkManager.SkidBufferColors[(index * 4) + 3] = curr.Intensity;
        index = SkidmarkManager.SkidmarkIndex * 4 + 3;
        SkidmarkManager.SkidBufferColors[index * 4] = 1.0;
        SkidmarkManager.SkidBufferColors[(index * 4) + 1] = 1.0;
        SkidmarkManager.SkidBufferColors[(index * 4) + 2] = 1.0;
        SkidmarkManager.SkidBufferColors[(index * 4) + 3] = curr.Intensity;
        // ..
        // Update Coord Buffers Directly
        // ..
        index = SkidmarkManager.SkidmarkIndex * 4 + 0;
        SkidmarkManager.SkidBufferUvs[index * 2] = 0;
        SkidmarkManager.SkidBufferUvs[(index * 2) + 1] = 0;
        index = SkidmarkManager.SkidmarkIndex * 4 + 1;
        SkidmarkManager.SkidBufferUvs[index * 2] = 1;
        SkidmarkManager.SkidBufferUvs[(index * 2) + 1] = 0;
        index = SkidmarkManager.SkidmarkIndex * 4 + 2;
        SkidmarkManager.SkidBufferUvs[index * 2] = 0;
        SkidmarkManager.SkidBufferUvs[(index * 2) + 1] = 1;
        index = SkidmarkManager.SkidmarkIndex * 4 + 3;
        SkidmarkManager.SkidBufferUvs[index * 2] = 1;
        SkidmarkManager.SkidBufferUvs[(index * 2) + 1] = 1;
        // ..
        // Update Triangle 1 Buffers Directly (QUAD)
        //..
        SkidmarkManager.SkidBufferIndices[SkidmarkManager.SkidmarkIndex * 6 + 0] = SkidmarkManager.SkidmarkIndex * 4 + 0;
        SkidmarkManager.SkidBufferIndices[SkidmarkManager.SkidmarkIndex * 6 + 2] = SkidmarkManager.SkidmarkIndex * 4 + 1;
        SkidmarkManager.SkidBufferIndices[SkidmarkManager.SkidmarkIndex * 6 + 1] = SkidmarkManager.SkidmarkIndex * 4 + 2;
        // ..
        // Update Triangle 2 Buffers Directly (QUAD)
        // ..
        SkidmarkManager.SkidBufferIndices[SkidmarkManager.SkidmarkIndex * 6 + 3] = SkidmarkManager.SkidmarkIndex * 4 + 2;
        SkidmarkManager.SkidBufferIndices[SkidmarkManager.SkidmarkIndex * 6 + 5] = SkidmarkManager.SkidmarkIndex * 4 + 1;
        SkidmarkManager.SkidBufferIndices[SkidmarkManager.SkidmarkIndex * 6 + 4] = SkidmarkManager.SkidmarkIndex * 4 + 3;
    }
    private static UpdateSkidmarkManager():void {
        if (SkidmarkManager.SkidmarkMesh != null && SkidmarkManager.SkidmarkUpdated === true) {
            SkidmarkManager.SkidmarkUpdated = false;
            if (SkidmarkManager.SkidmarkMesh.geometry != null) {
                SkidmarkManager.SkidmarkMesh.geometry.updateVerticesDataDirectly(BABYLON.VertexBuffer.PositionKind, SkidmarkManager.SkidBufferPositions, 0, false);
                SkidmarkManager.SkidmarkMesh.geometry.updateVerticesDataDirectly(BABYLON.VertexBuffer.NormalKind, SkidmarkManager.SkidBufferNormals, 0, false);
                SkidmarkManager.SkidmarkMesh.geometry.updateVerticesDataDirectly(BABYLON.VertexBuffer.TangentKind, SkidmarkManager.SkidBufferTangents, 0, false);
                SkidmarkManager.SkidmarkMesh.geometry.updateVerticesDataDirectly(BABYLON.VertexBuffer.ColorKind, SkidmarkManager.SkidBufferColors, 0, false);
                SkidmarkManager.SkidmarkMesh.geometry.updateVerticesDataDirectly(BABYLON.VertexBuffer.UVKind, SkidmarkManager.SkidBufferUvs, 0, false);
                SkidmarkManager.SkidmarkMesh.geometry.updateIndices(SkidmarkManager.SkidBufferIndices, 0, SkidmarkManager.GPU_TRIANGLES);
            }
        }
    }
}

And it works beautifully well :slight_smile:

Ill show when we get playground ammo fixed :slight_smile:

Yo @Pryme8 ā€¦ I made a little video so you can get a look at it.

I dont know why my screen recorder is so shitty all of the sudden. I gotta get better screen recording software for the mac.

Anywaysā€¦ Take a look to see my progress on creating native Ammo.JS Driving Physics.

All the track peices are meshes with mesh colliders (mesh impostors) using native Bullet Raycast Vehicleā€¦ Hundreds of Scene Enviroments meshes ā€¦ Very detailed Mustang modelā€¦ All rocking 60 FPSā€¦

My high speed follow camera is fucked upā€¦ Thats why car so far ahead of cameraā€¦ so i can at least get that turn lagā€¦ At it still jitters every now and thenā€¦ But that is what you and i working on fixingā€¦ I think you be able to better make the follow camera once i get you setup in da playground with all this Physics Stuff :slight_smile:

Check out: http://mackey.cloud/files/videos/TestLap1.mp4

Yo @Pryme8 ā€¦ Here is a playground to test (Once the Painting issue gets fixed)

Test Race Track Playground: Babylon.js Playground

use the WASD or ARROW Keys or Gamepad to drive the car.

The Space Bar and Gamepad X Button is For Handbrake for Skidding/Drifting

The Gamepad Triggers Accelerate and Brake As Well :slight_smile:

Try it out

1 Like

image

Something is happeningā€¦ lol

Yo @MarianG found the problem. I fixed the Scene Managerā€¦ Try Again Please :slight_smile:

FYIā€¦ Here is Another Playground Test with the native Babylon Follow Cameraā€¦ To show what i going forā€¦ has Jitter problems and cant have different lagging for the BEHIND position and the LEFT/RIGHT Turn .

But you can take a lap around the trackā€¦ Should have Audience Audio when racing by the crowds :slight_smile:

Note: When driving try go Full Screen ā€¦ Way better since the Playground Editor takes up browser window space

Alsoā€¦ I did in typescript and included the Babylon Scene Manager declaration file at bottom so you can get code completion and get a since of What the Scene Manager Can Do :slight_smile:

1 Like

https://www.babylonjs-playground.com/ts.html#3BIQ4K#3

It will need some fixing, but here is the basic steps. I ran into the wall and got the car on it side, and everything still works great.

I tested your scene with the default camera, Iā€™m not seeing the jitter?

Try and get up to high speedsā€¦ Every now and then the car will jitter/skip a little forward or backwardsā€¦

I tried on both my Mac and Dellā€¦ And i always get that little jitter/skipā€¦ Not a constant jitterā€¦ but take a few laps and watch the car and the backgroundā€¦ I can see it

But if i attach the camera as a child and drive its really smoothā€¦ But you loose all the LAGGING.

Thats why i suggested that camera boom or camera spring arm approachā€¦

I am open to Whateverā€¦ And whoever want to give a crackā€¦ I just need to end up with SMOOTHEST high speed camera movement i canā€¦ When its choppy, its makes the game look like shitā€¦ I spent alot of time writing logic (Especially Physics Code) for Pro Vehicle SDKā€¦ And i eventually want to use my Race Game Project to create a full blown Babylon Game Development Training Courseā€¦ So i want all the mechanics as perfect as possible.

And i REALLY appreciate all your helpā€¦ Everyone :slight_smile:

Im just really stoked about running Pure Babylon Scene Manager content on the Playgroundā€¦ That just proves my point of what i been saying about the Toolkitā€¦

Its All the Babylon Scene Manager Extension that does all the magic. The Unity Exporter is really just a fancy GLTF exporter that serializes a bit of extra metadata and it also bundles all your project script and has an OPTIONAL Preview Engine to view GLTF contentā€¦ That itā€¦ Now its very detailed in its exportā€¦ But it is just an Exporter (With a ton of Tooling to help create the best GLTF i can possibly make)

The Babylon Scene Manager is the real star of the show :slight_smile:

1 Like

Technically it is a camera boom setup, the height is angle the distance is the arm length.

If you want it to be more swingy then we activate the swivel that I was showing you in the first scene (the param you asked about) and we interpolate some sort of value from what the cars speed is and turn ratio.

Ok I see the jitter now:
https://www.babylonjs-playground.com/ts.html#3BIQ4K#4

hmmmm I feel like that is how the car is being updated for some reason.

https://www.babylonjs-playground.com/ts.html#3BIQ4K#5

I know this sounds like it might be dumbā€¦ but I LERPED the LERP (derpa dooo)ā€¦ and that seems to of fixed the jumps so what. Which meansā€¦ I dont knowā€¦ I figured doing a single one with half the value would effectively do the same, but Iā€™m not sureā€¦ I honestly think the culprit is the jumpy updates to position from the physics engine.

Btw the double LERP thing was a jokeā€¦ I donā€™t think that would ever really fix somethingā€¦

I dunno eitherā€¦ but try attaching camera as child of Mustang transform node with an offset to be be behindā€¦ take a few laps like thatā€¦ I donā€™t get any skips thenā€¦ So that says to me itā€™s not the physics moving the car thatā€™s the problemā€¦ I would think :thinking:

I tell you though, out of the complex issues I encountered while making the toolkitā€¦ A smooth camera has been one of the more difficult things to get right.

But if we can get that goingā€¦ thatā€™s is the making of a web based racing game

What is the latest update we can do to the camera? Timing wise? I bet thatā€™s our problem.

Give me a second

Give this a shot:
https://www.babylonjs-playground.com/ts.html#3BIQ4K#8

Another option is if you are saying that when we parent it to the car there is no chop, lets go with that, and then just manipulate its relative position and target in accordance to the cars stats, like speed and turn amount.