Skip to content

Shaders

Deze handleiding helpt u aan de slag te gaan met shaders in TresJS.

We zullen een eenvoudige scène bouwen met een blob. Vervolgens zullen we de blob animeren om deze zachtjes te vervormen.

WARNING

Basis kennis over hoe shaders werken is noodzakelijk

De scene opzetten (optoneel)

We importeren alle modules die we nodig hebben. Om het gemakkelijker te maken zullen we de orbit-controls van cientos importeren en gebruiken, kijk hier om te zien hoe.

Laten we nu onze camera in de [11,11,11] positie plaatsen.

Om ons ten slotte te helpen met de locatie, voegen we een eenvoudig vlak toe, geroteerd in de X-as, met [10, 10] eenheden.

vue
<script setup lang="ts">
import { TresCanvas } from '@tresjs/core'
import { OrbitControls } from '@tresjs/cientos'
</script>

<template>
  <TresCanvas
    clear-color="#111"
    window-size
  >
    <OrbitControls />
    <TresPerspectiveCamera :position="[11, 11, 11]" />

    <TresMesh :rotation="[-Math.PI / 2, 0, 0]">
      <TresPlaneGeometry :args="[10, 10]" />
      <TresMeshBasicMaterial color="#444" />
    </TresMesh>
  </TresCanvas>
</template>

ShaderMaterial

Zoals u weet is elke instantie in ThreeJs beschikbaar in TresJs, en dat geldt ook voor ShaderMaterial. We hoeven alleen maar het voorvoegsel Tres toe te voegen om het te gebruiken.

Voor onze blob kunnen we een eenvoudige SphereGeometry gebruiken, waarbij enkele breedte- en hoogtesegmenten worden toegevoegd om een vloeiend effect te creëren, en onze blob 4 eenheden in de positieve Y-as plaatsen

vue
<TresMesh :position="[0, 4, 0]">
  <TresSphereGeometry :args="[2, 32, 32]" />
  <TresShaderMaterial />
</TresMesh>

Het ShaderMaterial accepteert speciale eigenschappen, zoals uniforms vertexShader en fragmentShader, zodat we het in onze scriptsectie kunnen maken en de binding met onze instantie kunnen maken.

Voor dit voorbeeld zien onze uniformen er als volgt uit:

ts
import { Vector2 } from 'three'

// ...
const uniforms = {
  uTime: { value: 0 },
  uAmplitude: { value: new Vector2(0.1, 0.1) },
  uFrequency: { value: new Vector2(20, 5) },
}
// ..

Onze fragment shader ziet er als volgt uit:

ts
// ...
const fragmentShader = `
precision mediump float;
varying vec2 vUv;

void main() {
    gl_FragColor = vec4(1.0, vUv.y, 0.5, 1.0);
}
`
// ..

En tot slot onze vertexShader:

ts
const vertexShader = `
uniform vec2 uAmplitude;
uniform vec2 uFrequency;
uniform float uTime;

varying vec2 vUv;

void main() {
    vec4 modelPosition = modelMatrix * vec4(position, 1.0);
    modelPosition.y += sin(modelPosition.x * uFrequency.x - uTime) * uAmplitude.x;
    modelPosition.x += cos(modelPosition.y * uFrequency.y - uTime) * uAmplitude.y;

    vec4 viewPosition = viewMatrix * modelPosition;
    gl_Position = projectionMatrix * viewPosition;
    vUv = uv;
}
`
// ..

De blob animeren

Vergelijkbaar met wat we leren in het voorbeeld van Basic Animations, beginnen we met het verwijzen naar onze blob, met behulp van Template Ref

vue
<script setup lang="ts">
import { shallowRef } from 'vue'
import { TresCanvas } from '@tresjs/core'
import { OrbitControls } from '@tresjs/cientos'

const blobRef = shallowRef(null)
// ...
</script>

<template>
  <TresCanvas
    clear-color="#111"
    window-size
  >
    <OrbitControls />
    <TresPerspectiveCamera :position="[11, 11, 11]" />
    <TresMesh
      ref="blobRef"
      :position="[0, 4, 0]"
    >
      <TresSphereGeometry :args="[2, 32, 32]" />
      <TresShaderMaterial :vertex-shader="vertexShader" :fragment-shader="fragmentShader" :uniforms="uniforms" />
    </TresMesh>
  </TresCanvas>
</template>

Zodra we dat hebben, kunnen we de onLoop callback gebruiken om onze uTime te animeren.

ts
import { TresCanvas, useRenderLoop } from '@tresjs/core'

// ...
const { onLoop } = useRenderLoop()

onLoop(({ elapsed }) => {
  if (blobRef.value) {
    blobRef.value.material.uniforms.uTime.value = elapsed
  }
})
// ...

En dat is alles, onze basisshader werkt soepel. 🎉

Gebruik van GLSL vite-pluging (optioneel)

Deze stap is volledig optioneel en uit scope van het TresJs team

Het inline definiëren van onze shader is niet altijd het beste idee, maar als u vite gebruikt, kunt u uw GLSL-bestanden in een ander bestand plaatsen door gewoon de vite-plugin-glsl (bekijk de link voor de officiële documentatie).

En je zou een structuur kunnen hebben die er ongeveer zo uitziet:

├── src/
│   ├── myTresJsComponent.vue
│   ├── shaders/
│       ├── vertexShader.glsl
│       ├── fragmentShader.glsl