Skip to content

着色器

本指南将帮助你开始在 TresJS 中使用着色器。

我们将构建一个带有 blob 的简单场景。然后,我们将对 blob 进行动画处理,使其柔和地扭曲。

WARNING

需要了解着色器工作原理的基本知识

设置场景(可选)

我们导入所需的所有模块,为了方便,我们可以使用 cientos 中的轨道控件,点击此处查看方法

现在,我们将相机放在 [11,11,11] 位置。

最后,为了帮助我们确定位置,我们添加一个简单的平面,绕 X 轴旋转,单位为 [10, 10]

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

如你所知,ThreeJs 中的每个实例都可以在 TresJs 中使用,ShaderMaterial 也是如此,我们只需要添加 Tres 前缀即可使用它。

对于我们的 blob ,我们可以使用简单的 SphereGeometry,添加一些 widthSegmentsheightSegments 来创建平滑效果,并将 blob 放在 Y 轴正方向的 4 个单位处

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

ShaderMaterial 接受特殊属性,如 uniforms vertexShaderfragmentShader,因此我们可以在脚本部分创建它,并与我们的实例进行绑定。

对于此示例,我们的 uniforms 如下所示:

ts
import { Vector2 } from 'three'

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

我们的片段着色器如下所示:

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

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

最后是我们的顶点着色器:

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;
}
`
// ..

为 blob 添加动画

类似于我们在 基本动画 示例中学习到的,我们首先使用 模板引用 引用 blob

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 />
    </TresMesh>
  </TresCanvas>
</template>

获得引用后,我们可以使用 onLoop 回调为 uTime 添加动画。

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

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

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

就这样,我们的基本着色器顺利运行。

使用 GLSL vite 插件(可选)

此步骤完全是可选的,并且超出了 TresJs 团队的范围

将着色器定义为内联形式并不总是最好的主意,但是如果你正在使用 vite,你可以通过使用 vite-plugin-glsl 将你的 GLSL 文件放在另一个文件中(查看链接以获取官方文档)。

你可以拥有类似于这样的结构:

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