MOODUL 10b · TASE 4 — EDASIJÕUDNUD+

✨ Shaderid ja Visuaalsed Efektid

GLSL vertex/fragment shaderid, post-processing, bloom, cel-shading — kontrolli iga pikslit ekraanil!

⏱️ ~5-7 tundi 📝 5 harjutust 🔴 Edasijõudnud+

🎨 Samm 1 — GLSL Põhialused

Shaderid on programmid mis jooksevad GPU-l. Vertex shader liigutab punkte, fragment shader värvib piksleid.

vertex.glsl
// Vertex Shader — iga tipu jaoks
uniform float uTime;

varying vec2 vUv;       // Edasta fragment shaderile
varying vec3 vNormal;
varying vec3 vPosition;

void main() {
  vUv = uv;
  vNormal = normal;
  vPosition = position;

  // Laineline deformatsioon
  vec3 pos = position;
  pos.y += sin(pos.x * 3.0 + uTime * 2.0) * 0.3;
  pos.y += cos(pos.z * 2.0 + uTime * 1.5) * 0.2;

  gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}
fragment.glsl
// Fragment Shader — iga piksli jaoks
uniform float uTime;
uniform vec3 uColor;
uniform sampler2D uTexture;

varying vec2 vUv;
varying vec3 vNormal;
varying vec3 vPosition;

void main() {
  // Lihtne valgustusmudel
  vec3 lightDir = normalize(vec3(1.0, 1.0, 1.0));
  float diff = max(dot(vNormal, lightDir), 0.0);

  // Aeg-põhine värvivahetus
  vec3 color = uColor;
  color.r += sin(uTime) * 0.2;
  color.g += cos(uTime * 0.7) * 0.2;

  // Lõplik piksel
  gl_FragColor = vec4(color * (diff * 0.8 + 0.2), 1.0);
}

🔧 Samm 2 — ShaderMaterial Three.js-s

customShader.ts
import * as THREE from 'three';

const customMaterial = new THREE.ShaderMaterial({
  uniforms: {
    uTime: { value: 0 },
    uColor: { value: new THREE.Color(0.13, 0.77, 0.36) },
    uResolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) },
  },
  vertexShader: `
    uniform float uTime;
    varying vec2 vUv;
    varying vec3 vNormal;

    void main() {
      vUv = uv;
      vNormal = normal;

      vec3 pos = position;
      pos += normal * sin(pos.y * 5.0 + uTime * 3.0) * 0.1;

      gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
    }
  `,
  fragmentShader: `
    uniform float uTime;
    uniform vec3 uColor;
    varying vec2 vUv;
    varying vec3 vNormal;

    void main() {
      // Fresnel efekt (ääre helendus)
      vec3 viewDir = normalize(cameraPosition - vNormal);
      float fresnel = pow(1.0 - max(dot(vNormal, viewDir), 0.0), 3.0);

      vec3 color = uColor + fresnel * vec3(0.3, 0.6, 1.0);

      // Pulseeriv alpha
      float alpha = 0.8 + sin(uTime * 2.0) * 0.2;

      gl_FragColor = vec4(color, alpha);
    }
  `,
  transparent: true,
  side: THREE.DoubleSide,
});

// Mängutsüklis:
// customMaterial.uniforms.uTime.value = clock.getElapsedTime();

🌟 Samm 3 — Post-Processing

postprocessing.ts
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer';
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass';
import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass';
import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass';

// Composer
const composer = new EffectComposer(renderer);

// 1. Render pass — põhi renderdamine
composer.addPass(new RenderPass(scene, camera));

// 2. Bloom — helendusefekt
const bloomPass = new UnrealBloomPass(
  new THREE.Vector2(window.innerWidth, window.innerHeight),
  0.8,   // strength
  0.3,   // radius
  0.85   // threshold
);
composer.addPass(bloomPass);

// 3. Custom post-processing shader (vignette)
const vignetteShader = {
  uniforms: {
    tDiffuse: { value: null },
    uIntensity: { value: 0.4 },
  },
  vertexShader: `
    varying vec2 vUv;
    void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  fragmentShader: `
    uniform sampler2D tDiffuse;
    uniform float uIntensity;
    varying vec2 vUv;
    void main() {
      vec4 color = texture2D(tDiffuse, vUv);
      float dist = distance(vUv, vec2(0.5));
      color.rgb *= 1.0 - dist * uIntensity;
      gl_FragColor = color;
    }
  `,
};
composer.addPass(new ShaderPass(vignetteShader));

// Mängutsüklis kasuta composer.render() mitte renderer.render()
function animate() {
  requestAnimationFrame(animate);
  composer.render();
}

🖌️ Samm 4 — Populaarsed Shader Efektid

Cel-shading (Toon)
// Fragment shader — cel-shading
fragmentShader: `
  varying vec3 vNormal;
  uniform vec3 uColor;
  uniform vec3 uLightDir;

  void main() {
    float intensity = dot(normalize(vNormal), normalize(uLightDir));

    // Kvantiseeri valgus 4 tasemele
    vec3 color;
    if (intensity > 0.95)      color = uColor * 1.0;
    else if (intensity > 0.5)  color = uColor * 0.7;
    else if (intensity > 0.25) color = uColor * 0.4;
    else                       color = uColor * 0.2;

    gl_FragColor = vec4(color, 1.0);
  }
`,

// Piirjoonte shader (outline)
// Teine pass — suurenda objekti normaalide suunas ja joonista mustana
outlineVertexShader: `
  void main() {
    vec3 pos = position + normal * 0.05;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
  }
`,
outlineFragmentShader: `
  void main() {
    gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
  }
`

📝 Harjutused

  • Esimene custom shader

    Loo ShaderMaterial: vertex shader liigutab tippe sinusoidaalselt, fragment shader värvib UV-koordinaatide järgi. Lisa uTime uniform animatsiooniks.

  • Fresnel ja hologramm efekt

    Loo hologrammiline materjal: läbipaistev keskelt, helendav äärtest (Fresnel). Lisa skaneerimisjoone efekt mis liigub üles-alla. Sinine toon.

  • Post-processing pipeline

    Seadista EffectComposer: Bloom (helendavad objektid), vignette (pimenev ääris), chromatic aberration (värvi nihe). GUI kontrollid igale efektile.

  • Cel-shading / toon shader

    Loo cel-shading materjal: kvantiseeritud valgustus (3-4 astet), must piirjoon (outline pass). Rakenda 3D tegelasele. Anime/joonistusfilmi stiil.

  • Shader galerii

    Loo veebileht 6+ erineva shader efektiga: vesi, tuli, portaal, dissolve, force field, glitch. Iga efekt oma sfääri/kuubiku peal. Lisa GUI kontrollid.

← Moodul 10 Moodul 11: 3D Mängumootor →