threejs后期处理

news2024/11/23 22:37:46

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

1. 如何使用Threejs的后期处理

后期处理就是在场景渲染完后,最后对场景显示效果调整的手段。

使用后期处理步骤:

(1)创建THREE.EffectComposer对象。(效果组合器)

(2)在该对象上添加后期处理通道。(渲染时就会按照添加的顺序依次处理–即渲染管线类似)

(3)在render循环中,使用THREE.EffectComposer来渲染场景。

<!-- chapter-11-01.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Effect composings</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>
    <script type="text/javascript" src="../libs/postprocessing/ShaderPass.js"></script>
    <script type="text/javascript" src="../libs/shaders/CopyShader.js"></script>
    <script type="text/javascript" src="../libs/postprocessing/EffectComposer.js"></script>
    <script type="text/javascript" src="../libs/postprocessing/MaskPass.js"></script>
    <script type="text/javascript" src="../libs/postprocessing/FilmPass.js"></script>
    <script type="text/javascript" src="../libs/shaders/FilmShader.js"></script>
    <script type="text/javascript" src="../libs/postprocessing/RenderPass.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 = -10;
        camera.position.y = 15;
        camera.position.z = 25;
        camera.lookAt(new THREE.Vector3(0, 0, 0));

        var orbitControls = new THREE.OrbitControls(camera);
        orbitControls.autoRotate = false;
        var clock = new THREE.Clock();

        var ambi = new THREE.AmbientLight(0x181818);
        scene.add(ambi);

        var spotLight = new THREE.DirectionalLight(0xffffff);
        spotLight.position.set(550, 100, 550);
        spotLight.intensity = 0.6;
        scene.add(spotLight);
        document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);
		
    	// 1. 创建效果组合器对象
    	var composer = new THREE.EffectComposer(webGLRenderer);
    	// 2. 添加后期处理通道
        var renderPass = new THREE.RenderPass(scene, camera); // 该通道会在当前场景和摄像机的基础上渲染出一个新场景
        var effectFilm = new THREE.FilmPass(0.8, 0.325, 256, false); // 该通道可以实现电视栅格效果
        effectFilm.renderToScreen = true;  // 渲染到界面(不是所有通道都有该属性)
        composer.addPass(renderPass);
        composer.addPass(effectFilm);

        var controls = new function () {
            this.scanlinesCount = 256;  // 控制扫描线数量
            this.grayscale = false; // 如果设置为true,输出结果将会被转换为灰度图
            this.scanlinesIntensity = 0.3; // 指定扫描线的显著程度
            this.noiseIntensity = 0.8; // 控制场景的粗糙程度
            this.updateEffectFilm = function () {
                effectFilm.uniforms.grayscale.value = controls.grayscale;
                effectFilm.uniforms.nIntensity.value = controls.noiseIntensity;
                effectFilm.uniforms.sIntensity.value = controls.scanlinesIntensity;
                effectFilm.uniforms.sCount.value = controls.scanlinesCount;
            };
        };

        var gui = new dat.GUI();
        gui.add(controls, "scanlinesIntensity", 0, 1).onChange(controls.updateEffectFilm);
        gui.add(controls, "noiseIntensity", 0, 3).onChange(controls.updateEffectFilm);
        gui.add(controls, "grayscale").onChange(controls.updateEffectFilm);
        gui.add(controls, "scanlinesCount", 0, 2048).step(1).onChange(controls.updateEffectFilm);

        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(0x4444aa);
            planetMaterial.normalMap = normalTexture;
            planetMaterial.map = planetTexture;
			//planetMaterial.shininess = 150;
            var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, [planetMaterial]);
            return mesh;
        }

    	var delta = clock.getDelta();
        function render() {
            stats.update();
            orbitControls.update(delta);
            sphere.rotation.y += 0.002;
            requestAnimationFrame(render);
			// 3. 用效果组合器来渲染 
            composer.render(delta);
        }
    	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. Threejs提供的后期处理通道

Threejs库提供了许多后期处理通道,这些通道可以直接添加到THREE.EffectComposer组合器中使用。

(1)简单后期处理通道

<!-- chapter-11-02.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Simple passes</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>
    <script type="text/javascript" src="../libs/postprocessing/ShaderPass.js"></script>
    <script type="text/javascript" src="../libs/shaders/CopyShader.js"></script>
    <script type="text/javascript" src="../libs/postprocessing/BloomPass.js"></script>
    <script type="text/javascript" src="../libs/shaders/ConvolutionShader.js"></script>
    <script type="text/javascript" src="../libs/postprocessing/DotScreenPass.js"></script>
    <script type="text/javascript" src="../libs/shaders/DotScreenShader.js"></script>
    <script type="text/javascript" src="../libs/postprocessing/EffectComposer.js"></script>
    <script type="text/javascript" src="../libs/postprocessing/MaskPass.js"></script>
    <script type="text/javascript" src="../libs/postprocessing/FilmPass.js"></script>
    <script type="text/javascript" src="../libs/shaders/FilmShader.js"></script>
    <script type="text/javascript" src="../libs/postprocessing/RenderPass.js"></script>
    <script type="text/javascript" src="../libs/postprocessing/TexturePass.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 = -10;
        camera.position.y = 15;
        camera.position.z = 25;
        camera.lookAt(new THREE.Vector3(0, 0, 0));

        var orbitControls = new THREE.OrbitControls(camera);
        orbitControls.autoRotate = false;

        var ambi = new THREE.AmbientLight(0x686868);
        scene.add(ambi);

        var spotLight = new THREE.DirectionalLight(0xffffff);
        spotLight.position.set(550, 100, 550);
        spotLight.intensity = 0.6;
        scene.add(spotLight);
        document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);
		
    	// 复制场景
        var renderPass = new THREE.RenderPass(scene, camera);
        var effectCopy = new THREE.ShaderPass(THREE.CopyShader);
        effectCopy.renderToScreen = true;
    	var composer = new THREE.EffectComposer(webGLRenderer);
        composer.addPass(renderPass);
        composer.addPass(effectCopy);
    	// 将上面场景输出为纹理,然后就可以作为其它组合器输入使用,这样就可以重复使用而不必每次都从零开始渲染场景。
    	var renderScene = new THREE.TexturePass(composer.renderTarget2);
		
    	// 简单组合器
        var bloomPass = new THREE.BloomPass(3, 25, 5.0, 256);
        var effectFilm = new THREE.FilmPass(0.8, 0.325, 256, false);
        effectFilm.renderToScreen = true;
        var dotScreenPass = new THREE.DotScreenPass();

        // 左下(黑点图层通道)
        var composer1 = new THREE.EffectComposer(webGLRenderer);
        composer1.addPass(renderScene);
        composer1.addPass(dotScreenPass);
        composer1.addPass(effectCopy);

        // 右下(原始图)
        var composer2 = new THREE.EffectComposer(webGLRenderer);
        composer2.addPass(renderScene);
        composer2.addPass(effectCopy);

        // 左上(泛光效果)
        var composer3 = new THREE.EffectComposer(webGLRenderer);
        composer3.addPass(renderScene);
        composer3.addPass(bloomPass);
        composer3.addPass(effectCopy);

        // 右上(电视栅格效果)
        var composer4 = new THREE.EffectComposer(webGLRenderer);
        composer4.addPass(renderScene);
        composer4.addPass(effectFilm);

        var controls = new function () {
            // film
            this.scanlinesCount = 256;   // 控制扫描线数量
            this.grayscale = false; // 设为true,输出结果将会被转换为灰度图
            this.scanlinesIntensity = 0.3; // 指定扫描线的显著程度
            this.noiseIntensity = 0.8; // 控制场景的粗糙程度

            // bloompass
            this.strength = 3; // 泛光效果强度
            this.kernelSize = 25; // 泛光效果的偏移量
            this.sigma = 5.0; // 控制泛光效果的锐利程度,值越大,泛光效果看起来越模糊
            this.resolution = 256; // 泛光效果的精确度,值越小,泛光效果的方块化越严重

            // dotscreen
            this.centerX = 0.5;     // 点偏移量
            this.centerY = 0.5;
            this.angle = 1.57;  // 改变点的对齐方式
            this.scale = 1; // 设置点的大小。值越小,则点越大

            this.updateEffectFilm = function () {
                effectFilm.uniforms.grayscale.value = controls.grayscale;
                effectFilm.uniforms.nIntensity.value = controls.noiseIntensity;
                effectFilm.uniforms.sIntensity.value = controls.scanlinesIntensity;
                effectFilm.uniforms.sCount.value = controls.scanlinesCount;
            };

            this.updateDotScreen = function () {
                var dotScreenPass = new THREE.DotScreenPass(new THREE.Vector2(controls.centerX, controls.centerY), controls.angle, controls.scale);

                composer1 = new THREE.EffectComposer(webGLRenderer);
                composer1.addPass(renderScene);
                composer1.addPass(dotScreenPass);
                composer1.addPass(effectCopy);
            };

            this.updateEffectBloom = function () {
                bloomPass = new THREE.BloomPass(controls.strength, controls.kernelSize, controls.sigma, controls.resolution);
                composer3 = new THREE.EffectComposer(webGLRenderer);
                composer3.addPass(renderScene);
                composer3.addPass(bloomPass);
                composer3.addPass(effectCopy);
            };
        };


        var gui = new dat.GUI();
        var bpFolder = gui.addFolder("BloomPass");
        bpFolder.add(controls, "strength", 1, 10).onChange(controls.updateEffectBloom);
        bpFolder.add(controls, "kernelSize", 1, 100).onChange(controls.updateEffectBloom);
        bpFolder.add(controls, "sigma", 1, 10).onChange(controls.updateEffectBloom);
        bpFolder.add(controls, "resolution", 0, 1024).onChange(controls.updateEffectBloom);

        var fpFolder = gui.addFolder("FilmPass");
        fpFolder.add(controls, "scanlinesIntensity", 0, 1).onChange(controls.updateEffectFilm);
        fpFolder.add(controls, "noiseIntensity", 0, 3).onChange(controls.updateEffectFilm);
        fpFolder.add(controls, "grayscale").onChange(controls.updateEffectFilm);
        fpFolder.add(controls, "scanlinesCount", 0, 2048).step(1).onChange(controls.updateEffectFilm);

        var dsFolder = gui.addFolder("DotScreenPass");
        dsFolder.add(controls, "centerX", 0, 1).onChange(controls.updateDotScreen);
        dsFolder.add(controls, "centerY", 0, 1).onChange(controls.updateDotScreen);
        dsFolder.add(controls, "angle", 0, 3.14).onChange(controls.updateDotScreen);
        dsFolder.add(controls, "scale", 0, 10).onChange(controls.updateDotScreen);

        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(0x4444aa);
            planetMaterial.normalMap = normalTexture;
            planetMaterial.map = planetTexture;
            var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, [planetMaterial]);
            return mesh;
        }

        var width = window.innerWidth || 2;
        var height = window.innerHeight || 2;
        var halfWidth = width / 2;
        var halfHeight = height / 2;
    	var clock = new THREE.Clock();
    	var delta = clock.getDelta();
        function render() {
            stats.update();
            orbitControls.update(delta);
            sphere.rotation.y += 0.002;
            requestAnimationFrame(render);
			
            // 多场景视口设置
            webGLRenderer.autoClear = false;
            webGLRenderer.clear();
			
            // 副本渲染,后续才能使用这个副本
            webGLRenderer.setViewport(0, 0, 2 * halfWidth, 2 * halfHeight);
            composer.render(delta);
			
            // 分别渲染4个视口场景
            webGLRenderer.setViewport(0, 0, halfWidth, halfHeight);
            composer1.render(delta);

            webGLRenderer.setViewport(halfWidth, 0, halfWidth, halfHeight);
            composer2.render(delta);

            webGLRenderer.setViewport(0, halfHeight, halfWidth, halfHeight);
            composer3.render(delta);

            webGLRenderer.setViewport(halfWidth, halfHeight, halfWidth, halfHeight);
            composer4.render(delta);
        }
    	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)使用掩码的高级效果组合器

前面使用后期处理的通道都是针对整个屏幕上,而下面讨论的掩码通道就可以指定特定区域上使用通道。添加掩码通道后,则后续的通道只作用于这个掩码通道区域。

<!-- chapter-11-03.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Post processing masks</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>
    <script type="text/javascript" src="../libs/postprocessing/ShaderPass.js"></script>
    <script type="text/javascript" src="../libs/shaders/CopyShader.js"></script>
    <script type="text/javascript" src="../libs/shaders/ColorifyShader.js"></script>
    <script type="text/javascript" src="../libs/postprocessing/BloomPass.js"></script>
    <script type="text/javascript" src="../libs/shaders/ConvolutionShader.js"></script>
    <script type="text/javascript" src="../libs/postprocessing/EffectComposer.js"></script>
    <script type="text/javascript" src="../libs/postprocessing/MaskPass.js"></script>
    <script type="text/javascript" src="../libs/postprocessing/FilmPass.js"></script>
    <script type="text/javascript" src="../libs/shaders/FilmShader.js"></script>
    <script type="text/javascript" src="../libs/shaders/SepiaShader.js"></script>
    <script type="text/javascript" src="../libs/postprocessing/RenderPass.js"></script>
    <script type="text/javascript" src="../libs/postprocessing/SavePass.js"></script>
    <script type="text/javascript" src="../libs/postprocessing/TexturePass.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();
    	// 3个场景分别渲染地球、火星、背景
        var sceneEarth = new THREE.Scene();
        var sceneMars = new THREE.Scene();
        var sceneBG = new THREE.Scene();

        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        var cameraBG = new THREE.OrthographicCamera(-window.innerWidth, window.innerWidth, window.innerHeight, -window.innerHeight, -10000, 10000); // 用正交相机来显示背景图
        cameraBG.position.z = 50;

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

        var sphere = createEarthMesh(new THREE.SphereGeometry(10, 40, 40));
        sphere.position.x = -10;
        var sphere2 = createMarshMesh(new THREE.SphereGeometry(5, 40, 40));
        sphere2.position.x = 10;
        sceneEarth.add(sphere);
        sceneMars.add(sphere2);
        camera.position.x = -10;
        camera.position.y = 15;
        camera.position.z = 25;
        camera.lookAt(new THREE.Vector3(0, 0, 0));
    
    	var materialColor = new THREE.MeshBasicMaterial({
            map: THREE.ImageUtils.loadTexture("../assets/textures/starry-deep-outer-space-galaxy.jpg"),
            depthTest: false
        });
        var bgPlane = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), materialColor);
        bgPlane.position.z = -100;
        bgPlane.scale.set(window.innerWidth * 2, window.innerHeight * 2, 1);
        sceneBG.add(bgPlane);

        var orbitControls = new THREE.OrbitControls(camera);
        orbitControls.autoRotate = false;
        var clock = new THREE.Clock();
		
    	// 注意不同场景光源要独立
        var ambi = new THREE.AmbientLight(0x181818);
        var ambi2 = new THREE.AmbientLight(0x181818);
        sceneEarth.add(ambi);
        sceneMars.add(ambi2);
        var spotLight = new THREE.DirectionalLight(0xffffff);
        spotLight.position.set(550, 100, 550);
        spotLight.intensity = 0.6;
        var spotLight2 = new THREE.DirectionalLight(0xffffff);
        spotLight.position.set(550, 100, 550);
        spotLight.intensity = 0.6;
        sceneEarth.add(spotLight);
        sceneMars.add(spotLight2);
        document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);
		
    	// 3个对应的渲染场景通道
        var bgPass = new THREE.RenderPass(sceneBG, cameraBG);
        var renderPass = new THREE.RenderPass(sceneEarth, camera);
        renderPass.clear = false;  // 要设置为false,不然每次渲染前会把前面已经渲染的给清除
        var renderPass2 = new THREE.RenderPass(sceneMars, camera);
        renderPass2.clear = false;

		// 复制当前渲染结果显示到屏幕通道
        var effectCopy = new THREE.ShaderPass(THREE.CopyShader);
        effectCopy.renderToScreen = true;

		// THREE.MaskPass到THREE.ClearMaskPass之间的通道只作用在THREE.MaskPass掩码通道对象上
        var clearMask = new THREE.ClearMaskPass();
        // earth mask
        var earthMask = new THREE.MaskPass(sceneEarth, camera);
		// earthMask.inverse = true;  // 反转掩码
        // mars mask
        var marsMask = new THREE.MaskPass(sceneMars, camera);
		// marsMask.inverse = true;

        var effectSepia = new THREE.ShaderPass(THREE.SepiaShader);
        effectSepia.uniforms['amount'].value = 0.8;

        var effectColorify = new THREE.ShaderPass(THREE.ColorifyShader);
        effectColorify.uniforms['color'].value.setRGB(0.5, 0.5, 1);

        var composer = new THREE.EffectComposer(webGLRenderer);
    	// 使用掩码要启动模板缓存
        composer.renderTarget1.stencilBuffer = true;
        composer.renderTarget2.stencilBuffer = true;
    	// 渲染原始场景
        composer.addPass(bgPass);
        composer.addPass(renderPass);
        composer.addPass(renderPass2);
		// 添加火星球体场景掩码,后续通道只能作用在这个区域
        composer.addPass(marsMask);
        composer.addPass(effectColorify);
		// 同上对地球场景添加掩码,只是要注意添加另一个掩码前要先清除上一个掩码通道
        composer.addPass(clearMask);
        composer.addPass(earthMask);
        composer.addPass(effectSepia);
		// 清除上次掩码通道,复制当前场景渲染到屏幕
        composer.addPass(clearMask);
        composer.addPass(effectCopy);

        function createMarshMesh(geom) {
            var planetTexture = THREE.ImageUtils.loadTexture("../assets/textures/planets/Mars_2k-050104.png");
            var normalTexture = THREE.ImageUtils.loadTexture("../assets/textures/planets/Mars-normalmap_2k.png");
            var planetMaterial = new THREE.MeshPhongMaterial();
            planetMaterial.normalMap = normalTexture;
            planetMaterial.map = planetTexture;
            var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, [planetMaterial]);
            return mesh;
        }

        function createEarthMesh(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(0x4444aa);
            planetMaterial.normalMap = normalTexture;
            planetMaterial.map = planetTexture;
            var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, [planetMaterial]);
            return mesh;
        }
		
    	var delta = clock.getDelta();
        function render() {
            webGLRenderer.autoClear = false;
            stats.update();
            orbitControls.update(delta);
            sphere.rotation.y += 0.002;
            sphere2.rotation.y += 0.002;
            requestAnimationFrame(render);
            composer.render(delta);
        }
    	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)使用THREE.ShaderPass自定义效果

这个通道可以传递一个自定义的着色器,将大量的额外效果添加到场景中。

Threejs提供的简单着色器:

另外,一些提供模糊效果的着色器:

最后,还有一些提供高级效果的着色器:

<!-- chapter-11-04.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Shader Pass simple</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/OBJLoader.js"></script>
    <script type="text/javascript" src="../libs/MTLLoader.js"></script>
    <script type="text/javascript" src="../libs/OBJMTLLoader.js"></script>
    <script type="text/javascript" src="../libs/postprocessing/EffectComposer.js"></script>
    <script type="text/javascript" src="../libs/postprocessing/ShaderPass.js"></script>
    <script type="text/javascript" src="../libs/postprocessing/RenderPass.js"></script>
    <script type="text/javascript" src="../libs/postprocessing/MaskPass.js"></script>
    <script type="text/javascript" src="../libs/shaders/CopyShader.js"></script>
    <script type="text/javascript" src="../libs/shaders/BrightnessContrastShader.js"></script>
    <script type="text/javascript" src="../libs/shaders/ColorifyShader.js"></script>
    <script type="text/javascript" src="../libs/shaders/SepiaShader.js"></script>
    <script type="text/javascript" src="../libs/shaders/RGBShiftShader.js"></script>
    <script type="text/javascript" src="../libs/shaders/ColorCorrectionShader.js"></script>
    <script type="text/javascript" src="../libs/shaders/MirrorShader.js"></script>
    <script type="text/javascript" src="../libs/shaders/VignetteShader.js"></script>
    <script type="text/javascript" src="../libs/shaders/HueSaturationShader.js"></script>
    <script type="text/javascript" src="../libs/shaders/BlendShader.js"></script>
    <script type="text/javascript" src="../libs/shaders/KaleidoShader.js"></script>
    <script type="text/javascript" src="../libs/shaders/LuminosityShader.js"></script>
    <script type="text/javascript" src="../libs/shaders/TechnicolorShader.js"></script>
    <script type="text/javascript" src="../libs/shaders/UnpackDepthRGBAShader.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(0xaaaaff, 1.0));
        webGLRenderer.setSize(window.innerWidth, window.innerHeight);
        webGLRenderer.shadowMapEnabled = true;
        camera.position.x = 20;
        camera.position.y = 30;
        camera.position.z = 40;
        camera.lookAt(new THREE.Vector3(-15, -10, -25));

        var spotLight = new THREE.SpotLight(0xffffff);
        spotLight.castShadow = true;
        spotLight.position.set(0, 60, 50);
        spotLight.intensity = 1;
        spotLight.shadowMapWidth = 2048;
        spotLight.shadowMapHeight = 2048;
        spotLight.shadowCameraFov = 120;
        spotLight.shadowCameraNear = 1;
        spotLight.shadowCameraFar = 1000;

        var ambiLight = new THREE.AmbientLight(0x444444);
        scene.add(ambiLight);
        scene.add(spotLight);
    	
        var plane = new THREE.BoxGeometry(1600, 1600, 0.1, 40, 40);
        var cube = new THREE.Mesh(plane, new THREE.MeshPhongMaterial(
                {
                    color: 0xffffff,
                    map: THREE.ImageUtils.loadTexture("../assets/textures/general/plaster-diffuse.jpg"),
                    normalMap: THREE.ImageUtils.loadTexture("../assets/textures/general/plaster-normal.jpg"),
                    normalScale: new THREE.Vector2(0.6, 0.6)
                }));
        cube.material.map.wrapS = THREE.RepeatWrapping;
        cube.material.map.wrapT = THREE.RepeatWrapping;
        cube.material.normalMap.wrapS = THREE.RepeatWrapping;
        cube.material.normalMap.wrapT = THREE.RepeatWrapping;
        cube.rotation.x = Math.PI / 2;
        cube.material.map.repeat.set(80, 80);
        cube.receiveShadow = true;
        cube.position.z = -150;
        cube.position.x = -150;
        scene.add(cube);

        var cube1 = new THREE.Mesh(new THREE.BoxGeometry(30, 10, 2), new THREE.MeshPhongMaterial({color: 0xff0000}));
        cube1.position.x = -15;
        cube1.position.y = 5;
        cube1.position.z = 15;
        cube1.castShadow = true;
        scene.add(cube1);

        var cube2 = cube1.clone();
        cube2.material = cube1.material.clone();
        cube2.material.color = new THREE.Color(0x00ff00);
        cube2.position.z = 5;
        cube2.position.x = -20;
        scene.add(cube2);

        var cube3 = cube1.clone();
        cube3.material = cube1.material.clone();
        cube3.material.color = new THREE.Color(0x0000ff);
        cube3.position.z = -8;
        cube3.position.x = -25;
        scene.add(cube3);
        document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);

		var mesh;
        var loader = new THREE.OBJMTLLoader();
        loader.load('../assets/models/sol/libertStatue.obj', '../assets/models/sol/libertStatue.mtl',
                function (event) {
                    var object = event;
                    // fix for incorrect uvs.
                    console.log(event);
                    var geom = object.children[0].geometry;
                    var uv3 = geom.faceVertexUvs[0][0];
                    var uv4 = geom.faceVertexUvs[0][10];

                    // fill in the missing ones
                    for (var j = 0; j < 7616 - 7206; j++) {
                        if (geom.faces[j + 7206] instanceof THREE.Face4) {
                            geom.faceVertexUvs[0].push(uv4);
                        } else {
                            geom.faceVertexUvs[0].push(uv4);
                        }
                    }

                    object.children.forEach(function (e) {
                        e.castShadow = true
                    });

                    object.scale.set(20, 20, 20);
                    mesh = object;
                    mesh.position.x = 15;
                    mesh.position.z = 5;
                    scene.add(object);
                });

		// 各种shader通道
        var mirror = new THREE.ShaderPass(THREE.MirrorShader);
        mirror.enabled = false;

        var hue = new THREE.ShaderPass(THREE.HueSaturationShader);
        hue.enabled = false;

        var vignette = new THREE.ShaderPass(THREE.VignetteShader);
        vignette.enabled = false;

        var colorCorrection = new THREE.ShaderPass(THREE.ColorCorrectionShader);
        colorCorrection.enabled = false;
        var rgbShift = new THREE.ShaderPass(THREE.RGBShiftShader);
        rgbShift.enabled = false;

        var brightness = new THREE.ShaderPass(THREE.BrightnessContrastShader);
        brightness.uniforms.brightness.value = 0;
        brightness.uniforms.contrast.value = 0;
        brightness.enabled = false;
        brightness.uniforms.brightness.value = 0;
        brightness.uniforms.contrast.value = 0;

        var colorify = new THREE.ShaderPass(THREE.ColorifyShader);
        colorify.uniforms.color.value = new THREE.Color(0xffffff);
        colorify.enabled = false;

        var sepia = new THREE.ShaderPass(THREE.SepiaShader);
        sepia.uniforms.amount.value = 1;
        sepia.enabled = false;

        var kal = new THREE.ShaderPass(THREE.KaleidoShader);
        kal.enabled = false;

        var lum = new THREE.ShaderPass(THREE.LuminosityShader);
        lum.enabled = false;

        var techni = new THREE.ShaderPass(THREE.TechnicolorShader);
        techni.enabled = false;

        var unpack = new THREE.ShaderPass(THREE.UnpackDepthRGBAShader);
        unpack.enabled = false;

        var renderPass = new THREE.RenderPass(scene, camera);
        var effectCopy = new THREE.ShaderPass(THREE.CopyShader);
        effectCopy.renderToScreen = true;

        var composer = new THREE.EffectComposer(webGLRenderer);
        composer.addPass(renderPass);
        composer.addPass(brightness);
        composer.addPass(sepia);
        composer.addPass(mirror);
        composer.addPass(colorify);
        composer.addPass(colorCorrection);
        composer.addPass(rgbShift);
        composer.addPass(vignette);
        composer.addPass(hue);
        composer.addPass(kal);
        composer.addPass(lum);
        composer.addPass(techni);
        composer.addPass(unpack);
        composer.addPass(effectCopy);

        var controls = new function () {
            this.brightness = 0.01;
            this.contrast = 0.01;
            this.select = 'none';
            this.color = 0xffffff;
            this.amount = 1;
            this.powRGB_R = 2;
            this.mulRGB_R = 1;
            this.powRGB_G = 2;
            this.mulRGB_G = 1;
            this.powRGB_B = 2;
            this.mulRGB_B = 1;
            this.rgbAmount = 0.005;
            this.angle = 0.0;
            this.side = 1;
            this.offset = 1;
            this.darkness = 1;
            this.hue = 0.01;
            this.saturation = 0.01;
            this.kalAngle = 0;
            this.kalSides = 6;
            this.rotate = false;

            this.switchShader = function () {
                switch (controls.select) {
                    case 'none' :
                    {
                        enableShader();
                        break;
                    }

                    case 'colorify' :
                    {
                        enableShader(colorify);
                        break;
                    }

                    case 'brightness' :
                    {
                        enableShader(brightness);
                        break;
                    }

                    case 'sepia' :
                    {
                        enableShader(sepia);
                        break;
                    }

                    case 'colorCorrection' :
                    {
                        enableShader(colorCorrection);
                        break;
                    }

                    case 'rgbShift' :
                    {
                        enableShader(rgbShift);
                        break;
                    }

                    case 'mirror' :
                    {
                        enableShader(mirror);
                        break;
                    }

                    case 'vignette' :
                    {
                        enableShader(vignette);
                        break;
                    }

                    case 'hueAndSaturation' :
                    {
                        enableShader(hue);
                        break;
                    }

                    case 'kaleidoscope' :
                    {
                        enableShader(kal);
                        break;
                    }
                    case 'luminosity' :
                    {
                        enableShader(lum);
                        break;
                    }
                    case 'technicolor' :
                    {
                        enableShader(techni);
                        break;
                    }
                    case 'unpackDepth' :
                    {
                        enableShader(unpack);
                        break;
                    }
                }
            };

            this.changeBrightness = function () {
                brightness.uniforms.brightness.value = controls.brightness;
                brightness.uniforms.contrast.value = controls.contrast;
            };

            this.changeColor = function () {
                colorify.uniforms.color.value = new THREE.Color(controls.color);
            };

            this.changeSepia = function () {
                sepia.uniforms.amount.value = controls.amount;
            };

            this.changeCorrection = function () {
                colorCorrection.uniforms.mulRGB.value = new THREE.Vector3(controls.mulRGB_R, controls.mulRGB_G, controls.mulRGB_B);
                colorCorrection.uniforms.powRGB.value = new THREE.Vector3(controls.powRGB_R, controls.powRGB_G, controls.powRGB_B);
            };

            this.changeRGBShifter = function () {
                rgbShift.uniforms.amount.value = controls.rgbAmount;
                rgbShift.uniforms.angle.value = controls.angle;
            };

            this.changeMirror = function () {
                mirror.uniforms.side.value = controls.side;
            };

            this.changeVignette = function () {
                vignette.uniforms.darkness.value = controls.darkness;
                vignette.uniforms.offset.value = controls.offset;
            };

            this.changeHue = function () {
                hue.uniforms.hue.value = controls.hue;
                hue.uniforms.saturation.value = controls.saturation;
            };

            this.changeKal = function () {
                kal.uniforms.sides.value = controls.kalSides;
                kal.uniforms.angle.value = controls.kalAngle;
            };

            function enableShader(shader) {
                for (var i = 1; i < composer.passes.length - 1; i++) {
                    if (composer.passes[i] == shader) {
                        composer.passes[i].enabled = true;
                    } else {
                        composer.passes[i].enabled = false;
                    }
                }
            }
        };

        var gui = new dat.GUI();
        gui.add(controls, "select", ['none', "colorify", 'brightness', 'sepia', 'colorCorrection', 'rgbShift', 'mirror', 'vignette', 'hueAndSaturation', 'kaleidoscope', 'luminosity', 'technicolor']).onChange(controls.switchShader);
        gui.add(controls, "rotate");

        var bnFolder = gui.addFolder("Brightness");
        bnFolder.add(controls, "brightness", -1, 1).onChange(controls.changeBrightness);
        bnFolder.add(controls, "contrast", -1, 1).onChange(controls.changeBrightness);

        var clFolder = gui.addFolder("Colorify");
        clFolder.addColor(controls, "color").onChange(controls.changeColor);

        var colFolder = gui.addFolder('Color Correction');
        colFolder.add(controls, "powRGB_R", 0, 5).onChange(controls.changeCorrection);
        colFolder.add(controls, "powRGB_G", 0, 5).onChange(controls.changeCorrection);
        colFolder.add(controls, "powRGB_B", 0, 5).onChange(controls.changeCorrection);
        colFolder.add(controls, "mulRGB_R", 0, 5).onChange(controls.changeCorrection);
        colFolder.add(controls, "mulRGB_G", 0, 5).onChange(controls.changeCorrection);
        colFolder.add(controls, "mulRGB_B", 0, 5).onChange(controls.changeCorrection);

        var sepiaFolder = gui.addFolder("Sepia");
        sepiaFolder.add(controls, "amount", 0, 2).step(0.1).onChange(controls.changeSepia);

        var shiftFolder = gui.addFolder("RGB Shift");
        shiftFolder.add(controls, "rgbAmount", 0, 0.1).step(0.001).onChange(controls.changeRGBShifter);
        shiftFolder.add(controls, "angle", 0, 3.14).step(0.001).onChange(controls.changeRGBShifter);

        var mirrorFolder = gui.addFolder("mirror");
        mirrorFolder.add(controls, "side", 0, 3).step(1).onChange(controls.changeMirror);

        var vignetteFolder = gui.addFolder("vignette");
        vignetteFolder.add(controls, "darkness", 0, 2).onChange(controls.changeVignette);
        vignetteFolder.add(controls, "offset", 0, 2).onChange(controls.changeVignette);

        var hueAndSat = gui.addFolder("hue and saturation");
        hueAndSat.add(controls, "hue", -1, 1).step(0.01).onChange(controls.changeHue);
        hueAndSat.add(controls, "saturation", -1, 1).step(0.01).onChange(controls.changeHue);


        var kalMenu = gui.addFolder("Kaleidoscope");
        kalMenu.add(controls, "kalAngle", -2 * Math.PI, 2 * Math.PI).onChange(controls.changeKal);
        kalMenu.add(controls, "kalSides", 2, 20).onChange(controls.changeKal);

        function render() {
            stats.update();
            if (controls.rotate) {
                if (mesh) mesh.rotation.y += 0.01;
                cube1.rotation.y += 0.01;
                cube2.rotation.y += 0.01;
                cube3.rotation.y += 0.01;
            }
            requestAnimationFrame(render);
            composer.render();
        }
    	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. 创建自定义后期处理着色器

自定义着色器主要是两个:

  • 顶点着色器:用于改变每个顶点的位置。
  • 片段着色器:用于定义每个像素的颜色。

着色器程序是使用OpenGL着色器语言GLSL写的,有点像C语言。关于这个是一个很大的话题,本节只会简单介绍使用流程。

示例写了两个着色器,一个是将图片转换为灰度图,一个是将图片转换为8位图。

架子(就是用上面的THREE.ShaderPass通道,只是把传递的着色器程序换成我们自定义的了):

<!-- chapter-11-05.html -->
<!DOCTYPE html>
<html>
<head>
    <title>custom shaderpass</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>
    <script type="text/javascript" src="../libs/postprocessing/ShaderPass.js"></script>
    <script type="text/javascript" src="../libs/shaders/CopyShader.js"></script>
    <script type="text/javascript" src="../libs/postprocessing/EffectComposer.js"></script>
    <script type="text/javascript" src="../libs/postprocessing/MaskPass.js"></script>
    <script type="text/javascript" src="../libs/postprocessing/ShaderPass.js"></script>
	<script type="text/javascript" src="../libs/postprocessing/RenderPass.js"></script>
    <!--- 导入自定义着色器程序 -->
	<script type="text/javascript" src="custom-shader.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<div id="Stats-output">
</div>
<!-- Div which will hold the Output -->
<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 = -10;
        camera.position.y = 15;
        camera.position.z = 25;
        camera.lookAt(new THREE.Vector3(0, 0, 0));

        var orbitControls = new THREE.OrbitControls(camera);
        orbitControls.autoRotate = false;
        var clock = new THREE.Clock();

        var ambi = new THREE.AmbientLight(0x181818);
        scene.add(ambi);

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

        var renderPass = new THREE.RenderPass(scene, camera);
        var effectCopy = new THREE.ShaderPass(THREE.CopyShader);
        effectCopy.renderToScreen = true;
    	
    	// 置灰着色器通道
        var shaderPass = new THREE.ShaderPass(THREE.CustomGrayScaleShader);
        shaderPass.enabled = false;
		// 转8位图着色器通道
        var bitPass = new THREE.ShaderPass(THREE.CustomBitShader);
        bitPass.enabled = false;

        var composer = new THREE.EffectComposer(webGLRenderer);
        composer.addPass(renderPass);
        composer.addPass(shaderPass);
        composer.addPass(bitPass);
        composer.addPass(effectCopy);

        var controls = new function () {
            this.grayScale = false;
            this.rPower = 0.2126;
            this.gPower = 0.7152;
            this.bPower = 0.0722;
            this.bitShader = false;
            this.bitSize = 8;

            this.updateEffectFilm = function () {
                shaderPass.enabled = controls.grayScale;
                shaderPass.uniforms.rPower.value = controls.rPower;
                shaderPass.uniforms.gPower.value = controls.gPower;
                shaderPass.uniforms.bPower.value = controls.bPower;
            };

            this.updateBit = function () {
                bitPass.enabled = controls.bitShader;
                bitPass.uniforms.bitSize.value = controls.bitSize;
            }
        };

        var gui = new dat.GUI();
        var grayMenu = gui.addFolder('gray scale');
        grayMenu.add(controls, 'grayScale').onChange(controls.updateEffectFilm);
        grayMenu.add(controls, 'rPower', 0, 1).onChange(controls.updateEffectFilm);
        grayMenu.add(controls, 'gPower', 0, 1).onChange(controls.updateEffectFilm);
        grayMenu.add(controls, 'bPower', 0, 1).onChange(controls.updateEffectFilm);
        var bitMenu = gui.addFolder('bit');
        bitMenu.add(controls, 'bitShader').onChange(controls.updateBit);
        bitMenu.add(controls, 'bitSize', 2, 24).step(1).onChange(controls.updateBit);

        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(0x4444aa);
            planetMaterial.normalMap = normalTexture;
            planetMaterial.map = planetTexture;
            var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, [planetMaterial]);
            return mesh;
        }

    	var delta = clock.getDelta();
        function render() {
            stats.update();
            orbitControls.update(delta);
            sphere.rotation.y += 0.002;
            requestAnimationFrame(render);
            composer.render(delta);
        }
    	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>

着色器程序:

// custom-shader.js

THREE.CustomGrayScaleShader = {
    uniforms: {
        "tDiffuse": {type: "t", value: null},
        "rPower": {type: "f", value: 0.2126},
        "gPower": {type: "f", value: 0.7152},
        "bPower": {type: "f", value: 0.0722}
    },

    // 0.2126 R + 0.7152 G + 0.0722 B
    // vertexshader is always the same for postprocessing steps
    vertexShader: [
        "varying vec2 vUv;",
        "void main() {",
        	"vUv = uv;",
        	"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
        "}"
    ].join("\n"),

    fragmentShader: [
        // pass in our custom uniforms
        "uniform float rPower;",
        "uniform float gPower;",
        "uniform float bPower;",

        // pass in the image/texture we'll be modifying
        "uniform sampler2D tDiffuse;",

        // used to determine the correct texel we're working on
        "varying vec2 vUv;",

        // executed, in parallel, for each pixel
        "void main() {",
            // get the pixel from the texture we're working with (called a texel)
            "vec4 texel = texture2D( tDiffuse, vUv );",

            // calculate the new color
            "float gray = texel.r*rPower + texel.g*gPower + texel.b*bPower;",

            // return this new color
            "gl_FragColor = vec4( vec3(gray), texel.w );",
        "}"
    ].join("\n")
};

THREE.CustomBitShader = {
    uniforms: {
        "tDiffuse": {type: "t", value: null},
        "bitSize": {type: "i", value: 4}
    },

    vertexShader: [
        "varying vec2 vUv;",
        "void main() {",
        	"vUv = uv;",
        	"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
        "}"
    ].join("\n"),

    fragmentShader: [
        "uniform int bitSize;",
        "uniform sampler2D tDiffuse;",
        "varying vec2 vUv;",
        "void main() {",
        	"vec4 texel = texture2D( tDiffuse, vUv );",
        	"float n = pow(float(bitSize),2.0);",
        	"float newR = floor(texel.r*n)/n;",
        	"float newG = floor(texel.g*n)/n;",
        	"float newB = floor(texel.b*n)/n;",
        	"gl_FragColor = vec4( vec3(newR,newG,newB), 1.0);",
        "}"
    ].join("\n")
};

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

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

相关文章

指定某个时间,计算和当前时间间隔几天几时几分

dateDiff(startTime,endTime) {let t1 new Date(startTime).getTime()*1000; //开始时间 2023-06-29 10:00:00let t2 new Date(endTime).getTime()*1000; //结束时间 1688090400000000 2023-06-30 10:00:00 1688092230000000 2023-06-30 10:30:30let dateTime 1000 *…

小程序反编译

第一步&#xff1a;下载软件 根据把博客下载好三个软件 夜神模拟器 RE文件管理器 Node.js 第二步&#xff1a;打开模拟器中的 “微信” 第三步&#xff1a;点击要下载的小程序 并 记录当时的时间 方便一会查找pkg文件 第四步&#xff1a;打开文件资源管理器 第五步&#xff1a…

PyTorch的ONNX结合MNIST手写数字数据集的应用(.pth和.onnx的转换与onnx运行时)

在PyTorch以前的模型都是.pth格式&#xff0c;后面Meta跟微软一起做了一个.onnx的通用格式。这里对这两种格式文件&#xff0c;分别做一个介绍&#xff0c;依然使用MNIST数据集来做示例 1、CUDA下的pth文件 那pth文件里面是什么结构呢&#xff1f;其实在以前的文章就有介绍过…

0基础学习VR全景平台篇 第50篇:高级功能-自定义右键

本期为大家带来蛙色VR平台&#xff0c;高级功能—自定义右键功能操作。 功能位置示意 一、本功能将用在哪里&#xff1f; 自定义右键功能&#xff0c;观看者可通过电脑端右键和手机端长按屏幕&#xff0c;出现作者配置的自定义内容&#xff0c;使VR全景玩法变得多样化。 二、…

欧科云链2023年报:毛利达1.55亿港元,数字资产业务成最大增长点

据香港商报报道&#xff0c;2023年6月28日&#xff0c;欧科云链控股有限公司&#xff08;以下简称“欧科云链”&#xff09;及其附属公司&#xff08;股份代号&#xff1a;1499.HK&#xff0c;以下简称“集团”&#xff09;发布了截至2023年3月31日的年度报告。报告期内&#x…

工业读码器的选择和使用注意事项有哪些?

工业读码器是一种能够读取条形码、二维码等信息的设备&#xff0c;广泛应用于物流、生产制造、零售等行业。如何选择和使用工业读码器呢?下面是一些注意事项。 选择工业读码器 要根据应用场景选择合适的读码器类型&#xff0c;如手持式、固定式、手动旋转式等。 要考虑读取码的…

【C++】详解多态

目录 一、多态的概念二、多态的定义及实现1、多态的构成条件2、虚函数3、虚函数的重写1、虚函数重写的两个例外 4、C11 override 和 final5、重载、覆盖(重写)、隐藏(重定义)的对比 三、抽象类1、概念2、接口继承和实现继承 四、多态的原理1、虚函数表2、多态的原理3、动态绑定…

Mysql架构篇--Mysql(M-S) 主从同步

文章目录 前言&#xff1a;一、主从同步是什么&#xff1f;二、主从同步实现&#xff1a;1.准备工作&#xff1a;2.开启主从复制&#xff1a;2.1 mysql 服务端配置文件修改&#xff1a;2.2 mysql master 节点用户创建&#xff1a;2.3 mysql slave 节点开启数据复制&#xff1a;…

突破传统设计灵感,虚拟展厅设计方案

导语&#xff1a; 随着科技的不断发展&#xff0c;虚拟展厅设计方案正成为现代设计行业的新宠。这种创新的设计形式不仅突破了传统设计的局限&#xff0c;还为传统设计公司带来了诸多优势和特点&#xff0c;从而提高了设计产量和创意灵感。 在这篇软文中&#xff0c;我们将深入…

雅迪、爱玛谁是“新宠”?

电动两轮车下半场&#xff0c;谁是“新王”&#xff1f; 6月15日&#xff0c;爱玛科技有限公司&#xff08;下称“爱玛”&#xff0c;603529.SH)迎来了上市两周年。 作为电动两轮车的头部玩家&#xff0c;雅迪控股有限公司&#xff08;下称“雅迪”&#xff0c;01585.HK&…

HJ101 输入整型数组和排序标识,对其元素

描述 输入整型数组和排序标识&#xff0c;对其元素按照升序或降序进行排序 数据范围&#xff1a; 1≤n≤1000 1≤n≤1000 &#xff0c;元素大小满足 0≤val≤100000 0≤val≤100000 输入描述&#xff1a; 第一行输入数组元素个数 第二行输入待排序的数组&#xff0c;每个…

python实现九九乘法表

九九乘法表 i 1 while i < 9:j 1while j < i:print(f{j}*{i}{i * j}, end\t)j 1print()i 1结果&#xff1a;

window10 查看本机TCP协议进程

1. netstat 是一个常见的网络工具&#xff0c;用于显示网络连接状态、路由表、接口统计信息等网络相关的信息&#xff0c;可以帮助诊断和解决网络问题。 其中&#xff0c;各参数的含义为&#xff1a; -a&#xff1a;显示所有的网络连接和监听端口。 -e&#xff1a;显示以太网…

CDH yarn Fair 队列最大资源使用限制,任务无法提交

一、问题背景描述 1.任务提交异常日志 2023-06-29 15:48:20,877 INFO org.apache.flink.yarn.YarnClusterDescriptor [] - Deployment took more than 60 seconds. Please check if the requested resources are available in the YARN cluster 2023-06-29 15:48:21,129 IN…

1-什么是NumPy?【视频版】

目录 问题解答观看视频 问题 解答 NumPy&#xff0c;全称Numerical Python&#xff0c;是一个开源的Python科学计算库。它为Python提供了大量的数学库&#xff0c;包括&#xff1a; 强大的N维数组对象成熟的广播功能集成C/C和Fortran代码的工具有用的线性代数、傅里叶变换和随…

第一个spring程序

我们今天写第一个spring程序 我们采用maven形式创建工程。 我们首先在pom.xml中加入引用。 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSch…

(6)蜂鸣器(又称音调报警)

文章目录 6.1 使用有源蜂鸣器而不是无源蜂鸣器 6.2 安装蜂鸣器 6.3 使蜂鸣器安静 蜂鸣器&#xff08;或音调报警器&#xff09;可用于以声音指示飞行器的状态变化。根据电路板的能力&#xff0c;它可以是一个有源设备&#xff08;只需要施加电压来产生一个单一频率的音调&am…

给定一组数据样本,计算:【样本的平均值】, 【样本的标准差】, 【样本的变异系数】,【样本的标准误差】

一、指标含义 样本的平均值&#xff1a;指样本中所有数据的总和除以样本大小&#xff0c;是样本的中心趋势的度量。平均值常用于描述数据的集中程度&#xff0c;具有良好的代表性和易于计算的优点。 样本的标准差&#xff1a;指样本中每个数据与平均值的偏差的平方和的平均值的…

openssl版本升级与降级

openssl版本升级与降级 flyfish 环境 Ubuntu 22.04 1.1.1升级3.1.1 查看openssl版本 openssl versionOpenSSL 1.1.1t 7 Feb 2023https://www.openssl.org/source/ 编译和安装 ./config --prefix/usr/local/openssl311 make -j8 make install进入/usr/local/openssl311/l…

JavaWeb两大组件FILTERLISTENER

一.Filter&#xff1a;过滤器 是什么&#xff1a; 当访问服务器的资源时&#xff0c;过滤器可以将请求拦截下来&#xff0c;完成一些特殊的功能。 作用&#xff1a; 一般用于完成通用的操作。如&#xff1a;登录验证、统一编码处理、敏感字符过滤… 具体流程&#xff1a; 原始…