【Three.js基础学习】7.Material

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

课程要点;材质 meterials  

    测试不同材质

    1.让我们创建三个几何体,和材质放到场景中

    2.让它们旋转,同时自动更新

    3.结合texture,想一想如何创建纹理

    4.纹理如何放到材质中

    5.材质的属性 常用的,map ,color , wireframe , side,opacity,transparent ,alphaMap

    6.创建新的材质  不同的材质对应不同运用的场景

    MeshNormalMaterial // 网格法线材质 法向量映射到RGB颜色的材质

    MeshMatcapsMaterial // 材质捕捉(MatCap,或光照球(Lit Sphere))纹理所定义,其编码了材质的颜色与明暗。

        guthub matcaps https://github.com/nidorx/matcaps  

    MeshDepthMaterial // 深度网格材质 深度基于相机远近平面。白色最近,黑色最远 用于迷雾等处理

    // 续看

    1. 三个物体 球,平面,环形

    SphereGeometry

    PlaneGeometry

    TorusGeometry

    2.使用法线贴图,环境光遮挡等  需要纹理

    TextureLoading()  load()

    知道了很多的纹理,因此我们可以使用不同的网格材质进行测试

    3.

    3.1 MeshBasicMaterial 网格基本材质

    map:纹理名  要将纹理应用:请使用贴图,

    wrieframe : 是否线性展示

    opacity: 透明度 ,不过要配合transparent使用

    alphaMap: 外面是黑色,里面是白色  白色可见 黑色不可见 同上配合transparent使用

    side: 侧面 ,如果我们移动平面 会发现背面是不可见

    有三个属性: THREE.FrontSide(default),THREE.BackSide,THREE.DoubleSide

    3.2 MeshNormalMaterial 网格法线材质 (不会有帧率的问题)

    应用场景:法线包含面是面外部方向的信息,x,y,z;为什么需要法线材质,它是关于闪电,反射和折射

    法线指向灯光的方向,也就是摄像机的正上方,人脸看的很清楚;若是在球体的对面,是在光线的对面

    则看不清人类

    新属性: flatShading : 布尔  平面阴影

    3.3 MeshMatcapMaterial (matcap材质)

    主要是通过法线作为参考来显示颜色,纹理上的正确颜色,放到材质上

    3.4 MeshDepthMaterial 网格深度材质

    如何工作:简单的将 几何体为白色,若它接近摄像机远近,近时候会是白色,远的时候会是黑色

    应用场景:雾,无声的山丘效应等 ,光线对深度材料不起作用

    3.5 关于灯光 ,由于下面的材质需要灯光 ,先加入两盏灯光

    new THREE.AmbientLight() // 颜色,强度 是指 环境光

    new THREE.PointLight() // 颜色,强度  是指 点光源

    3.6 MeshLambertMaterial 网格木材材质  (对于光源有反应)无参数

    // 仔细看 会在几何图形中看到模糊的线条,这是问题

    3.7 MeshPhongMaterial  网状织物材质

    可以看到光的反射,切模糊的线条等问题消失 但是性能不如上一个

    shininess : 材料光泽平等 ,可以更好的享受光的反射

    specular : 高光 ,

    3.8 MeshToonMaterial  卡通材质

    3.9 MeshStanderMaterial 标准材质  比Phong更好的算法和参数,如:粗糙度和金属度

    metalness : 金属度

    roughness : 粗糙度

    遵顼PBR原则

    4.0 引入gui 调试面板

    4.1 实现阴影 环境光遮挡纹理 aoMap

    由于门 在平面中展示需要有层次感,要有阴影; 所以需要uv坐标 来帮助实现

    uv坐标:防止环境纹理上的遮挡; 2*2

    4.2 位移贴图 ,高度

    displacementMap

    4.3 金属度的贴图

    4.4 法线贴图

    4.5 环境贴图

    立方体纹理加载器  CubeTextureLoader

二、代码

import * as THREE from 'three'
import { CubeTextureLoader, LineLoop, Mesh, NearestFilter, PointLight } from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import * as lil from 'lil-gui'

/* 
* Debug ui
*/
const gui = new lil.GUI()

/**
 * Base
 */
// Canvas
const canvas = document.querySelector('canvas.webgl')

// Scene
const scene = new THREE.Scene()

/* 
    textrue 
*/
const TextureLoader = new THREE.TextureLoader() // 纹理加载器 load方法加载需要的纹理图
const cubeTextureLoader = new THREE.CubeTextureLoader()

const doorColorTexture = TextureLoader.load('/textures/door/color.jpg')
// 阿尔法
const doorAlphaTexture = TextureLoader.load('/textures/door/alpha.jpg')
// 环境光遮挡
const doorAmbientOcclusionTexture = TextureLoader.load('/textures/door/ambientOcclusion.jpg')
// 八
const doorHeightTexture = TextureLoader.load('/textures/door/height.jpg' )
// 正常
const doorNormalTexture = TextureLoader.load('/textures/door/normal.jpg' )
// 金属
const doorMetalnessTexture = TextureLoader.load('/textures/door/metalness.jpg' )
// 粗糙度
const doorRoughnessTexture = TextureLoader.load('/textures/door/roughness.jpg' )
// matcap纹理
const matcapTexture = TextureLoader.load('/textures/matcaps/1.png' )
// 渐变
const gradientTexture = TextureLoader.load('/textures/gradients/3.jpg' )

//环境贴图 参数 :左右 上下 前后  立方体纹理加载器
const environmentMapTexture = cubeTextureLoader.load([
    '/textures/environmentMaps/0/px.jpg',
    '/textures/environmentMaps/0/nx.jpg',
    '/textures/environmentMaps/0/py.jpg',
    '/textures/environmentMaps/0/ny.jpg',
    '/textures/environmentMaps/0/pz.jpg',
    '/textures/environmentMaps/0/nz.jpg',
]) 

gradientTexture.minFilter = THREE.NearestFilter
gradientTexture.magFilter = THREE.NearestFilter
gradientTexture.generateMipmaps = false

/* 
    Object  
    我想要在一个网格内创建一个球体,平面,曲线
    我要有物体,or 材质 or 在网格中,放到场景
    一个网格下,三个网孔
*/
// const material = new THREE.MeshBasicMaterial() // 网格材质
// material.map = doorColorTexture  
// material.color = new THREE.Color('#ff0000')
// material.wireframe = true
// material.opacity = 0.5 // 设置透明度要设置transparent
// material.transparent = true;
// material.alphaMap = doorAlphaTexture // 要设置transparent 得到一个完整的,门
// material.side = THREE.DoubleSide // 这是会发现背面也有图

// const material = new THREE.MeshNormalMaterial()   //网格法线材质 彩色 包含外部方向信息
// material.flatShading = true

// const material = new THREE.MeshMatcapMaterial() // 因为正确显示颜色,可以在没有灯光的情况下,模拟灯光
// material.matcap = matcapTexture  

// const material = new THREE.MeshDepthMaterial()

// const material = new THREE.MeshLambertMaterial() // 此时若关闭光源 会一片漆黑

// const material = new THREE.MeshPhongMaterial()

// const material = new THREE.MeshToonMaterial() // 颜色极具变化 ,可以通过渐变贴图实现颜色平滑过渡
//  // 加上这个,失去卡通色,原因MIP拉伸导致 ;防止发生,在纹理中使用过滤器,同时禁用MIP
// material.gradientMap = gradientTexture 

// const material = new THREE.MeshStandardMaterial()
// material.metalness = 0.5
// material.roughness = 0.5
// material.map = doorColorTexture
// material.aoMap = doorAmbientOcclusionTexture
// material.aoMapIntensity = 1 // aoMapIntensity 环境光强度
// material.displacementMap = doorHeightTexture // 使用了置换贴图 和 门高纹理
// material.displacementScale = 0.05  // 位移比例
// material.metalnessMap = doorMetalnessTexture  // 金属度的贴图
// material.rounghMap = doorRoughnessTexture  // 金属度的贴图
// material.normalMap = doorNormalTexture  // 法线贴图
// material.normalScale.set(0.5,0.5) // 可以设置更多的细节

// // 此时没有展现一个完整的门 因为 左右两边拉伸呢
// // 此时用到 alphaMap  , 需要设置transparent = true
// material.transparent = true
// material.alphaMap = doorAlphaTexture

// 环境贴图
const material = new THREE.MeshStandardMaterial()
material.metalness = 0.5
material.roughness = 0.5
material.envMap = environmentMapTexture


gui.add(material,'metalness').min(0).max(1).step(0.0001)
gui.add(material,'roughness').min(0).max(1).step(0.0001)
gui.add(material,'aoMapIntensity').min(0).max(10).step(0.0001)
gui.add(material,'displacementScale').min(0).max(1).step(0.0001)
// gui.add(material,'normalScale').min(0).max(1).step(0.0001)

material.shininess = 100;
material.specular = new THREE.Color('#ff0000')

const sphere = new Mesh(
    new THREE.SphereGeometry(0.5,16,16),
    material
)
sphere.position.x = -1.5

sphere.geometry.setAttribute(
    'uv2',
    new THREE.BufferAttribute(sphere.geometry.attributes.uv.array, 2),
)

const plane = new Mesh(
    // new THREE.PlaneGeometry(0.5,0.5),
    new THREE.PlaneGeometry(0.5,0.5,100,100), // 宽高,
    material
)
plane.geometry.setAttribute(
    'uv2',
    new THREE.BufferAttribute(plane.geometry.attributes.uv.array, 2),
)

console.log(plane.geometry.attributes.uv)

const torus = new Mesh(
    new THREE.TorusGeometry(0.5,0.2,16,30),
    material
)
torus.position.x = 1.5
torus.geometry.setAttribute(
    'uv2',
    new THREE.BufferAttribute(torus.geometry.attributes.uv.array, 2),
)

// 补充,不需要重复add, 可以接收多个对象
scene.add(sphere,plane,torus)

/* 
*   Lights
*/
const ambientLight = new THREE.AmbientLight('#ffffff',0.5)
scene.add(ambientLight)

const pointLight = new THREE.PointLight('#ffffff',0.5)
pointLight.position.x = 2
pointLight.position.y = 2
pointLight.position.y = 2
scene.add(pointLight)


/**
 * Sizes
 */
const sizes = {
    width: window.innerWidth,
    height: window.innerHeight
}

window.addEventListener('resize', () =>
{
    // Update sizes
    sizes.width = window.innerWidth
    sizes.height = window.innerHeight

    // Update camera
    camera.aspect = sizes.width / sizes.height
    camera.updateProjectionMatrix()

    // Update renderer
    renderer.setSize(sizes.width, sizes.height)
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})

/**
 * Camera
 */
// Base camera
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100)
// camera.position.x = 1
// camera.position.y = 1
camera.position.z = 2
scene.add(camera)

// Controls
const controls = new OrbitControls(camera, canvas)
controls.enableDamping = true

/**
 * Renderer
 */
const renderer = new THREE.WebGLRenderer({
    canvas: canvas
})
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))

/**
 * Animate
 */
const clock = new THREE.Clock()

const tick = () =>
{
    const elapsedTime = clock.getElapsedTime()

    // Updata Object
    sphere.rotation.x = 0.2* elapsedTime
    plane.rotation.x = 0.2* elapsedTime
    torus.rotation.x = 0.2* elapsedTime

    sphere.rotation.y = 0.2* elapsedTime
    plane.rotation.y = 0.2* elapsedTime
    torus.rotation.y = 0.2* elapsedTime

    // Update controls
    controls.update()

    // Render
    renderer.render(scene, camera)

    // Call tick again on the next frame
    window.requestAnimationFrame(tick)
}

tick()

三,知识点

1.1 球,平面,环形

new THREE.SphereGeometry() // 参数: 球体半径,水平分段数,垂直分段数。。。

new THREE.PlaneGeometry()   //参数:宽,高 ,宽度分段数,高度分段数

new THREE.TorusGeometry() // 参数:环面的半径,管道的半径,管道横截面的分段数,管道分段数

1.2 纹理

有了几何体,还要有纹理和材质,可以使用法线贴图,环境遮挡光等

new THREE.TextureLoading()

const TextureLoader = new THREE.TextureLoader() // 纹理加载器 load方法加载需要的纹理图
const cubeTextureLoader = new THREE.CubeTextureLoader()

const doorColorTexture = TextureLoader.load('/textures/door/color.jpg')
// 阿尔法
const doorAlphaTexture = TextureLoader.load('/textures/door/alpha.jpg')
// 环境光遮挡
const doorAmbientOcclusionTexture = TextureLoader.load('/textures/door/ambientOcclusion.jpg')
// 八
const doorHeightTexture = TextureLoader.load('/textures/door/height.jpg' )
// 正常
const doorNormalTexture = TextureLoader.load('/textures/door/normal.jpg' )
// 金属
const doorMetalnessTexture = TextureLoader.load('/textures/door/metalness.jpg' )
// 粗糙度
const doorRoughnessTexture = TextureLoader.load('/textures/door/roughness.jpg' )
// matcap纹理
const matcapTexture = TextureLoader.load('/textures/matcaps/1.png' )
// 渐变
const gradientTexture = TextureLoader.load('/textures/gradients/3.jpg' )

//环境贴图 参数 :左右 上下 前后  立方体纹理加载器
const environmentMapTexture = cubeTextureLoader.load([
    '/textures/environmentMaps/0/px.jpg',
    '/textures/environmentMaps/0/nx.jpg',
    '/textures/environmentMaps/0/py.jpg',
    '/textures/environmentMaps/0/ny.jpg',
    '/textures/environmentMaps/0/pz.jpg',
    '/textures/environmentMaps/0/nz.jpg',
]) 


gradientTexture.minFilter = THREE.NearestFilter
gradientTexture.magFilter = THREE.NearestFilter
gradientTexture.generateMipmaps = false

加载不同的纹理图片 ,在不同的材质中显示不同的效果!

1.3 Material

不同的纹理,对应不同的材质方法!

1.3.1  MeshBasicMaterial()  网格基本材质

const material = new THREE.MeshBasicMaterial() // 网格材质
material.map = doorColorTexture  // map : 贴图方法

// 在创建的几何图形中放入

const sphere = new Mesh(
    new THREE.SphereGeometry(0.5,16,16),
    material
)
sphere.position.x = -1.5

const plane = new Mesh(
    // new THREE.PlaneGeometry(0.5,0.5),
    new THREE.PlaneGeometry(0.5,0.5,100,100), // 宽高,
    material
)


const torus = new Mesh(
    new THREE.TorusGeometry(0.5,0.2,16,30),
    material
)
torus.position.x = 1.5

 material.color = new THREE.Color('#ff0000')   // 设置颜色时需要这样设置 不能直接等于red这种

material.wireframe = true  // 展示线条 ,可以看到中间平面基本没有顶点,左右两边有很多顶点

material.opacity = 0.5 // 设置透明度要设置transparent

material.transparent = true  // 几何体之间可以透视

material.alphaMap = doorAlphaTexture // 同样也要设置transparent  ,这种的是阿尔法贴图

黑色没有,白色有,因此中间会显示一个完整的门,左右的拉伸你都会隐藏掉

material.side = THREE.DoubleSide // 我们在观察时 ,如果我们移动平面 会发现背面是不可见,是虚无的没有的,因此可以设置DoubleSize 显示背面 ,当然还有两外两个参数, THREE.FrontSide(default),THREE.BackSide,THREE.DoubleSide

1.3.2 MeshNormalMaterial  网格法线材质

概念:彩色的,包含外部的方向信息!,x,y,z等坐标的外部方向信息。不会有帧率的问题!

应用场景:法线包含面是面外部方向的信息,x,y,z;为什么需要法线材质,它是关于闪电,反射和折射 法线指向灯光的方向,也就是摄像机的正上方,人脸看的很清楚;若是在球体的对面,是在光线的对面 则看不清人类

const material = new THREE.MeshNormalMaterial()
material.flatShading = true

对比一下啊没有设置平面阴影,很明显几何体表面的颜色是无阴影的!

1.3.3 MeshMatcapMaterial (网格matcap材质)、

概念:主要是通过法线作为参考来显示颜色,纹理上的正确颜色,放到材质上。因为正确显示颜色,可以在没有灯光的情况下,模拟灯光。

将原本设置的光源注释掉,观察在matcap材质下,在摄像机拉近球体,光源的显示

const material = new THREE.MeshMatcapMaterial()
material.matcap = matcapTextrue

上面可以看到的是,原本图片上的光源,可以说是颜色,原本图片上的颜色信息 ,只是正确的展示出来。

1.3.4 MeshDepthMaterial 网格深度材质

如何工作:简单的将 几何体为白色,若它接近摄像机远近,近时候会是白色,远的时候会是黑色应用场景:雾,无声的山丘效应等 ,光线对深度材料不起作用

在远近时,几何体的展示

const material = new THREE.MeshDepthMaterial()

1.3.5 MeshLambertMaterial 网格木制材质 对光源有反应

关于灯光,由于下面的材质需要灯光 ,先加入两盏灯光

    new THREE.AmbientLight() // 颜色,强度 是指 环境光

    new THREE.PointLight() // 颜色,强度  是指 点光源

const ambientLight = new THREE.AmbientLight('#ffffff',0.5)
scene.add(ambientLight)

const pointLight = new THREE.PointLight('#ffffff',0.5)
pointLight.position.x = 2
pointLight.position.y = 2
pointLight.position.y = 2
scene.add(pointLight)

此时已经设置好环境光和点光源

const material = new THREE.MeshLambertMaterial() // 此时若关闭光源 会一片漆黑

可以看到反射出红色的光,

当然已经设置光源,想要设置反射光颜色和材料光泽等

其中shininess:材料光泽平等; specular:高光

需要在设置好材料之后 设置其属性

material.shininess = 100;
material.specular = new THREE.Color('#ff0000')

1.3.6 MeshPhongMaterial  网格织物材质

可以看到光的反射,切模糊的线条等问题消失 但是性能不如上一个

1.3.7 MeshToonMaterial 网格卡通材质

颜色极具变化 ,可以通过渐变贴图实现颜色平滑过渡

const material = new THREE.MeshToonMaterial()

// 加上这个,失去卡通色,原因MIP拉伸导致 ;防止发生,在纹理中使用过滤器,同时禁用MIP
material.gradientMap = gradientTexture 

1.3.8 MeshStandarMaterial 网格标准材质

比Phong更好的算法和参数,如:粗糙度和金属度     遵顼PBR原则

    metalness : 金属度

    roughness : 粗糙度

const material = new THREE.MeshStandardMaterial()
material.metalness = 0.5
material.roughness = 0.5
material.map = doorColorTexture
material.aoMap = doorAmbientOcclusionTexture
material.aoMapIntensity = 1 // aoMapIntensity 环境光强度
material.displacementMap = doorHeightTexture // 使用了置换贴图 和 门高纹理
material.displacementScale = 0.05  // 位移比例
material.metalnessMap = doorMetalnessTexture  // 金属度的贴图
material.rounghMap = doorRoughnessTexture  // 金属度的贴图
material.normalMap = doorNormalTexture  // 法线贴图
material.normalScale.set(0.5,0.5) // 可以设置更多的细节

其中aoMap,aoMapINtensity,可以看到在阴影处的痕迹

displacementMap是属于门高贴图,配合displacementScale 位移比例实现平面门 有凹凸

同时可以使用金属度贴图 rounghMap属性 增加细节

使用法线贴图增加纹理 normalMap属性 material.normalScale.set(0.5,0.5)设置更多细节

 因为 左右两边拉伸呢
// 此时用到 alphaMap  , 需要设置transparent = true
material.transparent = true
material.alphaMap = doorAlphaTexture

1.3.8 环境贴图

const material = new THREE.MeshStandardMaterial()
material.metalness = 0.5
material.roughness = 0.5
material.envMap = environmentMapTexture
//环境贴图 参数 :左右 上下 前后  立方体纹理加载器
const environmentMapTexture = cubeTextureLoader.load([
    '/textures/environmentMaps/0/px.jpg',
    '/textures/environmentMaps/0/nx.jpg',
    '/textures/environmentMaps/0/py.jpg',
    '/textures/environmentMaps/0/ny.jpg',
    '/textures/environmentMaps/0/pz.jpg',
    '/textures/environmentMaps/0/nz.jpg',
]) 


总结

迷迷糊糊,迷迷糊糊 哈哈哈!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值