three.js 细一万倍教程 从入门到精通(三)

目录

五、详解PBR材质纹理

5.1、详解PBR物理渲染

5.2、标准网格材质与光照物理效果

5.3、置换贴图与顶点细分设置

5.4、设置粗糙度与粗糙度贴图

5.5、设置金属度与金属贴图

5.6、法线贴图应用

5.7、如何获取各种类型纹理贴图

5.8、纹理加载进度情况

单张图片加载

多张图片加载

5.9、详解环境贴图

5.10、经纬线映射贴图与HDR

经纬线映射贴图

HDR

六、详解灯光与阴影

6.1、灯光与阴影的关系与设置

6.2、平行光阴影属性与阴影相机原理


五、详解PBR材质纹理

5.1、详解PBR物理渲染

灯光属性:直接照明、间接照明、直接高光、间接高光、阴影、环境光闭塞。

表面属性:基础色、法线、高光、粗糙度、金属度。

5.2、标准网格材质与光照物理效果

案例1:【环境光】照射物体

// 灯光(环境光)
// 参数分别为光的颜色和光的强度
const light = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(light)

案例2:【平行光】照射物体

// 直线光源
const directionaLight = new THREE.DirectionalLight(0xffffff, 0.5);
// 设置光从哪个位置直射
directionaLight.position.set(10, 10, 10);
scene.add(directionaLight)

5.3、置换贴图与顶点细分设置

首先准备一张贴图

黑色还是不动,浅灰格外突出,特别是门把手和两块铁片要突出。

// 导入纹理
const textureLoader = new THREE.TextureLoader();
const doorColorTexture = textureLoader.load("./textures/door/color.jpg");
const doorAplhaTexture = textureLoader.load("./textures/door/alpha.jpg");
const doorAoTexture = textureLoader.load("./textures/door/ambientOcclusion.jpg")
// 导入置换贴图
const doorHeightTexture = textureLoader.load("./textures/door/height.jpg")

const cubeGeometry = new THREE.BoxGeometry(1, 1, 1, 200, 200);
// 材质
const material = new THREE.MeshStandardMaterial({
    color: "#ffff00",
    map: doorColorTexture,
    alphaMap: doorAplhaTexture,
    transparent: true,
    aoMap: doorAoTexture,
    aoMapIntensity: 1,
    displacementMap: doorHeightTexture,
    displacementScale: 0.1 // 默认是1,深浅度,0.1代表稍微突出一点
})
const cube = new THREE.Mesh(cubeGeometry, material);
scene.add(cube);

// 灯光(环境光)
// 参数分别为光的颜色和光的强度
const light = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(light)

5.4、设置粗糙度与粗糙度贴图

// 添加物体
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1, 200, 200);
// 材质
const material = new THREE.MeshStandardMaterial({
    color: "#ffff00",
    map: doorColorTexture,
    alphaMap: doorAplhaTexture,
    transparent: true,
    aoMap: doorAoTexture,
    aoMapIntensity: 1,
    displacementMap: doorHeightTexture,
    displacementScale: 0.1,
    roughness: 0 // 设置粗糙度为0,直接光滑到底
})
const cube = new THREE.Mesh(cubeGeometry, material);
scene.add(cube);

// 灯光(环境光)
// 参数分别为光的颜色和光的强度
const light = new THREE.AmbientLight(0xffffff);
scene.add(light)

// 直线光源
const directionaLight = new THREE.DirectionalLight(0xffffff);
// 设置光从哪个位置直射
directionaLight.position.set(10, 10, 10);
scene.add(directionaLight)

假如我们想单独设置金属片粗糙,门光滑怎么办?

使用粗糙度贴图

白色代表粗糙度为1,黑色代表粗糙度为0。

5.5、设置金属度与金属贴图

现在我们想让金属片完全像金属,门不用。

准备金属贴图

黑色完全不用金属材质,而白色完全用金属材质。

// 导入纹理
const textureLoader = new THREE.TextureLoader();
const doorColorTexture = textureLoader.load("./textures/door/color.jpg");
const doorAplhaTexture = textureLoader.load("./textures/door/alpha.jpg");
const doorAoTexture = textureLoader.load("./textures/door/ambientOcclusion.jpg")
// 导入置换贴图
const doorHeightTexture = textureLoader.load("./textures/door/height.jpg");
// 粗糙度贴图
const doorRoughnessTexture = textureLoader.load("./textures/door/roughness.jpg");
// 金属贴图
const doorMetalnessTexture = textureLoader.load("./textures/door/metalness.jpg");

// 添加物体
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1, 200, 200);
// 材质
const material = new THREE.MeshStandardMaterial({
    color: "#ffff00",
    map: doorColorTexture,
    alphaMap: doorAplhaTexture,
    transparent: true,
    aoMap: doorAoTexture,
    aoMapIntensity: 1,
    displacementMap: doorHeightTexture,
    displacementScale: 0.1,
    // roughness: 0, // 设置粗糙度为0,直接光滑到底
    roughnessMap: doorRoughnessTexture,
    metalness: 1, // 金属度打满
    metalnessMap: doorMetalnessTexture // 引入金属贴图
})
const cube = new THREE.Mesh(cubeGeometry, material);
scene.add(cube);

// 灯光(环境光)
// 参数分别为光的颜色和光的强度
const light = new THREE.AmbientLight(0xffffff);
scene.add(light)

// 直线光源
const directionaLight = new THREE.DirectionalLight(0xffffff);
// 设置光从哪个位置直射
directionaLight.position.set(10, 10, 10);
scene.add(directionaLight)

5.6、法线贴图应用

上一节中虽然体现出了金属的质感,但还不够完美,我们发现在光折射的时候,门和金属片并没有凹凸不平的样子,都是一个平面的感觉。

我们再引入一个凹凸感(法线)的贴图

每个颜色都代表不同的朝向,相同的颜色相同朝向。

5.7、如何获取各种类型纹理贴图

网站:Poliigon - Textures, Models and HDRIs for 3D rendering

我们下载个免费的,解压一下

5.8、纹理加载进度情况

单张图片加载

let event = {}
// 单张纹理图的加载进度(color.jpg)
event.onLoad = function () {
    console.log("图片加载完成");
}
event.onProgress = function (e) {
    console.log("图片加载进度", e)
}
event.onError = function (e) {
    console.log("图片加载出现错误", e)
}

// 导入纹理
const textureLoader = new THREE.TextureLoader();
const doorColorTexture = textureLoader.load("./textures/door/color.jpg", event.onLoad, event.onProgress, event.onError);

多张图片加载

let event = {}
event.onLoad = function () {
    console.log("图片加载完成");
}
event.onProgress = function (url, num, total) {
    console.log("图片加载路径", url)
    console.log("图片加载进度", num)
    console.log("图片总数", total)
    console.log("图片加载进度百分比", (num / total * 100).toFixed(2))
}
event.onError = function (e) {
    console.log("图片加载出现错误", e)
}

// 设置加载管理器
const loadingManager = new THREE.LoadingManager(event.onLoad, event.onProgress, event.onError);

// 导入纹理
const textureLoader = new THREE.TextureLoader(loadingManager);
const doorColorTexture = textureLoader.load("./textures/door/color.jpg");
const doorAplhaTexture = textureLoader.load("./textures/door/alpha.jpg");
const doorAoTexture = textureLoader.load("./textures/door/ambientOcclusion.jpg")
// 导入置换贴图
const doorHeightTexture = textureLoader.load("./textures/door/height.jpg");
// 粗糙度贴图
const doorRoughnessTexture = textureLoader.load("./textures/door/roughness.jpg");
// 金属贴图
const doorMetalnessTexture = textureLoader.load("./textures/door/metalness.jpg");
// 法线贴图
const doorNormalTexture = textureLoader.load("./textures/door/normal.jpg");

5.9、详解环境贴图

// 设置cube纹理加载器
const cubeTextureLoader = new THREE.CubeTextureLoader();
const envMapTexture = cubeTextureLoader.load([
    "./textures/environmentMaps/1/px.jpg",
    "./textures/environmentMaps/1/nx.jpg",
    "./textures/environmentMaps/1/py.jpg",
    "./textures/environmentMaps/1/ny.jpg",
    "./textures/environmentMaps/1/pz.jpg",
    "./textures/environmentMaps/1/nz.jpg",
]);
const sphereGeometry = new THREE.SphereGeometry(1, 20, 20);
const material = new THREE.MeshStandardMaterial({
    metalness: 0.7, // 金属材质
    roughness: 0.1, // 光滑度
    envMap: envMapTexture, // 导入环境贴图
});
const sphere = new THREE.Mesh(sphereGeometry, material);
scene.add(sphere);

5.10、经纬线映射贴图与HDR

经纬线映射贴图

HDR

import {RGBELoader} from 'three/examples/jsm/loaders/RGBELoader'

// 加载HDR环境图
const rgbeLoader = new RGBELoader();
rgbeLoader.loadAsync("./textures/hdr/002.hdr").then((texture) => {
    // 如果不设置映射mapping。则HDR环境图不会动
    texture.mapping = THREE.EquirectangularReflectionMapping;
    scene.background = texture;
    // 设置环境图(物体小球)
    scene.environment = texture;
});

六、详解灯光与阴影

6.1、灯光与阴影的关系与设置

目标:灯光与阴影

1、材质要满足对光照有反应。

2、设置渲染器开启阴影的计算 renderer.shadowMap.enabled = true;

3、设置光照投射阴影 directionaLight.castShadow = true;

4、设置物体投射阴影 sphere.castShadow = true;

5、设置物体接收阴影 plane.receiveShadow = true;

// 圆
const sphereGeometry = new THREE.SphereGeometry(1, 20, 20);
const material = new THREE.MeshStandardMaterial();
const sphere = new THREE.Mesh(sphereGeometry, material);
// 投射阴影
sphere.castShadow = true;
scene.add(sphere);

// 创建平面
const planeGeometry = new THREE.PlaneGeometry(10, 10);
const plane = new THREE.Mesh(planeGeometry, material);
plane.position.set(0, -1, 0);
plane.rotation.x = -Math.PI / 2;
// 接收阴影
plane.receiveShadow = true;
scene.add(plane);

// 直线光源
const directionaLight = new THREE.DirectionalLight(0xffffff, 0.5);
// 设置光从哪个位置直射
directionaLight.position.set(10, 10, 10);
// 设置该平行光会产生动态阴影
directionaLight.castShadow = true;
scene.add(directionaLight);


// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
// 开启场景中的阴影贴图
renderer.shadowMap.enabled = true;
// 将webgl渲染的canvas内容添加到body
document.body.appendChild(renderer.domElement);

6.2、平行光阴影属性与阴影相机原理

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/387053.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java学习手册——第七篇基础语法

Java学习手册——第七篇基础语法 1. 注释2. 顺序语句3. 条件语句3.1 if语句3.2 switch语句 4. 循环语句4.1 for循环4.2 while 语句4.3 do...while语句 本篇为大家快速入门Java基础语法,了解一个语言的基础语法是必要的, 因为我们后期都是需要用这些基础语…

基于CU,PO,RD,IPO矩阵图分析数据资产-自创

术语 数据资产:数据资产是具有价值的数据资源。没有价值的数据资源,通过采集,整理,汇总等加工后,也可以成为具有直接或间接价值的数据资产。传统企业逐渐数字化转型,尤其是互联网企业,都十分重视…

文献速递:肿瘤分割---- 弱监督肝肿瘤分割,使用Couinaud区段标注

文献速递:肿瘤分割---- 弱监督肝肿瘤分割,使用Couinaud区段标注 01 文献速递介绍 肝癌是世界上导致癌症死亡的主要原因之一,也是第二大常见的癌症死因。本稿件于2021年10月28日收到,2021年11月24日修订,2021年12月1…

[Linux开发工具]项目自动化构建工具-make/Makefile

📙 作者简介 :RO-BERRY 📗 学习方向:致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 📒 日后方向 : 偏向于CPP开发以及大数据方向,欢迎各位关注,谢谢各位的支持 目录 1.背景2.依赖关系和依…

【制作100个unity游戏之23】实现类似七日杀、森林一样的生存游戏17(附项目源码)

本节最终效果演示 文章目录 本节最终效果演示系列目录前言制作木板UI直接复制和工具一样的即可检查背包是否有指定数量的空插槽 源码完结 系列目录 前言 欢迎来到【制作100个Unity游戏】系列!本系列将引导您一步步学习如何使用Unity开发各种类型的游戏。在这第23篇…

品牌之门:概率与潜力的无限延伸

在品牌的世界里,每一个成功的推广都像是打开一扇门,从未知走向已知,从潜在走向显现。这扇门,既是品牌的起点,也是品牌发展的无限可能。 品牌,就像一扇紧闭的门,它静静地矗立在那里,…

toString()、equals()、clone()用法

Java中所有类的对象都可以直接使用Object类中提供的一些方法 1. toString():返回对象的字符串表示形式,通常在类中重写,以便于返回的是对象的内容 2. equals():判断两个对象的地址是否相等,直接使用也一样,…

【蓝桥杯】灭鼠先锋

一.题目描述 二.解题思路 博弈论&#xff1a; 只能转移到必胜态的&#xff0c;均为必败态。 可以转移到必败态的&#xff0c;均为必胜肽。 最优的策略是&#xff0c;下一步一定是必败态。 #include<iostream> #include<map> using namespace std;map<string,bo…

【Linux系统学习】6.Linux系统软件安装

实战章节&#xff1a;在Linux上部署各类软件 前言 为什么学习各类软件在Linux上的部署 在前面&#xff0c;我们学习了许多的Linux命令和高级技巧&#xff0c;这些知识点比较零散&#xff0c;进行练习虽然可以基础掌握这些命令和技巧的使用&#xff0c;但是并没有一些具体的实…

C++:priority_queue模拟实现

C&#xff1a;priority_queue模拟实现 什么是priority_queue模拟实现向上调整算法向下调整算法插入与删除 仿函数 什么是priority_queue priority_queue称为优先级队列。优先级队列是一种特殊的队列&#xff0c;其中每个元素都有一个相关的优先级。元素的优先级决定了它们在队…

NSSCTF Round#18 RE GenshinWishSimulator WP

恶搞原神抽卡模拟器 看到软件的界面&#xff0c;大致有三种思路&#xff1a; 修改石头数量一直抽&#xff0c;如果概率正常肯定能抽到&#xff08;但是估计设置的概率是0&#xff09;在源码里找flag的数据把抽卡概率改成100%直接抽出来 Unity逆向&#xff0c;根据经验应该dnsp…

助眠神器小程序源码|白噪音|小睡眠|微信小程序前后端开源

安装要求和说明后端程序运行环境&#xff1a;NginxPHP7.4MySQL5.6 PHP程序扩展安装&#xff1a;sg11 网站运行目录设置为&#xff1a;public 伪静态规则选择&#xff1a;thinkphp 数据库修改文件路径&#xff1a;/config/database.php需要配置后端的小程序配置文件&#xff0c;…

力扣hot1--哈希

推荐一个博客&#xff1a; 一文看懂哈希表并学会使用C STL 中的哈希表_哈希表end函数-CSDN博客 哈希做法&#xff1a; 我们将nums[i]记为key&#xff0c;将i记为value。 判断target-nums[i]是否在哈希表中&#xff0c;如果在说明这两个值之和为target&#xff0c;那么返回这两…

【Java】零基础蓝桥杯算法学习——线性动态规划(一维dp)

线性dp——一维动态规划 1、考虑最后一步可以由哪些状态得到&#xff0c;推出转移方程 2、考虑当前状态与哪些参数有关系&#xff0c;定义几维数组来表示当前状态 3、计算时间复杂度&#xff0c;判断是否需要进行优化。 一维动态规划例题&#xff1a;最大上升子序列问题 Java参…

Linux第48步_编译正点原子的出厂Linux内核源码

编译正点原子的出厂 Linux 内核源码&#xff0c;为后面移植linux做准备。研究对象如下&#xff1a; 1)、linux内核镜像文件“uImage” 路径为“arch/arm/boot”&#xff1b; 2)、设备树文件“stm32mp157d-atk.dtb” 路径为“arch/arm/boot/dts” 3)、默认配置文件“stm32m…

第二部分阶段总结

第二部分阶段总结 1.知识补充1.1 nolocal关键字1.2 yield from1.3 深浅拷贝 2.阶段总结3.考试题 1.知识补充 1.1 nolocal关键字 在之前的课程中&#xff0c;我们学过global关键字。 name rootdef outer():name "武沛齐"def inner():global namename 123inner()…

LeetCode、739. 每日温度【中等,单调栈】

文章目录 前言LeetCode、739. 每日温度【中等&#xff0c;单调栈】题目链接及分类思路单调栈 资料获取 前言 博主介绍&#xff1a;✌目前全网粉丝2W&#xff0c;csdn博客专家、Java领域优质创作者&#xff0c;博客之星、阿里云平台优质作者、专注于Java后端技术领域。 涵盖技…

【每日一题】尾随零

尾随零 目录 思路&#xff1a;代码实现&#xff1a; 思路&#xff1a; 最开始看到这题就只想到规规矩矩的做题&#xff0c;先算阶乘在算0&#xff0c;后来提交时总是提示溢出&#xff0c;不死心&#xff0c;改来改去最后没招了。 后来看题解才知道要看5的个数&#xff01; …

Java 基于 SpringBoot+Vue 的智慧外贸平台的研究与实现,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

CVE-2023-41892 漏洞复现

CVE-2023-41892 开题&#xff0c;是一个RCE Thanks for installing Craft CMS! You’re looking at the index.twig template file located in your templates/ folder. Once you’re ready to start building out your site’s front end, you can replace this with someth…