render.ts
  import { SketchGl, type SketchConfig, type SketchFn } from "sketchgl"
import { Uniforms, Program } from "sketchgl/program"
import { Matrix4, Vector3 } from "sketchgl/math"
import { MouseCoords } from "sketchgl/interactive"
import { ImagesCubeTexture } from "sketchgl/texture"
import { Cube, Icosahedron, Sphere } from "sketchgl/geometry"
import vert from "./index.vert?raw"
import frag from "./index.frag?raw"
import top from "@/assets/cube-map/sky/top.png"
import bottom from "@/assets/cube-map/sky/bottom.png"
import left from "@/assets/cube-map/sky/left.png"
import right from "@/assets/cube-map/sky/right.png"
import front from "@/assets/cube-map/sky/front.png"
import back from "@/assets/cube-map/sky/back.png"
const sketch: SketchFn = (skCanvas) => {
  const { gl, canvas } = skCanvas
  const uniforms = new Uniforms(gl, [
    "uMatView",
    "uMatModel",
    "uMatProj",
    "uEyePosition",
    "uRefraction",
    "uRefractiveIndex"
  ])
  let uRefractiveIndex = 0.6
  const matP = Matrix4.perspective(45, canvas.width / canvas.height, 0.1, 200)
  const mouse = new MouseCoords(canvas)
  const program = new Program(gl)
  program.attach(vert, frag)
  program.activate()
  uniforms.init(program.glProgram)
  uniforms.fmatrix4("uMatProj", matP.values)
  const cubeMap = new ImagesCubeTexture(gl, { top, bottom, left, right, front, back })
  const polyhedron = new Icosahedron(gl)
  polyhedron.setLocations({ vertices: 0, normals: 1 })
  const sphere = new Sphere(gl, { radius: 1, segments: 64, rings: 64 })
  sphere.setLocations({ vertices: 0, normals: 1 })
  const cube = new Cube(gl, { size: 2 })
  cube.setLocations({ vertices: 0, normals: 1 })
  gl.clearColor(1.0, 1.0, 1.0, 1.0)
  gl.clearDepth(1.0)
  gl.enable(gl.DEPTH_TEST)
  gl.depthFunc(gl.LEQUAL)
  let count = 0
  return {
    preload: [cubeMap.load()],
    drawOnFrame: () => {
      gl.viewport(0, 0, gl.canvas.width, gl.canvas.height)
      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
      count++
      const rad = ((count % 360) * Math.PI) / 180
      const rad2 = (((count + 180) % 360) * Math.PI) / 180
      const rot = mouse.quaternion()
      const eye = rot.toRotatedVector3(0, 0, 8)
      const up = rot.toRotatedVector3(0, 1, 0)
      const matV = Matrix4.view(eye, new Vector3(0, 0, 0), up)
      uniforms.fmatrix4("uMatView", matV.values)
      
      cube.bind()
      let matM = Matrix4.scaling(100, 100, 100)
      uniforms.fmatrix4("uMatModel", matM.values)
      uniforms.fvector3("uEyePosition", eye.rawValues)
      uniforms.float("uRefractiveIndex", uRefractiveIndex)
      uniforms.bool("uRefraction", false)
      cubeMap.activate(program.glProgram, "uCubeMap")
      cube.draw({ primitive: "TRIANGLES" })
      
      sphere.bind()
      matM = Matrix4.rotationZ(rad).translate(2, 0, 0)
      uniforms.fmatrix4("uMatModel", matM.values)
      uniforms.bool("uRefraction", true)
      sphere.draw({ primitive: "TRIANGLES" })
      
      polyhedron.bind()
      matM = Matrix4.rotationZ(rad2).translate(2, 0, 0)
      uniforms.fmatrix4("uMatModel", matM.values)
      uniforms.bool("uRefraction", true)
      polyhedron.draw({ primitive: "TRIANGLES" })
    },
    control(ui) {
      ui.number("屈折率の比", uRefractiveIndex, 0.0, 1.0, 0.01, (v) => {
        uRefractiveIndex = v
      })
    }
  }
}
export const onload = () => {
  const config: SketchConfig = {
    canvas: {
      el: "gl-canvas",
      fit: "square",
      autoResize: true
    }
  }
  SketchGl.init(config, sketch)
}