threejs学习笔记-04

Posted weixin_43739821

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了threejs学习笔记-04相关的知识,希望对你有一定的参考价值。

16.threejs的标准、物理材质
(1)标准材质:

<!DOCTYPE html>
<html>

<head>
    <title>threejs</title>
    <meta charset="UTF-8" />
    <style>
        body 
            margin: 0;
            overflow: hidden;
        
    </style>

</head>

<body>
    <div id="webgl-output">

    </div>

    <div id="myStats"></div>
    <script type="module">
        import * as THREE from "../../libs/build/three.module.js"
        import  dat  from "../../libs/dat.gui/dat.gui.js"
        import  Stats  from "../../libs/Stats/Stats.js"
        //模型文件是OBJ模式的,所以我们需要在代码上方导入OBJ加载器
        import  OBJLoader  from "../../libs/three.js/jsm/loaders/OBJLoader.js"
        import  GLTFLoader  from "../../libs/three.js/jsm/loaders/GLTFLoader.js"
        import  OrbitControls  from "../../libs/three.js/jsm/controls/OrbitControls.js"

        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.001, 100000);
        var render = new THREE.WebGLRenderer();
        render.setClearColor(new THREE.Color(0x000000));
        render.setSize(window.innerWidth, window.innerHeight);
        render.shadowMap.enabled = true;

        document.getElementById("webgl-output").appendChild(render.domElement);

        var axes = new THREE.AxesHelper(500);
        scene.add(axes);

        camera.position.set(10, 10, 10);
        camera.lookAt(scene.position);
        scene.add(camera);

        var ambienLight = new THREE.AmbientLight(0xcccccc);
        ambienLight.intensity = 1;
        scene.add(ambienLight);

        const directionalLight = new THREE.DirectionalLight(0xffffff, 2);
        directionalLight.castshadow = true;
        directionalLight.shadow.mapSize.width = 2048;
        directionalLight.shadow.mapSize.height = 2048;
        directionalLight.position.set(10000, 10000, 10000);
        directionalLight.intensity = 2;
        scene.add(directionalLight);

        //开始标准材质的介绍
        var planeGeometry = new THREE.PlaneGeometry(200, 200, 4, 4);
        var planeMaterial = new THREE.MeshLambertMaterial( color: 0xAAAAAA );
        var plane = new THREE.Mesh(planeGeometry, planeMaterial);

        plane.rotation.x = -0.5 * Math.PI;
        plane.position.set(15, 0, 0)
        plane.recevieShadow = true;
        //scene.add(plane);

        var ctrl = new dat.GUI();

        var material = new THREE.MeshStandardMaterial( color: 0x7777ff );//创建一个标准材质对象,并设置颜色为浅蓝色,用于赋给模型
        loadModel(material).then(function (model) //现在开始加载模型文件,把标准材质作为参数传进去,这样一来加载好的模型中的各个网格对象都采用这个标准材质了
            scene.add(model);//模型加载好之后我们就可以直接将网格对象加入场景中了
        );//刷新浏览器可以看到我们的模型,一辆车

        //我们现在把标准材质中的属性添加到右上角属性控件,方便我们接下来观察每个属性值的改变对外观效果影响
        var props = 
            color: material.color.getStyle(),//标准材质有一个基础颜色
            emissive: material.emissive.getStyle(),//自发光颜色
        
        var smGUI = ctrl.addFolder("MeshStandardMaterial");//添加标准材质属性分组
        smGUI.addColor(props, "color").onChange(function (e) 
            material.color.setStyle(e);
        )
        smGUI.addColor(props, "emissive").onChange(function (e) 
            material.emissive = new THREE.Color(e);
        )
        smGUI.add(material, "metalness", 0, 1, 0.01);//金属感程度,0代表完全塑料的感觉,1代表完全金属质感
        smGUI.add(material, "roughness", 0, 1, 0.01);//粗糙程度,0时产生镜面的效果,1时产生完全的漫反射效果
        smGUI.add(material, "wireframe");//线框开关
        smGUI.add(material, "wireframeLinewidth", 0, 20);//线框中线条的宽度

        var controls = new OrbitControls(camera, render.domElement);
        controls.update();

        var stats = addStats();
        renderScene();

        function renderScene() 

            controls.update();
            stats.update();
            requestAnimationFrame(renderScene);
            render.render(scene, camera);
        

        window.addEventListener('resize', onWindowResize, false);

        function onWindowResize() 
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            render.setSize(window.innerWidth, window.innerHeight);
        

        function addStats() 
            var stats = new Stats();
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            stats.setMode(0);

            document.getElementById("myStats").appendChild(stats.domElement);
            return stats;
        

        //我们开始编写模型文件加载函数,这种加载方式只加载模型的几何体而不加载材质,我们自己传入材质与该模型结合
        function loadModel(material) //这里我们要把材质对象作为参数传入进来
            var loader = new OBJLoader();//声明一个OBJ加载器
            loader.setPath("./model/car/source/");//设置加载器的相对路径
            var mesh = null;
            var p = new Promise(function (resolve) //模型加载成功后需要添加到场景中,所以只能借助Promise去实现这个效果,所谓的Promise,简单的来说就是一个可以存放未来才能结束的任务或者事件。
                loader.load('Lamborghini_Countach_LP800.obj', function (loadedMesh) //模型开始加载
                    mesh = loadedMesh;//把加载的模型网格保存为临时变量
                    if (material) //下一步就是对网格对象进行材质的设置
                        setMaterialGroup(material, mesh);//设置模型中所有网格的材质为material
                    ;
                    resolve(mesh);//加载完成后把模型的数据放到resolve中
                );
            )
            return p;
        

        //现在我们具体来看看如何设置模型中所有网格的材质的
        function setMaterialGroup(material, group) 
            if (group instanceof THREE.Mesh) //第一步,先对自身设置材质
                group.material = material;
            
            else if (group instanceof THREE.Group) //然后遍历儿子,通过模型的父子关系递归遍历,来对所有的网格对象进行同一个材质的设置
                group.children.forEach(function (child) 
                    setMaterialGroup(material, child);
                )
            
        
    </script>

</body>

</html>


(2)物理材质,上面介绍的标准材质属性物理材质都有,介绍几个物理材质独有属性

//开始物理材质的介绍
        var ctrl = new dat.GUI();

        var material = new THREE.MeshPhysicalMaterial( color: 0x7777ff );//把类对象名字修改为物理材质
        loadModel(material).then(function (model) 
            scene.add(model);
        );

        var props = 
            color: material.color.getStyle(),//基础颜色
            emissive: material.emissive.getStyle(),//自发光颜色
        
        var smGUI = ctrl.addFolder("MeshPhysicalMaterial");//添加物理材质属性分组
        smGUI.addColor(props, "color").onChange(function (e) 
            material.color.setStyle(e);
        )
        smGUI.addColor(props, "emissive").onChange(function (e) 
            material.emissive = new THREE.Color(e);
        )
        smGUI.add(material, "metalness", 0, 1, 0.01);//金属感程度,0代表完全塑料的感觉,1代表完全金属质感
        smGUI.add(material, "roughness", 0, 1, 0.01);//粗糙程度,0时产生镜面的效果,1时产生完全的漫反射效果
        smGUI.add(material, "wireframe");//线框开关
        smGUI.add(material, "wireframeLinewidth", 0, 20);//线框中线条的宽度
        //下面添加几个物理材质特有的属性到右上角的属性控件中

        //clearcoat,清漆属性,该属性控制物体表面清漆涂层效果的明显程度,属性值越高,清漆涂层越厚,范围0到1默认为0
        smGUI.add(material, "clearcoat", 0, 1, 0.01);

        //clearcoatRoughness,该属性控制物体表面清漆涂层的粗糙程度,粗糙程度越高,漫反射越明显,该属性与上面的clearcoat配合使用,取值在0到1,默认为0
        smGUI.add(material, "clearcoatRoughness", 0, 1, 0.01);

        //reflectivity反光度,用于控制非金属表面的反光度,因此当metalness金属感程度接近1时,该属性作用很小,取值范围在0到1之间,默认0.5
        smGUI.add(material, "reflectivity", 0, 1, 0.01);

17.创建自己的着色器
使用自定义shader渲染的材质ShaderMaterial
使用ShaderMaterial时需要注意以下注意事项:

**顶点着色器(Vertex Shader):**它接受attributes,计算和操作每个顶点的位置,进行图元装配,所谓图元装配就是由顶点生成一个个图元(即三角形),为了使我们有更高的可控性,即自由控制顶点位置,WebGL把这个权利交给了我们,这就是可编程渲染管线。同时,顶点着色器传递额外的数据(varying)给片段着色器。
顶点着色器处理流程:会先将坐标转换完毕,然后由GPU进行图元装,有多少顶点,这段顶点着色器程序就运行了多少次。
在图元生成完毕之后,我们需要给模型"上色",而完成这部分工作的,则是运行在GPU的"片元着色器"来完成。它同样是一段opengl es程序,模型看起来是什么质地(颜色、漫反射贴图等)、灯光等由片元着色器来计算,有多少片元,就会运行几次片元着色器程序。
**片元着色器(Fragment Shader)😗*片元是栅格化之后,在形成像素之前的数据。片元着色器是每个片元会调用一次的程序,因此,片元着色器特别适合用来做图像后处理。

着色器编程:
全局变量: 默认输出值vec4 gl_FragColor//全局颜色
gl_Position//全局位置
gl_打头的就是全局变量
着色器变量主要有以下三种:
(1)uiforms–即可以传入顶点着色器,也可以传入片元着色器,它们包含了哪些在整个渲染过程中保持不变的变量,比如灯光、雾。
(2)attributes–与每个顶点相关联的变量,例如,顶点位置,法线和顶点颜色都是存储在attributes中的数据。attributes只可以在顶点着色器重新访问。
(3)varyings–是从顶点着色器传递到片段着色器的变量。对于每一个片段,每一个varying的值将是相邻顶点值的平滑插值。

注意:在shader编程中浮点数不能写0、1这样的整数,不能只写整数部分,表示0也要写成0.0,1写成1.0,否则会误认为是整数

18.一些稀碎知识点
(1)计算俩个顶点之前的距离

var p1=new THREE.Vector3(3,9,6);
var p2=new THREE.Vector3(12,24,16);
var L=p1.clone().sub(p2).length();
console.log('俩点之间距离',L);

sub函数会修改调用者,使得调用者减去参数,而参数不会被修改,所以要用clone()函数深拷贝一个顶点。
用拷贝后的顶点来执行sub,防止我们的p1以后还要用但是已经被修改了。

(2)OrbitControls轨道控制器的一些属性
.enableDamping : Boolean
设置为true可启用阻尼(惯性),它可用于给控件一种重量感。默认是假的。
注意,如果启用了此功能,则必须在动画循环中调用.update()。

.maxDistance : Float
你可以移动多远(仅透视相机)。默认是无穷。

.maxZoom : Float
您可以移动多远(仅适用于正交相机)。默认是无穷。

以上是关于threejs学习笔记-04的主要内容,如果未能解决你的问题,请参考以下文章

threejs学习笔记-04

threejs学习笔记04---物体动

threejs学习笔记04---相机动

一大波ThreeJS学习笔记来啦

threejs学习笔记-03

threejs学习笔记