ThreeJS-3D教学十二:ShaderMaterial
一、首先 Shader 是做什么的
Shader 可以自定义每个顶点、每个片元/像素如何显示,而控制顶点和片元显示是通过设置 vertexShader 顶点着色器和 fragmentShader 片元着色器,这两个着色器用在 ShaderMaterial 和 RawShaderMaterial 材质上。
我们先看一个例子:
<!DOCTYPE html>
<html lang="en">
<head><title>three.js webgl - raw shader</title><meta charset="utf-8"><meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
</head>
<body>
<div id="container"></div>
<script id="vertexShader" type="x-shader/x-vertex">uniform mat4 modelViewMatrix;uniform mat4 projectionMatrix;attribute vec3 position;void main() {gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );}
</script><script id="fragmentShader" type="x-shader/x-fragment">void main() {gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);}</script>
<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';let container, stats, controls;let camera, scene, renderer;init();animate();initObject();function initObject() {// geometry// 第一个是生成几个三角形 const vertexCount = 2 * 3;const geometry = new THREE.BufferGeometry();const positions = [];const colors = [];for ( let i = 0; i < vertexCount; i ++ ) {// adding x,y,zpositions.push( Math.random() - 0.5 );positions.push( Math.random() - 0.5 );positions.push( Math.random() - 0.5 );// adding r,g,b,acolors.push( Math.random() * 255 );colors.push( Math.random() * 255 );colors.push( Math.random() * 255 );colors.push( Math.random() * 255 );}const positionAttribute = new THREE.Float32BufferAttribute( positions, 3 );const colorAttribute = new THREE.Uint8BufferAttribute( colors, 4 );colorAttribute.normalized = true; // this will map the buffer values to 0.0f - +1.0f in the shadergeometry.setAttribute( 'position', positionAttribute );geometry.setAttribute( 'color', colorAttribute );// materialconst material = new THREE.RawShaderMaterial({uniforms: {time: { value: 1.0 }},vertexShader: document.getElementById( 'vertexShader' ).textContent,fragmentShader: document.getElementById( 'fragmentShader' ).textContent,side: THREE.DoubleSide,transparent: true});const mesh = new THREE.Mesh( geometry, material );scene.add( mesh );}function init() {container = document.getElementById( 'container' );camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 10 );camera.position.z = 2;scene = new THREE.Scene();scene.background = new THREE.Color( 0x101010 );renderer = new THREE.WebGLRenderer();renderer.setPixelRatio( window.devicePixelRatio );renderer.setSize( window.innerWidth, window.innerHeight );container.appendChild( renderer.domElement );controls = new OrbitControls( camera, renderer.domElement );stats = new Stats();container.appendChild( stats.dom );window.addEventListener( 'resize', onWindowResize );}function onWindowResize() {camera.aspect = window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();renderer.setSize( window.innerWidth, window.innerHeight );}function animate() {requestAnimationFrame( animate );render();controls.update();stats.update();}function render() {const time = performance.now();const object = scene.children[0];if (object) {// object.rotation.y = time * 0.0005;object.material.uniforms.time.value = time * 0.005;}renderer.render( scene, camera );}
</script>
</body>
</html>
以上代码 顶点着色器 我们用的是固定写法计算顶点的位置
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
或者也可以这样:
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4( position, 1.0 );
而片元着色器我们设置了一个白色
我相信大家会对 scropt 中 x-shader/x-vertex、x-shader/x-fragment 很陌生,没关系咱们学习 Shader 其实大部分就是学这里面怎么写:
它是一种类似C语言的 GLSL 语言——即 OpenGL Shading Language——,
JavaScript、C 等语言通常在 CPU 上执行,而着色器语言通常在 GPU 上执行,由 GPU 分别对每个顶点、每个片元独立执行
shader 程序可以单独写在诸如 vertex.glsl、fragment.glsl 的文件里再导入使用,也可以和示例一样写在script中,或者在 JavaScript 里用字符串格式表示(后面会介绍)
在顶点着色器里需要设置 gl_Position顶点位置,在片元着色器里需要设置 gl_FragColor 片元/像素颜色,两者都在没有返回值的 void main() {} 主函数里设置,并且 main 函数会被自动执行
着色器语言三种变量 attribute、uniform 和 varying
- 简单总结
顶点着色器渲染定位顶点位置
片段着色器为该几何体的每个可见片元(像素)进行着色
片段着色器在顶点着色器之后执行
在每个顶点之间会有变化的数据(如顶点的位置)称为attribute,只能在顶点着色器中使用
顶点之间不变的数据(如网格位置或颜色)称为uniform,可以在顶点着色器和片段着色器中使用
从顶点着色器发送到片元着色器中的插值计算数据被称为varying
看了上面的内容,我们再来看一个案例,提前说下 在这里我无意将所有 GLSL 语言的方法一一列出,我相信大家也不愿意看,毕竟网上一大堆类似文章,官网上也能看,我只是通过案例,把一些常用的知识点给到大家,能让各位对 编写Shader有个初步的认知:
let vertexShader = `precision mediump float;precision mediump int;uniform mat4 modelViewMatrix;uniform mat4 projectionMatrix;attribute vec3 position;attribute vec4 color;varying vec3 vPosition;varying vec4 vColor;void main() {vPosition = position;vColor = color;gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );}
`;
let fragmentShader = `precision mediump float;precision mediump int;uniform float time;varying vec3 vPosition;varying vec4 vColor;void main() {vec4 color = vec4( vColor );color.g += sin( vPosition.x * 10.0 + time ) * 0.5;gl_FragColor = color;}
`;
上面有几点知识点,先从简单的来,
1、通过 varying 可以将vPosition、vColor 从 vertexShader 到 fragmentShader
2、上面的写法是 shader 程序刚才提到的 字符串格式写法
3、precision 一个新的知识点 - 着色器运算精度设置
通过设置着色器数值的精度可以更好的配置资源,可以根据需要,在不太影响渲染效果前提下,可以尽量降低运算精度。
lowp、mediump和highp关键字 分别对应 低、中、高三个精度
1)通过precision关键字可以批量声明一些变量精度。
比如顶点着色器代码设置precision highp float;,表示顶点着色器中所有浮点数精度为高精度。
2)比如片元着色器代码设置precision lowp int;,表示片元着色器中所有整型数精度为低精度。
3)顶点和片元着色器不同类型数据默认精度
顶点着色器默认精度
数据类型 | 默认精度 |
---|---|
int | 高精度hight |
float | 高度hight |
sampler2D | 低精度lowp |
samplerCube | 低精度lowp |
片元着色器默认精度
数据类型 | 默认精度 |
---|---|
int | 中精度mediump |
float | 无默认值,如果片元着色器用到浮点数,注意一定手动设置 |
sampler2D | 低精度lowp |
samplerCube | 低精度lowp |
4、我们发现有申明 modelViewMatrix、projectionMatrix、position、color变量,这是因为我们使用 RawShaderMaterial材质,这个方法没有默认的内置变量声明,与之对应的我们可以用 ShaderMaterial 材质,此时就可以这样写:
let vertexShader = `precision mediump float;precision mediump int;varying vec3 vPosition;varying vec4 vColor;void main() {vPosition = position;vColor = color;gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );}
`;
更多的 内置变量请看这里
通过以上案例我们算是简单的了解了 Shader,发现 Shader其实就是改变 顶点位置 和 片元/像素颜色
二、图形构成的基础 三角形
我们将 geometry 换为一个球体来认识一下图形的基础构成
const geometry = new THREE.SphereGeometry( 0.5, 16, 8 );
const material = new THREE.RawShaderMaterial({uniforms: {time: { value: 1.0 }},vertexShader: document.getElementById( 'vertexShader1' ).textContent,fragmentShader: document.getElementById( 'fragmentShader1' ).textContent,side: THREE.DoubleSide,transparent: false,wireframe: true // 将几何体渲染为线框,默认值为false(即渲染为平面多边形)。});
通过这个球体 可以很好的理解 图形的构成,其实就是一个个的三角形,三角形越是多,图形效果越好 当然对电脑性能要求越高,
const geometry = new THREE.SphereGeometry( 0.5, 128, 64);
可以看到 这个球体就很完美了,通过这个案例也能更好的帮大家理解
顶点着色器渲染顶点位置的顶点 是哪些点、从哪来的点
片段着色器为该几何体的每个可见片元(像素)进行着色
相关文章:

ThreeJS-3D教学十二:ShaderMaterial
一、首先 Shader 是做什么的 Shader 可以自定义每个顶点、每个片元/像素如何显示,而控制顶点和片元显示是通过设置 vertexShader 顶点着色器和 fragmentShader 片元着色器,这两个着色器用在 ShaderMaterial 和 RawShaderMaterial 材质上。 我们先看一个例…...

计算机网络面试TCP篇之TCP三次握手与四次挥手
TCP 三次握手与四次挥手面试题 任 TCP 虐我千百遍,我仍待 TCP 如初恋。 巨巨巨巨长的提纲,发车!发车! PS:本次文章不涉及 TCP 流量控制、拥塞控制、可靠性传输等方面知识,这些知识在这篇: TCP …...

Python-数据分析组合可视化实例图【附完整源码】
数据分析组合可视化实例图 开篇:应女朋友的要求,于是写下了这篇详细的数据可视化代码及完整注释 一:柱状图、折线图横向组合网格布局 本段代码使用了pyecharts库来创建一个包含多个图表(柱状图、折线图)和网格布局的…...

【JavaEE】Spring Web MVC详解
一.基本概念. 1.什么是Spring Web MVC? 官方链接: https://docs.spring.io/spring-framework/reference/web/webmvc.html Spring Web MVC is the original web framework built on the Servlet API and has been included in the Spring Framework from the very beginning…...

docker安装rocketMq5x以上的版本
1.背景 安装RocketMQ 5.x以上的版本主要是因为新版本引入了许多性能优化、新功能以及对已有特性的增强,这些改进可以帮助提升消息队列系统的稳定性和效率。 1.性能提升:RocketMQ 5.x版本通常包括了对消息处理速度、吞吐量和延迟的优化,使得系…...

【Spring】DAO 和 Repository 的区别
DAO 和 Repository 的区别 1.概述2.DAO 模式2.1 User2.2 UserDao2.3 UserDaoImpl 3.Repository 模式3.1 UserRepository3.2 UserRepositoryImpl 4.具有多个 DAO 的 Repository 模式4.1 Tweet4.2 TweetDao 和 TweetDaoImpl4.3 增强 User 域4.4 UserRepositoryImpl 5.比较两种模式…...
高阶面试-秒杀系统的设计
场景 特价商品如茅台,在8月1日22点10分0秒开始秒杀 平台用户量:几千万,预计几十万用户感兴趣 需求 临时性的活动,不要太大技术改动 原则 商品不能超卖下单成功的订单不能丢失服务器和数据库不能崩溃尽量不让机器人抢走商品 …...
四十五、 证券基金业数据出境有无特别规范需要注意?
证券基金业数据合规除应遵守本《实务问答》前述的各项通用规定外,还应注意中国证券监督管理委员会等其他机构发布的相关规范。其中,与数据出境相关的主要包括《证券期货业数据分类分级指引》(JR/T 0158—2018,2018年 9月 27日实施…...

02.Linux下安装FFmpeg
目录 一、下载FFmpeg的编译源码 二、编译源码 三、ffmpeg工具结构解析 1、bin目录 2、include库 3、lib库 四、注意事项 五、可能出现的一些问题 1、某些工具未安装/版本过久 2、缺少pkg-config工具 3、缺少ffmplay FFmpeg 是一个开源的跨平台音视频处理工具集&…...

华为RH2288H V2服务器,远程端口安装Linux操作系统
1、管理口 每台服务器的管理口不一样的,假如我的管理IP地址为:192.168.111.201 使用网线,将管理口和自己电脑连接起来,自己ip地址设置成和管理ip同一网段。 使用 ie 浏览器,如果是Edge,必须在Internet Exp…...

JS在线加密简述
JS在线加密,是指:在线进行JS代码混淆加密。通过混淆、压缩、加密等手段,使得JS源代码难以阅读和理解。从而可以有效防止代码被盗用或抄袭,保护开发者的知识产权和劳动成果。常用的JS在线加密网站有:JShaman、JS-Obfusc…...

理想汽车提出3DRealCar:首个大规模3D真实汽车数据集
理想提出3DRealCar,这是第一个大规模 3D 实车数据集,包含 2500 辆在真实场景中拍摄的汽车。我们希望 3DRealCar 可以成为促进汽车相关任务的宝贵资源。 理想汽车提出3DRealCar:首个大规模3D真实汽车数据集! 我们精心策划的高质量3DRealCar数…...

HTML5文旅文化旅游网站模板源码
文章目录 1.设计来源文旅宣传1.1 登录界面演示1.2 注册界面演示1.3 首页界面演示1.4 文旅之行界面演示1.5 文旅之行文章内容界面演示1.6 关于我们界面演示1.7 文旅博客界面演示1.8 文旅博客文章内容界面演示1.9 联系我们界面演示 2.效果和源码2.1 动态效果2.2 源代码2.3 源码目…...

山东大学多核并行2024年回忆版
2024.6.13回忆版 矩阵向量乘不可整除代码 集合通信与点对点通信的区别 块划分、循环划分、循环块划分(14个向量,4个进程) 按行访问还是按列访问快 SISD系统问题 循环依赖问题 问题:为什么不能对这个循环并行化࿰…...
CentOS 7 上搭建 JavaEE 环境
CentOS 7 上搭建 JavaEE 环境 安装 Java 环境 1)检查系统中是否已安装 Java java -version如果未安装,将返回提示信息。 2)安装 Java 8 sudo yum install java-1.8.0-openjdk3)配置 Java 环境变量,编辑 /etc/prof…...
库与表管理的终极指南
数据库的库和表的管理 库的管理1.库的创建2.数据库的查看和使用3.数据库的修改4.数据库的删除 表的管理1.表的创建2.表的修改3.表的删除4.查看一个表 阅读指南: 本文章是数据库教程系列的一部分,专注于数据库的库和表管理。读者可以根据兴趣选择阅读相关…...
等级保护测评在测评中Linux系统怎么改
在等级保护测评中,针对Linux系统的整改主要是为了提高其安全性,使之符合等级保护的基本要求。 以下是一些常见的整改步骤和建议: 1. 身份鉴别: • 强化密码策略,例如设置复杂的密码规则、密码长度、密码复杂度、密码…...
Python项目开发实战:微信跳一跳辅助工具,案例教程编程实例课程详解
一、项目背景与意义 微信跳一跳是微信推出的一款小游戏,玩家需要控制一个小人从一个平台跳到另一个平台上,每成功跳过一个平台,分数就会增加。然而,随着游戏难度的增加,玩家需要更精准的控制和更快的反应速度,这往往让许多玩家感到力不从心。因此,开发一款微信跳一跳的辅…...

STM32 SWD烧写
最小电路 stm32f103x 内部已经集成了振荡电路,可以省略;rst引脚电路,可以省略,boot0,boot1不需要设置 正常烧录 -------------------------------------------------------------------STM32CubeProgrammer v2.9.0 …...

数据库系统概论(第5版教材)
第一章 绪论 1、数据(Data)是描述事物的符号记录; 2、数据库系统的构成:数据库 、数据库管理系统(及其开发工具) 、应用程序和数据库管理员; 3、数据库是长期存储在计算机内、有组织、可共享的大量数据的集合&…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...

【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
Spring Security 认证流程——补充
一、认证流程概述 Spring Security 的认证流程基于 过滤器链(Filter Chain),核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤: 用户提交登录请求拦…...
【FTP】ftp文件传输会丢包吗?批量几百个文件传输,有一些文件没有传输完整,如何解决?
FTP(File Transfer Protocol)本身是一个基于 TCP 的协议,理论上不会丢包。但 FTP 文件传输过程中仍可能出现文件不完整、丢失或损坏的情况,主要原因包括: ✅ 一、FTP传输可能“丢包”或文件不完整的原因 原因描述网络…...

C++--string的模拟实现
一,引言 string的模拟实现是只对string对象中给的主要功能经行模拟实现,其目的是加强对string的底层了解,以便于在以后的学习或者工作中更加熟练的使用string。本文中的代码仅供参考并不唯一。 二,默认成员函数 string主要有三个成员变量,…...

CMS内容管理系统的设计与实现:多站点模式的实现
在一套内容管理系统中,其实有很多站点,比如企业门户网站,产品手册,知识帮助手册等,因此会需要多个站点,甚至PC、mobile、ipad各有一个站点。 每个站点关联的有站点所在目录及所属的域名。 一、站点表设计…...