Skip to content

UseOGL

功能描述

UseOGL 是一个用于 OGL 3D 渲染的 Vue 组合式函数,支持自定义渲染器配置、相机设置和事件监听,可用于创建交互式 3D 图形应用。

安装

bash
# 使用 pnpm
pnpm add @oiij/ogl

# 使用 npm
npm install @oiij/ogl

# 使用 yarn
yarn add @oiij/ogl

依赖

  • vue: ^3.0.0
  • @vueuse/core: ^10.0.0
  • ogl: ^1.0.0

基本使用

loading

API

useOGL(templateRef, options?)

使用 OGL 创建 WebGL 渲染实例。

参数

参数类型说明
templateRefTemplateRef<HTMLElement>OGL 容器的模板引用
optionsOGLOptionsOGL 配置选项

OGLOptions

选项类型默认值说明
rendererOptionsRendererOptions-渲染器选项
cameraOptionsCameraOptions-相机选项
cameraOptions.position[number, number, number][0, 0, 5]相机位置
manualbooleanfalse是否手动控制渲染循环
disableRenderbooleanfalse是否禁用自动渲染

返回值

属性类型说明
templateRefTemplateRef<HTMLElement>容器引用
rendererRendererOGL 渲染器实例
glWebGL2RenderingContextWebGL 上下文
cameraCameraOGL 相机实例
sceneTransformOGL 场景根节点
onRendered(callback)Function渲染完成事件
onResize(callback)Function尺寸变化事件
onDisposed(callback)Function销毁事件
onLoop(callback)Function渲染循环事件
resume()Function恢复渲染循环
pause()Function暂停渲染循环
dispose()Function销毁实例
isActiveRef<boolean>渲染循环是否激活

类型定义

ts
import type { CameraOptions, RendererOptions } from 'ogl'
import type { TemplateRef } from 'vue'

export type OGLOptions = {
  /**
   * 渲染器选项
   */
  rendererOptions?: RendererOptions
  /**
   * 相机选项
   */
  cameraOptions?: CameraOptions & {
    /**
     * 相机位置
     * @default [0, 0, 5]
     */
    position?: [number, number, number]
  }
  /**
   * 是否手动控制
   * @default false
   */
  manual?: boolean
  /**
   * 是否禁用渲染
   * @default false
   */
  disableRender?: boolean
}

export type ResizeArguments = {
  /**
   * 宽度
   */
  width: number
  /**
   * 高度
   */
  height: number
  /**
   * 宽高比
   */
  aspect: number
  /**
   * 设备像素比
   */
  dpr: number
}

export type UseOGLReturns = {
  templateRef: TemplateRef<HTMLElement>
  renderer: Renderer
  gl: WebGL2RenderingContext
  camera: Camera
  scene: Transform
  onRendered: (callback: (renderer: Renderer) => void) => void
  onResize: (callback: (args: ResizeArguments) => void) => void
  onDisposed: (callback: () => void) => void
  onLoop: (callback: (renderer: Renderer, args: UseRafFnCallbackArguments) => void) => void
  resume: () => void
  pause: () => void
  dispose: () => void
  isActive: Ref<boolean>
}

export declare function useOGL(templateRef: TemplateRef<HTMLElement>, options?: OGLOptions): UseOGLReturns

使用示例

基础用法

vue
<script setup>
import { useOGL } from '@oiij/ogl'
import { useTemplateRef } from 'vue'

const { scene, gl, onLoop } = useOGL(useTemplateRef('canvas'))

onLoop(({ renderer }) => {
  // 在这里添加渲染逻辑
})
</script>

<template>
  <div ref="canvas" style="width: 100%; height: 400px;" />
</template>

自定义着色器

vue
<script setup>
import { useOGL } from '@oiij/ogl'
import { Geometry, Mesh, Program } from 'ogl'
import { useTemplateRef } from 'vue'

const { gl, onLoop } = useOGL(useTemplateRef('canvas'), {
  disableRender: true
})

const geometry = new Geometry(gl, {
  position: { size: 2, data: new Float32Array([-1, -1, 3, -1, -1, 3]) },
  uv: { size: 2, data: new Float32Array([0, 0, 2, 0, 0, 2]) },
})

const program = new Program(gl, {
  vertex: `
    attribute vec2 uv;
    attribute vec2 position;
    varying vec2 vUv;
    void main() {
      vUv = uv;
      gl_Position = vec4(position, 0, 1);
    }
  `,
  fragment: `
    precision highp float;
    uniform float uTime;
    varying vec2 vUv;
    void main() {
      gl_FragColor.rgb = vec3(0.8, 0.7, 1.0) + 0.3 * cos(vUv.xyx + uTime);
      gl_FragColor.a = 1.0;
    }
  `,
  uniforms: {
    uTime: { value: 0 },
  },
})

const mesh = new Mesh(gl, { geometry, program })

onLoop((renderer, { timestamp }) => {
  program.uniforms.uTime.value = timestamp * 0.001
  renderer.render({ scene: mesh })
})
</script>

<template>
  <div ref="canvas" style="width: 100%; height: 400px;" />
</template>

自定义相机位置

vue
<script setup>
import { useOGL } from '@oiij/ogl'
import { useTemplateRef } from 'vue'

const { camera, scene, onLoop } = useOGL(useTemplateRef('canvas'), {
  cameraOptions: {
    position: [0, 0, 10],
    fov: 45
  }
})

onLoop(({ renderer }) => {
  // 渲染逻辑
})
</script>

<template>
  <div ref="canvas" style="width: 100%; height: 400px;" />
</template>

手动控制渲染

vue
<script setup>
import { useOGL } from '@oiij/ogl'
import { useTemplateRef } from 'vue'

const { resume, pause, isActive, dispose } = useOGL(useTemplateRef('canvas'), {
  manual: true
})
</script>

<template>
  <div ref="canvas" style="width: 100%; height: 400px;" />
  <button @click="resume">
    开始渲染
  </button>
  <button @click="pause">
    暂停渲染
  </button>
  <button @click="dispose">
    销毁
  </button>
  <p>渲染状态: {{ isActive ? '运行中' : '已暂停' }}</p>
</template>

监听事件

vue
<script setup>
import { useOGL } from '@oiij/ogl'
import { useTemplateRef } from 'vue'

const { onRendered, onResize, onDisposed } = useOGL(useTemplateRef('canvas'))

onRendered((renderer) => {
  console.log('渲染器已创建', renderer)
})

onResize(({ width, height, aspect }) => {
  console.log(`尺寸变化: ${width}x${height}, 宽高比: ${aspect}`)
})

onDisposed(() => {
  console.log('渲染器已销毁')
})
</script>

<template>
  <div ref="canvas" style="width: 100%; height: 400px;" />
</template>