ThreeJS-3D教学五-材质

news2024/11/17 10:04:20

我们在ThreeJS-3D教学二:基础形状展示中有简单介绍过一些常用的材质,这次我们举例来具体看下效果:
在这里插入图片描述
代码是这样的:

<!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';
let stats, labelRenderer, gpuPanel, spotLight;
let camera, scene, renderer, controls, earth;
const group = new THREE.Group();
let widthImg = 200;
let heightImg = 200;
let time = 0;
init();
initHelp();
initLight();
axesHelperWord();
animate();
// 添加平面
addPlane();
addBox();

function addBox() {
  /**
   * 凹凸贴图可以使纹理也有厚度,看起来更立体。凹凸贴图一般使用一张灰度图,设置成材料的bumpMap属性
   * */
  const loader = new THREE.TextureLoader();
  loader.load("../materials/line_images/stone.jpg", texture => {
    loader.load("../materials/line_images/stone-bump.jpg",bumpTexture => {
      const boxGeo = new THREE.BoxGeometry(60, 60, 2);
      const material = new THREE.MeshStandardMaterial({
        map: texture,
        bumpMap: bumpTexture,
        bumpScale: 1
      });
      const box = new THREE.Mesh(boxGeo,material);
      box.position.set(-45, 10, 0);
      box.castShadow = true;
      scene.add(box);
    });
  });
  /**
   * 法向贴图使用一张法向图来表示纹理图片某个点的法向量。即用一张图片保存另一张图片的法向量信息,
   * 然后再在threejs中将这两个图片的信息合在一起,就形成了一个细节丰富的立体纹理
   * 设置材质的 normalMap 属性
   * */
  loader.load("../materials/line_images/normal2.jpg", texture => {
    loader.load("../materials/line_images/normal1.jpg", bumpTexture => {
      const boxGeo = new THREE.BoxGeometry(60, 60, 2);
      const material = new THREE.MeshStandardMaterial({
        map: texture,
        normalMap: bumpTexture
      });
      // material.normalScale.set(1, 1)
      const box = new THREE.Mesh(boxGeo,material);
      box.position.set(45, 10, 0);
      box.castShadow = true;
      scene.add(box);
    });
  });

  // 高光贴图
  loader.load("../materials/line_images/earth.jpg",textureNormal => {
    loader.load("../materials/line_images/earthSpec.png", textureSpec => {
      const meterial = new THREE.MeshPhongMaterial({
        shininess: 5, //高光部分的亮度,默认30
        map: textureNormal, // 普通纹理贴图
        specularMap: textureSpec, // 高光贴图
        specular: '#fff' // 高光部分的颜色
      });
      /**
       SphereGeometry(radius:浮点,widthSegments:整数,heightSegments:整数)
          radius——球体半径。默认值为1。
          widthSegments—水平线段的数量。最小值为3,默认值为32。
          heightSegments—垂直线段的数量。最小值为2,默认值为16。
       */
      const earthGeo = new THREE.SphereGeometry(15, 50, 50);
      earth = new THREE.Mesh(earthGeo, meterial);
      earth.position.set(0, 15, 70);
      earth.castShadow = true;
      scene.add(earth);
    });
  });
}

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, 1000 );
  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 );

  renderer.shadowMap.enabled = true;
  renderer.shadowMap.type = THREE.PCFSoftShadowMap;
  renderer.toneMapping = THREE.ACESFilmicToneMapping;
  // 色调映射的曝光级别
  renderer.toneMappingExposure = 1;

  document.body.appendChild( renderer.domElement );

  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.minDistance = 20;
  controls.maxDistance = 1000;

  window.addEventListener( 'resize', onWindowResize );

  stats = new Stats();
  stats.setMode(1); // 0: fps, 1: ms
  document.body.appendChild( stats.dom );

  gpuPanel = new GPUStatsPanel( renderer.getContext() );
  stats.addPanel( gpuPanel );
  stats.showPanel( 0 );

  scene.add( group );
}

function initLight() {

  const targetObject = new THREE.Object3D();
  targetObject.position.set(0, 0, 0);
  scene.add(targetObject);

  spotLight = new THREE.SpotLight(0xffffff);
  spotLight.position.set(0, 80, 150);
  spotLight.target = targetObject;
  spotLight.angle = Math.PI / 4;
  spotLight.intensity = 500;
  spotLight.penumbra = 1;
  spotLight.decay = 1;
  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);
  const lightHelper = new THREE.SpotLightHelper(spotLight);
  scene.add(lightHelper);

  const AmbientLight = new THREE.AmbientLight(new THREE.Color('rgb(255, 255, 255)'));
  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 );

  if (earth) {
    time += 0.00005;
    earth.rotateY(time);
  }

  stats.update();
  controls.update();
  labelRenderer.render( scene, camera );
  renderer.render( scene, camera );
}
</script>
</body>
</html>

图片我依次放进来,方便大家本地看效果

stone.jpg

在这里插入图片描述

stone-bump.jpg

在这里插入图片描述

normal2.jpg

在这里插入图片描述

normal1.jpg

在这里插入图片描述

earth.jpg

在这里插入图片描述

earthSpec.png

在这里插入图片描述
具体的注释也都放代码里了!感觉不错的点个赞,光白嫖可还行!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

4.绘制颜色点(点击)

愿你出走半生,归来仍是少年&#xff01; 在点击绘制点的基础上&#xff0c;通过片源着色器给每个点设置颜色。以原点为中心&#xff0c;在一象限的点为红色&#xff0c;三象限为绿色&#xff0c;其他象限为白色。 1.知识点 1.1.Uniform变量 向片源着色器传入的数据变量。 1.…

1700*D. Flowers(DP前缀和预处理打表)

Problem - 474D - Codeforces 题意&#xff1a; 有白花和红花两种&#xff0c;把 x 朵花排成一排&#xff0c;要求白花必须连续 k 个一块放置&#xff0c;则有 cnt 种情况。给出 a 和 b&#xff0c;计算a到b之间的 x 对应的 cnt 总和&#xff0c;并且对1e97取模。 解析&#x…

第二证券:A股反弹已至?9月最牛金股涨超41%

进入10月&#xff0c;作为券商月度战略精华的新一期金股也连续宣布。 从各券商关于十月份的大势研判来看&#xff0c;一些券商达观地认为反弹行情正在打开&#xff0c;也有一些券商认为仍是轰动市。具体配备上&#xff0c;AI、科创相关的标的仍然遭到喜欢&#xff0c;一起不少…

OWASP Top 10漏洞解析(3)- A3:Injection 注入攻击

作者&#xff1a;gentle_zhou 原文链接&#xff1a;OWASP Top 10漏洞解析&#xff08;3&#xff09;- A3:Injection 注入攻击-云社区-华为云 Web应用程序安全一直是一个重要的话题&#xff0c;它不但关系到网络用户的隐私&#xff0c;财产&#xff0c;而且关系着用户对程序的新…

SAP BC TSV_TNEW_PAGE_ALLOC_FAILED

解决方案&#xff1a; 1)业务上&#xff0c;限制数据量&#xff0c;分多次查数据 2)调整参数 临时调整 se38 -rsmemory

PLC之间无线通信-不用编程实现多品牌PLC无线通讯的解决方案

本文是PLC设备之间基于IGT-DSER系列智能网关实现WIFI无线通讯的案例。采用西门子S7-1500系列的PLC作为主站&#xff0c;与其它品牌的PLC之间进行网络通讯。案例包括智能网关AP方式、现场WIFI信号两种方式。有线以太网方式实现PLC之间通讯的案例 一、智能网关AP方式 将网络中的其…

Vercel部署个人静态之DNS污染劫持问题

vercel是我第一次接触静态网站托管所使用的服务&#xff0c;类似的还有github以及Netfily。但是Vercel的自动化构建远比github page方便的多。通过github授权给Vercel就实现了自动拉取构建及发布的一系列流程。在本地推送代码可以使用小乌龟工具&#xff0c;线上代码发布使用Ve…

【msg_msg+sk_buff】D3CTF2022-d3kheap

前言 本方法来自 CVE-2021-22555&#xff0c;非常漂亮的组合拳&#xff0c;仅仅一个 1024 的 UAF 即可提权&#xff0c;但是对于小堆块的 UAF 不适用。 程序分析 启动脚本如下&#xff1a; #!/bin/sh qemu-system-x86_64 \-m 256M \-cpu kvm64,smep,smap \-smp cores2,thr…

python性能分析

基于cProfile统计函数级的时延&#xff0c;生成排序列表、火焰图&#xff0c;可以快速定位python代码的耗时瓶颈。参考如下博文结合实操&#xff0c;总结为三步&#xff1a; 使用 cProfile 和火焰图调优 Python 程序性能 - 知乎本来想坐下来写篇 2018 年的总结&#xff0c;仔细…

目标识别项目实战:基于Yolov7-LPRNet的动态车牌目标识别算法模型(二)

前言 目标识别如今以及迭代了这么多年&#xff0c;普遍受大家认可和欢迎的目标识别框架就是YOLO了。按照官方描述&#xff0c;YOLOv8 是一个 SOTA 模型&#xff0c;它建立在以前 YOLO 版本的成功基础上&#xff0c;并引入了新的功能和改进&#xff0c;以进一步提升性能和灵活性…

全平台高速下载器Gopeed

什么是 Gopeed ? Gopeed &#xff08;全称 Go Speed&#xff09;是一款支持全平台的高速下载器&#xff0c;开源、轻量、原生&#xff0c;采用 Golang Flutter 开发&#xff0c;支持&#xff08;HTTP、BitTorrent、Magnet 等&#xff09;协议&#xff0c;并支持所有平台。 已…

linearlayout中使用多个weight导致部分子控件消失异常

问题描述&#xff1a; 在一个linearlayout中写了两个用到weight的布局&#xff0c;在androidstudio中显示正常 但是代码跑起来之后最下面哪一行都消失了&#xff1b; 解决办法1 把两个用到weight的改成一个了&#xff0c;外面那层的weight写成固定宽度就能正常显示出丢失的…

【C++】vector的模拟实现 | 使用memcpy拷贝时的问题 | 实现深拷贝

目录 基本框架及接口 构造函数 无参构造 迭代器区间构造 初始化构造 析构函数 size() | capacity() 扩容的reserve() 使用memcpy拷贝的问题 改变大小的resize() operator[] 迭代器的实现 vector的增删 尾插push_back() 尾删pop_back() 在指定位置插入insert() …

【prism】prism 框架代码

前言 这个是针对整个专栏的一个示例程序,应用了专栏里讲的一些知识点,他是一个小而美的Prism的框架代码,一个模板,方便大家去扩展一个prism工程。 下面是一些代码片段,最后我给出整个工程的下载链接~~~ 代码片段 主界面代码 <Window x:Class="PrismTest.View…

企业加密软件哪个最好用?

天锐绿盾是一款专业的企业级加密软件&#xff0c;提供专业版、行业增强版和旗舰版&#xff0c;分别针对不同的用户需求。 PC访问地址&#xff1a; 首页 天锐绿盾专业版主要面向企事业单位的通用需求&#xff0c;以"让防泄密的管理更简单有效"为核心理念&#xff0c;…

ipv6跟ipv4如何通讯

IPv6的128位地址通常写成8组&#xff0c;每组为四个十六进制数的形式。比如:AD80:0000:0000:0000:ABAA:0000:00C2:0002 是一个合法的IPv6地址。这个地址比较长&#xff0c;看起来不方便也不易于书写。零压缩法可以用来缩减其长度。如果几个连续段位的值都是0&#xff0c;那么这…

从本地到全球:跨境电商的壮丽崛起

跨境电商&#xff0c;作为数字时代的商业现象&#xff0c;正在以惊人的速度改变着全球贸易的面貌。它不仅仅是一种商业模式&#xff0c;更是一场无国界的革命&#xff0c;使商业不再受限于地理位置&#xff0c;而是全面融入全球市场。 本文将深入探讨跨境电商的崛起&#xff0…

Ansys Speos | 将Rayfile光源转换为面光源

概览 本文将讲述如何rayfile转换为面光源&#xff0c;Rayfile光源文件包含有限数量的光线&#xff0c;表面光源有无限量的光线&#xff0c;这使得表面源对于使用逆模拟&#xff0c;得到清晰可视化仿真特别有用。 表面光源均匀地从几何形状表面的每个点发射光&#xff0c;这种简…

Ansys Optics Launcher 提升客户体验

概述 为了改善用户体验&#xff0c;Ansys Optics 团队开发了一个新的一站式启动应用程序&#xff0c;简化了工作流程并提高了效率。随着Ansys 2023 R2的最新更新&#xff0c;Ansys Optics Launcher 现已安装在Ansys Speos, Ansys Lumerical和Ansys Zemax OpticStudio中。作为一…

DVWA -xss

什么是XSS 跨站点脚本(Cross Site Scripting,XSS)是指客户端代码注入攻击&#xff0c;攻击者可以在合法网站或Web应用程序中执行恶意脚本。当wb应用程序在其生成的输出中使用未经验证或未编码的用户输入时&#xff0c;就会发生XSS。 跨站脚本攻击&#xff0c;XSS(Cross Site S…