本文示例用随机几何体、光照、纹理贴图、着色器整合起来绘制一个水晶簇。经过调整着色器,能够产生岩浆、蓝宝石等各类效果。git
示例效果图:github
不少三维库的几何体基本都是规则几何体,没有随机的美感,所以捣鼓了一个随机水晶生成器,源码地址:github.com/guoweish/ve…web
实现思路以下:canvas
实现步骤以下:bash
...
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简单渲染一下是否顶点和索引正确;ide
fragColor = vec4(0.6, 0.6, 0.6, 1.0);
复制代码
增长光照,使用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函数融合得颜色,看上去效果更天然;webgl
...
float colorMixFactor = pow(v_uv.y, 3.0);
...
vec3 baseColor = mix(CRISTAL_COLOR, GEM_COLOR_GREEN, colorMixFactor);
...
复制代码
为了表面有石头纹样效果,找一张大理石图片作贴图过滤一下颜色;魔改一下光照模型,贴图过滤diffuse而不过滤specular,这样使得表面反色不受影响而产生表面光滑的效果;ui
...
fragColor = vec4(diffuse + diffuse * textureFilter + specular + AMB_COLOR, 1.0);
复制代码
能够使用perlin噪音和fbm让随机几何体的视觉效果天然,好比大小个体比例和空间位置的分布;光照能够改用pbr模型,比Blinn-Phong会更好,计划下一篇更新尝试(但愿有空填坑-_-!!)。spa