ThreeJS-3D教学四-光源

three模拟的真实3D环境,一个非常炫酷的功能便是对光源的操控,之前教学一中已经简单的描述了多种光源,这次咱们就详细的讲下一些最常见的光源:

AmbientLight
该灯光在全局范围内平等地照亮场景中的所有对象。
该灯光不能用于投射阴影,因为它没有方向。

AmbientLight( color : Integer, intensity : Float )
color - (可选)颜色的RGB分量的数值。默认值为0xffffff。
intensity - (可选)灯光强度/强度的数值。默认值为1。

DirectionalLight
向特定方向发射的光。这种光的行为就像它是无限遥远的,并且从它产生的光线都是平行的。这方面的常见用例是模拟日光;太阳离得足够远,它的位置可以被认为是无限的,所有来自它的光线都是平行的。

DirectionalLight( color : Integer, intensity : Float )
color - (可选)灯光的十六进制颜色。默认值为0xffffff(白色)。
intensity - (可选)灯光强度/强度的数值。默认值为1。

PointLight
从一个点向所有方向发射的光。这方面的一个常见用例是复制裸灯泡发出的光。

PointLight( color : Integer, intensity : Float, distance : Number, decay : Float )
color - (可选)灯光的十六进制颜色。默认值为0xffffff(白色)
intensity - (可选)灯光强度/强度的数值。默认值为1.
distance - 光线的最大范围。默认值为0(无限制)
decay - 灯光沿着灯光的距离变暗的量。默认值为2.

HemisphereLight
位于场景正上方的光源,颜色从天空颜色渐变为地面颜色。此灯光不能用于投射阴影。

HemisphereLight( skyColor : Integer, groundColor : Integer, intensity : Float )
skyColor - (可选)天空的十六进制颜色。默认为0xffffff。
groundColor - (可选)地球的十六进制颜色。默认为0xffffff。
intensity - 可选)光的强度/强度的数值。默认为1。

SpotLight
这种光从一个方向的单个点发射,沿着一个圆锥体,该圆锥体的大小随着光的传播而增加。类似车灯的效果,可以做射灯、车灯等

SpotLight( color : Integer, intensity : Float, distance : Float, angle : Radians, penumbra : Float, decay : Float )
color -(可选)灯光的十六进制颜色。默认值为0xffffff(白色)。
intensity -(可选)灯光强度/强度的数值。默认值为1。
distance - 灯光的最大范围。默认值为0(无限制)。
angle - 光从其方向散射的最大角度,其上限为Math。π/2。
penumbra - 由于半影而衰减的聚光灯圆锥体的百分比。取值介于0和1之间。默认值为零。
decay - 光线沿着光线的距离变暗的量。

看了定义后,我们先看下本次案例的效果图
在这里插入图片描述
这个案例中涉及到了以上所有光源效果,其中DirectionalLight和HemisphereLight是注释掉了的,为的是突出PointLight 和 SpotLight的效果,在代码中会发现AmbientLight的灯光强度我也特意变暗了。
案例中首次使用了GUI操作器和物体阴影效果。
GUI主要作用:
1、获取一个对象和该对象上的属性名,并根据属性的类型自动生成一个界面组件来操作该属性。
2、使用它后,我们可以通过界面组件来控制场景中的物体,提高调试效率。

看代码:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><style>body {width: 100%;height: 100%;}* {margin: 0;padding: 0;}.label {font-size: 20px;color: #000;font-weight: 700;}</style>
</head>
<body>
<div id="container"></div>
<script type="importmap">{"imports": {"three": "../three-155/build/three.module.js","three/addons/": "../three-155/examples/jsm/"}}
</script>
<script type="module">
import * as THREE from 'three';
import Stats from 'three/addons/libs/stats.module.js';
import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
import {GPUStatsPanel} from 'three/addons/utils/GPUStatsPanel.js';
import {CSS2DRenderer, CSS2DObject} from 'three/addons/renderers/CSS2DRenderer.js';
import {PLYLoader} from 'three/addons/loaders/PLYLoader.js';
import {GUI} from 'three/addons/libs/lil-gui.module.min.js';let stats, labelRenderer, gpuPanel, curve, lightHelper, textures;
let camera, scene, renderer, target, controls, lights, spotLight;
const group = new THREE.Group();
let progress = 0; // 物体运动时在运动路径的初始位置,范围0~1
const velocity = 0.0005; // 影响运动速率的一个值,范围0~1,需要和渲染频率结合计算才能得到真正的速率
let widthImg = 200;
let heightImg = 200;
let time = 0;
init();
initHelp();
initLight();
axesHelperWord();
animate();
// 添加平面
addPlane();lights = initPointLight(20, 1);
initSpotLight();
addModel();
addGUI();function initPointLight(lightNum, lightR) {let vector = new THREE.Vector3();let geometry = new THREE.SphereGeometry(lightR, 15, 15);let lights = [];for (let i = 0; i < lightNum; i++) {let pointLight = new THREE.PointLight(0xff0000, 150, 30, 2);vector.set(Math.random(), Math.random(), Math.random()).normalize();pointLight.color.setRGB(vector.x, vector.y, vector.z);scene.add(pointLight);lights.push(pointLight);let material = new THREE.MeshBasicMaterial({color: pointLight.color});let emitter = new THREE.Mesh(geometry, material);pointLight.add(emitter);}return lights;
}function initSpotLight() {// 位于场景正上方的光源,颜色从天空颜色渐变为地面颜色。此灯光不能用于投射阴影。// const ambient = new THREE.HemisphereLight( 0xffffff, 0x8d8d8d, 0.15 );// scene.add( ambient );const loader = new THREE.TextureLoader().setPath('../js_three-0.108.0/examples/textures/');const filenames = ['disturb.jpg', 'colors.png', 'uv_grid_opengl.jpg'];textures = {none: null};for (let i = 0; i < filenames.length; i++) {const filename = filenames[i];const texture = loader.load(filename);texture.minFilter = THREE.LinearFilter;texture.magFilter = THREE.LinearFilter;texture.colorSpace = THREE.SRGBColorSpace;textures[filename] = texture;}const targetObject = new THREE.Object3D();targetObject.position.set(-50, 0, -50);scene.add(targetObject);spotLight = new THREE.SpotLight(0xffffff, 100);spotLight.position.set(-50, 50, -50);spotLight.target = targetObject;spotLight.angle = Math.PI / 4;spotLight.intensity = 10000;spotLight.penumbra = 1;spotLight.decay = 1.5;spotLight.distance = 300;spotLight.map = textures['uv_grid_opengl.jpg'];spotLight.castShadow = true;spotLight.shadow.mapSize.width = 1024;spotLight.shadow.mapSize.height = 1024;spotLight.shadow.camera.near = 1;spotLight.shadow.camera.far = 200;spotLight.shadow.focus = 1;scene.add(spotLight);lightHelper = new THREE.SpotLightHelper(spotLight);scene.add(lightHelper);
}function addModel() {new PLYLoader().load('../js_three-0.108.0/examples/models/ply/binary/Lucy100k.ply', function (geometry) {let scale = 0.02;geometry.scale(scale, scale, scale);geometry.computeVertexNormals();const material = new THREE.MeshLambertMaterial();const mesh = new THREE.Mesh(geometry, material);mesh.rotation.y = -Math.PI / 2;mesh.position.y = 12;mesh.position.x = -50;mesh.position.z = -50;mesh.castShadow = true;mesh.receiveShadow = true;scene.add(mesh);});
}function addGUI() {// GUIconst gui = new GUI();const params = {map: textures['disturb.jpg'],color: spotLight.color.getHex(),intensity: spotLight.intensity,distance: spotLight.distance,angle: spotLight.angle,penumbra: spotLight.penumbra,decay: spotLight.decay,focus: spotLight.shadow.focus,shadows: true};gui.add(params, 'map', textures).onChange(function (val) {spotLight.map = val;});gui.addColor(params, 'color').onChange(function (val) {spotLight.color.setHex(val);});gui.add(params, 'intensity', 0, 20000).onChange(function (val) {spotLight.intensity = val;});gui.add(params, 'distance', 50, 200).onChange(function (val) {spotLight.distance = val;});gui.add(params, 'angle', 0, Math.PI / 3).onChange(function (val) {spotLight.angle = val;});gui.add(params, 'penumbra', 0, 1).onChange(function (val) {spotLight.penumbra = val;});gui.add(params, 'decay', 1, 2).onChange(function (val) {spotLight.decay = val;});gui.add(params, 'focus', 0, 1).onChange(function (val) {spotLight.shadow.focus = val;});gui.add(params, 'shadows').onChange(function (val) {renderer.shadowMap.enabled = val;scene.traverse(function (child) {if (child.material) {child.material.needsUpdate = true;}});});gui.open();
}function addPlane() {// 创建一个平面 PlaneGeometry(width, height, widthSegments, heightSegments)const planeGeometry = new THREE.PlaneGeometry(widthImg, heightImg, 1, 1);// 创建 Lambert 材质:会对场景中的光源作出反应,但表现为暗淡,而不光亮。const planeMaterial = new THREE.MeshPhongMaterial({color: 0xb2d3e6,side: THREE.DoubleSide});const plane = new THREE.Mesh(planeGeometry, planeMaterial);// 以自身中心为旋转轴,绕 x 轴顺时针旋转 45 度plane.rotation.x = -0.5 * Math.PI;plane.position.set(0, -4, 0);plane.castShadow = true;plane.receiveShadow = true;scene.add(plane);
}function init() {camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 10, 2000);camera.up.set(0, 1, 0);camera.position.set(60, 40, 60);camera.lookAt(0, 0, 0);scene = new THREE.Scene();scene.background = new THREE.Color('#ccc');renderer = new THREE.WebGLRenderer({antialias: true});renderer.setPixelRatio(window.devicePixelRatio);renderer.setSize(window.innerWidth, window.innerHeight);document.getElementById('container').appendChild(renderer.domElement);renderer.shadowMap.enabled = true;renderer.shadowMap.type = THREE.PCFSoftShadowMap;renderer.toneMapping = THREE.ACESFilmicToneMapping;// 色调映射的曝光级别renderer.toneMappingExposure = 1;labelRenderer = new CSS2DRenderer();labelRenderer.setSize(window.innerWidth, window.innerHeight);labelRenderer.domElement.style.position = 'absolute';labelRenderer.domElement.style.top = '0px';labelRenderer.domElement.style.pointerEvents = 'none';document.getElementById('container').appendChild(labelRenderer.domElement);controls = new OrbitControls(camera, renderer.domElement);controls.mouseButtons = {LEFT: THREE.MOUSE.PAN,MIDDLE: THREE.MOUSE.DOLLY,RIGHT: THREE.MOUSE.ROTATE};controls.enablePan = true;// 设置最大最小视距controls.minDistance = 5;controls.maxDistance = 1200;window.addEventListener('resize', onWindowResize);stats = new Stats();stats.setMode(1); // 0: fps, 1: msdocument.body.appendChild(stats.dom);gpuPanel = new GPUStatsPanel(renderer.getContext());stats.addPanel(gpuPanel);stats.showPanel(0);scene.add(group);
}function initLight() {// const light = new THREE.DirectionalLight(new THREE.Color('rgb(253,253,253)'));// light.position.set(10, 10, 1);// light.intensity = 3; // 光线强度const AmbientLight = new THREE.AmbientLight(new THREE.Color('rgb(255, 255, 255)'), 0.3);// scene.add( light );scene.add(AmbientLight);
}function initHelp() {// const size = 100;// const divisions = 5;// const gridHelper = new THREE.GridHelper( size, divisions );// scene.add( gridHelper );// The X axis is red. The Y axis is green. The Z axis is blue.const axesHelper = new THREE.AxesHelper(100);scene.add(axesHelper);
}function axesHelperWord() {let xP = addWord('X轴');let yP = addWord('Y轴');let zP = addWord('Z轴');xP.position.set(50, 0, 0);yP.position.set(0, 50, 0);zP.position.set(0, 0, 50);
}function addWord(word) {let name = `<span>${word}</span>`;let moonDiv = document.createElement('div');moonDiv.className = 'label';// moonDiv.textContent = 'Moon';// moonDiv.style.marginTop = '-1em';moonDiv.innerHTML = name;const label = new CSS2DObject(moonDiv);group.add(label);return label;
}function onWindowResize() {camera.aspect = window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth, window.innerHeight);
}function animate() {requestAnimationFrame(animate);time += 0.05;if (lights) {let swordTime = time * 0.1;let dis = 60;for (let i = 0, il = lights.length; i < il; i++) {let light = lights[i];let x = Math.sin(swordTime + i * 7.0) * dis;let y = Math.cos(swordTime + i * 5.0) * dis;let z = Math.cos(swordTime + i * 3.0) * dis;light.position.set(x, y, z);}}if (lightHelper) {lightHelper.update();const time = performance.now() / 2000;spotLight.position.x = Math.cos(time) * 2 - 50;spotLight.position.z = Math.sin(time) * 2 - 50;}stats.update();controls.update();if (labelRenderer) {labelRenderer.render(scene, camera);}renderer.render(scene, camera);
}
</script>
</body>
</html>

关于shadow效果的设置我们需要特别注意:
1、我们需要首先在renderer中设置
2、需要阴影的物体需要设置
3、这一点是比较容易遗忘的,那就是物体通过光源产生的阴影 投射在哪,相应的物体也需要设置,这个点写这个案例时,我也忘了 折腾半天模型的投影看不到,突然想到我addPlane函数创建的平面没有设置,简直了,耗费了很长时间
当然案例中只是shadow的一种设置方式,后面会讲到别的方式。

案例中还有一个知识点,之所以我将人像模型放在边缘,也是为了这个。那就是spotLight光源默认指向中心点也就是 (0, 0, 0)点,这时我们还需要spotLight实现案例中的效果,必须改变spotLight的指向

  const targetObject = new THREE.Object3D();targetObject.position.set(-50, 0, -50);scene.add(targetObject);// 这样就可以了spotLight.target = targetObject;

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

k8s部署gin-vue-admin框架、gitlab-ci、jenkins pipeline 、CICD

测试环境使用的jenkins 正式环境使用的gitlab-ci 测试环境 创建yaml文件 apiVersion: v1 kind: ConfigMap metadata:name: dtk-go-tiktok-admin-configlabels:app.kubernetes.io/name: dtk-go-tiktok-adminapp.kubernetes.io/business: infrastructureapp.kubernetes.io/run…

Windows系统利用cpolar内网穿透搭建Zblog博客网站并实现公网访问内网!

文章目录 1. 前言2. Z-blog网站搭建2.1 XAMPP环境设置2.2 Z-blog安装2.3 Z-blog网页测试2.4 Cpolar安装和注册 3. 本地网页发布3.1. Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语 1. 前言 想要成为一个合格的技术宅或程序员&#xff0c;自己搭建网站制作网页是绕…

What is a UDP Flood Attack?

用户数据报协议 &#xff08;UDP&#xff09; 是计算机网络中使用的无连接、不可靠的协议。它在互联网协议 &#xff08;IP&#xff09; 的传输层上运行&#xff0c;并提供跨网络的快速、高效的数据传输。与TCP&#xff08;其更可靠的对应物&#xff09;不同&#xff0c;UDP不提…

GitHub配置SSH key

GitHub配置SSH key Git配置信息并生成密钥 设置用户名和密码 设置用户名 git config --global user.name "用户名" 设置邮箱 git confir --global user.email "邮箱" 生成密钥 ssh-keygen -t rsa -C "邮箱" 查看密钥 到密钥所保存的位置 复…

ubuntu与win之间共享文件夹

ubuntu上设置共享文件夹 第一步&#xff1a;点击【设置】或【虚拟机弹窗下面的【设置】选项】 第二步&#xff1a;进入【虚拟机设置】页面&#xff0c;点击【选项】如下图所示 第三步&#xff1a;启用共享文件&#xff1a;点击【总是启用】第四步&#xff1a;添加共享文件&…

uni-app:canvas-绘制图形4(获取画布宽高,根据画布宽高进行图形绘制)

效果 代码 var width ; var height ; const query uni.createSelectorQuery(); //获取宽度 query.select(#firstCanvas).fields({ size: true }, (res) > { width res.width; height res.height; }).exec(); console.log(宽度width); console.log(高…

国庆day1

发送数据 #include<myhead.h>//消息结构体 typedef struct {long msgtype; //消息类型char data[1024]; //消息正文 }Msg_ds;#define SIZE sizeof(Msg_ds)-sizeof(long) //正文大小 int main(int argc, const char *argv[]) {//1、创建key值key_t ke…

五、接口测试工具:Postman

Postman是一款接口调试工具&#xff0c;是一款免费的可视化软件&#xff0c;同时支持各种操作系统平台&#xff0c;是测试接口的首选工具。 官网下载&#xff1a; https://www.postman.com/downloads/ 工作面板 简易的get请求 简易的post请求 案例&#xff1a;请求百度地图…

Unity实现设计模式——中介者模式

Unity实现设计模式——中介者模式 用一个中介者对象来封装一系列的对象交互&#xff0c;中介者使各对象不需要显示地相互引用&#xff0c;从而使其松散耦合&#xff0c;而且可以独立地改变它们之间的交互。 这里使用一个生活中的例子来介绍中介者模式&#xff0c;比如当我们在…

使用Python爬虫抓取网站资源的方法

Python爬虫是一种自动化程序&#xff0c;用于从互联网上获取数据。使用Python爬虫可以轻松地抓取网站上的各种资源&#xff0c;例如文本、图片、视频等。在本文中&#xff0c;我们将介绍如何使用Python爬虫抓取网站资源。 安装Python 在使用Python爬虫之前&#xff0c;需要先安…

【SSL】用Certbot生成免费HTTPS证书

1. 实验背景 服务器&#xff1a;CentOS7.x 示例域名&#xff1a; www.example.com 域名对应的web站点目录&#xff1a; /usr/local/openresty/nginx/html 2. 安装docker # yum -y install yum-utils# yum-config-manager --add-repo https://download.docker.com/linux/ce…

矢量图形编辑软件illustrator 2023 mac软件特点

illustrator 2023 mac是一款矢量图形编辑软件&#xff0c;用于创建和编辑排版、图标、标志、插图和其他类型的矢量图形。 illustrator mac软件特点 矢量图形&#xff1a;illustrator创建的图形是矢量图形&#xff0c;可以无限放大而不失真&#xff0c;这与像素图形编辑软件&am…

国庆周《Linux学习第三课》

国庆周《Linux学习第三课》 国庆周《Linux学习第二课》_IHOPEDREAM的博客-CSDN博客 总结 用户的管理 增加一个用户 删除一个用户 修改一个用户 查看一个用户 用户组的管理 增加一个组 删除一个组 修改一个组 查看一个组 将用户成员增加到该组中去 移除组的成员 1 用户

【深度学习实验】卷积神经网络(六):卷积神经网络模型(VGG)训练、评价

目录 一、实验介绍 二、实验环境 1. 配置虚拟环境 2. 库版本介绍 三、实验内容 0. 导入必要的工具包 1. 构建数据集&#xff08;CIFAR10Dataset&#xff09; a. read_csv_labels&#xff08;&#xff09; b. CIFAR10Dataset 2. 构建模型&#xff08;FeedForward&…

python监控ES索引数量变化

文章目录 1, datafram根据相同的key聚合2, 数据合并&#xff1a;获取采集10,20,30分钟es索引数据脚本测试验证 1, datafram根据相同的key聚合 # 创建df1 > json {key:A, value:1 } {key:B, value:2 } data1 {key: [A, B], value: [1, 2]} df1 pd.DataFrame(data1)# 创建d…

rhel8 网络操作学习

一、查询dns服务器地址汇总 1.查询dns服务器地址&#xff1a; &#xff08;1&#xff09;方法一&#xff1a;执行命令 cat /etc/resolv.conf 执行结果如下&#xff1a; nameserver后面就是dns服务器的ip地址。 &#xff08;2&#xff09;方法2&#xff1a;查看/etc/syscon…

蓝海彤翔亮相2023新疆网络文化节重点项目“新疆动漫节”

9月22日上午&#xff0c;2023新疆网络文化节重点项目“新疆动漫节”&#xff08;以下简称“2023新疆动漫节”&#xff09;在克拉玛依科学技术馆隆重开幕&#xff0c;蓝海彤翔作为国内知名的文化科技产业集团应邀参与此次活动&#xff0c;并在美好新疆e起向未来动漫展映区设置展…

【C++数据结构】二叉树搜索树【完整版】

目录 一、二叉搜索树的定义 二、二叉搜索树的实现&#xff1a; 1、树节点的创建--BSTreeNode 2、二叉搜索树的基本框架--BSTree 3、插入节点--Insert 4、中序遍历--InOrder 5、 查找--Find 6、 删除--erase 完整代码&#xff1a; 三、二叉搜索树的应用 1、key的模型 &a…

工具学习--easyexcel-3.x 使用--写入基本使用,自定义转换--动态表头以及宽设置-

写在前面&#xff1a; easyexcel是alibaba开发简单导出未excel的工具。使用的情况还是比较多的。 文章目录 依赖导入写Excel快速入门对象设置ExcelProperty设置列属性ExcelIgnore 忽视列宽、行高格式转换时间格式化数字格式化自定义格式化 合并单元格其他更加个性化需求动态表…

【Java 进阶篇】MySQL多表关系详解

MySQL是一种常用的关系型数据库管理系统&#xff0c;它允许我们创建多个表格&#xff0c;并通过各种方式将这些表格联系在一起。在实际的数据库设计和应用中&#xff0c;多表关系是非常常见的&#xff0c;它能够更好地组织和管理数据&#xff0c;实现数据的复杂查询和分析。本文…