PixiJS

我睡着的时候不困唉大约 8 分钟2D图形WebGL API可视化2D渲染器

PixiJS

介绍

PixiJS 是一个非常快的2D sprite渲染引擎 项目地址open in new window

项目依赖

yarn add pixi-filters pixi.js

示例

绘制图形

<template>
  <div id="tag"></div>
</template>

<script>
import * as PIXI from 'pixi.js'
// /绘制图形
export default {
  name: 'Home',
  mounted() {
    let _this = this
    this.$nextTick(() => {
      _this.initPixi()
    })
  },
  methods: {
    initPixi() {
      const options = {
        width: window.innerWidth,
        height: window.innerHeight,
        backgroundColor: 0x1099bb,
        resolution: window.devicePixelRatio || 1,
        antialias: true
      }
      // 创建应用
      const app = new PIXI.Application(options)
      // 将应用画布添加到DOM中
      document.querySelector('#tag').appendChild(app.view)

      // 绘制矩形=============================
      const rectangle = new PIXI.Graphics()
      // 设置边框样式
      rectangle.lineStyle(4, 0xff0000, 1) // 线宽,颜色,透明度
      rectangle.beginFill(0xffffff, 1) // 填充颜色,透明度
      rectangle.drawRect(0, 0, 50, 50) // 绘制矩形
      rectangle.endFill() // 结束填充
      // 图形缩放
      rectangle.scale.set(2, 2)
      // 图形位移
      rectangle.position.set(100, 100)
      // 图形旋转
      rectangle.rotation = 0.8
      // 图形锚点
      rectangle.pivot.set(10, 12)
      // 将矩形添加到画布
      app.stage.addChild(rectangle)

      // 绘制圆形=============================
      const circle = new PIXI.Graphics()
      circle.beginFill(0x66ccff, 0.9)
      circle.drawCircle(0, 0, 32)
      circle.endFill() // 结束填充
      circle.position.set(300, 300)
      app.stage.addChild(circle)

      // 绘制圆角矩形=============================
      const roundedRectangle = new PIXI.Graphics()
      roundedRectangle.beginFill(0x66ccff, 0.9)
      // drawRoundedRect(x: number, y: number, width: number, height: number, radius: number)
      roundedRectangle.drawRoundedRect(0, 0, 164, 164, 10)
      roundedRectangle.endFill() // 结束填充
      roundedRectangle.position.set(600, 600)
      app.stage.addChild(roundedRectangle)

      // 绘制椭圆=============================
      const ellipse = new PIXI.Graphics()
      ellipse.beginFill(0x66ccff, 0.9)
      // drawEllipse(x: number, y: number, width: number, height: number)
      ellipse.drawEllipse(0, 0, 120, 164)
      ellipse.endFill() // 结束填充
      ellipse.position.set(500, 500)
      app.stage.addChild(ellipse)

      // 绘制多边形=============================
      const polygon = new PIXI.Graphics()
      polygon.beginFill(0x660000, 0.9)
      // 绘制多边形,参数为数组
      polygon.drawPolygon([0, 0, 100, 0, 100, 100, 0, 100])
      polygon.endFill() // 结束填充
      polygon.position.set(50, 300)
      app.stage.addChild(polygon)

      // 绘制圆弧=============================
      const arc = new PIXI.Graphics()
      arc.beginFill(0x70eb77, 1)
      // PIXI.Graphics.arc(cx: number, cy: number, radius: number, startAngle: number, endAngle: number)
      arc.arc(0, 0, 32, Math.PI / 2, false)
      arc.endFill() // 结束填充
      arc.position.set(800, 80)
      app.stage.addChild(arc)

      // 绘制线段=============================
      const line = new PIXI.Graphics()
      line.lineStyle(4, 0xed6341, 1)
      line.moveTo(0, 0) // 线段开始位置
      line.lineTo(100, 100) // 线段结束位置
      line.lineTo(200, 1)
      line.position.set(800, 120)
      app.stage.addChild(line)
    }
  }
}
</script>
<style>
#tag {
  width: 100%;
  height: 100%;
}
</style>

纹理和动画

<template>
  <div id="vein"></div>
</template>

<script>
import * as PIXI from 'pixi.js'
export default {
  name: 'vein',
  mounted() {
    let _this = this
    this.$nextTick(() => {
      _this.initPixi()
    })
  },
  methods: {
    initPixi() {
      const options = {
        width: window.innerWidth,
        height: window.innerHeight,
        backgroundColor: 0x1099bb,
        resolution: window.devicePixelRatio || 1,
        antialias: true
      }
      // 创建应用
      const app = new PIXI.Application(options)
      // 将应用画布添加到DOM中
      document.querySelector('#vein').appendChild(app.view)

      // 创建纹理
      const texture = PIXI.Texture.from('/textures/arrow.png')

      // 创建精灵
      const sprite = new PIXI.Sprite(texture)
      // 设置精灵锚点
      sprite.anchor.set(0.5, 0.5)
      // 设置位置
      sprite.x = app.screen.width / 2
      sprite.y = app.screen.height / 2
      // 设置精灵旋转-45°
      sprite.rotation = Math.PI / -4
      // 设置精灵缩放
      sprite.scale.set(2, 2)
      // 设置精灵透明度
      sprite.alpha = 0.8
      // 添加到画布
      app.stage.addChild(sprite)

      // ticker 实现动画
      app.ticker.add((delta) => {
        sprite.rotation += 0.01 * delta
      })
    }
  }
}
</script>

事件和交互

<template>
  <div id="event"></div>
</template>

<script>
import * as PIXI from 'pixi.js'
export default {
  name: 'event',
  mounted() {
    let _this = this
    this.$nextTick(() => {
      _this.initPixi()
    })
  },
  methods: {
    initPixi() {
      const options = {
        width: window.innerWidth,
        height: window.innerHeight,
        backgroundColor: 0x1099bb,
        resolution: window.devicePixelRatio || 1,
        antialias: true
      }
      // 创建应用
      const app = new PIXI.Application(options)
      // 将应用画布添加到DOM中
      document.querySelector('#event').appendChild(app.view)

      // 创建纹理
      const texture = PIXI.Texture.from('/textures/arrow.png')

      // 创建精灵
      const sprite = new PIXI.Sprite(texture)
      // 设置精灵锚点
      sprite.anchor.set(0.5, 0.5)
      // 设置位置
      sprite.x = app.screen.width / 2
      sprite.y = app.screen.height / 2
      // 设置精灵旋转-45°
      sprite.rotation = Math.PI / -4
      // 设置精灵缩放
      sprite.scale.set(2, 2)
      // 设置精灵透明度
      sprite.alpha = 0.5
      // 添加到画布
      app.stage.addChild(sprite)

      // ticker 实现动画
      app.ticker.add((delta) => {
        sprite.rotation += 0.01 * delta
      })

      // 为精灵添加交互事件
      sprite.interactive = true // 使精灵对象可以点击
      sprite.on('click', () => {
        alert('点击了')
      })

      // 鼠标进入
      sprite.on('pointerover', () => {
        console.log('鼠标移入 :>> ')
        sprite.alpha = 0.5
      })
      sprite.on('pointerout', () => {
        console.log('鼠标移出 :>> ')
        sprite.alpha = 1
      })

      // 绘制矩形
      const rect = new PIXI.Graphics()
      rect.beginFill(0xff0000)
      rect.drawRect(0, 0, 100, 100)
      rect.endFill()
      rect.x = 100
      rect.y = 100
      app.stage.addChild(rect)
      // 给矩形添加点击事件
      rect.interactive = true
      rect.on('click', () => {
        console.log('点击矩形 :>> ')
      })
    }
  }
}
</script>
<style>
#tag {
  width: 100%;
  height: 100%;
}
</style>

资源管理

<template>
  <div id="resourceManagement"></div>
</template>

<script>
import * as PIXI from 'pixi.js'
export default {
  name: 'as',
  mounted() {
    let _this = this
    this.$nextTick(() => {
      _this.initPixi()
    })
  },
  methods: {
    initPixi() {
      const options = {
        width: window.innerWidth,
        height: window.innerHeight,
        backgroundColor: 0x1099bb,
        resolution: window.devicePixelRatio || 1,
        antialias: true
      }
      // 创建应用
      const app = new PIXI.Application(options)
      // 将应用画布添加到DOM中
      document.querySelector('#resourceManagement').appendChild(app.view)

      // 添加资源
      // PIXI.Assets.add('arrow', require('../assets/textures/arrow.png'))
      // PIXI.Assets.add('dog', require('../assets/textures/dog.png'))
      // // 异步加载资源
      // const texturesPromise = PIXI.Assets.load(['arrow', 'dog'], (progress) => {
      //   console.log('加载完成...', progress)
      // })
      // texturesPromise.then((textures) => {
      //   // 创建容器
      //   const container = new PIXI.Container()

      //   // 创建精灵位置
      //   const sprite = new PIXI.Sprite(textures.arrow)
      //   // 精灵位置
      //   sprite.x = app.screen.width / 2
      //   sprite.y = app.screen.height / 2
      //   // 设置精灵锚点
      //   sprite.anchor.set(0.5)
      //   // 设置透明度
      //   sprite.alpha = 0.5
      //   // 设置缩放
      //   sprite.scale.set(0.5)
      //   // 设置旋转
      //   sprite.rotaion = 0.5
      //   // 设置混合模式
      //   sprite.blendMode = PIXI.BLEND_MODES.ADD
      //   // 设置交互
      //   sprite.interactive = true
      //   // 设置鼠标样式
      //   sprite.buttonMode = true
      //   // 设置鼠标事件
      //   sprite.on('click', () => {
      //     alert('点击')
      //   })
      //   // 容器添加arrow
      //   container.addChild(sprite)

      //   const dog = new PIXI.Sprite(textures.dog)
      //   dog.scale.set(0.5)
      //   // 容器添加dog
      //   container.addChild(dog)
      //   // 添加到画布
      //   app.stage.addChild(container)
      // })

      /* ******************************************** */
      // 添加场景1的资源文件
      PIXI.Assets.addBundle('scene1', {
        arrow: '/textures/arrow.png',
        dog: '/textures/dog.png'
      })
      const assets = PIXI.Assets.loadBundle('scene1', (progress) => {
        console.log('加载完成...', progress)
      })
      assets.then((textures) => {
        // 创建容器
        const container = new PIXI.Container()

        // 创建精灵位置
        const sprite = new PIXI.Sprite(textures.arrow)
        // 精灵位置
        sprite.x = app.screen.width / 2
        sprite.y = app.screen.height / 2
        // 设置精灵锚点
        sprite.anchor.set(0.5)
        // 设置透明度
        sprite.alpha = 0.5
        // 设置缩放
        sprite.scale.set(1)
        // 设置旋转
        sprite.rotaion = 0.5
        // 设置混合模式
        sprite.blendMode = PIXI.BLEND_MODES.ADD
        // 设置交互
        sprite.interactive = true
        // 设置鼠标样式
        sprite.buttonMode = true
        // 设置鼠标事件
        sprite.on('click', () => {
          alert('点击')
        })
        // 容器添加arrow
        container.addChild(sprite)

        const dog = new PIXI.Sprite(textures.dog)
        dog.scale.set(0.5)
        // 容器添加dog
        container.addChild(dog)
        // 添加到画布
        app.stage.addChild(container)
      })
    }
  }
}
</script>
<style>
#tag {
  width: 100%;
  height: 100%;
}
</style>

文字与遮罩

<template>
  <div id="texts"></div>
</template>

<script>
import * as PIXI from 'pixi.js'

export default {
  name: 'texts',
  mounted() {
    let _this = this
    this.$nextTick(() => {
      _this.initPixi()
    })
  },
  methods: {
    initPixi() {
      const options = {
        width: window.innerWidth,
        height: window.innerHeight,
        backgroundColor: 0x1099bb,
        resolution: window.devicePixelRatio || 1,
        antialias: true
      }
      // 创建应用
      const app = new PIXI.Application(options)
      // 将应用画布添加到DOM中
      document.querySelector('#texts').appendChild(app.view)

      // 显示文字
      const text = new PIXI.Text('文本信息', {
        fontSize: 300,
        fill: 0xff0000,
        align: 'center'
      })
      // 设置文字位置
      text.x = app.screen.width / 2
      text.y = app.screen.height / 2
      // 设置锚点
      text.anchor.set(0.5)
      // app.stage.addChild(text)

      // 创建一个圆形
      const circle = new PIXI.Graphics()
      circle.beginFill(0x0000ff)
      circle.drawCircle(app.screen.width / 2, app.screen.height / 2, 100)
      circle.endFill()
      circle.x = app.screen.width / 2
      circle.y = app.screen.height / 2

      const arrow = PIXI.Sprite.from('/textures/arrow.png')

      // 创建精灵
      const bunny = PIXI.Sprite.from('/textures/bg.png')
      // 设置精灵铺满屏幕
      bunny.width = app.screen.width
      bunny.height = app.screen.height
      // 使用文字作为精灵的遮罩
      bunny.mask = text
      // 使用圆形作为精灵的遮罩
      // bunny.mask = arrow
      app.stage.addChild(bunny)
    }
  }
}
</script>
<style>
#texts {
  width: 100%;
  height: 100%;
}
</style>

滤镜特效

<template>
  <div id="filterEffect"></div>
</template>

<script>
import * as PIXI from 'pixi.js'
import { OutlineFilter, GlowFilter } from 'pixi-filters'
export default {
  name: 'filterEffect',
  mounted() {
    let _this = this
    this.$nextTick(() => {
      _this.initPixi()
    })
  },
  methods: {
    initPixi() {
      const options = {
        width: window.innerWidth,
        height: window.innerHeight,
        backgroundColor: 0x1099bb,
        resolution: window.devicePixelRatio || 1,
        antialias: true
      }
      // 创建应用
      const app = new PIXI.Application(options)
      // 将应用画布添加到DOM中
      document.querySelector('#filterEffect').appendChild(app.view)

      const arrow = PIXI.Texture.from('/textures/arrow.png')
      const sprite = new PIXI.Sprite(arrow)
      sprite.x = app.screen.width / 2
      sprite.y = app.screen.height / 2
      // 设置精灵锚点
      sprite.anchor.set(0.5)
      // 添加到画布
      app.stage.addChild(sprite)

      // 创建模糊滤镜
      const blurFilter = new PIXI.BlurFilter()
      // 设置模糊程度
      blurFilter.blur = 0
      // 模糊应用到精灵
      // sprite.filters = [blurFilter]
      // // 监听鼠标是否进入
      // sprite.interactive = true
      // sprite.on('pointerover', () => {
      //   blurFilter.blur = 10
      // })
      // sprite.on('pointerout', () => {
      //   blurFilter.blur = 0
      // })

      // 轮廓滤镜
      const outlineFilter = new OutlineFilter(3, 0xffff00)
      // 辉光滤镜
      const glowFilter = new GlowFilter({
        distance: 120,
        outerStrength: 3,
        innerStrength: 0,
        color: 0xff0000,
        quality: 0.5
      })
      sprite.filters = [outlineFilter, glowFilter]
    }
  }
}
</script>
<style>
#tag {
  width: 100%;
  height: 100%;
}
</style>

水滴特效主页

<template>
  <div id="waterDrop"></div>
</template>

<script setup>
import { onMounted } from 'vue'
import * as PIXI from 'pixi.js'
import { ShockwaveFilter } from 'pixi-filters'

onMounted(() => {
  initPixi()
})
// 初始化
const initPixi = () => {
  const optoions = {
    width: window.innerWidth,
    height: window.innerHeight,
    backgroundColor: 0x1099bb,
    resolution: window.devicePixelRatio || 1,
    antialias: true
  }
  const app = new PIXI.Application(optoions)
  document.querySelector('#waterDrop').appendChild(app.view)
  // 创建纹理
  const texture = PIXI.Texture.from('/textures/002.jpg')
  // 创建精灵
  const sprite = new PIXI.Sprite(texture)
  sprite.width = app.screen.width
  sprite.height = app.screen.height
  // 创建容器
  const container = new PIXI.Container()
  // 将精灵添加到容器中
  container.addChild(sprite)
  // 将容器添加到画布
  app.stage.addChild(container)
  // 添加文字
  const text = new PIXI.Text('Hello PixiJs', {
    fontFamily: 'Arial',
    fontSize: 30 + Math.floor(app.screen.width * 0.1),
    fill: 0xffffff,
    align: 'center',
    dropShadow: true,
    dropShadowColor: '#000000',
    dropShadowBlur: 40, // 阴影模糊度
    dropShadowAngle: Math.PI / 2, // 阴影照射角度
    dropShadowDistance: 2 // 阴影厚度
  })
  text.x = app.screen.width / 2
  text.y = app.screen.height / 2
  text.anchor.set(0.5)
  container.addChild(text)

  // 添加置换滤镜
  const displacementSprite = PIXI.Sprite.from('/textures/water.png')
  displacementSprite.scale.set(3)
  // 纹理重复模式
  displacementSprite.texture.baseTexture.wrapMode = PIXI.WRAP_MODES.REPEAT

  // 将纹理放到滤镜上
  const displacementFilter = new PIXI.DisplacementFilter(displacementSprite)
  // 精灵天机到容器
  container.addChild(displacementSprite)

  // 添加水波纹
  const shockwaveFilter1 = new ShockwaveFilter(
    [Math.random() * app.screen.width, Math.random() * app.screen.height],
    {
      radius: 100, // 半径
      wavelength: 80, // 波长
      amplitude: 108, // 振幅
      speed: 150 // 速度
    },
    0
  )
  const shockwaveFilter2 = new ShockwaveFilter(
    [Math.random() * app.screen.width, Math.random() * app.screen.height],
    {
      radius: 40, // 半径
      wavelength: 30, // 波长
      amplitude: 10, // 振幅
      speed: 200 // 速度
    },
    0
  )
  const shockwaveFilter3 = new ShockwaveFilter(
    [Math.random() * app.screen.width, Math.random() * app.screen.height],
    {
      radius: 160, // 半径
      wavelength: 65, // 波长
      amplitude: 105, // 振幅
      speed: 300 // 速度
    },
    0
  )

  // 将滤镜添加到容器
  container.filters = [
    displacementFilter,
    shockwaveFilter1,
    shockwaveFilter2,
    shockwaveFilter3
  ]
  // 添加动画
  app.ticker.add((delta) => {
    displacementSprite.x += 0.5
    displacementSprite.y += 0.5
    createRandomWave(shockwaveFilter1, 1.2)
    createRandomWave(shockwaveFilter2, 1)
    createRandomWave(shockwaveFilter3, 0.7)
  })

  function createRandomWave(waveFilter, restTime) {
    waveFilter.time += 0.01
    if (waveFilter.titme > restTime) {
      waveFilter.time = 0
      waveFilter.center = [
        Math.random() * app.screen.width,
        Math.random() * app.screen.height
      ]
    }
  }

  // 监听点击事件,根据位置及创建波纹
  app.view.addEventListener('click', (e) => {
    shockwaveFilter1.center = [e.clientX, e.clientY]
    shockwaveFilter1.time = 0
  })
}
</script>