110. まとめ & 完成したコード

チュートリアルの振り返りと、すべてのエフェクトを組み合わせた最終的なスケッチを確認します。

p5.js 2.0 WebGL p5.strands Shader GLSL
Learning Tutorial

振り返り

このチュートリアルでは 4 つのシェーダーを書き、p5.strands で頂点シェーダーとフラグメントシェーダーを操作する方法を学びました。

  • 基本的なカラーシェーダー (Basic Color Shader): 最終的な色を修正し、フラグメントシェーダーでの色の扱いを学びました。
  • インスタンス化されたパーティクル (Instanced Particles): GPU インスタンス化を試み、数百のパーティクルをレンダリングしました。頂点シェーダーでワールド空間内のオブジェクトを移動させました。
  • フレネルによる縁の強調 (Fresnel Edge Highlighting): カメラ空間を使用して、3D オブジェクトの見え方に応じた高度なエフェクトを作成しました。
  • ポストプロセッシング (Post-processing): フィルターシェーダーを使用して、ピクセル化とブルーム効果を加え、シーン全体を統合しました。

完成したコード

右のスケッチは、これらすべての要素を組み合わせた完成版です。

let instancedShader;
let instancedStrokeShader;
let stars;
let originalImage;
let pixelateShader;
let fresnelShader;
let bloomShader;

function fresnelShaderCallback() {
  const fresnelPower = uniformFloat(2);
  const fresnelBias = uniformFloat(-0.1);
  const fresnelScale = uniformFloat(2);

  getCameraInputs((inputs) => {
    let n = normalize(inputs.normal);
    let v = normalize(-inputs.position);
    let base = 1.0 - dot(n, v);
    let fresnel = fresnelScale * pow(base, fresnelPower) + fresnelBias;
    let col = mix([0, 0, 0], [1, 0.5, 0.7], fresnel);
    inputs.color = [col, 1];
    return inputs;
  });
}

function starShaderCallback() {
  const time = uniformFloat(() => millis());
  const skyRadius = uniformFloat(250);

  function rand2(st) {
    return fract(sin(dot(st, [12.9898, 78.233])) * 43758.5453123);
  }

  function semiSphere() {
    let id = instanceID();
    let theta = rand2([id, 0.1234]) * TWO_PI + time / 100000;
    let phi = rand2([id, 3.321]) * PI + time / 50000;

    let r = skyRadius;
    r *= sin(phi);
    let x = r * sin(phi) * cos(theta);
    let y = r * 1.5 * cos(phi);
    let z = r * sin(phi) * sin(theta);
    return [x, y, z];
  }

  getWorldInputs((inputs) => {
    inputs.position += semiSphere();
    return inputs;
  });

  getObjectInputs((inputs) => {
    let size = 1 + 0.5 * sin(time * 0.002 + instanceID());
    inputs.position *= size;
    return inputs;
  });
}

function pixelateShaderCallback() {
  const pixelCountX = uniformFloat(() => 280);

  getColor((inputs, canvasContent) => {
    const aspectRatio = inputs.canvasSize.x / inputs.canvasSize.y;
    const pixelSize = [pixelCountX, pixelCountX / aspectRatio];

    let coord = inputs.texCoord;
    coord = floor(coord * pixelSize) / pixelSize;

    let col = getTexture(canvasContent, coord);
    return col;
  });
}

function bloomShaderCallback() {
  const preBlur = uniformTexture(() => originalImage);

  getColor((input, canvasContent) => {
    const blurredCol = getTexture(canvasContent, input.texCoord);
    const originalCol = getTexture(preBlur, input.texCoord);

    const intensity = max(originalCol, 0.1) * 12.2;

    const bloom = originalCol + blurredCol * intensity;
    return [bloom.rgb, 1];
  });
}

async function setup() {
  createCanvas(800, 600, WEBGL);
  pixelDensity(1);
  stars = buildGeometry(() => sphere(8, 4, 2));
  originalImage = createFramebuffer();

  starShader = baseMaterialShader().modify(starShaderCallback);
  starStrokeShader = baseStrokeShader().modify(starShaderCallback);
  fresnelShader = baseColorShader().modify(fresnelShaderCallback);
  bloomShader = baseFilterShader().modify(bloomShaderCallback);
  pixelateShader = baseFilterShader().modify(pixelateShaderCallback);
}

function draw() {
  originalImage.begin();
  background(0);
  orbitControl();

  push();
  strokeWeight(2);
  stroke(255, 0, 0);
  rotateX(PI / 2 + millis() * 0.0005);
  fill(255, 100, 150);
  strokeShader(starStrokeShader);
  shader(starShader);
  model(stars, 1000);
  pop();

  push();
  shader(fresnelShader);
  noStroke();
  sphere(90);
  filter(pixelateShader);
  pop();

  originalImage.end();

  imageMode(CENTER);
  image(originalImage, 0, 0);

  filter(BLUR, 15);
  filter(bloomShader);
}

次のステップは?

p5.strands は GLSL の多くの機能をサポートしているため、既存の多くの GLSL サンプルを p5.strands に移植することができます。ぜひ、今回の手法を応用して、独自のストランドを書いて実験を続けてください。

さらに学びたい場合は、以下のリソースが役立ちます:

License

Original URL: https://beta.p5js.org/tutorials/intro-to-p5-strands/

License: MIT License

Copyright (c) 2015-present p5.js contributors & The Processing Foundation