使用three.js的着色器通道渲染地球模型

2018-5-11    seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

我们都知道,three.js库里面内置了很多着色器通道对象供我们渲染场景,本文将对EffectComposer、RenderPass、FilmPass这三个通道进行学习和实现:

1.RenderPass这个通道会在当前场景(scene)和摄像机(camera)的基础上渲染出一个新场景,新建:

[javascript] view plain copy
  1. let renderPass = new THREE.RenderPass(scene, camera);  

2.FilmPass这个通道通过扫描线和失真模拟电视屏幕效果,实现的效果超有时代感,新建:

[javascript] view plain copy
  1. /*四个参数分别为粗糙程度,扫描线强度,扫描线数量,是否转换为灰度图*/  
  2. let effectFilm = new THREE.FilmPass(0.8, 0.325, 256, false);  
  3. //将渲染结果输出到屏幕  
  4. effectFilm.renderToScreen = true;  

3.EffectComposer可以理解为着色器通道容器,着色器通道按照先后顺序添加进来并执行,新建:

[javascript] view plain copy
  1. /*渲染效果组合器,每个通道都按照传入的顺序执行*/  
  2. let composer = new THREE.EffectComposer(renderer);  
  3. composer.addPass(renderPass);  
  4. composer.addPass(effectFilm);  

本文实现的demo基于three.js_r86(请自行下载),代码所用js文件和图片都在下载的那个包里面,请读者自行引用。

实现效果:



代码:

[html] view plain copy
  1. <!DOCTYPE html>  
  2. <html lang="en">  
  3. <head>  
  4.     <meta charset="UTF-8">  
  5.     <title>shader_2_earth</title>  
  6.     <style>  
  7.         body{  
  8.             margin: 0;  
  9.             overflow: hidden;  
  10.         }  
  11.     </style>  
  12. </head>  
  13. <body>  
  14. <script src="build/three.js"></script>  
  15. <script src="js/libs/stats.min.js"></script>  
  16. <script src="js/libs/dat.gui.min.js"></script>  
  17. <script src="js/controls/OrbitControls.js"></script>  
  18. <script src="js/Detector.js"></script>  
  19.   
  20. <script src="js/postprocessing/EffectComposer.js"></script>  
  21. <script src="js/postprocessing/ShaderPass.js"></script>  
  22. <script src="js/postprocessing/MaskPass.js"></script>  
  23. <script src="js/postprocessing/FilmPass.js"></script>  
  24. <script src="js/postprocessing/BloomPass.js"></script>  
  25. <script src="js/postprocessing/RenderPass.js"></script>  
  26.   
  27. <script src="js/shaders/CopyShader.js"></script>  
  28. <script src="js/shaders/FilmShader.js"></script>  
  29.   
  30. <div id="stats"></div>  
  31. <div id="container"></div>  
  32. <script>  
  33.     //检测webgl的兼容性  
  34.    if(!Detector.webgl) Detector.addGetWebGLMessage();  
  35.   
  36.    let scene;  
  37.    let camera, renderer, sphere, controls, stats;  
  38.    let ambientLight, spotLight;  
  39.    let composer;  
  40.    let clock;  
  41.   
  42.    main();  
  43.    render();  
  44.   
  45.    function main() {  
  46.        scene = new THREE.Scene();  
  47.   
  48.        camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000);  
  49.        camera.position.set(-10, 15, 25);  
  50.        camera.lookAt(new THREE.Vector3(0, 0, 0));  
  51.   
  52.        renderer = new THREE.WebGLRenderer({antialias:true});  
  53.        renderer.setClearColor(new THREE.Color(0,0,0));  
  54.        renderer.setSize(window.innerWidth, window.innerHeight);  
  55.        renderer.shadowMapEnabled = true;  
  56.   
  57.        controls = new THREE.OrbitControls(camera);  
  58.        controls.autoRotate = false;  
  59.   
  60.        clock = new THREE.Clock();  
  61.   
  62.        ambientLight = new THREE.AmbientLight(0x181818);  
  63.        scene.add(ambientLight);  
  64.   
  65.        spotLight = new THREE.SpotLight(0xffffff);  
  66.        spotLight.position.set(550, 100, 550);  
  67.        spotLight.intensity = 0.6;  
  68.        scene.add(spotLight);  
  69.   
  70.        //创建地球  
  71.        sphere = createMesh(new THREE.SphereGeometry(10, 60, 60));  
  72.        scene.add(sphere);  
  73.   
  74.        document.getElementById("container").appendChild(renderer.domElement);  
  75.   
  76.        /**  
  77.         * 添加渲染通道  
  78.         */  
  79.        //在当前场景和摄像机的基础上渲染一个新场景  
  80.        let renderPass = new THREE.RenderPass(scene, camera);  
  81.        //通过扫描线和失真来实现模拟电视屏幕的效果  
  82.        let effectFilm = new THREE.FilmPass(0.8, 0.325, 256, false);  
  83.        //将渲染结果输出到屏幕  
  84.        effectFilm.renderToScreen = true;  
  85.   
  86.        //渲染效果组合器,每个通道都按照传入的顺序执行  
  87.        composer = new THREE.EffectComposer(renderer);  
  88.        composer.addPass(renderPass);  
  89.        composer.addPass(effectFilm);  
  90.   
  91.        //菜单栏元素  
  92.        let guiFields = {  
  93.            "扫描线数量": 256,  
  94.            "灰度图像": false,  
  95.            "扫描线强度": 0.3,  
  96.            "粗糙程度": 0.8,  
  97.            "updateEffectFilm": function () {  
  98.                effectFilm.uniforms.grayscale.value = guiFields.灰度图像;  
  99.                effectFilm.uniforms.nIntensity.value = guiFields.粗糙程度;  
  100.                effectFilm.uniforms.sIntensity.value = guiFields.扫描线强度;  
  101.                effectFilm.uniforms.sCount.value = guiFields.扫描线数量;  
  102.            }  
  103.        };  
  104.   
  105.        //新建一个菜单栏  
  106.        let gui = new dat.GUI();  
  107.        gui.add(guiFields, "扫描线数量", 0, 2048).onChange(guiFields.updateEffectFilm);  
  108.        gui.add(guiFields, "扫描线强度", 0, 1).onChange(guiFields.updateEffectFilm);  
  109.        gui.add(guiFields, "粗糙程度", 0, 3).onChange(guiFields.updateEffectFilm);  
  110.        gui.add(guiFields, "灰度图像").onChange(guiFields.updateEffectFilm);  
  111.   
  112.        stats = initStats();  
  113.    }  
  114.   
  115.    //创建一个Mesh  
  116.    function createMesh(geometry) {  
  117.   
  118.        //初始化纹理加载器  
  119.        let textureLoader = new THREE.TextureLoader();  
  120.        //加载图片  
  121.        let uniforms = {  
  122.            planetTexture:{value:textureLoader.load("textures/planets/earth_atmos_2048.jpg")},  
  123.            specularTexture:{value:textureLoader.load("textures/planets/earth_specular_2048.jpg")},  
  124.            normalTexture:{value:textureLoader.load("textures/planets/earth_normal_2048.jpg")}  
  125.        };  
  126.   
  127.        //创建phong材料,并进行相应图片的贴图  
  128.        let planetMaterial = new THREE.MeshPhongMaterial();  
  129.        planetMaterial.specularMap = uniforms.specularTexture.value;  
  130.        planetMaterial.specular = new THREE.Color(0x4444aa);  
  131.   
  132.        planetMaterial.normalMap = uniforms.normalTexture.value;  
  133.        planetMaterial.map = uniforms.planetTexture.value;  
  134.   
  135.        //新建一个mesh  
  136.        let mesh = new THREE.SceneUtils.createMultiMaterialObject(geometry, [planetMaterial]);  
  137.   
  138.        return mesh;  
  139.    }  
  140.   
  141.    //渲染更新场景  
  142.   
  143.    function render() {  
  144.        stats.update();  
  145.        let delta = clock.getDelta();  
  146.        controls.update(delta);  
  147.        sphere.rotation.y += 0.002;  
  148.        requestAnimationFrame(render);  
  149.   
  150.        //没有着色器通道系统默认为WebGLRenderer.render  
  151.        //使用着色器通道后,应使用使用composer.render  
  152.        composer.render(delta);  
  153.    }  
  154.   
  155.    //左上角帧显示  
  156.    function initStats() {  
  157.        let stats = new Stats();  
  158.        stats.setMode(0);  
  159.        stats.domElement.style.position = 'absolute';  
  160.        stats.domElement.style.left = '0px';  
  161.        stats.domElement.style.top = '0px';  
  162.        document.getElementById("stats").appendChild(stats.domElement);  
  163.   
  164.        return stats;  
  165.    }  
  166. </script>  
  167. </body>  
  168. </html>  
蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

分享本文至:

日历

链接

blogger

蓝蓝 http://www.lanlanwork.com

存档