threejs 基本功3

556 阅读7分钟

法向量(normal)【存在辅助器helpers VertexNormalsHelper.js】:

  概念上来说就是垂直于某个平面的所有支线的一个向量。 功能上来表述,法向量用于光线反射, 比如有一束光照到平面上,存在法向量就可以计算出反射光的射出方向。

  • geometry.computedVertexNormals() 直接计算出法向量
  • 使用geome.setAttribute("normal", new THREE.BufferAttribute(normals, 3))  normals 是一个Float32Array 数组

包围盒(boudingBox)和包围球(boundingSphere):

   将3d物体完全包裹的一个立方体就叫做包围盒,使用场景例如:在3d编辑器中,用户点击一个物体,然后出现包围盒,让用户知道目前选择的是哪个物体(高亮物体也是一种方案), 或者计算两个物体是否发生碰撞时,直接去计算每个顶点是否发生碰撞,计算量太大, 可以借助包围盒,直接计算两个包围盒是否碰撞等等

  • targetGeometry.computedBoundingBox() // 计算物体包围盒
  • targetBox  = targetGeometry.boundingBox

在使用时候有一个需要注意的点:就是可能会出现包围盒比物体大很多的情况,这是因为包围盒默认是按照物体scale = 1 来设定的。 所以当物体scale !=1时,需要进行世界矩阵转换: 

  • targetMesh.updateWorldMatrix(true, true) // 更新mesh 世界坐标

  • targetBox.applyMatrix4(targetMesh.matrixWorld) // 更新包围盒

  • 包围球:

     有了包围盒/球, 物体的居中也就简单了,只要保证物体在包围盒、球中的center就可以了   targetGeometry.center()即可。

  • 多个物体的包围盒  两种方式: 1. 使用 box3 对象上的union() 2. 使用Box上的setFromObject(推荐2)

边缘几何体(edgesGeometry):

类似于 线框模式  wireframe,  但是不会解析每个结构然后生成线框, 只有外部边缘才会。

usage:

复制代码

gltfLoader.load(url, (gltf) =>{// edgesGeometry
  let mesh  = gltf.scene.children[0];
  let geometry = mesh.geometry;
  let edgesGeometry = mew THREE.EdgesGeometry(geometry);
  let material = new THREE.LineBasicMatrial({color:oxffffff});
  let edgesMesh = new THREE.LineSegments(edgesGeometry, matrial)//创建线段
  mesh.updateWorldMatrix(true, true); //更新mesh世界转换矩阵
  edgesMesh.matrix.copy(mesh.matrixWorld);
  edgesMesh.matrix.decompose(edges.position, edges.quaternion, edges.scale)
})
//线框几何体 WireframeGeometry  上面替换结合体为 WireframeGemotry即可


通透性_厚度_衰减 

物理MeshPhysicalMaterial材质下: 

参数: 

{

transparent:true,

transmission:1, // 透光率 0-1【1表示透光最强,0表示完全不透光】但是如果设置完全透光时, 物体有可能还是不会透明, 这是因为没有设置粗糙度roughness

//如果是立方体,那么最好设置厚度属性【厚度属性可以设置贴图:thinknessMap = textureMap!!!】,thinknessMap 贴图可用一些特定玉器等透光时,不同位置看起来有不同的纹理的效果

让其看起来更真实,也会有折射效果,折射率可以设置!

 attenuationColor: new THREE.Color(0.6, 0, 0) // 衰减颜色

attenuationDistance:1, // 衰减距离, 如果厚度为2,那么光线穿过一半厚度的时候,就会显示出现衰减颜色

ior:折射率 0-int

reflectivity:反射率0-1

}

清漆clearcoats和粗糙度

清漆就有点类似于新车,表面那个反光的涂层的那种效果

材质参数{

clearcoat : 1,

clearcoatRoughness:设置清漆粗糙度

clearcoatMap: 也可以设置纹理 

clearcoatRoughnessMap:粗糙度纹理,不过这个效果会受clearcoatRoughness这个值的影响

clearcoatNormalMap: 清漆法相贴图

normalMap: 上面的属性需要配合normalMap一起使用, 但是normalMap贴图不一定要求和clearcoatNormalMap一样

clearcoatNormaScale:  清晰贴图效果的规格, vector2 (1,1)表示默认贴图效果, (0.1,0.1)表示贴图效果淡化十倍

}

 

毛茸茸光泽质感:

 

就比如那个很柔软舒适的毛巾,非皮质沙发,等物体,正面看和测面看, 效果是不一样的。这个效果就可以通过光泽 sheen 来实现

{

  }

虹彩效应:肥皂泡,油滴,蝴蝶翅膀等薄膜的虹彩效应

MeshPhysicalMaterial({

color:,

roughness:

transmission: 

thinkness:0.1 薄膜效应,厚度需要小

iridescence:1  //彩虹效应, 和设置的折射率有关

iridescenceIOR:默认1.3

还有设置贴图iridescenceThicknessRange:厚薄范围

iridescenceThicknessMap:厚薄贴图

})

 

如果做到频繁切换几何体,纹理,做到内存不泄露():

1.从场景中移除掉物体 scene.remove(mesh)

2.清除几何体,材质,纹理贴图

geometry.dispose()   material.dispose()    texture.dispose()

 

贴图和属性的关联: 比如粗糙度贴图和粗糙度 金属材质和金属材质贴图,如果设置粗糙度为0,光滑,name粗糙度贴图就会效果差或者没有效果

 

平面着色:

flatShadering: 默认false, 某些宝石模型,不设置这个属性,看上起就没有name棱角分明。切片感没有。

 宝石等物体的折射效果: 设置 厚度 thinkness  + 衰减距离

在threejs Editor中调好一些样式属性后, 可以直接选择导出具体的格式,或者导出成json【json 一般体积大很多,比glb】(场景,通过objectLoader 加载json!!!)

自发光属性和自发光贴图:

.emissive

.emissiveMap

【有时候模型导出后,使用threejs展示的时候,现实的效果会和在3d编辑器中效果有差异, 具体到,就比如手机模型,编辑器里的效果是屏幕很亮,而且是贴图颜色的亮, 但是使用threejs  加载屏幕会暗很多,仅仅调节自发光强度,屏幕是发白的亮,而不是贴图的那种颜色的亮度,这时候就可以加载这张自发光贴图即可 】

设置一些金属效果,毛绒反光效果,等都是通过

一些室内的模型,比如vr 看房, 限制控制器位移,旋转角度避免穿帮

控制思路:

1,首先将摄像机定位在一个合适的角度(集合 axesHelper xyz坐标轴辅助器,看调节哪些个方向)

2.控制器 controls.target.set(设定在和相机lookat 的同一位置)

  1. 一般禁用  鼠标右键移动模型  controls.enablePan = false

4.设置缩放的最大最小距离(指的是离这个controls.target的距离)controls.minDistance/maxDistance

5.设置垂直Polar/水平Azimuth的旋转角度, 一般都需要 controls.minPolarAngle/maxPolarAngle[minAzimuthangle/maxAzimuth]

 

纹理:

1.重复   texture.wrapS(水平)/wrapT(竖直) 方向上重复 + texture.repeat.set(4, 4) [表示x,y轴都重复四次]

2.偏移:  texture.offset.set(x, y )

3旋转:texture.rotation (默认 center为 0 0) 可以通过 texture.center.set()  修改旋转中心点 

4.  纹理翻转flipY和 预乘alpha premultiplyAlpha (存在alpha 的话)(最常见的效果就是贴图会出现描边效果)

 一些优化项    

 动态【Hdr格式|EXR格式|Tif|png】全景背景图色调曝光度的自适应: 主要是用于处理如果是很亮的场景, 不注意曝光度太高导致晃眼,看不清, 太暗的也不会乌漆嘛黑

渲染器设置【

render.toneMapping = 设置曝光模式

render.toneMappingExposure = 1 设置曝光度 【可以模拟关灯和 开灯,天亮了等场景】

 

纹理的各项异性过滤(Anisotropic filtering)贴图当中解决角度失真问题的技术,通常在地面、墙面或其他倾斜的表面上观察到这种现象。

当视角接近平行于纹理表面时,例如查看地平线上的地板纹理,由于取样密度的不均匀,导致远离观察者的纹理区域显得模糊。各向异性过滤通过沿着轴取样更多的纹理像素以解决这个问题,使纹理在不同的观察角度下看起来更清晰。

 texture.anisotropy = 1~16 区间 默认为1

 

压缩图片纹理 :可以借助 mvidia  的 图片压缩工具, 支持多种格式:

 

Threejs 中使用KTX2/DDS/TGA \EXR\TIF/PNG纹理

  1. 加载KTX2  :需要借助 ktx2Loader.js  以及工具类 basis  [位置:three/axamples/jsm/lib/basis] 复制basis到public下最好

const  ktx2loader = new KTX2Loader().setTranscodePath('basis').detectSupport(renderer)

(有个重要的点就是,使用nvidia贴图压缩的时候,如果压缩导出的时候,设置了 生产mipmap的话, 那么全景环境贴图可能就会失效)

 2.dds 

 3. tga

 4.EXR

 5. tif

6.png 

材质深度 决定多个物体渲染层级【遮挡如何显示的问题】:

materal.depthFunc (默认是THREE.LessEqualDpeth)

material depthWrite

material depthTest

 

材质混合 实例中的问题

 默认类似于这种组合, 多个透明物体的渲染时候,threejs默认渲染公式会有问题, 旋转角度后,被子里的有色液体看起来就不见了 ,这时候就需要调整混合模式来解决

r:两个不完全透明物体叠加的时候,threejs默认会当做完全透明去计算 。 

【单独给每个物体单独设置材质, 然后加上透明度属性!!!】

s: 可能会碰到的问题  这三者渲染顺序,  先渲染冰块,在渲染液体.  借助renderOrder