本文示例用隨機幾何體、光照、紋理貼圖、着色器整合起來繪製一個水晶簇。經過調整着色器,能夠產生岩漿、藍寶石等各類效果。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