【Three.js基础学习】28.Coffee Smoke

前言

/*

   

        补充:材质本身纹理有光源等信息因此能看到模型

        gltf.scene.traverse((child) => {

            if (child.isMesh) {

                child.material.map = null; // 移除贴图

            }

        });

        此时是纯白色,按照正常逻辑 没有光会是灰/黑色

        为什么显示白色

        1.默认材质颜色

        2.材质的表现是均匀的纯色,而非根据光影变化显示灰色

        3.Three.js 默认的行为是让材质按照它本身的颜色显示

    课程

        制作咖啡的烟雾(热气)    

        预制纹理: https://opengameart.org/content/noise-texture-pack

        制作纹理器: https://mebiusbox.github.io/contents/EffectTextureMaker/

       

        在选择噪声纹理时,请记住3条规则

            足够的变体

            大到足够

            重复的模式(或“耕作”)

       

        1.创建smoke ,

            创建一个几何体PlanGeometry, 移动几何体位置,同时缩放(在第一帧时可以做,但是不要在tick中执行)

            创建材质,创建网格,添加到场景中

        2. 使用着色器材质,创建顶点着色器,片段着色器

            projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0)

            这里我写的顺序不对,导致渲染时候中间烟雾随着视角转动而围绕杯子(注意)

       

        3. 之后跟写国旗的差不多(不过其中关于片段和顶点着色器要修改部分)

        4.其中烟雾 设置透明  要在材质中添加 transparent:true;

        5. 设置uTiem添加动画 ,同时让纹理重复 wrapS wrapT

        6.设置边缘淡化

        7.设置随风飘动

            我们希望顶点绕着平面中心旋转,并使旋转随仰角变化。

            风向

        8. 烟雾遮挡

            实现

       

        着色器中创建includes文件夹 区分函数

            #include ../includes/rotate.glsl

            注意:  #include <tonemapping_fragment>

                    #include <colorspace_fragment>

                是应用three.js的和上面的#includes不一样

*/


一、代码

script.js

import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
import GUI from 'lil-gui'
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'
import coffeeSmokeVertexShader from './shaders/coffeeSmoke/vertex.glsl'
import coffeeSmokeFragmentShader from './shaders/coffeeSmoke/fragment.glsl'/*** Base*/
// Debug
const gui = new GUI()// Canvas
const canvas = document.querySelector('canvas.webgl')// Scene
const scene = new THREE.Scene()// Loaders
const textureLoader = new THREE.TextureLoader()
const gltfLoader = new GLTFLoader()/*** Sizes*/
const sizes = {width: window.innerWidth,height: window.innerHeight
}window.addEventListener('resize', () =>
{// Update sizessizes.width = window.innerWidthsizes.height = window.innerHeight// Update cameracamera.aspect = sizes.width / sizes.heightcamera.updateProjectionMatrix()// Update rendererrenderer.setSize(sizes.width, sizes.height)renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})/*** Camera*/
// Base camera
const camera = new THREE.PerspectiveCamera(25, sizes.width / sizes.height, 0.1, 100)
camera.position.x = 8
camera.position.y = 10
camera.position.z = 12
scene.add(camera)// Controls
const controls = new OrbitControls(camera, canvas)
controls.target.y = 3
controls.enableDamping = true/*** Renderer*/
const renderer = new THREE.WebGLRenderer({canvas: canvas,antialias: true
})
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))/*** Model*/
gltfLoader.load('./bakedModel.glb',(gltf) =>{gltf.scene.getObjectByName('baked').material.map.anisotropy = 8console.log(gltf.scene)scene.add(gltf.scene)}
)/* Smoke
*/
// Geometry
const smokeGeometry = new THREE.PlaneGeometry(1,1,16,64)
smokeGeometry.translate(0,0.5,0)
smokeGeometry.scale(1.5,6,1.5)// Perlin texture
const perlinTexture = textureLoader.load('./perlin.png')
perlinTexture.wrapS = THREE.RepeatWrapping
perlinTexture.wrapT = THREE.RepeatWrapping// Material
const smokeMaterial = new THREE.ShaderMaterial({// wireframe:true,vertexShader:coffeeSmokeVertexShader,fragmentShader:coffeeSmokeFragmentShader,side:THREE.DoubleSide,transparent:true, // 支持材料透明depthWrite:false, //深度 写入 (防止透明遮挡)uniforms:{uTime: new THREE.Uniform(0),uPerlinTexture: new THREE.Uniform(perlinTexture), // {value:perlinTexture} 一样}
})//Mesh
const smoke = new THREE.Mesh(smokeGeometry,smokeMaterial)
smoke.position.y = 1.83
scene.add(smoke)/*** Animate*/
const clock = new THREE.Clock()const tick = () =>
{const elapsedTime = clock.getElapsedTime()// update materialsmokeMaterial.uniforms.uTime.value = elapsedTime// Update controlscontrols.update()// Renderrenderer.render(scene, camera)// Call tick again on the next framewindow.requestAnimationFrame(tick)
}tick()

vertex.glsl


// 这里特别注意  projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0) 乘的顺序是固定的,不然会出问题
/* pow(x,y)  x的y次方。如果x小于0,结果是未定义的。同样,如果x=0并且y<=0,结果也是未定义的。
*/uniform float uTime;
uniform sampler2D uPerlinTexture;// attribute vec2 uv; // 获取顶点的属性 uv,坐标等varying vec2 vUv;#include ../includes/rotate.glsl // 引入函数void main(){vec3 newPosition = position;// Twistfloat twistPerlin = texture2D(uPerlinTexture,vec2(0.5,uv.y * 0.2 - uTime * 0.005) // 添加动画,随风飘散).r;float angle = twistPerlin * 10.0; // 海拔newPosition.xz = rotate2D(newPosition.xz,angle);// Windvec2 windOffset = vec2(texture2D(uPerlinTexture,vec2(0.25,uTime * 0.01)).r - 0.5, // 另一个取值 风向偏移 0-1减去0.5 x轴就是正负0.5 ,x轴;texture2D(uPerlinTexture,vec2(0.75,uTime * 0.01)).r - 0.5  // z轴正负移动);windOffset *=  pow(uv.y,2.0) * 10.0; // 得到曲线newPosition.xz += windOffset;vec4 modelPosition = modelMatrix * vec4(newPosition,1.0); // 通过模型矩阵获得模型位置vec4 viewPosition = viewMatrix * modelPosition; // 通过视图矩阵获取视图位置vec4 projectionPosition = projectionMatrix * viewPosition; // 通过投影矩阵获取投影位置gl_Position = projectionPosition;vUv = uv;
}

fragment.glsl

uniform float uTime; 
uniform sampler2D uPerlinTexture; // texture2D 2D采样器/* smoothstep(edge0, edge1, x)如果x <= edge0,返回0.0 ;如果x >= edge1 返回1.0;如果edge0 < x < edge1,则执行0~1之间的平滑埃尔米特差值。如果edge0 >= edge1,结果是未定义的。*/varying vec2 vUv;void main(){// Scale and animatevec2 smokeUv = vUv;smokeUv.x *= 0.3;smokeUv.y *= 0.3;smokeUv.y -= uTime * 0.03;// smokefloat smoke = texture2D(uPerlinTexture,smokeUv).r;// Remapsmoke = smoothstep(0.4,1.0,smoke);// // Edges  重新映射 淡化边缘 (由于边缘边界很明显)组合起来相乘即可// smoke = 1.0;smoke *= smoothstep(0.0,0.1,vUv.x); // 0-1 左侧0.0-0.1淡化smoke *= smoothstep(1.0,0.9,vUv.x); smoke *= smoothstep(0.0,0.1,vUv.y); // 0-1 左侧0.0-0.1淡化smoke *= smoothstep(1.0,0.4,vUv.y); gl_FragColor = vec4(0.6,0.3,0.2,smoke);// gl_FragColor = vec4(1.0,0.0,0.0,1.0);// 色调映射#include <tonemapping_fragment>#include <colorspace_fragment>}

rotate.glsl

vec2 rotate2D(vec2 value,float angle){float s = sin(angle);float c = cos(angle);mat2 m = mat2(c,s,-s,c);return m * value;
}

二、效果

shaders - coffee smoke


总结

如何制作烟雾,以及着色器中热气的运动状态应用。

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

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

相关文章

Linux(命令行扩展+命令行历史 大白话+图片)

后面也会持续更新&#xff0c;学到新东西会在其中补充。 建议按顺序食用&#xff0c;欢迎批评或者交流&#xff01; 缺什么东西欢迎评论&#xff01;我都会及时修改的&#xff01; 在这里真的很感谢这位老师的教学视频让迷茫的我找到了很好的学习视频 王晓春老师的个人空间…

渗透测试---shell(5)字符串运算符与逻辑运算符

声明&#xff1a;学习素材来自b站up【泷羽Sec】&#xff0c;侵删&#xff0c;若阅读过程中有相关方面的不足&#xff0c;还请指正&#xff0c;本文只做相关技术分享,切莫从事违法等相关行为&#xff0c;本人与泷羽sec团队一律不承担一切后果 目录 一、字符串运算符 创建u.sh文…

06、Spring AOP

在我们接下来聊Spring AOP之前我们先了解一下设计模式中的代理模式。 一、代理模式 代理模式是23种设计模式中的一种,它属于结构型设计模式。 对于代理模式的理解: 程序中对象A与对象B无法直接交互,如:有人要找某个公司的老总得先打前台登记传达程序中某个功能需要在原基…

游戏陪玩系统开发功能需求分析

电竞游戏陪玩系统是一种专门为游戏玩家提供陪伴、指导和互动服务的平台。这类系统通常通过专业的陪玩师&#xff08;也称为陪练师&#xff09;为玩家提供一对一或多对一的游戏陪伴服务&#xff0c;帮助玩家提升游戏技能、享受游戏乐趣&#xff0c;甚至解决游戏中的各种问题。电…

【数据库入门】关系型数据库入门及SQL语句的编写

1.数据库的类型&#xff1a; 数据库分为网状数据库&#xff0c;层次数据库&#xff0c;关系型数据库和非关系型数据库四种。 目前市场上比较主流的是&#xff1a;关系型数据库和非关系型数据库。 关系型数据库使用结构化查询语句&#xff08;SQL&#xff09;对关系型数据库进行…

【2024亚太杯亚太赛APMCM C题】数学建模竞赛|宠物行业及相关产业的发展分析与策略|建模过程+完整代码论文全解全析

第一个问题是&#xff1a;请基于附件 1 中的数据以及你的团队收集的额外数据&#xff0c;分析过去五年中国宠物行业按宠物类型的发展情况。并分析中国宠物行业发展的因素&#xff0c;预测未来三年中国宠物行业的发展。 第一个问题&#xff1a;分析中国宠物行业按宠物类型的发展…

合法三元数量计算

问题描述 小C、小U 和小R 三个好朋友喜欢做一些数字谜题。这次他们遇到一个问题&#xff0c;给定一个长度为n的数组a&#xff0c;他们想要找出符合特定条件的三元组 (i, j, k)。具体来说&#xff0c;三元组要满足 0 < i < j < k < n&#xff0c;并且 max(a[i], a[…

wsl虚拟机中的dockers容器访问不了物理主机

1 首先保证wsl虚拟机能够访问宿主机IP地址&#xff0c;wsl虚拟机通过vEthernet (WSL)的地址访问&#xff0c;着意味着容器也要通过此IP地址访问物理主机。 2 遇到的问题&#xff1a;wsl虚拟机中安装了docker&#xff0c;用在用到docker容器内的开发环境&#xff0c;但是虚拟机…

深入了解 Linux htop 命令:功能、用法与示例

文章目录 深入了解 Linux htop 命令&#xff1a;功能、用法与示例什么是 htop&#xff1f;htop 的安装htop的基本功能A区&#xff1a;系统资源使用情况B区&#xff1a;系统概览信息C区&#xff1a;进程列表D区&#xff1a;功能键快捷方式 与 top 的对比常见用法与示例实际场景应…

如何删除Kafka中的数据以及删除topic

如何删除Kafka数据已经以及删除topic呢&#xff1f; 1、删除数据 先启动Kafka实例 docker exec -it kafka-0 /bin/bash #进去容器 rm -rf /bitnami/kafka/data/* #删除数据 exit #退出如果删除失败&#xff0c;可能是数据不存在于/bitnami/kafka/data&#xff0c;使用 cd /o…

Easyexcel(4-模板文件)

相关文章链接 Easyexcel&#xff08;1-注解使用&#xff09;Easyexcel&#xff08;2-文件读取&#xff09;Easyexcel&#xff08;3-文件导出&#xff09;Easyexcel&#xff08;4-模板文件&#xff09; 文件导出 获取 resources 目录下的文件&#xff0c;使用 withTemplate 获…

【2024最新】基于springboot+vue的疫情网课管理系统lw+ppt

作者&#xff1a;计算机搬砖家 开发技术&#xff1a;SpringBoot、php、Python、小程序、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;Java精选实战项…

贴代码框架PasteForm特性介绍之image

简介 PasteForm是贴代码推出的 “新一代CRUD” &#xff0c;基于ABPvNext&#xff0c;目的是通过对Dto的特性的标注&#xff0c;从而实现管理端的统一UI&#xff0c;借助于配套的PasteBuilder代码生成器&#xff0c;你可以快速的为自己的项目构建后台管理端&#xff01;目前管…

从 IDC 到云原生:稳定性提升 100%,成本下降 50%,热联集团的数字化转型与未来展望

作者&#xff1a;金峰&#xff08;项良&#xff09;、朱永林、赵世振&#xff08;寰奕&#xff09; 公司简介 杭州热联集团股份有限公司成立于 1997 年 10 月&#xff0c;是隶属杭州市实业投资集团的国有控股公司。公司专业从事国际、国内钢铁贸易黑色大宗商品及产业服务&…

Python Turtle召唤童年:喜羊羊与灰太狼之懒羊羊绘画

Python Turtle召唤童年&#xff1a;喜羊羊与灰太狼之懒羊羊绘画 &#x1f438; 前言 &#x1f438;&#x1f41e;往期绘画&#x1f41e;&#x1f40b; 效果图 &#x1f40b;&#x1f409; 代码 &#x1f409; &#x1f438; 前言 &#x1f438; 小时候&#xff0c;每次打开电视…

SpringBoot学习记录(四)之分页查询

SpringBoot学习记录&#xff08;四&#xff09;之分页查询 一、业务需求1、基本信息2、请求参数3、相应数据 二、传统方式分页三、使用PageHelper分页插件 一、业务需求 根据条件进行员工数据的条件分页查询 1、基本信息 请求路径&#xff1a; /emps 请求方式&#xff1a; …

6. Spring Cloud Gateway网关超详细内容配置解析说明

6. Spring Cloud Gateway网关超详细内容配置解析说明 文章目录 6. Spring Cloud Gateway网关超详细内容配置解析说明前言1 Spring Cloud Gateway 概述1.1 Spring Cloud Gateway网关 的核心功能1.2 Spring Cloud Gateway VS Zuul 的区别1.3 Spring Cloud Gateway 的基本原理1.4 …

远程管理不再难!树莓派5安装Raspberry Pi OS并实现使用VNC异地连接

前言&#xff1a;大家好&#xff01;今天我要教你们如何在树莓派5上安装Raspberry Pi OS&#xff0c;并配置SSH和VNC权限。通过这些步骤&#xff0c;你将能够在Windows电脑上使用VNC Viewer&#xff0c;结合Cpolar内网穿透工具&#xff0c;实现长期的公网远程访问管理本地树莓派…

Centos 8, add repo

Centos repo前言 Centos 8更换在线阿里云创建一键更换repo 自动化脚本 华为Centos 源 , 阿里云Centos 源 华为epel 源 , 阿里云epel 源vim /centos8_repo.sh #!/bin/bash # -*- coding: utf-8 -*- # Author: make.han

【机器学习】回归模型(线性回归+逻辑回归)原理详解

线性回归 Linear Regression 1 概述 线性回归类似高中的线性规划题目。线性回归要做的是就是找到一个数学公式能相对较完美地把所有自变量组合&#xff08;加减乘除&#xff09;起来&#xff0c;得到的结果和目标接近。 线性回归分为一元线性回归和多元线性回归。 2 一元线…