ThreeJS Shader的效果样例网格平面和网格球体(一)
本文中效果主要采用ThreeJS 中的着色器(Shader)以及结合ShaderMaterial实现的。
主要用到的内置方法有:
一、网格平面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | const vertex = '\ varying vec3 vPos;\ void main() {\ vPos = position;\ gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4( position, 1.0 ); \ }\ ' ; const frag = '\ varying vec3 vPos;\ void main() {\ vec3 mask1 = vec3(step(0.5, fract(vPos.x * 2.0)));\ vec3 mask2 = vec3(step(0.5, fract(vPos.y * 2.0)));\ vec3 mask3 = vec3(step(0.5, fract(vPos.z * 2.0)));\ vec3 color = abs(mask1 - mask2);\ gl_FragColor = vec4(color, 1.0);\ }\ ' ; |
原理:如果设置平面的大小为2,那么坐标轴X点的范围为-1.0 ~ 1.0,已X坐标为示例,数据变化形式如下图
如上图可以将数据分为4个部分,X轴和Y轴同理:
1) 0~0.25的数据经过fract和step函数处理后数据变为0;
2) 0.25~0.5的数据经过fract和step函数处理后数据变为1;
3) 0.5~0.75的数据经过处理变为0;
4) 0.75~1.0的数据经过处理变为1;
最后将生成的向量X轴-Y轴数据可以绘制成如下图:
这样就生成了第一象限的图形,第二、三、四象限结果同上。
二、网格状的球体
本列中涉及到GLSL的几个内置函数:
dot:两个向量的点积,可以获得向量的夹角
asin: 反三角函数,获得弧度值
1. 第一个图就是要实现的最终效果,一个网格状的球体,实现原理主要可以分为分别计算经度方向的线圈和纬度方向的线圈。
2. 与平面网格计算颜色值相同,将两个颜色值相减即可得到一个网格球体
3. 如何实现纬度方向的线圈?
实现逻辑:将球体沿球心纵向切一刀生成一个圆形横截面M,将圆分成弧度相等的N个圆弧,然后再间隔开赋予不同的颜色就可以形成图一的效果。
const vertex = '\ varying vec3 vPos;\ void main() {\ vPos = position;\ gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4( position, 1.0 ); \ }\ '; // 获取UV点对应的单位向量B // 获取Z轴方向的单位向量A // 计算向量B和向量A的夹角 // 通过degree将夹角的弧度转换成角度,除以要拆分的条数latBeta,通过配合fract和step即可获取间隔的0、1值 // 最后生成间隔的黑白颜色值 const frag = '\ uniform float latBeta;\ varying vec3 vPos;\ void main() {\ vec3 latEveryVec = normalize(vPos);\ vec3 latBaseVec = normalize(vec3(vPos.x, 0, vPos.z));\ float latAngle = asin(dot(latBaseVec, latEveryVec));\ vec3 latColor = vec3(step(0.5, fract(degrees(latAngle) / latBeta)));\ gl_FragColor = vec4(latColor, 1.0);\ }\ ';
4. 如何实现经度方向的线圈?
实现逻辑:与第三步生成纬度方向的线圈类似,将球体沿球心横向切一刀生成一个圆形横截面M,将圆分成弧度相等的N个圆弧,然后再间隔开赋予不同的颜色就可以形成图一的效果。
const vertex = '\ varying vec3 vPos;\ void main() {\ vPos = position;\ gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4( position, 1.0 ); \ }\ '; // 获取UV点对应的单位向量B // 获取X轴正方向的单位向量A // 计算向量B和向量A的夹角 // 通过degree将夹角的弧度转换成角度,除以要拆分的条数lonBeta,通过配合fract和step即可获取间隔的0、1值 // 最后生成间隔的黑白颜色值 const frag = '\ uniform float lonBeta;\ varying vec3 vPos;\ void main() {\ vec3 lonEveryVec = normalize(vec3(vPos.x, 0.0, vPos.z));\ vec3 lonBaseVec = vec3(0.0, 0.0, 1.0);\ float lonAngle = asin(dot(lonBaseVec, lonEveryVec));\ vec3 lonColor = vec3(step(0.5, fract(degrees(lonAngle) / lonBeta)));\ gl_FragColor = vec4(lonColor, 1.0);\ }\ ';
完整代码如下:
const vertex = '\ varying vec3 vPos;\ void main() {\ vPos = position;\ gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4( position, 1.0 ); \ }\ '; const frag = '\ uniform float latBeta;\ uniform float lonBeta;\ varying vec3 vPos;\ void main() {\ vec3 latEveryVec = normalize(vPos);\ vec3 latBaseVec = normalize(vec3(vPos.x, 0, vPos.z));\ float latAngle = asin(dot(latBaseVec, latEveryVec));\ vec3 latColor = vec3(step(0.5, fract(degrees(latAngle) / latBeta)));\ \ vec3 lonEveryVec = normalize(vec3(vPos.x, 0.0, vPos.z));\ vec3 lonBaseVec = vec3(0.0, 0.0, 1.0);\ float lonAngle = asin(dot(lonBaseVec, lonEveryVec));\ vec3 lonColor = vec3(step(0.5, fract(degrees(lonAngle) / lonBeta)));\ vec3 color = abs(latColor - lonColor);\ gl_FragColor = vec4(color, 1.0);\ }\ ';
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器