如何使用WebGL渲染一簇水晶

本文介绍如何使用随机几何体、光照、纹理贴图和着色器整合绘制水晶簇,包括单晶生成、簇合、光照应用及祖母绿效果实现。

水晶体效果

本文示例用随机几何体、光照、纹理贴图、着色器整合起来绘制一个水晶簇。通过调整着色器,可以产生岩浆、蓝宝石等各种效果。

示例效果图:

27个单晶45度随机分布的蓝色水晶簇。

uv

77个单晶180度随机分布的红色水晶簇。

uv

制作随机水晶体生成器

很多三维库的几何体基本都是规则几何体,没有随机的美感,因此捣鼓了一个随机水晶生成器,源码地址:github.com/guoweish/ve…

实现思路如下:

  • 生成单个水晶顶点

uv

  • 生成水晶簇顶点

uv

实现步骤如下:

  • 一个圆周上取多边形点,使用随机角度,形成不同宽度面
  ...
  angle = i / faceNumber * PI * 2 + r * angleDithringFactor * angleDithringUnit;
  px = Math.sin(angle) * polygonCircleRadius;
  py = Math.cos(angle) * polygonCircleRadius;
  ...
复制代码
  • 随机缩放圆半径,圆周上同角度取多边形点,形成不同柱体半径
  ...
  pxd = Math.sin(angle) * polygonCircleRadius* (circleRadiusDithringFactor + radiusDithringDistance);
  pyd = Math.cos(angle) * polygonCircleRadius* (circleRadiusDithringFactor + radiusDithringDistance);
  ...
复制代码
  • 形成多边形棱柱的上下两层顶点
  ...
  vertexs.topPositions.push(px);
  vertexs.topPositions.push(py);
  ...
复制代码
  • 增加正对圆心的顶点,形成水晶柱顶点
  ...
  vertexsCon = [0, cylinderHeight+conHeight, 0];
  ...
复制代码
  • 生成一个水晶体几何体
  ...
  vertexs = [...vertexsCylinderDown, ...vertexsCylinderTop, ...vertexsCon];
  ...
复制代码
  • 矩阵变换缩放、旋转单个水晶体的顶点,并复制顶点
  ...
  let scaleMatrix = new Matrix4();
  scaleMatrix.setScale(scaleFactor, scaleFactor, scaleFactor);
  let rotateMatrix = new Matrix4();
  rotateMatrix.setRotate(rotateAngle, rotateCenter.x, rotateCenter.y, rotateCenter.z);
  ...
  let vScaledRotated = rotateMatrix.multiplyVector4(vScaled);
  ...
复制代码
  • 生成水晶簇几何体
  ...
  let extendedIndices = extendIndices(cristalTransformed.indices, currentIndicesLength);
  cluster.indices = cluster.indices.concat(extendedIndices);
  cluster.positions = cluster.positions.concat(cristalTransformed.positions);
  cluster.uvs = cluster.uvs.concat(cristal.uvs);
  ...
复制代码

渲染几何体

用纯色shader简单渲染一下是否顶点和索引正确;

  • 片元着色器
  fragColor = vec4(0.6, 0.6, 0.6, 1.0);
复制代码

uv

添加光照

增加光照,使用Blinn-Phong模型;

  • 片元着色器
  vec3 diffuse = max(dot(normal, ec_lightDirection), 0.0) * lightColor * lightIntensity * baseColor;

  vec3 viewDirection = -normalize(ec_position);
  vec3 halfAngle = normalize(viewDirection + ec_lightDirection);
  float specularFactor = clamp(dot(normal, halfAngle), 0.0, 1.0);
  float spec = pow(specularFactor, specularIntensity);
  vec3 specular = clamp(spec * specularColor, 0.0, 1.0);

  fragColor = vec4(diffuse + specular + ambient, 1.0);
复制代码

着色器添加渐变的祖母绿效果

为了看上去像祖母绿宝石效果,用纹理做一个渐变;用pow函数使得渐变非线性,用mix函数融合得颜色,看上去效果更自然;

  • 片元着色器
  ...
  float colorMixFactor = pow(v_uv.y, 3.0);
  ...
  vec3 baseColor = mix(CRISTAL_COLOR, GEM_COLOR_GREEN,  colorMixFactor);
  ...
复制代码

uv

使用贴图增强表面细节

为了表面有石头纹样效果,找一张大理石图片做贴图过滤一下颜色;魔改一下光照模型,贴图过滤diffuse而不过滤specular,这样使得表面反色不受影响而产生表面光滑的效果;

  • 片元着色器
  ...
  fragColor = vec4(diffuse + diffuse * textureFilter + specular + AMB_COLOR, 1.0);
复制代码

uv

结语

可以使用perlin噪音和fbm让随机几何体的视觉效果自然,比如大小个体比例和空间位置的分布;光照可以改用pbr模型,比Blinn-Phong会更好,计划下一篇更新尝试(希望有空填坑-_-!!)。

关于作者

郭不耐 github.com/guoweish

参考文献

Webgl Programing Guide

OpenGl Shading Language

The Book of Shaders

ShaderToy

转载于:https://juejin.im/post/5c7290b36fb9a049b07dfb98

<think>好的,用户想要获取MATLAB实现水晶爱心的完整代码。首先,我需要回顾之前的对话历史。用户之前提到了水晶爱心形状异常的问题,并给出了修正后的代码片段,但用户现在需要完整的代码。同时,用户引用了站内的一篇关于MATLAB绘制水晶簇和水晶爱心的文章,其中提到坐标变换和晶体结构的内容。 用户当前的需求是获取完整的MATLAB代码来生成水晶爱心。需要确保代码结构完整,包含所有必要的参数设置、坐标变换、渲染效果以及可能的注释。需要参考之前提供的修正方案,尤其是关键参数部分,如半径函数、波纹变形、Z轴比例和噪声调整。此外,用户可能希望代码能够生成美观的水晶效果,因此需要考虑颜色映射、光照设置和透明度调整等可视化部分。 接下来需要检查之前的回答中是否有遗漏的部分。在之前的回答中,提供了修正后的函数代码片段,但可能没有包含完整的绘图和渲染部分。需要整合这些部分,形成一个完整的可运行脚本或函数。同时,确保使用正确的LaTeX格式,符合用户规定的系统级指令,比如行内公式用$...$,独立公式用$$...$$,并且生成相关问题。 还需要考虑用户可能的潜在需求,比如代码的可调参数,如何修改颜色或晶体密度,以及如何优化渲染性能。因此,在完整代码中,可以添加注释说明哪些参数可以调整,以及调整的效果。此外,可能需要解释代码的关键部分,比如坐标变换和晶体生成逻辑,帮助用户理解代码结构。 最后,生成的相关问题需要与MATLAB绘图、参数优化、三维渲染等相关,确保问题对用户进一步学习有帮助。需要确保回答结构清晰,分步骤解释代码,并标注关键部分,如参数说明和效果调整。</think>根据晶体生长原理和心形参数方程,以下是完整MATLAB水晶爱心代码实现(包含关键注释和参数说明): ```matlab function crystalHeart % 水晶爱心生成主函数 % 作者:深度学习推进材料科学创新[^1] %% 基础参数设置 [t,phi] = meshgrid(linspace(0,2*pi,250), linspace(-pi/2,pi/2,100)); % 参数网格 R = (1 - sin(t)) .* (1.4 - 0.4*cos(5*t)); % 心形半径调制函数 ⭐ %% 三维坐标变换 X = R .* cos(t) .* cos(phi); Y = R .* sin(t) .* cos(phi) + 0.12*cos(4*t); % 添加波纹变形 Z = 0.85 * R .* sin(phi); % 垂直方向压缩 %% 晶体表面处理 noise = 0.03*randn(size(R)); % 生成晶面缺陷 crystal = surf(X.*(1+noise), Y.*(1+noise), Z.*(1+noise)); %% 高级渲染设置 colormap(hot) % 使用热色系模拟晶体光泽 shading interp % 颜色插值 material metal % 金属材质反射 light('Position',[1 1 1],'Style','infinite') % 添加定向光源 alpha(0.8) % 设置透明度 axis equal off % 等比例坐标系 view(-30,25) % 最佳观察视角 rotate3d on % 开启三维旋转 %% 辅助晶簇生成(可选) hold on for k = 1:20 % 生成随机小晶体 scatter3(0.2*randn+X(randi(100)), 0.2*randn+Y(randi(100)),... 0.1*randn+Z(randi(100)), 10, 'cyan','filled') end end ``` ### 代码关键参数说明(⭐表示建议调整项) | 参数 | 作用域 | 推荐范围 | 数学表达式 | |------|--------|----------|------------| | 5*t项系数 | 半径调制 | 4-6 | $R=(1-\sin t)(a-b\cos nt)$ | | 波纹系数0.12 | Y轴变形 | 0.1-0.15 | $Y = R\sin t\cos\phi + \varepsilon\cos(4t)$ | | Z轴系数0.85 | 垂直压缩 | 0.8-1.0 | $Z = kR\sin\phi$ | | 噪声幅度0.03 | 表面粗糙度 | 0.02-0.05 | $\delta = \alpha\cdot\mathcal{N}(0,1)$ | ### 运行效果增强技巧 1. **动态调参**:使用`uicontrol`创建滑块实时调整波纹系数 ```matlab uicontrol('Style','slider','Min',0,'Max',0.3,'Position',[20 20 120 20],... 'Callback',@(src,~)set(crystal,'YData',Y*(1+src.Value))); ``` 2. **晶体优化**:将`randn`替换为`perlin2d(size(R))`生成更自然的噪声[^1] 3. **多色渲染**:修改`colormap(jet)`可获得彩虹色晶体效果
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值