threejs纹理

news2025/1/24 11:49:31

个人博客地址: https://cxx001.gitee.io

前面我们介绍了各种可以用来覆盖对象的材质,也介绍了如何修改材质的颜色、关泽和不透明度,但是我们还没有详细介绍如何在材质中使用外部图片(也叫纹理).

将纹理应用于材质

1. 加载纹理并应用到网格

纹理最基础的用法是作为贴图被添加在材质上,当你使用这样的材质创建网格时,网格的颜色则来源于纹理。

注: 为了达到最好效果,图片最好使用2的次方的正方形。

  • 纹理的放大和缩小:

由于纹理可以放大或缩小,所以纹理上的像素不会一对一映射到面的像素上。为此,Threejs提供了各种不同的选项,你可以指定magFilter或minFilter属性来设置纹理如何放大或缩小。

magFilter可选值:

名称描述
THREE.NearestFilter(最邻近过滤)会将纹理上最近的像素颜色应用于面上。在放大时,会导致方块化;在缩小时,会丢失很多细节
THREE.LinearFilter(线性过滤)最终颜色由周围四个像素值来决定。这样虽然在缩小时仍会丢失一些细节,但是在放大时会平滑很多,方块化也比较少出现(默认选择)

minFilter属性是要使用mipmap,mipmap是把纹理按照2的倍数进行缩小,直到图形为1×1的大小,然后把这些图都存储起来,这些图片是在加载纹理时创建的,可以用于生成比较光滑的过滤效果。

过滤模式有下面这些:

名称描述
THREE.NearestMipMapNearestFilter选择最邻近的mip层,并执行上表中最邻近过滤。虽然放大时仍然会有方块化,但是缩小时效果会好很多
THREE.NearestMipMapLinearFilter选择最邻近的两个mip层,并分别在这两个mip层上运行最邻近过滤获取两个中间值,最后将这两个中间值传递到线性过滤器中获取最终值
THREE.LinearMipMapNearestFilter选择最邻近的mip层,并执行前表中的线性过滤
THREE.LinearMipMapLinearFilter选择最邻近的两个mip层,并分别在这两个mip层上运行线性过滤获取两个中间值,最后将这两个中间值传递到线性过滤器中获取最终值(默认选择)
  • 其它格式纹理加载器:

除了使用THREE.ImageUtils.loadTexture方法加载标志格式的png,gif或jpeg图片,Threejs还提供了一些自定义加载器,以此来加载其它格式的纹理文件。

<!-- chapter-10-01.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Basic textures</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output">
</div>
<div id="WebGL-output">
</div>

<script type="text/javascript">
    function init() {
        var stats = initStats();
        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        var webGLRenderer = new THREE.WebGLRenderer();
        webGLRenderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
        webGLRenderer.setSize(window.innerWidth, window.innerHeight);
        webGLRenderer.shadowMapEnabled = true;
		
    	// 二十面体
        var polyhedron = createMesh(new THREE.IcosahedronGeometry(5, 0), "metal-rust.jpg");
        polyhedron.position.x = 12;
        scene.add(polyhedron);
		// 球体
        var sphere = createMesh(new THREE.SphereGeometry(5, 20, 20), "floor-wood.jpg");
        scene.add(sphere);
		// 立方体
        var cube = createMesh(new THREE.BoxGeometry(5, 5, 5), "brick-wall.jpg");
        cube.position.x = -12;
        scene.add(cube);
        console.log(cube.geometry.faceVertexUvs);

        camera.position.x = 00;
        camera.position.y = 12;
        camera.position.z = 28;
        camera.lookAt(new THREE.Vector3(0, 0, 0));

        var ambiLight = new THREE.AmbientLight(0x141414);
        scene.add(ambiLight);

        var light = new THREE.DirectionalLight();
        light.position.set(0, 30, 20);
        scene.add(light);

        document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);
		
    	// 使用外部纹理作为材质创建网格对象
        function createMesh(geom, imageFile) {
            // 如果加载其它格式纹理,使用上面介绍的对应加载器即可
            var texture = THREE.ImageUtils.loadTexture("../assets/textures/general/" + imageFile);
            var mat = new THREE.MeshPhongMaterial();
            mat.map = texture;
            var mesh = new THREE.Mesh(geom, mat);
            return mesh;
        }
    
		var step = 0;
        function render() {
            stats.update();
            polyhedron.rotation.y = step += 0.01;
            polyhedron.rotation.x = step;
            cube.rotation.y = step;
            cube.rotation.x = step;
            sphere.rotation.y = step;
            sphere.rotation.x = step;
            requestAnimationFrame(render);
            webGLRenderer.render(scene, camera);
        }
    	render();

        function initStats() {
            var stats = new Stats();
            stats.setMode(0); // 0: fps, 1: ms
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    }
    window.onload = init;
</script>
</body>
</html>

在这里插入图片描述

2. 使用凹凸贴图创建褶皱

凹凸贴图用于为材质添加厚度,网格面看起来有起伏、深度的感觉,更加立体。我们使用材质的bumpMap属性和bumpScale属性。

但是注意像素的密集程度定义的是凹凸的高度,但是凹凸图只包含像素的相对高度,没有任何倾斜的方向信息。所以使用凹凸贴图所能表达的深度信息有限,要想实现更多的细节可以使用法向贴图。

<!-- chapter-10-02.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Bump maps</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output">
</div>
<div id="WebGL-output">
</div>

<script type="text/javascript">
    function init() {
        var stats = initStats();
        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        var webGLRenderer = new THREE.WebGLRenderer();
        webGLRenderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
        webGLRenderer.setSize(window.innerWidth, window.innerHeight);
        webGLRenderer.shadowMapEnabled = true;
		
    	// 右边没有使用凹凸贴图墙体
        var sphere1 = createMesh(new THREE.BoxGeometry(15, 15, 2), "stone.jpg");
        sphere1.rotation.y = -0.5;
        sphere1.position.x = 12;
        scene.add(sphere1);
		
    	// 左边使用凹凸贴图墙体
        var sphere2 = createMesh(new THREE.BoxGeometry(15, 15, 2), "stone.jpg", "stone-bump.jpg");
        sphere2.rotation.y = 0.5;
        sphere2.position.x = -12;
        scene.add(sphere2);
        console.log(sphere2.geometry.faceVertexUvs);
		
    	// 地面
        var floorTex = THREE.ImageUtils.loadTexture("../assets/textures/general/floor-wood.jpg");
        var plane = new THREE.Mesh(new THREE.BoxGeometry(200, 100, 0.1, 30), new THREE.MeshPhongMaterial({
            color: 0x3c3c3c,
            map: floorTex
        }));
        plane.position.y = -7.5;
        plane.rotation.x = -0.5 * Math.PI;
        scene.add(plane);

        camera.position.x = 00;
        camera.position.y = 12;
        camera.position.z = 28;
        camera.lookAt(new THREE.Vector3(0, 0, 0));

        var ambiLight = new THREE.AmbientLight(0x242424);
        scene.add(ambiLight);

        var light = new THREE.SpotLight();
        light.position.set(0, 30, 30);
        light.intensity = 1.2;
        scene.add(light);
        document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);

        var controls = new function () {
            this.bumpScale = 0.2;
            this.rotate = false;
            
            this.changeTexture = function (e) {
                var texture = THREE.ImageUtils.loadTexture("../assets/textures/general/" + e + ".jpg");
                sphere2.material.map = texture;
                sphere1.material.map = texture;

                var bump = THREE.ImageUtils.loadTexture("../assets/textures/general/" + e + "-bump.jpg");
                sphere2.material.bumpMap = bump;
            };

            this.updateBump = function (e) {
                console.log(sphere2.material.bumpScale);
                sphere2.material.bumpScale = e;
            }
        };

        var gui = new dat.GUI();
        gui.add(controls, "bumpScale", -2, 2).onChange(controls.updateBump);
        gui.add(controls, "changeTexture", ['stone', 'weave']).onChange(controls.changeTexture);
        gui.add(controls, "rotate");

        function createMesh(geom, imageFile, bump) {
            var texture = THREE.ImageUtils.loadTexture("../assets/textures/general/" + imageFile);
            geom.computeVertexNormals();
            var mat = new THREE.MeshPhongMaterial();
            mat.map = texture;
			
            // 加载使用凹凸贴图
            if (bump) {
                var bump = THREE.ImageUtils.loadTexture("../assets/textures/general/" + bump);
                mat.bumpMap = bump;   // 指定凹凸纹理
                mat.bumpScale = 0.2;  // 指定凹凸程度
                console.log('d');
            }

            var mesh = new THREE.Mesh(geom, mat);
            return mesh;
        }

        function render() {
            stats.update();
            if (controls.rotate) {
                sphere1.rotation.y -= 0.01;
                sphere2.rotation.y += 0.01;
            }
            requestAnimationFrame(render);
            webGLRenderer.render(scene, camera);
        }
    	render();

        function initStats() {
            var stats = new Stats();
            stats.setMode(0); // 0: fps, 1: ms
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    }
    window.onload = init;
</script>
</body>
</html>

3. 使用法向贴图创建更加细致的凹凸和褶皱

法线贴图保存的不是高度信息,而是法向量的方向。简单来讲,使用法向量贴图只需要使用很少的顶点和面就可以创建出细节很丰富的模型。

<!-- chapter-10-03.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Normal maps</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output">
</div>
<div id="WebGL-output">
</div>

<script type="text/javascript">
    function init() {
        var stats = initStats();
        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        var webGLRenderer = new THREE.WebGLRenderer();
        webGLRenderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
        webGLRenderer.setSize(window.innerWidth, window.innerHeight);
        webGLRenderer.shadowMapEnabled = true;
		
    	// 右边普通纹理立方体
        var sphere1 = createMesh(new THREE.BoxGeometry(15, 15, 15), "plaster.jpg");
        sphere1.rotation.y = -0.5;
        sphere1.position.x = 12;
        scene.add(sphere1);
		
    	// 左边法向贴图立方体
        var sphere2 = createMesh(new THREE.BoxGeometry(15, 15, 15), "plaster.jpg", "plaster-normal.jpg");
        sphere2.rotation.y = 0.5;
        sphere2.position.x = -12;
        scene.add(sphere2);
        console.log(sphere2.geometry.faceVertexUvs);
		
    	// 地面
        var floorTex = THREE.ImageUtils.loadTexture("../assets/textures/general/floor-wood.jpg");
        var plane = new THREE.Mesh(new THREE.BoxGeometry(200, 100, 0.1, 30), new THREE.MeshPhongMaterial({
            color: 0x3c3c3c,
            map: floorTex
        }));
        plane.position.y = -7.5;
        plane.rotation.x = -0.5 * Math.PI;
        scene.add(plane);

        camera.position.x = 00;
        camera.position.y = 12;
        camera.position.z = 38;
        camera.lookAt(new THREE.Vector3(0, 0, 0));

        var ambiLight = new THREE.AmbientLight(0x242424);
        scene.add(ambiLight);

        var light = new THREE.SpotLight();
        light.position.set(0, 30, 30);
        light.intensity = 1.2;
        scene.add(light);

        var pointColor = "#ff5808";
        var directionalLight = new THREE.PointLight(pointColor);
        scene.add(directionalLight);
		
    	// 光源标志小球
        var sphereLight = new THREE.SphereGeometry(0.2);
        var sphereLightMaterial = new THREE.MeshBasicMaterial({color: 0xac6c25});
        var sphereLightMesh = new THREE.Mesh(sphereLight, sphereLightMaterial);
        sphereLightMesh.castShadow = true;
        sphereLightMesh.position = new THREE.Vector3(3, 3, 3);
        scene.add(sphereLightMesh);

        document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);

        var controls = new function () {
            this.normalScale = 1;
            this.changeTexture = "plaster";
            this.rotate = false;

            this.changeTexture = function (e) {
                var texture = THREE.ImageUtils.loadTexture("../assets/textures/general/" + e + ".jpg");
                sphere2.material.map = texture;
                sphere1.material.map = texture;

                var bump = THREE.ImageUtils.loadTexture("../assets/textures/general/" + e + "-normal.jpg");
                sphere2.material.normalMap = bump;  // 指定法向贴图纹理
            };

            this.updateBump = function (e) {
                sphere2.material.normalScale.set(e, e);  // 指定法向贴图凹凸程度
            }
        };

        var gui = new dat.GUI();
        gui.add(controls, "normalScale", -2, 2).onChange(controls.updateBump);
        gui.add(controls, "changeTexture", ['plaster', 'bathroom', 'metal-floor']).onChange(controls.changeTexture);
        gui.add(controls, "rotate");
        
        function createMesh(geom, imageFile, normal) {
            if (normal) {
                // 创建法向贴图网格
                var t = THREE.ImageUtils.loadTexture("../assets/textures/general/" + imageFile);
                var m = THREE.ImageUtils.loadTexture("../assets/textures/general/" + normal);
                var mat2 = new THREE.MeshPhongMaterial();
                mat2.map = t;  // 指定外部纹理
                
                // 使用法向贴图最大问题是这个贴图的创建,需要使用如Blender或Photoshop这样的特殊工具。
                // 这些工具可以讲高分辨率的效果图或纹理作为输入来创建法向贴图。
                // Threejs同样提供了在运行期创建法向贴图的方法,THREE.ImageUtils对象的getNormalMap方法。
                mat2.normalMap = m;  // 指定法向贴图纹理
                
                var mesh = new THREE.Mesh(geom, mat2);
                return mesh;
            } else {
                // 创建普通纹理网格
                var t = THREE.ImageUtils.loadTexture("../assets/textures/general/" + imageFile);
                var mat1 = new THREE.MeshPhongMaterial({
                    map: t
                });
                var mesh = new THREE.Mesh(geom, mat1);
                return mesh;
            }
            return mesh;
        }

        var invert = 1;
        var phase = 0;
		var step = 0;
        function render() {
            stats.update();
            step += 0.1;
            if (controls.rotate) {
                sphere1.rotation.y -= 0.01;
                sphere2.rotation.y += 0.01;
            }

            if (phase > 2 * Math.PI) {
                invert = invert * -1;
                phase -= 2 * Math.PI;
            } else {
                phase += 0.03;
            }

            sphereLightMesh.position.z = +(21 * (Math.sin(phase)));
            sphereLightMesh.position.x = -14 + (14 * (Math.cos(phase)));

            if (invert < 0) {
                var pivot = 0;
                sphereLightMesh.position.x = (invert * (sphereLightMesh.position.x - pivot)) + pivot;
            }
			// 平行光源随小球一起运动
            directionalLight.position.copy(sphereLightMesh.position);

            requestAnimationFrame(render);
            webGLRenderer.render(scene, camera);
        }
    	render();

        function initStats() {
            var stats = new Stats();
            stats.setMode(0); // 0: fps, 1: ms
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    };

    window.onload = init;
</script>
</body>
</html>

在这里插入图片描述

4. 使用光照贴图创建阴影效果

前面我们也介绍了可以受光照影响实时产生阴影的材质。本节来看看另一种产生阴影的方法–光照贴图。它是预先渲染好的阴影,可以用它来模拟真实的阴影,效率更高,主要用于静态场景的阴影。

<!-- chapter-10-04.html -->
<!DOCTYPE html>
<html>
<head>
    <title>LightMap</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output">
</div>
<div id="WebGL-output">
</div>

<script type="text/javascript">
    function init() {
        var stats = initStats();
        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        var renderer;
        var webGLRenderer = new THREE.WebGLRenderer();
        webGLRenderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
        webGLRenderer.setSize(window.innerWidth, window.innerHeight);
        webGLRenderer.shadowMapEnabled = true;
        renderer = webGLRenderer;
		
    	// 地面,使用光照贴图
        var groundGeom = new THREE.PlaneGeometry(95, 95, 1, 1);
        var lm = THREE.ImageUtils.loadTexture('../assets/textures/lightmap/lm-1.png');
        var wood = THREE.ImageUtils.loadTexture('../assets/textures/general/floor-wood.jpg');
        var groundMaterial = new THREE.MeshBasicMaterial(
                {
                    color: 0x777777,
                    lightMap: lm,   // 指定光照贴图
                    map: wood       // 指定纹理
                });

		// 要让光照贴图显示出来还需要指定它的UV映射,详情请参考:
        // http://stackoverflow.com/questions/15137695/three-js-lightmap-causes-an-error-webglrenderingcontext-gl-error-gl-invalid-op
        // https://github.com/mrdoob/three.js/pull/2372
        groundGeom.faceVertexUvs[1] = groundGeom.faceVertexUvs[0];

        var groundMesh = new THREE.Mesh(groundGeom, groundMaterial);
        groundMesh.rotation.x = -Math.PI / 2;
        groundMesh.position.y = 0;
        scene.add(groundMesh);
		
    	// 创建两个立方体,并放到阴影正确位置
        var cubeGeometry = new THREE.BoxGeometry(12, 12, 12);
        var cubeGeometry2 = new THREE.BoxGeometry(6, 6, 6);
        var meshMaterial = new THREE.MeshBasicMaterial();
        meshMaterial.map = THREE.ImageUtils.loadTexture('../assets/textures/general/stone.jpg');
        var cube = new THREE.Mesh(cubeGeometry, meshMaterial);
        var cube2 = new THREE.Mesh(cubeGeometry2, meshMaterial);
        cube.position.set(0.9, 6, -12);
        cube2.position.set(-13.2, 3, -6);
        scene.add(cube);
        scene.add(cube2);

        camera.position.x = -20;
        camera.position.y = 20;
        camera.position.z = 30;
        camera.lookAt(new THREE.Vector3(0, 0, 0));

        var ambientLight = new THREE.AmbientLight(0x0c0c0c);
        scene.add(ambientLight);
        document.getElementById("WebGL-output").appendChild(renderer.domElement);
        
        function render() {
            stats.update();
            requestAnimationFrame(render);
            renderer.render(scene, camera);
        }
    	render();

        function initStats() {
            var stats = new Stats();
            stats.setMode(0); // 0: fps, 1: ms
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    }
    window.onload = init;
</script>
</body>
</html>

5. 使用环境贴图创建反光效果

计算环境的反光效果对CPU耗费是非常巨大的,而且通常会使用光线追踪算法。本节我们用另一种方式实现反光效果,通过创建一个对象所处环境的纹理来伪装反光,并将它应用到指定的对象上。

<!-- chapter-10-05.html -->
<!DOCTYPE html>
<html>
<head>
    <title>dynamic envmap</title>
    <script src="../libs/three.js"></script>
    <script src="../libs/dat.gui.js"></script>
    <script src="../libs/OrbitControls.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<script>
    var renderer;
    var scene;
    var camera, cubeCamera;
    var control;
    var orbit;
    var sphere;
    function init() {
        scene = new THREE.Scene();
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
        orbit = new THREE.OrbitControls(camera);
        renderer = new THREE.WebGLRenderer();
        renderer.setClearColor(0x000000, 1.0);
        renderer.setSize(window.innerWidth, window.innerHeight);
		
        //1. 创建天空盒,你处于盒子中间,看到的是盒子里的纹理图形,就像你身处场景中一样。
        // 创建盒子贴图纹理(6个面是场景的360全景图纹理)
        var textureCube = createCubeMap();
        textureCube.format = THREE.RGBFormat;
        // 使用Shader材质
        var shader = THREE.ShaderLib["cube"];
        shader.uniforms["tCube"].value = textureCube;
        var material = new THREE.ShaderMaterial({
            fragmentShader: shader.fragmentShader,
            vertexShader: shader.vertexShader,
            uniforms: shader.uniforms,
            depthWrite: false,
            side: THREE.DoubleSide
        });
        // 创建天空盒,使用上面的环境材质创建立方盒子
        var skybox = new THREE.Mesh(new THREE.BoxGeometry(10000, 10000, 10000), material);
        scene.add(skybox);
        
        // 2. 将场景中的纹理反射到网格上(环境纹理获取两种方式:1.THREE.CubeCamera快照 2.直接使用上面创建的CubeMap纹理)
        // 创建一个获取环境贴图的cubeCamera,可以为场景中的所有渲染的物体创建快照。
        cubeCamera = new THREE.CubeCamera(0.1, 20000, 256);
        scene.add(cubeCamera);
		
        // 动态反射:将THREE.CubeCamera生成的环境贴图纹理指定到球体材质上
        var sphereGeometry = new THREE.SphereGeometry(4, 15, 15);
        var dynamicEnvMaterial = new THREE.MeshBasicMaterial({envMap: cubeCamera.renderTarget, side: THREE.DoubleSide}); // envMap环境贴图属性,通过cubeCamera的renderTarget对象获取生成的立方体纹理
        sphere = new THREE.Mesh(sphereGeometry, dynamicEnvMaterial);
        sphere.name = 'sphere';
        scene.add(sphere);
		
        // 静态反射:将加载全景图的6面生成的环境贴图纹理指定到圆锥材质上
        var cylinderGeometry = new THREE.CylinderGeometry(2, 4, 10, 20, 20, false);
        var envMaterial = new THREE.MeshBasicMaterial({envMap: textureCube, side: THREE.DoubleSide});
        var cylinder = new THREE.Mesh(cylinderGeometry, envMaterial);
        cylinder.name = 'cylinder';
        scene.add(cylinder);
        cylinder.position.set(10, 0, 0);
		
        // 立方体使用同上材质
        var boxGeometry = new THREE.BoxGeometry(5, 5, 5);
        var cube = new THREE.Mesh(boxGeometry, envMaterial);
        cube.name = 'cube';
        scene.add(cube);
        cube.position.set(-10, 0, 0);

        camera.position.x = 0;
        camera.position.y = 5;
        camera.position.z = 33;
        camera.lookAt(scene.position);
        document.body.appendChild(renderer.domElement);
        render();
    }

	// 创建环境贴图立方盒子
    function createCubeMap() {
        var path = "../assets/textures/cubemap/parliament/";
        var format = '.jpg';
        // 360全景图转换而来, 有在线工具可以转
        var urls = [
            path + 'posx' + format, path + 'negx' + format,  // 左右面纹理
            path + 'posy' + format, path + 'negy' + format,  // 上下面纹理
            path + 'posz' + format, path + 'negz' + format   // 前后面纹理
        ];
        // 创建CubeMap对象
        var textureCube = THREE.ImageUtils.loadTextureCube(urls, new THREE.CubeReflectionMapping());
        return textureCube;
        
        /*
         * threejs也可以直接使用全景图来创建CubeMap对象
         * var textureCube = THREE.ImageUtils.loadTexture("360-degrees.png", new THREE.UVMapping());
        */
    }

    function render() {
        orbit.update();  // 控制拖拽
        sphere.visible = false;
        cubeCamera.updateCubeMap(renderer, scene);  // 当前场景快照
        sphere.visible = true;
        renderer.render(scene, camera);
        scene.getObjectByName('cube').rotation.x += 0.005;
        scene.getObjectByName('cube').rotation.y += 0.005;
        scene.getObjectByName('cylinder').rotation.x += 0.005;
        requestAnimationFrame(render);
    }

    window.onload = init;
</script>
<body>
</body>
</html>

6. 使用高光贴图创建闪亮效果

通过高光贴图,你可以为材质指定一个闪亮的、色彩明快的贴图。

下面示例:海洋区域反光、明亮;陆地不反光、暗淡。细节效果需要自调参数。

<!-- chapter-10-06.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Specular map</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <script type="text/javascript" src="../libs/OrbitControls.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output">
</div>
<div id="WebGL-output">
</div>

<script type="text/javascript">
    function init() {
        var stats = initStats();
        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        var webGLRenderer = new THREE.WebGLRenderer();
        webGLRenderer.setClearColor(new THREE.Color(0x000, 1.0));
        webGLRenderer.setSize(window.innerWidth, window.innerHeight);
        webGLRenderer.shadowMapEnabled = true;

        var sphere = createMesh(new THREE.SphereGeometry(10, 40, 40));
        scene.add(sphere);

        camera.position.x = 15;
        camera.position.y = 15;
        camera.position.z = 15;
        camera.lookAt(new THREE.Vector3(0, 0, 0));

        var orbitControls = new THREE.OrbitControls(camera);
        orbitControls.autoRotate = false;
        
        var ambi = new THREE.AmbientLight(0x3300000);
        scene.add(ambi);

        var spotLight = new THREE.DirectionalLight(0xffffff);
        spotLight.position.set(350, 350, 150);
        spotLight.intensity = 0.4;
        scene.add(spotLight);
        document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);

        function createMesh(geom) {
            var planetTexture = THREE.ImageUtils.loadTexture("../assets/textures/planets/Earth.png");
            var specularTexture = THREE.ImageUtils.loadTexture("../assets/textures/planets/EarthSpec.png");
            var normalTexture = THREE.ImageUtils.loadTexture("../assets/textures/planets/EarthNormal.png");

            var planetMaterial = new THREE.MeshPhongMaterial();
            planetMaterial.specularMap = specularTexture; // 高光贴图
            planetMaterial.specular = new THREE.Color(0xff0000); // 通常与specularMap一起使用,决定反光的颜色
            planetMaterial.normalMap = normalTexture; // 法向贴图
            planetMaterial.map = planetTexture; // 使用的纹理
            planetMaterial.shininess = 150; // 指定高光部分的亮度
            
            var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, [planetMaterial]);
            return mesh;
        }
		
    	var clock = new THREE.Clock();
        function render() {
            stats.update();
            var delta = clock.getDelta();
            orbitControls.update(delta);
            sphere.rotation.y += 0.005;
            requestAnimationFrame(render);
            webGLRenderer.render(scene, camera);
        }
    	render();

        function initStats() {
            var stats = new Stats();
            stats.setMode(0); // 0: fps, 1: ms
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    }
    window.onload = init;
</script>
</body>
</html>

在这里插入图片描述


纹理的高级用途

1. 自定义UV映射

UV映射是指指定纹理的哪部分显示在物体的表面上。默认是将整个纹理显示到物体表面上,一般不需要修改,如果要自定义UV映射,指定部分纹理显示到物体表面,通常都是借助建模工具完成(Blender)。

原理是修改几何体对应面的每个顶点的faceVertexUvs属性,这个属性有两个维度u/v,对应faceVertexUvs属性的x/y,取值范围0~1。

如修改几何体第一个面的UV映射:

// 第一个面(由3个顶点组成)
geom.faceVertexUvs[0][0][0].x = 0.5;  // 第一个面的第一个顶点的u值
geom.faceVertexUvs[0][0][0].y = 0.7;  // 第一个面的第一个顶点的v值
geom.faceVertexUvs[0][0][1].x = 0.4;  // 第一个面的第二个顶点...以此类推
geom.faceVertexUvs[0][0][1].y = 0.1;
geom.faceVertexUvs[0][0][2].x = 0.4;
geom.faceVertexUvs[0][0][2].y = 0.5;

很明显这样自定义设置很不直观,所以一般自定义UV映射我们一般通过专业工具完成,然后加载模型文件即可。

<!-- chapter-10-07.html -->
<!DOCTYPE html>
<html>
<head>
    <title>UV mapping </title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/OBJLoader.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output">
</div>
<div id="WebGL-output">
</div>

<script type="text/javascript">
    function init() {
        var stats = initStats();
        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        var webGLRenderer = new THREE.WebGLRenderer();
        webGLRenderer.setClearColor(new THREE.Color(0xffffff, 1.0));
        webGLRenderer.setSize(window.innerWidth, window.innerHeight);
        webGLRenderer.shadowMapEnabled = true;

        camera.position.x = -30;
        camera.position.y = 40;
        camera.position.z = 50;
        camera.lookAt(new THREE.Vector3(0, 0, 0));
        document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);
		
    	var mesh;
        var controls = new function () {
            // 第一组自定义UV模型
            this.loadCube1 = function () {
                var loader = new THREE.OBJLoader();
                // 加载自定义UV模型文件(修改的是面的顶点的uv值),决定纹理的哪些部分显示到表面上
                loader.load('../assets/models/UVCube1.obj', function (geometry) {
                    if (mesh) scene.remove(mesh);
                    var material = new THREE.MeshBasicMaterial({color: 0xffffff});
                    var texture = THREE.ImageUtils.loadTexture("../assets/textures/ash_uvgrid01.jpg");
                    material.map = texture;
                    geometry.children[0].material = material;
                    mesh = geometry;
                    geometry.scale.set(15, 15, 15);
                    scene.add(geometry);
                });
            };
			
            // 第二组自定义UV模型
            this.loadCube2 = function () {
                var loader = new THREE.OBJLoader();
                loader.load('../assets/models/UVCube2.obj', function (geometry) {
                    if (mesh) scene.remove(mesh);
                    var material = new THREE.MeshBasicMaterial({color: 0xffffff});
                    var texture = THREE.ImageUtils.loadTexture("../assets/textures/ash_uvgrid01.jpg");
                    material.map = texture;
                    geometry.children[0].material = material;
                    mesh = geometry;
                    geometry.scale.set(15, 15, 15);
                    geometry.rotation.x = -0.3;
                    scene.add(geometry);
                });
            };
        };

        var gui = new dat.GUI();
        gui.add(controls, 'loadCube1');
        gui.add(controls, 'loadCube2');
        controls.loadCube1();

        function render() {
            stats.update();
            requestAnimationFrame(render);
            webGLRenderer.render(scene, camera);
        }
    	render();

        function initStats() {
            var stats = new Stats();
            stats.setMode(0); // 0: fps, 1: ms
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    }
    window.onload = init;
</script>
</body>
</html>

loadCube1:

loadCube2:

在这里插入图片描述

2. 复制纹理

上面UV映射是指定纹理哪些部分显示到物体表面,Threejs会用选定的纹理包围整个物体表面。但是对于有些情形,你可能不想将纹理遍布整个面或整个几何体,而是让纹理进行重复(复制)。

通过material.map.wrapSmaterial.map.wrapT属性来设置纹理的包裹类型(wrapS是x轴方向纹理的行为,wrapT是y轴方向纹理的行为):

纹理包裹类型描述
THREE.RepeatWrapping允许纹理重复自己
THREE.ClampToEdgeWrapping默认值,纹理不会重复,用选择的纹理尽量包裹物体整个表面,只是在边缘的像素用重复纹理来填充剩下的空间
<!-- chapter-10-08.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Repeat mapping</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output">
</div>
<div id="WebGL-output">
</div>

<script type="text/javascript">
    function init() {
        var stats = initStats();
        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        var webGLRenderer = new THREE.WebGLRenderer();
        webGLRenderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
        webGLRenderer.setSize(window.innerWidth, window.innerHeight);
        webGLRenderer.shadowMapEnabled = true;

        var sphere = createMesh(new THREE.SphereGeometry(5, 20, 20), "floor-wood.jpg");
        scene.add(sphere);
        sphere.position.x = 7;

        var cube = createMesh(new THREE.BoxGeometry(6, 6, 6), "brick-wall.jpg");
        cube.position.x = -7;
        scene.add(cube);
        console.log(cube.geometry.faceVertexUvs);

        camera.position.x = 00;
        camera.position.y = 12;
        camera.position.z = 20;
        camera.lookAt(new THREE.Vector3(0, 0, 0));

        var ambiLight = new THREE.AmbientLight(0x141414);
        scene.add(ambiLight);

        var light = new THREE.DirectionalLight();
        light.position.set(0, 30, 20);
        scene.add(light);
        document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);

        var controls = new function () {
            this.repeatX = 1;
            this.repeatY = 1;
            this.repeatWrapping = true;
            
            // 更新纹理重复方式
            this.updateRepeat = function (e) {
                // 设置重复纹理在x/y轴方向多久重复1次,值为1则不重复,大于1开始重复,小于1纹理被放大,负数则会产生一个纹理镜像
                cube.material.map.repeat.set(controls.repeatX, controls.repeatY);
                sphere.material.map.repeat.set(controls.repeatX, controls.repeatY);
                if (controls.repeatWrapping) {
                    // 使用纹理重复
                    cube.material.map.wrapS = THREE.RepeatWrapping;
                    cube.material.map.wrapT = THREE.RepeatWrapping;
                    sphere.material.map.wrapS = THREE.RepeatWrapping;
                    sphere.material.map.wrapT = THREE.RepeatWrapping;
                } else {
                    // 不使用纹理重复
                    cube.material.map.wrapS = THREE.ClampToEdgeWrapping;
                    cube.material.map.wrapT = THREE.ClampToEdgeWrapping;
                    sphere.material.map.wrapS = THREE.ClampToEdgeWrapping;
                    sphere.material.map.wrapT = THREE.ClampToEdgeWrapping;
                }
                cube.material.map.needsUpdate = true;
                sphere.material.map.needsUpdate = true;
            }
        };

        var gui = new dat.GUI();
        gui.add(controls, "repeatX", -4, 4).onChange(controls.updateRepeat);
        gui.add(controls, "repeatY", -4, 4).onChange(controls.updateRepeat);
        gui.add(controls, "repeatWrapping").onChange(controls.updateRepeat);

        function createMesh(geom, texture) {
            var texture = THREE.ImageUtils.loadTexture("../assets/textures/general/" + texture);
            texture.wrapS = THREE.RepeatWrapping;
            texture.wrapT = THREE.RepeatWrapping;
            geom.computeVertexNormals();
            var mat = new THREE.MeshPhongMaterial();
            mat.map = texture;
            var mesh = new THREE.Mesh(geom, mat);
            return mesh;
        }
		
    	var step = 0;
        function render() {
            stats.update();
            step += 0.01;
            cube.rotation.y = step;
            cube.rotation.x = step;
            sphere.rotation.y = step;
            sphere.rotation.x = step;
            requestAnimationFrame(render);
            webGLRenderer.render(scene, camera);
        }
    	render();

        function initStats() {
            var stats = new Stats();
            stats.setMode(0); // 0: fps, 1: ms
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    }
    window.onload = init;
</script>
</body>
</html>

在这里插入图片描述

3. 在画布上绘制图案并作为纹理

前面我们都是加载本地静态图片作为纹理,其实Threejs也支持将HTML5的画布作为纹理使用。

下面示例我们将用Literally库(http://literallycanvas.com) ,来创建一个交互式的画布。在画布上你可以进行绘图,它可以作为纹理实时显示到网格对象上。

<!-- chapter-10-09.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Canvas texture</title>
    <link href="../libs/literally/css/literally.css" rel="stylesheet">
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <script type="text/javascript" src="../libs/perlin.js"></script>
    <script type="text/javascript" src="../libs/literally/jquery-1.8.2.js"></script>
    <script type="text/javascript" src="../libs/literally/underscore-1.4.2.js"></script>
    <script type="text/javascript" src="../libs/literally/js/literallycanvas.js"></script>

    <style>
        body {
            margin: 0;
            overflow: hidden;
            font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
        }

        .fs-container {
            width: 300px;
            height: 300px;
            margin: auto;
            bottom: 20px;
            position: absolute;
            x: 0;
            y: 0;
        "
        }

        #canvas-output {
            width: 300px;
            height: 300px;
        }
    </style>
</head>
<body>

<div id="Stats-output">
</div>

<div class="fs-container">
    <div id="canvas-output" style="float:left">
    </div>
</div>

<div id="WebGL-output">
</div>

<script type="text/javascript">
    var canvas = document.createElement("canvas");
    document.getElementById('canvas-output').appendChild(canvas);
    $('#canvas-output').literallycanvas({imageURLPrefix: '../libs/literally/img'}); // 使用Literally库的literallycanvas创建绘图工具

    function init() {
        var stats = initStats();
        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        var webGLRenderer = new THREE.WebGLRenderer();
        webGLRenderer.setClearColor(new THREE.Color(0xbbbbbb, 1.0));
        webGLRenderer.setSize(window.innerWidth, window.innerHeight);
        webGLRenderer.shadowMapEnabled = true;

        var cube = createMesh(new THREE.BoxGeometry(10, 10, 10));
        cube.position.x = 0;
        scene.add(cube);

        camera.position.x = 00;
        camera.position.y = 12;
        camera.position.z = 28;
        camera.lookAt(new THREE.Vector3(0, 0, 0));

        var ambiLight = new THREE.AmbientLight(0x141414);
        scene.add(ambiLight);

        var light = new THREE.DirectionalLight();
        light.position.set(0, 30, 20);
        scene.add(light);
        document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);

        function createMesh(geom) {
            var canvasMap = new THREE.Texture(canvas); // 将画布转为纹理对象
            var mat = new THREE.MeshPhongMaterial();
            mat.map = canvasMap;  // 使用画布纹理
            var mesh = new THREE.Mesh(geom, mat);
            return mesh;
        }

        function render() {
            stats.update();
            cube.rotation.y += 0.01;
            cube.rotation.x += 0.01;
            cube.material.map.needsUpdate = true;
            requestAnimationFrame(render);
            webGLRenderer.render(scene, camera);
        }
        render();

        function initStats() {
            var stats = new Stats();
            stats.setMode(0); // 0: fps, 1: ms
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    }
    window.onload = init;
</script>
</body>
</html>

在这里插入图片描述

4. 将视频输出作为纹理

Threejs也支持将HTML5的视频元素作为纹理输出。

<!-- chapter-10-10.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Video texture - non canvas</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output">
</div>

<video id="video" style="display: none; position: absolute; left: 15px; top: 75px;"
       src="../assets/movies/Big_Buck_Bunny_small.ogv" controls="true" autoplay="true"></video>

<div id="WebGL-output">
</div>

<script type="text/javascript">
    var texture;

    function init() {
        var stats = initStats();
        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        var webGLRenderer = new THREE.WebGLRenderer();
        webGLRenderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
        webGLRenderer.setSize(window.innerWidth, window.innerHeight);
        webGLRenderer.shadowMapEnabled = true;

        var video = document.getElementById('video');
        texture = new THREE.VideoTexture(video);  // 将视频元素作为纹理输出

        var cube = createMesh(new THREE.BoxGeometry(20, 10, 10));
        cube.position.y = 2;
        scene.add(cube);

        camera.position.x = 00;
        camera.position.y = 1;
        camera.position.z = 28;
        camera.lookAt(new THREE.Vector3(0, 0, 0));

        var ambiLight = new THREE.AmbientLight(0x141414);
        scene.add(ambiLight);

        var light = new THREE.DirectionalLight();
        light.position.set(0, 30, 20);
        scene.add(light);
        document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);

        var controls = new function () {
            this.rotate = false;
        };
        var gui = new dat.GUI();
        gui.add(controls, "rotate");

        function createMesh(geom) {
            var materialArray = [];
            materialArray.push(new THREE.MeshBasicMaterial({color: 0x0051ba}));
            materialArray.push(new THREE.MeshBasicMaterial({color: 0x0051ba}));
            materialArray.push(new THREE.MeshBasicMaterial({color: 0x0051ba}));
            materialArray.push(new THREE.MeshBasicMaterial({color: 0x0051ba}));
            materialArray.push(new THREE.MeshBasicMaterial({map: texture}));  // 这个面使用视频纹理
            materialArray.push(new THREE.MeshBasicMaterial({color: 0xff51ba}));
            var faceMaterial = new THREE.MeshFaceMaterial(materialArray);
            var mesh = new THREE.Mesh(geom, faceMaterial);
            return mesh;
        }

        function render() {
            stats.update();
            if (controls.rotate) {
                cube.rotation.x += -0.01;
                cube.rotation.y += -0.01;
                cube.rotation.z += -0.01;
            }
            requestAnimationFrame(render);
            webGLRenderer.render(scene, camera);
        }
        render();

        function initStats() {
            var stats = new Stats();
            stats.setMode(0); // 0: fps, 1: ms
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    }
    window.onload = init;
</script>
</body>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/703159.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微信小程序,考试小程序,答题小程序,刷题小程序,知识竞赛小程序,活动答题小程序

简介 微信小程序&#xff0c;考试小程序&#xff0c;答题小程序&#xff0c;刷题小程序&#xff0c;知识竞赛小程序&#xff0c;活动答题小程序。题库小程序。毕业设计小程序&#xff0c;有前后端完整源码和数据库&#xff0c;易于二次开发。 还可用于考试预约&#xff0c;企…

创客匠人标杆客户——毛丫绘本蒋凌

蒋凌&#xff08;毛丫&#xff09;老师专注绘本阅读职业培训领域&#xff0c;举办过数百场绘本故事会、家长讲座、职业培训&#xff0c;培训总人数超过10万人&#xff0c;携手创客匠人搭建【毛丫讲绘本】线上平台。两三年时间&#xff0c;线上营业额突破千万&#xff0c;成功联…

【Vue】axios发请求下载excel--20230630

1.关键点&#xff1a; blob乱码传参 2.参考资料&#xff1a;处理blob文件流和乱码问题 https://blog.csdn.net/qq_41512902/article/details/125680531 https://blog.csdn.net/qq_38804584/article/details/109238794 3.我的代码&#xff1a;axios发请求下载excel js代…

【C++学习】类和对象 | 运算符重载 | 赋值运算符重载

写在前面&#xff1a; 上一篇文章我们学了拷贝构造&#xff0c;还探索了操作符重载的使用&#xff0c; 如果有兴趣可以去看看&#xff1a;http://t.csdn.cn/dkD1g 今天我们接着学习类和对象相关的知识。 目录 写在前面&#xff1a; 1. 运算符重载 2. 赋值运算符重载 写在…

Nginx常用模块

Nginx常用模块 文章目录 Nginx常用模块1.Nginx常用模块1.1.Nginx目录索引/下载模块1.1.1.配置autoindex语法1.1.2.autoindex配置实例1.1.3上传资源1.1.4.autoindex_exact_size配置语法1.1.5.修改配置文件1.1.6.再次访问1.1.7.修改日期1.1.8.autoindex_localtime语法格式1.1.9.修…

【C51】基于51单片机的出租车计价器设计

摘 要 随着我国经济的快速发展&#xff0c;出行选择乘坐出租车的人越来越多。与此同时电子信息技术的发展更新&#xff0c;更加准确、便捷、稳定的出租车计价收费系统随之出现。基于单片机的出租车计价系统的设计&#xff0c;不仅可以更加准确、稳定的反映计价情况&#xff0c;…

FreeRTOS—任务基础知识

文章目录 一、FreeRTOS任务特性二、FreeRTOS任务状态三、FreeRTOS任务优先级四、FreeRTOS任务实现五、任务控制块六、任务堆栈 一、FreeRTOS任务特性 简单没有使用限制&#xff08;任务数量没有显示&#xff0c;一个优先级下可以有多个任务&#xff09;支持抢占&#xff08;高…

前端谷歌浏览器调试

【浏览器调试工具精讲】Chrome Dev Tools精讲&#xff0c;前端必看&#xff01; 文章目录 命令菜单主题切换截屏窗口停放位置 常用Tabelement查找ID修改样式、样式文件定位 样式的来源如继承、自定义等让某个状态常驻如鼠标悬停全局、部分样式的的选择与取消复制样式某个样式属…

Java开发 - Canal的基本用法

前言 今天给大家带来的是Canal的基本用法&#xff0c;Canal在Java中常被我们用来做数据的同步&#xff0c;当然不是MySQL与MySQL&#xff0c;Redis与Redis之间了&#xff0c;如果是他们&#xff0c;那就好办了&#xff0c;我们可以直接通过配置来完成他们之间的主从、主主&…

【AUTOSAR】BMS开发实际项目讲解(三十)----电池管理系统电池SOH和SOE估算

电池SOH估算 关联的系统需求 Sys_Req_4004、Sys_Req_4005; 功能实现描述 SOH主要包括以下内容&#xff1a; SOH模块输入信息 序号 参数 说明 1 满电电压 4.14V 3 电芯OCV曲线 [CELL] 4 充放电循环次数 [CELL] 2 电芯循环衰减数据表 [CELL] SOH算法 ID Descr…

在docker中使用tomcat

检查本地操作系统版本&#xff1a; [rootnode ~]# cat /etc/os-release NAME"CentOS Linux" VERSION"7 (Core)" ID"centos" ID_LIKE"rhel fedora" VERSION_ID"7" PRETTY_NAME"CentOS Linux 7 (Core)" ANSI_COLO…

第8届Python编程挑战赛初赛真题剖析-2022年全国青少年信息素养大赛

[导读]&#xff1a;超平老师计划推出《全国青少年信息素养大赛Python编程真题解析》50讲&#xff0c;这是超平老师解读Python编程挑战赛系列的第1讲。 全国青少年信息素养大赛&#xff08;原全国青少年电子信息智能创新大赛&#xff09;是“世界机器人大会青少年机器人设计与信…

如何做好云渗透测试的威胁建模(上)

NO.1 威胁建模相关定义 微软针对威胁建模&#xff08;Threat modeling&#xff09;的描述&#xff1a;威胁建模是帮助保护系统、应用程序、网络和服务的有效方法。这是一种工程技术&#xff0c;用于识别潜在的威胁和建议&#xff0c;以帮助降低风险并在开发生命周期的早期实现…

nodejs接口联动获取req的各种类型数据,搭建可视化流程引擎平台

nodejs接口联动获取req的各种类型数据&#xff0c;搭建可视化流程引擎平台 搭建nodejs服务创建对外开放端口&#xff0c;获取基础数据GET—queryGET—paramsPOST 联动MYSQL数据库获取websites表的所有书链接数据库 插入 搭建nodejs服务 考虑跨域等性能&#xff0c;简易的工程化…

基于SpringBoot和Mybatis用两种方式实现分页查询

上一篇文章中封装了通用的返回结果、通用分页结果。本文具体记录一下如何基于Mybatis实现分页查询。 参考文章&#xff1a; Github:pagehelper-spring-boot Github:HowToUse.md mybatis-plus分页查询三种方法 MyBatis-Plus分页插件 系列文章指路&#x1f449; 系列文章-基于Sp…

这会是下一代的 Java 程序员的技术栈吗?

Servlet 与 Reactive 技术栈 打开 Spring 的官方文档我们在 Reactive 一栏中可以看到下面的架构图&#xff0c;其中可以很明显的看到 Reactive 的技术栈跟 Servlet 技术栈是完全并行的。意思是说我们日常开发的 Servlet web 类型只是一半的内容&#xff0c;还有另外一半世界就…

TI AM64x开发板规格书(双核ARM Cortex-A53 + 单/四核Cortex-R5F + 单核Cortex-M4F,主频1GHz)

1 评估板简介 创龙科技TL64x-EVM是一款基于TI Sitara系列AM64x双核ARM Cortex-A53 单/四核Cortex-R5F 单核Cortex-M4F多核处理器设计的高性能评估板&#xff0c;由核心板和评估底板组成。核心板经过专业的PCB Layout和高低温测试验证&#xff0c;高性能低功耗&#xff0c;稳…

3.2C++抽象类

C 抽象类 C的抽象类是指至少包含一个纯虚函数的类&#xff0c;不能被实例化。 抽象类的作用是为了实现接口的统一规范&#xff0c;使得不同的子类可以通过实现相同的纯虚函数来实现不同的行为。 定义抽象类时&#xff0c;需要在类中至少包含一个纯虚函数。 抽象类不能被实例…

idea如何连接数据库

输入数据库的用户名和密码就行 Database这里些数据库的名字 快速打开数据库设计 这句话是说时区有问题&#xff1a;因为Mysql用的是美国时区&#xff0c;要搞成中国时区&#xff1a; set global time_zone8:00; 打开cmd窗口&#xff1a; 输入 mysql -u root -p 密码&…

MySql高级篇-006 MySQL架构篇-02MySQL的数据目录:数据库下的主要目录结构、文件系统如何存储数据

第02章_MySQL的数据目录 1.MySQL8的主要目录结构 # 查询名称叫做mysql的文件目录都有哪些[rootatguigu07 ~]# find / -name mysql安装好MySQL 8之后&#xff0c;我们查看如下的目录结构&#xff1a; 1.1 数据库文件的存放路径 MySQL数据库文件的存放路径&#xff1a;/var/…