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的主要内容,如果未能解决你的问题,请参考以下文章