Blender – Python – Simulation – Traffic Jam / Embouteillage

Python code to create and animate a simulation of Traffic Jam with Blender. You choose the number of cars and many other things


Code python pour créer et animer des embouteillages avec Blender. Vous choisissez le nombre de voitures et plein d’autres choses.

The only thing you need is a car model object named Car_Model

La seule chose dont vous aurez besoin c’est un objet qui sert de modèle de voiture et qui sera nommé Car_Model

import bpy
import numpy as np
import math
import random

# ********************************************************************
# Traffic Jam Simulator
# Blender version = 2.8
# Author = Doc OuatZat (DOZ) and by the way is creator (Patrick M)
# Web Site = docouatzat.com
# Mail = docouatzat@gmail.com
#
# Licence used = Creative Commons CC BY
# Check licence here : https://creativecommons.org
#
# Master variables :
#   SegCount = Mean the number of segments, one segment must be empty
#              or containing a car
#   LaneCount = Mean the number of Lane. This code is designed for 1 lane only
#   CarCount = Mean the number of cars
# ********************************************************************

# Design the Road
# The segment represent place to put one car (SizeCarX) or nothing
SegCount = 500
LaneCount = 1  # Must be a pure divider of SegCount
Road_Segments = np.zeros(((LaneCount + 1), (SegCount + 1)), dtype=int)

# Coef (divide by) for interpolate the road to screen
# Cars touching
CoefBlender = SegCount / 50

# Design the car
# 5 meters / 2,5 meters (x,y)
# You can use everything you want
obj_Model_Name = 'Car_Model'
SizeCarX = 5  # mean also the size of one segment
SizeCarY = 2.5
SizeOfRoad = SegCount * SizeCarX
# transform speed in km/h into segment unit in second
CoefSpeed = 1 / 3600 * 1000 / SizeCarX

# in Km/h
SpeedWish = 130

# Material Index StopLight
Mat_Idx_SL_Off = 1
Mat_Idx_SL_On = 5

CarCount = 32
# I know, I can use multidimmensionnal array but I won't
Car_Pos = np.zeros(((CarCount + 1), 3), dtype=int)  # 1 - lane, 2 - segment
Car_Rot = np.zeros((CarCount + 1), dtype=int)  # For managing rotations
Car_Speed = np.zeros((CarCount + 1), dtype=int)  # Speed in Km/h


# Research about a collection
def find_collection(context, item):
    collections = item.users_collection
    if len(collections) > 0:
        return collections[0]
    return context.scene.collection


# Create collection
def create_collection(collection_name, parent_collection):
    if collection_name in bpy.data.collections:
        return bpy.data.collections[collection_name]
    else:
        new_collection = bpy.data.collections.new(collection_name)
        parent_collection.children.link(new_collection)
        return new_collection


# Assign object to collection
def assign_to_collection(collect, ob):
    # Find actual collection to remove object for
    collect_to_unlink = find_collection(bpy.context, ob)
    # Assign object into collection
    collect.objects.link(ob)


# Initial State
# Create the number of cars choosing (by duplicating the car model)
# And place them belong the lanes of the road
def initial_state(collect):
    # Design the road

    # Dispatch cars on the road
    # For sample here we use the dispatch fair
    # Same amount of car by lane

    # Init the road
    for lane in range(1, LaneCount + 1):
        for segment in range(1, SegCount + 1):
            Road_Segments[lane, segment] = 0

    # Init car on the road
    CarCountByLane = (CarCount + 1) / LaneCount
    CarSpaceByLane = (SegCount + 1) / CarCountByLane
    TotalSegment = LaneCount * SegCount
    for car in range(1, CarCount + 1):
        lane = round((CarSpaceByLane * car)) // SegCount + 1
        segment = round((CarSpaceByLane * car)) % SegCount
        Road_Segments[lane, segment] = car
        Car_Pos[car, 1] = lane
        Car_Pos[car, 2] = segment

    # Design all cars
    for car in range(1, CarCount + 1):
        # Reproduce Model
        obj_Name = 'Car_' + str(car)
        ob = bpy.data.objects[obj_Model_Name]
        new_ob = bpy.data.objects.new(obj_Model_Name, ob.data.copy())
        assign_to_collection(collect, new_ob)
        new_ob.name = obj_Name
        new_ob.scale = 2.0, 2.0, 2.0
        if car == 10:
            mesh = new_ob.data
            for f in mesh.polygons:  # iterate over faces
                if f.material_index == 2:
                    f.material_index = 6
                    f.keyframe_insert('material_index')


# Redraw all car at their respectives positions
def redraw_car(scn):
    z = 1.2
    rx = math.radians(90)
    ry = 0
    theta = math.radians(360)  # 2Pi
    alpha = theta / SegCount
    for car in range(1, CarCount + 1):
        obj_Name = 'Car_' + str(car)
        ob = bpy.data.objects[obj_Name]

        # Place it
        lane = Car_Pos[car, 1]
        segment = Car_Pos[car, 2]
        angle = segment * alpha

        x = (SizeOfRoad * math.cos(angle) / CoefBlender) * (1 + (lane / 19))
        y = (SizeOfRoad * math.sin(angle) / CoefBlender) * (1 + (lane / 19))

        rot = math.radians(math.degrees(angle) + (360 * Car_Rot[car]) - 90)

        ob.location = (x, y, z)
        ob.keyframe_insert('location')
        ob.rotation_euler = (rx, ry, rot)
        ob.keyframe_insert('rotation_euler')


# Give space between car and car in front of
# reel space + freed space by supposed car in front speed
# return space_IFO in segment unit
def get_space_IFO(car) -> int:
    curlane = Car_Pos[car, 1]
    curseg = Car_Pos[car, 2]
    space_IFO = 0
    while 1 == 1:
        curseg += 1
        space_IFO += 1
        if curseg > SegCount:
            curseg = 1
        if (Road_Segments[curlane, curseg] != 0):
            Car_IFO = Road_Segments[curlane, curseg]
            Speed_Car_IFO = Car_Speed[Car_IFO]
            break
    return space_IFO


# calculate the new speed for a car
def new_speed(car, space_IFO) -> int:
    # Search the speed limit to preserve speed objective and security distance
    Speed = Car_Speed[car]

    # if speed < wish speed then attempt to accelerate a bit (10 percents)
    if (Speed < SpeedWish):
        if Speed == 0:
            Speed = SpeedWish // 10
        else:
            Speed = Speed + round(Speed * 0.10)
        if (Speed > SpeedWish):
            Speed = SpeedWish

    # and now check if the speed choosen is acceptable for security reason
    # if not, adapt it
    space_IFO = space_IFO * SizeCarX  # set space_IFO in meters
    Secure_Dist = (Speed * 0.55) * 1.35
    quantum = round(Speed * 0.10)
    while space_IFO < Secure_Dist:
        # Slow down a bit (10 percents)
        Speed = Speed - quantum
        Secure_Dist = (Speed * 0.55) * 1.35
        # In case of full stop
        if (Speed < 0):
            Speed = 0
            break
    return Speed  # km/h


# ------------------
# MAIN
# ------------------

bpy.ops.transform.translate(value=(1, 1, 1))

# Create a new collection
newCol = create_collection("Cars", bpy.context.scene.collection)

# Set the initial state
initial_state(newCol)

# Set the cars behavior
# and the default speed
# speed mean speed in km/h
for i in range(1, CarCount + 1):
    Car_Speed[i] = SpeedWish

# ----------
# Simulation
# ----------

# Set animation start
scn = bpy.context.scene
scn.frame_current = 1

# Draw initial state
redraw_car(scn)

# 60 here, mean 60 seconds
for t in range(1, 400):
    # Animate all individual car with type of behavior
    # part 1 - for segment position
    for car in range(1, CarCount + 1):
        space_IFO = 0
        curlane = Car_Pos[car, 1]
        curseg = Car_Pos[car, 2]
        curspeed = Car_Speed[car]

        # Each Car try to run at maximum speed (speedwish)
        # Remove car on actual segment
        Road_Segments[curlane, curseg] = 0
        # Set the new car segment position
        space_IFO = get_space_IFO(car)
        speed = new_speed(car, space_IFO)

        # Slow down one car
        if (car == 10) and (t > 20 and t < 40):
            speed = SpeedWish // 6

        Car_Speed[car] = speed
        Car_Pos[car, 2] += round(speed * CoefSpeed)

        # Assume the road is a circle
        # and count number of pass to Pos 0 for managing angle
        if Car_Pos[car, 2] > SegCount:
            Car_Pos[car, 2] = Car_Pos[car, 2] - SegCount
            Car_Rot[car] += 1
        # Set car on new segment
        Road_Segments[Car_Pos[car, 1], Car_Pos[car, 2]] = car

    # Add 6 frames
    scn.frame_current += 6

    # Draw initial state
    redraw_car(scn)

scn.frame_end = scn.frame_current + 25

# End of script - Enjoy


To learn how using Python code into Blender click here

Pour apprendre comment utiliser du code Python dans Blender, cliquez ici


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.