学习threejs,使用设置normalMap法向量贴图创建更加细致的凹凸和褶皱

news2024/11/26 8:49:10

👨‍⚕️ 主页: gis分享者
👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅!
👨‍⚕️ 收录于专栏:threejs gis工程师


文章目录

  • 一、🍀前言
    • 1.1 ☘️THREE.MeshPhongMaterial高光材质
    • 1.2 normalMap 法向量贴图
  • 二、🍀使用设置normalMap法向量贴图创建更加细致的凹凸和褶皱
    • 1. ☘️实现思路
    • 2. ☘️代码样例


一、🍀前言

本文详细介绍如何基于threejs在三维场景中使用设置normalMap法向量贴图创建更加细致的凹凸和褶皱效果,亲测可用。希望能帮助到您。一起学习,加油!加油!

1.1 ☘️THREE.MeshPhongMaterial高光材质

THREE.MeshPhongMaterial 是 Three.js 中的一种材质类型,用于模拟物体表面的光照效果,包括漫反射(diffuse)和镜面反射(specular)。这种材质遵循 Phong 反射模型,可以模拟出光滑表面的高光效果,因此非常适合用来渲染金属、塑料、瓷器等具有光泽表面的物体。
常用属性:
THREE.MeshPhongMaterial 继承自 THREE.Material,并具有一些特定的属性,可以用来控制材质的外观:

color:材质的基本颜色,默认为白色(0xffffff)。可以是一个整数,表示十六进制颜色值。
map:基础颜色贴图,可以用来替代材质的颜色。可以是一个 THREE.Texture 对象。
alphaMap:透明度贴图,可以用来定义材质的透明度。可以是一个 THREE.Texture 对象。
emissive:自发光颜色,默认为黑色(0x000000)。即使在没有光源的情况下,也会显示这个颜色。
emissiveMap:自发光贴图,可以用来定义自发光的颜色。可以是一个 THREE.Texture 对象。
specular:高光颜色,默认为白色(0x111111)。高光颜色定义了镜面反射的颜色。
shininess:高光强度,默认为 30。高光强度定义了高光区域的锐度,数值越高,高光越集中。
opacity:材质的全局透明度,默认为 1(不透明)。
transparent:是否开启透明模式,默认为 false。如果设置为 true,则需要设置 opacity 或者使用 alphaMap。
side:指定材质在哪一面渲染,可以是 THREE.FrontSide(正面)、THREE.BackSide(背面)或 THREE.DoubleSide(双面)。
wireframe:是否启用线框模式,默认为 false。
visible:是否渲染该材质,默认为 true。
depthTest:是否进行深度测试,默认为 true。
depthWrite:是否写入深度缓冲区,默认为 true。
blending:混合模式,默认为 THREE.NormalBlending。可以设置为 THREE.AdditiveBlending、THREE.SubtractiveBlending 等。
vertexColors:是否启用顶点颜色,默认为 THREE.NoColors。可以设置为 THREE.VertexBasicColors、THREE.VertexColors 或 THREE.FaceColors。
flatShading:是否使用平滑着色,默认为 false。如果设置为 true,则每个面片都将使用平均法线。
envMap:环境贴图,可以用来模拟环境光照。可以是一个 THREE.Texture 对象。
reflectivity:环境光反射率,默认为 1。
refractionRatio:折射率,默认为 0.98。
combine:环境贴图的组合方式,默认为 THREE.MixOperation。
bumpMap:凹凸贴图,可以用来模拟表面细节。可以是一个 THREE.Texture 对象。
bumpScale:凹凸贴图的比例,默认为 1。
normalMap:法线贴图,可以用来模拟表面细节。可以是一个 THREE.Texture 对象。
normalScale:法线贴图的比例,默认为 Vector2(1, 1)。
displacementMap:置换贴图,可以用来改变表面的高度。可以是一个 THREE.Texture 对象。
displacementScale:置换贴图的比例,默认为 1。
displacementBias:置换贴图的偏移,默认为 0。

1.2 normalMap 法向量贴图

概念:
normalMap 法向量贴图‌是一种在3D图形渲染中使用的技术,主要用于增强模型表面的细节和真实感。它通过使用一张特殊的纹理贴图来模拟物体表面的凹凸效果,从而在视觉上增加模型的细节和复杂度。
原理:
法线贴图的基本原理是将物体的法线信息存储在一张RGB纹理中。每个像素的RGB值代表该位置法线的方向,通过这种方式,可以在渲染时利用这些法线信息来模拟表面的凹凸效果。这种方法可以显著降低渲染时需要的面数和计算量,从而优化渲染效果‌。
与Bump Mapping(凹凸贴图)的区别:
法线贴图与Bump Mapping(凹凸贴图)是两种不同的技术,尽管它们在某些情况下可以相互替代。Bump Mapping需要计算每个像素的法线信息,而法线贴图则通过预计算的法线贴图来实现,简化了计算过程。此外,法线贴图能够提供更丰富的细节和更真实的视觉效果‌23。

二、🍀使用设置normalMap法向量贴图创建更加细致的凹凸和褶皱

1. ☘️实现思路

  • 1、初始化renderer渲染器
  • 2、初始化Scene三维场景
  • 3、初始化camera相机,定义相机位置 camera.position.set。
  • 4、初始化THREE.AmbientLight环境光源,scene场景加入环境光源,初始化THREE.DirectionalLight平行光源,设置平行光源位置,设置平行光源投影,scene添加平行光源,创建THREE.PointLight点光源,设置点光源位置,给点光源添加模型,scene添加点光源。
  • 5、加载几何模型:创建THREE.AxesHelper坐标辅助工具,创建THREE.PlaneBufferGeometry平面几何体、THREE.GridHelper地板割线,scene场景中加入创建的平面几何体和地板割线。创建正常纹理贴图对象normal和法向量纹理贴图对象bump,根据创建的纹理创建两个THREE.MeshPhongMaterial高光材质对象material1(使用normal和bump贴图)、material2(使用normal贴图),创建立方体THREE.BoxGeometry对象geometry,根据立方体geometry和材质THREE.MeshPhongMaterial对象创建两个THREE.Mesh网格对象cube1(使用material1材质)、cube2(使用material2材质)并设置位置,scene场景中加入cube1和cube2。具体实现参考代码样例。
  • 6、加入gui、controls控制,加入stats监控器,监控帧数信息。
  • 7、定义render方法,执行点光源动画以及其他渲染动画,具体代码参考代码样例。

2. ☘️代码样例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>learn53(使用设置NORMALMAP法向量贴图创建更加细致的凹凸和褶皱)</title>
    <script src="lib/threejs/127/three.js-master/build/three.js"></script>
    <script src="lib/threejs/127/three.js-master/examples/js/controls/OrbitControls.js"></script>
    <script src="lib/threejs/127/three.js-master/examples/js/libs/stats.min.js"></script>
    <script src="lib/threejs/127/three.js-master/examples/js/libs/dat.gui.min.js"></script>
    <script src="lib/js/Detector.js"></script>
    <script src="lib/js/ImageUtils.js"></script>
</head>
<style type="text/css">
    html, body {
        margin: 0;
        height: 100%;
    }

    canvas {
        display: block;
    }
</style>
<body onload="draw()">
</body>
<script>
  var renderer, camera, scene, gui, light, stats, controls, cube1, cube2, pointLight
  var angle = 0, radian, r = 5
  var initRender = () => {
    renderer = new THREE.WebGLRenderer({antialias: true})
    renderer.setSize(window.innerWidth, window.innerHeight)
    renderer.setPixelRatio(window.devicePixelRatio)
    renderer.setClearColor(0xeeeeee)
    renderer.shadowMap.enabled = true
    document.body.appendChild(renderer.domElement)
  }
  var initScene = () => {
    scene = new THREE.Scene()
    scene.backgroundColor = new THREE.Color(0xa0a0a0)
    scene.fog = new THREE.Fog(0xa0a0a0, 5, 50)
  }
  var initCamera = () => {
    camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 200)
    camera.position.set(0, 12, 15)
  }
  var initGui = () => {
    gui = {
      normalScale: 1,
      animation: false,
      changeTexture: () => {
        var image = new Image()
        image.src = 'data/texture/normalmap/crate.gif'
        image.onload = (ev) => {
          var texture = new THREE.Texture(image)
          texture.needsUpdate = true
          cube1.material.map = texture

          var normal = new THREE.Texture(THREE.ImageUtils.getNormalMap(image))
          normal.needsUpdate = true
          cube1.material.normalMap = normal

          cube2.material.map = texture
        }
      }
    }
    var datGui = new dat.GUI()
    datGui.add(gui, 'normalScale', -2, 30).onChange(e => {
      cube1.material.normalScale.set(e, e)
      cube1.material.needsUpdate = true
    })
    datGui.add(gui, 'animation')
    datGui.add(gui, 'changeTexture')
  }
  var initLight = () => {
    scene.add(new THREE.AmbientLight(0x444444))

    light = new THREE.DirectionalLight(0xffffff)
    light.position.set(0, 20, 10)
    light.castShadow = true
    scene.add(light)

    pointLight = new THREE.PointLight(0x00ffff)
    pointLight.position.set(0, 5, 0)
    scene.add(pointLight)

    // 点光源添加模型,显示位置
    pointLight.add(new THREE.Mesh(new THREE.SphereGeometry(0.05, 20, 20), new THREE.MeshBasicMaterial({color: 0x00ffff})))
  }
  var initModel = () => {
    var helper = new THREE.AxesHelper(50)
    scene.add(helper)

    // 地板
    var mesh = new THREE.Mesh(new THREE.PlaneBufferGeometry(200, 200), new THREE.MeshPhongMaterial({
      color: 0xffffff,
      depthWrite: false
    }))
    mesh.rotation.x = -0.5 * Math.PI
    mesh.receiveShadow = true
    scene.add(mesh)

    // 格网
    var grid = new THREE.GridHelper(200, 50, 0x000000, 0x000000)
    grid.material.opacity = 0.2
    grid.material.transparent = true
    scene.add(grid)
    // 凹凸纹理
    var bump = new THREE.TextureLoader().load('data/texture/normalmap/plaster-normal.jpg')
    // 正常纹理
    var normal = new THREE.TextureLoader().load('data/texture/normalmap/plaster.jpg')
    var material1 = new THREE.MeshPhongMaterial({
      map: normal
    })
    material1.normalMap = bump

    var geometry = new THREE.BoxGeometry(6, 6, 6)

    cube1 = new THREE.Mesh(geometry, material1)
    cube1.position.set(-5, 5, 0)
    cube1.rotation.y += Math.PI / 6
    scene.add(cube1)

    var material2 = new THREE.MeshPhongMaterial({
      map: normal
    })
    cube2 = new THREE.Mesh(geometry, material2)
    cube2.position.set(5, 5, 0)
    cube2.rotation.y -= Math.PI / 6
    scene.add(cube2)
  }
  var initStats = () => {
    stats = new Stats()
    document.body.appendChild(stats.domElement)
  }
  var initControls = () => {
    controls = new THREE.OrbitControls(camera, renderer.domElement)
    controls.target.set(0, 5, 0)
    controls.enableDamping = true
  }
  var render = () => {
    if (gui.animation) {
      cube1.rotation.y += 0.01
      cube2.rotation.y -= 0.01
    }
    angle += 1
    radian = angle / 180 * Math.PI
    var x = Math.sin(radian)
    var y = Math.cos(radian)

    if (angle % 720 > 360) {
      y = -y + 2
    }

    pointLight.position.z = x * r
    pointLight.position.x = y * r - r
  }
  var onWindowResize = () => {
    camera.aspect = window.innerWidth / window.innerHeight
    camera.updateProjectionMatrix()
    renderer.setSize(window.innerWidth, window.innerHeight)
  }
  var animate = () => {
    render()
    stats.update()
    controls.update()
    renderer.render(scene, camera)
    requestAnimationFrame(animate)
  }
  var draw = () => {
    if (!Detector.webgl) Detector.addGetWebGLMessage()
    initGui()
    initRender()
    initScene()
    initCamera()
    initLight()
    initModel()
    initStats()
    initControls()

    animate()

    window.onresize = onWindowResize
  }
</script>
</html>

效果如下:
在这里插入图片描述

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

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

相关文章

SAP ME2L/ME2M/ME3M报表增强添加字段

SAP ME2L/ME2M/ME3M报表增强添加字段&#xff08;包含&#xff1a;LMEREPI02、SE18:ES_BADI_ME_REPORTING&#xff09; ME2L、ME2M、ME3M这三个报表的字段增强&#xff0c;核心点都在同一个结构里 SE11:MEREP_OUTTAB_PURCHDOC 在这里加字段&#xff0c;如果要加的字段是EKKO、…

dubbo-go框架介绍

框架介绍 什么是 dubbo-go Dubbo-go 是 Apache Dubbo 的 go 语言实现&#xff0c;它完全遵循 Apache Dubbo 设计原则与目标&#xff0c;是 go 语言领域的一款优秀微服务开发框架。dubbo-go 提供&#xff1a; API 与 RPC 协议&#xff1a;帮助解决组件之间的 RPC 通信问题&am…

不只是请求和响应:使用Fiddler抓包URL和Method全指南(中)

欢迎浏览高耳机的博客 希望我们彼此都有更好的收获 感谢三连支持! 不只是请求和响应&#xff1a;使用Fiddler抓包HTTP协议全指南(上)-CSDN博客https://blog.csdn.net/Chunfeng6yugan/article/details/144005872?spm1001.2014.3001.5502 &#x1f649;在(上)篇博客中&#xf…

Linux操作系统学习---初识环境变量

目录 ​编辑 环境变量的概念&#xff1a; 小插曲&#xff1a;main函数的第一、二个参数 获取环境变量信息&#xff1a; 1.main函数的第三个参数 2.查看单个环境变量 3.c语言库函数getenv() 和环境变量相关的操作指令&#xff1a; 1.export---导出环境变量&#xff1a; 2.unse…

跨平台应用开发框架(1)----Qt(组件篇)

目录 1.Qt 1.Qt 的主要特点 2.Qt的使用场景 3.Qt的版本 2.QtSDK 1.Qt SDK 的组成部分 2.安装 Qt SDK 3.Qt SDK 的优势 3.Qt初识 1.快速上手 widget.cpp mian.cpp widget.h Helloworld.pro 2.对象树 3.坐标系 4.信号和槽 1. 信号和槽的基本概念 2. 信号和槽的…

mysql索引失效的五种情况

第一种 违反最左前缀法则 这个是针对联合索引的。 假设有个tb_seller表&#xff0c;现在给三个字段建立联合索引&#xff0c;建立的时候字段顺序不可随便设置&#xff0c;字段顺序&#xff1a; name, status, address。下图Seq_in_index对应的是联合索引顺序。 判断索引失效用…

H3C OSPF 多区域实验

目录 前言 实验拓扑 实验需求 实验解析 路由器配置 测试 前言 此篇文章为 OSPF多区域试验&#xff0c;建议先食用OSPF单区域实验&#xff0c;理解实验原理 学习基本配置&#xff0c;再来使用此篇&#xff0c;效果更佳&#xff01;&#xff08;当然如果你已经了解原理与基…

算法 Java实现

一.查找算法 1.分块查找 二.排序算法 1.冒泡排序

优先算法 —— 双指针系列 - 快乐数

1. 快乐数 题目链接&#xff1a; 202. 快乐数 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/happy-number/description/ 2. 题目解析 示例1&#xff1a; 示例2&#xff1a; 3. 算法原理 两种情况&#xff1a;我们可以把两种情况都看作为循环&#xff0…

【机器学习】——卷积与循环的交响曲:神经网络模型在现代科技中的协奏

&#x1f3bc;个人主页&#xff1a;【Y小夜】 &#x1f60e;作者简介&#xff1a;一位双非学校的大二学生&#xff0c;编程爱好者&#xff0c; 专注于基础和实战分享&#xff0c;欢迎私信咨询&#xff01; &#x1f386;入门专栏&#xff1a;&#x1f387;【MySQL&#xff0…

php 导出excel 一个单元格 多张图片

public function dumpData(){error_reporting(0); // 禁止错误信息输出ini_set(display_errors, 0); // 不显示错误$limit $this->request->post(limit, 20, intval);$offset $this->request->post(offset, 0, intval);$page floor($offset / $limit) 1 ;$wh…

几天游记啊

绿灯常亮&#xff0c;黄灯闪&#xff0c;就是没有上线状态 一 2024.11.24 青浦圆通信息中心&#xff1a;vsphere client IDC运维专员可能就这项技能稀缺 二 2024.11.25 1 字节服务器外包单位有孚网路 什么互联网交换中心 不了解的人还以为是国家火炬计划呢&#xff01;实际…

【C++动态规划 子集状态压缩】2002. 两个回文子序列长度的最大乘积|1869

本文涉及知识点 C动态规划 位运算、状态压缩、枚举子集汇总 LeetCode2002. 两个回文子序列长度的最大乘积 给你一个字符串 s &#xff0c;请你找到 s 中两个 不相交回文子序列 &#xff0c;使得它们长度的 乘积最大 。两个子序列在原字符串中如果没有任何相同下标的字符&…

记录:从.Net程序的内存转储文件中提取内存数据过程

1.准备材料&#xff1a;xxx.dump转储文件&#xff0c;VS2022 2.提取过程 使用VS打开xxx.dump文件VS中点击 调试托管内存 按钮查找需要导出的变量&#xff0c;注&#xff1a;通过类型查找时基础变量类型跟原类型不一样&#xff0c;如string对应String&#xff0c;bool对应Bool…

Nacos学习文档

目录 1、Nacos是什么2、Nacos名词介绍3、Nacos中的data id是如何组装的&#xff1f;4、Nacos 融合 Spring Cloud&#xff0c;成为注册配置中心4.1、Maven依赖作用4.2、启动配置管理4.2.1、添加依赖4.2.2、在 bootstrap.yml&#xff08;也支持properties格式&#xff09; 中添加…

QT简易项目 数据库可视化界面 数据库编程SQLITE QT5.12.3环境 C++实现

案例需求&#xff1a; 完成数据库插入&#xff0c;删除&#xff0c;修改&#xff0c;查看操作。 分为 插入&#xff0c;删除&#xff0c;修改&#xff0c;查看&#xff0c;查询 几个模块。 代码&#xff1a; widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget…

【Linux学习】【Ubuntu入门】2-3 make工具和makefile引入

1.使用命令新建三个.c文件vi main.c&#xff0c;vi input.c&#xff0c;vi caclcu.c&#xff0c;两个.h文件vi input.h&#xff0c;vi caclcu.h 2.vi Makefile&#xff1a;新建Makefile文件&#xff0c;输入一下内容 注意&#xff1a;命令列表中每条命令前用TAB键&#xff0c;不…

Gazebo仿真实现无人机+Apriltag码动态跟踪

目录 演示 一、环境 二、配置 创建模型 首先相机创建 添加相机 Apriltag创建 地图添加apriltag码 Apriltag_ros配置 三、代码运行 四、问题 修改相机模型的参数 演示 一、环境 ROSgazebo配置 Px4Mavros Apriltag_ros编译 二、配置 在默认的mavros_posix_sitl.l…

H.265流媒体播放器EasyPlayer.js播放器提示MSE不支持H.265解码可能的原因

随着人工智能和机器学习技术的应用&#xff0c;流媒体播放器将变得更加智能&#xff0c;能够根据用户行为和偏好提供个性化的内容推荐。总体而言&#xff0c;流媒体播放器的未来发展将更加注重技术创新和用户互动&#xff0c;以适应不断变化的市场需求和技术进步。 提示MSE不支…

加菲工具 - 好用免费的在线工具集合

加菲工具 https://orcc.online AI 工具 集合了目前主流的&#xff0c;免费可用的ai工具 文档处理 pdf转word、office与pdf互转等等工具都有链接 图片图标 统计了好用免费的在线工具 编码解码 base64编码解码、url编码解码、md5计算、进制转换等等 其它 还有其他好用的…