Three.js搭建小米SU7三维汽车实战(6)颜色切换

发布于:2025-06-02 ⋅ 阅读:(20) ⋅ 点赞:(0)

颜色切换
接下来我们来实现懂车帝的颜色切换效果
可以让ai帮我们生成页面结构以及样式,注意changeCarBodyColor这个函数需要我们自己来写

// 创建颜色选择器UI
function createColorSelector() {
  const colors = [
    { name: "深海蓝", hex: "#1A9CB0" },
    { name: "玛瑙红", hex: "#A00039" },
    { name: "橄榄绿", hex: "#6E7555" },
    { name: "雅灰", hex: "#D6D7D9" },
    { name: "紫檀", hex: "#614C63" }
  ];

  const container = document.createElement("div");
  container.className = "color-selector";

  colors.forEach((color, index) => {
    const colorBtn = document.createElement("div");
    colorBtn.className = "color-btn";
    colorBtn.setAttribute("data-color", color.hex);
    colorBtn.style.backgroundColor = color.hex;
    
    // 默认选中第一个
    if (index === 0) {
      colorBtn.classList.add('active');
    }

    // 颜色名称标签
    const colorLabel = document.createElement("div");
    colorLabel.className = "color-label";
    colorLabel.textContent = color.name;
    colorBtn.appendChild(colorLabel);

    container.appendChild(colorBtn);
  });

  // 使用事件委托添加点击事件
  container.addEventListener('click', function(event) {
    // 查找被点击的按钮元素
    let targetBtn = event.target;
    
    // 如果点击的是标签元素,则获取其父元素(按钮)
    if (targetBtn.classList.contains('color-label')) {
      targetBtn = targetBtn.parentElement;
    }
    
    // 确认点击的是按钮元素
    if (targetBtn.classList.contains('color-btn')) {
      // 移除所有按钮的active类
      document.querySelectorAll('.color-btn').forEach(btn => {
        btn.classList.remove('active');
      });
      
      // 为当前按钮添加active类
      targetBtn.classList.add('active');
      
      // 获取颜色值,用于外部实现的功能
      const colorValue = targetBtn.getAttribute('data-color');
      console.log('选中颜色:', colorValue);
      
      // 这里不实现具体功能,由用户自行实现
      changeCarBodyColor(colorValue)
    }
  });

  document.body.appendChild(container);
}
/* 颜色选择器样式 */
.color-selector {
    position: fixed;
    bottom: 60px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    gap: 20px;
    align-items: center;
    justify-content: center;
    width: 100%;
    max-width: 500px;
    padding: 0 10px;
    box-sizing: border-box;
}

.color-btn {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    cursor: pointer;
    position: relative;
    box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    transition: transform 0.2s ease, box-shadow 0.2s ease;
    flex: 0 0 auto;
}

.color-btn.active {
    transform: scale(1.1);
    box-shadow: 0 4px 12px rgba(0,0,0,0.15);
    border: 2px solid white;
}

.color-label {
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    margin-top: 8px;
    font-size: 12px;
    color: #333;
    white-space: nowrap;
}

接下来我们来实现切换功能,步骤如下
1收集汽车的材质信息
2找到汽车的车身材质,并进行颜色修改
3可以使用tween将颜色的过渡效果实现出来
在加载汽车的时候,就收集到所有的材质信息,并存储到数组中
materials结构,Car_body.004是核心属性

在点击到按钮之后,得到对应的颜色,然后修改材质,我们的车身材质名称为Car_body.004

const changeCarBodyColor=(colorString)=>{
    console.log(materials);
    if(materials.length){
        materials.forEach(m=>{
            if(m.name.includes('Car_body')){
                m.color=new THREE.Color(colorString)
            }
        })
    }
}

我们还可以通过Tweenjs来实现动画效果

import * as TWEEN from '@tweenjs/tween.js'

let tween
const TweenColorChange=(primColor,color)=>{
    return new TWEEN.Tween(primColor)
      .to(color, 600)
      .easing(TWEEN.Easing.Linear.None)
      .start()
}

将changeCarBodyColor修改一下

const changeCarBodyColor=(colorString)=>{
    if(materials.length){
        materials.forEach(m=>{
            if(m.name.includes('Car_body')){
                tween=TweenColorChange(m.color,new THREE.Color(colorString))
                //m.color=new THREE.Color(colorString)
            }
        })
    }
}

在渲染器中进行更新

renderer.setAnimationLoop(() => {
  if(tween){
      tween.update()
  }
  camera.lookAt(0,0,0)
  camera.updateProjectionMatrix();
  renderer.render(scene, camera);
});

** 4.其他优化细节**
我们仔细观察懂车帝的效果,发现其操作方式只能左右旋转小车,并不能上下偏移
我们可以通过设置轨道控制器的属性达成这一点,并且还可以把相机设置到一个合适的位置

camera.position.set(6.031,  1.39,  -5.08);
orbitControl.enablePan = false;
orbitControl.enableZoom = false;
orbitControl.minPolarAngle = (80 * Math.PI) / 180;
orbitControl.maxPolarAngle = (80 * Math.PI) / 180;

最终效果


网站公告

今日签到

点亮在社区的每一天
去签到