当前位置: 首页 > 工具软件 > jj.js > 使用案例 >

three.js实现一个汽车3D实景(颜色交互)

阮俊弼
2023-12-01

问题来源:
    和导师交流后决定以这个来做毕业设计,于是就开始了three.js的学习,经过半个多月的基础学习,终于入门,下面来看看成果。

代码演示:
html部分

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>3D(颜色交互)</title>
    <script src="js/jquery-3.3.1.min.js"></script>
    <script src="three.js/build/three.js"></script>
    <script src="js/OrbitControls.js"></script>
    <script src="three.js/examples/js/loaders/GLTFLoader.js"></script>
</head>
<body>
<div id="contorl">
    <input class="color" type="color">
</div>
<script src="js/model.js"></script>
</body>
</html>

model.css

body {
    margin: 0 ;
	padding: 0 ;
    overflow: hidden; /* 溢出隐藏 */
}
#contorl{
    position: absolute;
    width: 15%;
    height: 20%;
    right: 20px;
    top: 20px;
    background-color: white;
}
.select{
    font-family: "微软雅黑";
    background: rgba(0,0,0,0);
    width: 70%;
    height: 30%;
    font-size: 12px;
    color: black;
    text-align: center;
    border: 1px #1a1a1a solid;
    border-radius: 5px;
}
.select > option{
    color: black;
    background: #fff;
    line-height: 20px;
}
.select:focus{
    border: 2px #0000ff solid;
    box-shadow: 0 0 15px 1px #DDDDDD;
}
.select > option:hover{
    background: #EBCCD1;
}
.color{
    border: none;
    outline: none;
}
::-webkit-color-swatch-wrapper{background-color:#ffffff;}
::-webkit-color-swatch{position: relative;}

model.js(此处才是重点)

 let scene, camera, renderer, controls, guiControls;
    // let stats = initStats();

    /* 场景 */
    function initScene() {

        scene = new THREE.Scene();
        var skySphereGeometry = new THREE.SphereGeometry( 500, 30, 100 );
        var texture = new THREE.TextureLoader().load("images/timg.jpg");
        var skySphereMaterial = new THREE.MeshBasicMaterial( { map:texture, side: THREE.DoubleSide } );
        var skySphere = new THREE.Mesh( skySphereGeometry, skySphereMaterial );
        scene.add(skySphere);

    }

    /* 相机 */
    function initCamera() {

        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
        camera.position.set(70, 50, 100);
        camera.lookAt(new THREE.Vector3(0, 0, 0));

    }

    /* 渲染器 */
    function initRender() {

        renderer = new THREE.WebGLRenderer({antialias: true});
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setClearColor(0xffffff);
        renderer.shadowMap.enabled = true;
        document.body.appendChild(renderer.domElement);

    }

    /* 灯光 */
    function initLight() {
        // var axes = new THREE.AxesHelper(20);
        // scene.add(axes);

        var planeGeometry = new THREE.PlaneGeometry(200,200,100,1);
        var texture = new THREE.TextureLoader().load("images/5.png");
        var planeMaterial = new THREE.MeshLambertMaterial({map:texture});
        var plane = new THREE.Mesh(planeGeometry, planeMaterial);
        // plane.rotation.x = -0.5*Math.PI;
        // plane.name ='plane';
        // plane.position.set(0,0,0);
        // plane.receiveShadow = true;
        // scene.add(plane);

        var ambiColor = "#ffffff";
        var ambientLight = new THREE.AmbientLight(ambiColor);//设置颜色
        scene.add(ambientLight);
        var pointColor = "#ffffff";
        var directionalLight = new THREE.DirectionalLight(pointColor);
        directionalLight.position.set(-50, 60, 200);
        directionalLight.castShadow = true;
        directionalLight.shadow.camera.near = 20;
        directionalLight.shadow.camera.far = 200;
        directionalLight.shadow.camera.left = -50;
        directionalLight.shadow.camera.right = 50;
        directionalLight.shadow.camera.top = 50;
        directionalLight.shadow.camera.bottom = -50;
        directionalLight.distance = 0;
        directionalLight.intensity = 5;
        directionalLight.shadow.mapSize.height = 1024;
        directionalLight.shadow.mapSize.width = 1024;
        scene.add(directionalLight);
    }

    /* 控制器 */
    function initControls() {
        controls = new THREE.OrbitControls(camera, renderer.domElement);
		// 如果使用animate方法时,将此函数删除
		//controls.addEventListener( 'change', render );
		// 使动画循环使用时阻尼或自转 意思是否有惯性
		controls.enableDamping = true;
		//动态阻尼系数 就是鼠标拖拽旋转灵敏度
		controls.dampingFactor = 0.95;
		//是否可以缩放
		controls.enableZoom = true;
		//是否自动旋转
		// controls.autoRotate = true;
		//设置相机距离原点的最远距离
		controls.minDistance = 70;
		//设置相机距离原点的最远距离
		controls.maxDistance = 250;
		//是否开启右键拖拽
		controls.enablePan = false;
		//设置聚焦坐标
		// controls.target = new THREE.Vector3()
    }

    /* 调试插件 */
    function initGui() {

        guiControls = new function () {
            this.rotationSpeed = 0;
        };
    }

    /* 场景中的内容 */

    function initContent() {

        // 加载 glTF 格式的模型
        let loader = new THREE.GLTFLoader();/*实例化加载器*/
        loader.load('./example/11/scene.gltf',function (obj) {
            obj.scene.name = 'zp';
			var car = obj.scene;
			console.log(car.children[0].children[0].children[0].children[0]);
            scene.add(car);
        },function (xhr) {

            console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );

        },function (error) {
			console.log(error)
            // console.log('load error!'+error.getWebGLErrorMessage());
        })

    }

    /* 性能插件 */
    function initStats() {

        let stats = new Stats();
        document.body.appendChild(stats.domElement);
        return stats;

    }

    /* 窗口变动触发 */
    function onWindowResize() {

        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);

    }

    /* 数据更新 */
    function update() {

        // stats.update();

    }

    /* 初始化 */
    function init() {
        initScene();
        initCamera();
        initRender();
        initLight();
        initControls();
        initContent();
        initGui();
        /* 监听事件 */
        window.addEventListener('resize', onWindowResize, false);
    }

    /* 循环渲染 */
    function animate() {
        requestAnimationFrame(animate);
        renderer.render(scene, camera);
        update();

    }

    /* 初始加载 */
    (function () {
        console.log("three init start...");

        init();
        animate();

        console.log("three init send...");
    })();


    window.onload = function() {
        var color = document.getElementsByClassName('color')[0];
        color.onchange = function(e){
            var change_thing = scene.getObjectByName('confirm');
            colors = change_thing.material.color;
            var hex = document.getElementsByClassName('color')[0].value;
            var c = hex_rgb(hex);
            colors.r = c[0];
            colors.g = c[1];
            colors.b = c[2];
        };
        function hex_rgb(hex){
            var r = parseInt(hex[1]+ hex[2],16)/255;
            var g = parseInt(hex[3]+ hex[4],16)/255;
            var b = parseInt(hex[5]+ hex[6],16)/255;
            return [r, g, b];
        }
        function get_hex(x){
            var e = parseInt(x*255).toString(16);
            var z = e;
            if (e === 0){
                z = '00';
            }
            if (e.length === 1){
                z = '0'+ e;
            }
            return z;
        }
        function rgb_hex(r, g, b){
            var result = '#'+ get_hex(r) + get_hex(g) + get_hex(b);
            return result;
        }

        var raycaster = new THREE.Raycaster();
        var	mouse = new THREE.Vector3();
        var canvas = document.getElementsByTagName('canvas')[0];
        canvas.addEventListener('click', onDocumentMouseClick, false);
        function onDocumentMouseClick(event) {
            event.preventDefault();
            //将鼠标点击位置的屏幕坐标转成threejs中的标准坐标,具体解释见代码释义
            mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
            mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
            //新建一个三维单位向量 假设z方向就是0.5
            //根据照相机,把这个向量转换到视点坐标系
            var vector = new THREE.Vector3(mouse.x, mouse.y, 0.5).unproject(camera);
            //在视点坐标系中形成射线,射线的起点向量是照相机, 射线的方向向量是照相机到点击的点,这个向量应该归一标准化。
            var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
            //     //射线和模型求交,选中一系列直线
            var intersects = raycaster.intersectObjects(scene.children[3].children[0].children[0].children[0].children[0].children)[0].object;
            var car = scene.getObjectByName('zp').children[0].children[0].children[0].children[0].children;
            for(var i = 0 ;i < car.length; i++){
                car[i].name = '';
            }
            new_color = intersects.material.color;
            color.value = rgb_hex(new_color.r, new_color.g, new_color.b);
            intersects.name = 'confirm';
        }
    }

网页显示:
[外链图片转存失败(img-JJ42GWf9-1563801784739)(https://raw.githubusercontent.com/zpwyl/images/master/TIM图片20190405161647.png)]
[外链图片转存失败(img-gkN7jNo9-1563801784741)(https://raw.githubusercontent.com/zpwyl/images/master/TIM图片20190405161710.png)]
本人直男一枚,对于美工方面的确没什么天赋,最后做出来的效果差强人意。原本是准备做成点击车上的部位进而改变颜色,希望有看到鄙人拙作的大佬能指点一二,同时也是对自己过去这段时间的一个总结。

下面分享一些我在学习过程中遇到的问题和一些学习网站:
其他类型的3D文件的加载:
OBJ:

var mtlLoader = new THREE.MTLLoader();
mtlLoader.setPath('exapmle/4/');
mtlLoader.load('car.mtl', function(materials) {
	console.log(materials);
	materials.preload();
	var objLoader = new THREE.OBJLoader();
	objLoader.setMaterials(materials);
	objLoader.setPath('exapmle/4/');
	objLoader.load('car.obj', function(object) {
		console.log(object, 'obj');
		object.position.y = 0;
		object.rotation.y = 0.5;
		object.scale.set(0.05, 0.05, 0.05);
		console.log(object);
		scene.add(object);
     }, onProgress, onError);
 });

VTK:

var loader = new THREE.VTKLoader();
loader.addEventListener( 'load', function ( event ) {
	var geometry = event.content;
	var mesh = new THREE.Mesh( geometry, material );
	mesh.position.setY( - 0.09 );
	scene.add( mesh );
	} );
loader.load( "models/vtk/bunny.vtk" );

WebGL中文网           http://www.hewebgl.com/
Three.js官方文档       https://threejs.org/
3D模型下载               https://sketchfab.com

 类似资料: