> For the complete documentation index, see [llms.txt](https://docs.mapbox.com/mapbox-gl-js/ja/llms.txt)

# Add 3D model with source-driven interactions

This example illustrates a source-driven method for overriding the materials and orientation of model parts using [`model`](https://docs.mapbox.com/style-spec/reference/layers/#model) layer and [`model-source`](https://docs.mapbox.com/style-spec/reference/sources/#model).

To control material properties and model part orientations, the model source is updated directly using [`setModels`](https://docs.mapbox.com/mapbox-gl-js/ja/api/sources/#modelsource#setmodels). This approach is efficient, particularly for bulk updates.

> **Related content (example): [Add 3D model with style-driven interactions](https://docs.mapbox.com/mapbox-gl-js/ja/example/add-3d-model-with-interactions-style-driven/)**
> 
> For an alternative method that declares model overrides using expressions directly in the style, see this example.

> Example code:

**JavaScript**

```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Add 3D model with source-driven interactions</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<link href="https://api.mapbox.com/mapbox-gl-js/v3.30.0/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v3.30.0/mapbox-gl.js"></script>
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/tweakpane@3.1.4/dist/tweakpane.min.js"></script>
<div id="map"></div>

<script>
    const style = {
        'version': 8,
        'glyphs': 'mapbox://fonts/mapbox/{fontstack}/{range}.pbf',
        'lights': [
            {
                'type': 'ambient',
                'id': 'environment',
                'properties': {
                    'intensity': 0.4
                }
            },
            {
                'type': 'directional',
                'id': 'sun_light',
                'properties': {
                    'cast-shadows': true
                }
            }
        ],
        'sources': {
            // Set up model source
            '3d-model-source': {
                'type': 'model',
                'models': {
                    'car': {
                        'uri': 'https://docs.mapbox.com/mapbox-gl-js/assets/ego_car.glb',
                        'position': [-74.0138, 40.7154],
                        'orientation': [0, 0, 0]
                    }
                }
            }
        },
        'layers': [
            {
                'id': 'background',
                'type': 'background',
                'paint': {
                    'background-color': 'lightgray'
                }
            },
            // Model layer using model source '3d-model-source'.
            {
                'id': '3d-model-layer-for-source-based-updates',
                'type': 'model',
                'source': '3d-model-source',
                'paint': {
                    'model-scale': [10, 10, 10],
                    'model-type': 'location-indicator'
                }
            }
        ]
    };

    const map = (window.map = new mapboxgl.Map({
        // TO MAKE THE MAP APPEAR YOU MUST
        // ADD YOUR ACCESS TOKEN FROM
        // https://account.mapbox.com
        accessToken: 'YOUR_MAPBOX_ACCESS_TOKEN',
        container: 'map',
        devtools: true,
        projection: 'globe',
        style,
        pitch: 60,
        zoom: 19.3,
        bearing: 45,
        center: [-74.01372, 40.71535]
    }));

    const vehicleParams = {
        doorsFrontLeft: 0.5,
        doorsFrontRight: 0,
        trunk: 0,
        hood: 0,
        brakeLights: 0,
        color: { r: 255, g: 255, b: 255, a: 1 }
    };

    function mix(t, a, b) {
        return b * t - a * (t - 1);
    }

    function updateModelState() {
        const doorOpeningDegMax = 80;

        // Update contents of model source
        const modelSource = map.getSource('3d-model-source');
        if (modelSource) {
            const modelsSpec = {
                'car': {
                    'uri': 'https://docs.mapbox.com/mapbox-gl-js/assets/ego_car.glb',
                    'position': [-74.0138, 40.7154],
                    'orientation': [0, 0, 0],
                    'materialOverrides': {
                        'body': {
                            'model-color': [
                                vehicleParams.color.r / 255.0,
                                vehicleParams.color.g / 255.0,
                                vehicleParams.color.b / 255.0
                            ],
                            'model-color-mix-intensity': 1.0
                        },
                        'lights_brakes': {
                            'model-color': [0.88, 0.0, 0.0],
                            'model-color-mix-intensity':
                                vehicleParams.brakeLights,
                            'model-emissive-strength': vehicleParams.brakeLights
                        },
                        'lights-brakes_reverse': {
                            'model-color': [0.88, 0.0, 0.0],
                            'model-color-mix-intensity':
                                vehicleParams.brakeLights,
                            'model-emissive-strength': vehicleParams.brakeLights
                        },
                        'lights_brakes_volume': {
                            'model-color': [0.88, 0.0, 0.0],
                            'model-color-mix-intensity': 1.0,
                            'model-emissive-strength': 0.8,
                            'model-opacity': vehicleParams.brakeLights
                        },
                        'lights-brakes_reverse_volume': {
                            'model-color': [0.88, 0.0, 0.0],
                            'model-color-mix-intensity': 1.0,
                            'model-emissive-strength': 0.8,
                            'model-opacity': vehicleParams.brakeLights
                        }
                    },
                    'nodeOverrides': {
                        'doors_front-left': {
                            'orientation': [
                                0.0,
                                mix(
                                    vehicleParams.doorsFrontLeft,
                                    0,
                                    -doorOpeningDegMax
                                ),
                                0.0
                            ]
                        },
                        'doors_front-right': {
                            'orientation': [
                                0.0,
                                mix(
                                    vehicleParams.doorsFrontRight,
                                    0,
                                    doorOpeningDegMax
                                ),
                                0.0
                            ]
                        },
                        'hood': {
                            'orientation': [
                                mix(vehicleParams.hood, 0, 45),
                                0.0,
                                0.0
                            ]
                        },
                        'trunk': {
                            'orientation': [
                                mix(vehicleParams.trunk, 0, -60),
                                0.0,
                                0.0
                            ]
                        }
                    }
                }
            };

            modelSource.setModels(modelsSpec);
        }
    }

    // Set up UI for parameters
    {
        // eslint-disable-next-line no-undef
        const pane = new Tweakpane.Pane();

        const carFolder = pane.addFolder({ title: 'Car' });

        carFolder
            .addInput(vehicleParams, 'color', {
                label: 'Vehicle Color',
                picker: 'inline'
            })
            .on('change', updateModelState);

        carFolder
            .addInput(vehicleParams, 'trunk', {
                label: 'Trunk',
                min: 0,
                max: 1.0
            })
            .on('change', updateModelState);

        carFolder
            .addInput(vehicleParams, 'hood', {
                label: 'Hood',
                min: 0,
                max: 1.0
            })
            .on('change', updateModelState);

        carFolder
            .addInput(vehicleParams, 'doorsFrontLeft', {
                label: 'Front Left',
                min: 0,
                max: 1.0
            })
            .on('change', updateModelState);

        carFolder
            .addInput(vehicleParams, 'doorsFrontRight', {
                label: 'Front Right',
                min: 0,
                max: 1.0
            })
            .on('change', updateModelState);

        carFolder
            .addInput(vehicleParams, 'brakeLights', {
                label: 'Brake',
                min: 0,
                max: 1.0
            })
            .on('change', updateModelState);
    }

    map.on('load', () => {
        updateModelState();
    });
</script>

</body>
</html>
```