diff --git a/.gitignore b/.gitignore index 1e35c06..ae92265 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,5 @@ pnpm-debug.log* package-lock.json -_bk \ No newline at end of file +_bk +_note \ No newline at end of file diff --git a/README.md b/README.md index f5ba6bc..36a6d25 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,23 @@ -# Toys.028 | WebGL Carousel Demo.06 ~ PaperAnimation +# Toys.029 | WebGL School Task.07 ~ Plane geometry animation using pure WebGL. + +## 🪬 ~ 要件 +- テクスチャを複数同時に利用する実装に挑戦してみましょう。 +※ 生 WebGL で実装すること + ## 👾 ~ Demo -- https://dev.shoya-kajita.com/028/ + +- https://dev.shoya-kajita.com/029/ + + + + ## 🎮 ~ Getting Started ``` @@ -26,9 +36,17 @@ npm run preview ## 📝 ~ Note -- https://www.pentacreation.com/blog/2021/06/210605.html -- https://tympanus.net/codrops/2020/01/22/how-to-unroll-images-with-three-js/ -- https://tympanus.net/Development/UnrollingImages/ -- https://github.com/akella/UnrollingImages/blob/master/js/shader/vertex.glsl +### matcap + +- https://github.com/hughsk/matcap - +```glsl +// vec3 eye: the camera's current position. +// vec3 normal: the surface's normal vector. + +vec2 matcap(vec3 eye, vec3 normal) { + vec3 reflected = reflect(eye, normal); + float m = 2.8284271247461903 * sqrt( reflected.z+1.0 ); + return reflected.xy / m + 0.5; +} +``` diff --git a/package.json b/package.json index 3419764..b830be0 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "dependencies": { "astro": "^2.2.1", "gsap": "^3.11.4", - "three": "^0.148.0" + "lil-gui": "^0.18.2" }, "devDependencies": { "@astrojs/sitemap": "^1.2.2", diff --git a/public/assets/img/head/apple-touch-icon.webp b/public/assets/img/head/apple-touch-icon.webp index b2bffd3..c1b3971 100644 Binary files a/public/assets/img/head/apple-touch-icon.webp and b/public/assets/img/head/apple-touch-icon.webp differ diff --git a/public/assets/img/head/favicon.ico b/public/assets/img/head/favicon.ico index 9dd1ea6..0d0d2a0 100644 Binary files a/public/assets/img/head/favicon.ico and b/public/assets/img/head/favicon.ico differ diff --git a/public/assets/img/head/screenshot.webp b/public/assets/img/head/screenshot.webp index 56ef33e..43fe20a 100644 Binary files a/public/assets/img/head/screenshot.webp and b/public/assets/img/head/screenshot.webp differ diff --git a/public/assets/img/head/thumbnail.webp b/public/assets/img/head/thumbnail.webp index 1f9a44d..2a7897b 100644 Binary files a/public/assets/img/head/thumbnail.webp and b/public/assets/img/head/thumbnail.webp differ diff --git a/public/assets/img/item/blackpanther.webp b/public/assets/img/item/blackpanther.webp new file mode 100644 index 0000000..e348f9b Binary files /dev/null and b/public/assets/img/item/blackpanther.webp differ diff --git a/public/assets/img/item/blackwidow.webp b/public/assets/img/item/blackwidow.webp new file mode 100644 index 0000000..301fb3a Binary files /dev/null and b/public/assets/img/item/blackwidow.webp differ diff --git a/public/assets/img/item/captainamerica.webp b/public/assets/img/item/captainamerica.webp new file mode 100644 index 0000000..5dc346f Binary files /dev/null and b/public/assets/img/item/captainamerica.webp differ diff --git a/public/assets/img/item/doctorstrange.webp b/public/assets/img/item/doctorstrange.webp new file mode 100644 index 0000000..75d112f Binary files /dev/null and b/public/assets/img/item/doctorstrange.webp differ diff --git a/public/assets/img/item/drax.webp b/public/assets/img/item/drax.webp new file mode 100644 index 0000000..06fa2ce Binary files /dev/null and b/public/assets/img/item/drax.webp differ diff --git a/public/assets/img/item/falcon.webp b/public/assets/img/item/falcon.webp new file mode 100644 index 0000000..b50d46e Binary files /dev/null and b/public/assets/img/item/falcon.webp differ diff --git a/public/assets/img/item/gamora.webp b/public/assets/img/item/gamora.webp new file mode 100644 index 0000000..0af5b8c Binary files /dev/null and b/public/assets/img/item/gamora.webp differ diff --git a/public/assets/img/item/groot.webp b/public/assets/img/item/groot.webp new file mode 100644 index 0000000..77dcd68 Binary files /dev/null and b/public/assets/img/item/groot.webp differ diff --git a/public/assets/img/item/hulk.webp b/public/assets/img/item/hulk.webp new file mode 100644 index 0000000..a38a27b Binary files /dev/null and b/public/assets/img/item/hulk.webp differ diff --git a/public/assets/img/item/ironman.webp b/public/assets/img/item/ironman.webp new file mode 100644 index 0000000..f73d4af Binary files /dev/null and b/public/assets/img/item/ironman.webp differ diff --git a/public/assets/img/item/mantis.webp b/public/assets/img/item/mantis.webp new file mode 100644 index 0000000..39e73d5 Binary files /dev/null and b/public/assets/img/item/mantis.webp differ diff --git a/public/assets/img/item/nebula.webp b/public/assets/img/item/nebula.webp new file mode 100644 index 0000000..4b3f3b6 Binary files /dev/null and b/public/assets/img/item/nebula.webp differ diff --git a/public/assets/img/item/okoye.webp b/public/assets/img/item/okoye.webp new file mode 100644 index 0000000..ca17758 Binary files /dev/null and b/public/assets/img/item/okoye.webp differ diff --git a/public/assets/img/item/rocket.webp b/public/assets/img/item/rocket.webp new file mode 100644 index 0000000..45f2930 Binary files /dev/null and b/public/assets/img/item/rocket.webp differ diff --git a/public/assets/img/item/scarletwitch.webp b/public/assets/img/item/scarletwitch.webp new file mode 100644 index 0000000..6a6fd84 Binary files /dev/null and b/public/assets/img/item/scarletwitch.webp differ diff --git a/public/assets/img/item/spiderman.webp b/public/assets/img/item/spiderman.webp new file mode 100644 index 0000000..aa79c04 Binary files /dev/null and b/public/assets/img/item/spiderman.webp differ diff --git a/public/assets/img/item/starroad.webp b/public/assets/img/item/starroad.webp new file mode 100644 index 0000000..f39bc0c Binary files /dev/null and b/public/assets/img/item/starroad.webp differ diff --git a/public/assets/img/item/syuri.webp b/public/assets/img/item/syuri.webp new file mode 100644 index 0000000..2f56c30 Binary files /dev/null and b/public/assets/img/item/syuri.webp differ diff --git a/public/assets/img/item/thor.webp b/public/assets/img/item/thor.webp new file mode 100644 index 0000000..ee7b864 Binary files /dev/null and b/public/assets/img/item/thor.webp differ diff --git a/public/assets/img/item/vision.webp b/public/assets/img/item/vision.webp new file mode 100644 index 0000000..8b48f3b Binary files /dev/null and b/public/assets/img/item/vision.webp differ diff --git a/public/assets/img/item/warmachine.webp b/public/assets/img/item/warmachine.webp new file mode 100644 index 0000000..a610325 Binary files /dev/null and b/public/assets/img/item/warmachine.webp differ diff --git a/public/assets/img/item/wintersoldier.webp b/public/assets/img/item/wintersoldier.webp new file mode 100644 index 0000000..b5e0b75 Binary files /dev/null and b/public/assets/img/item/wintersoldier.webp differ diff --git a/public/assets/img/item/wong.webp b/public/assets/img/item/wong.webp new file mode 100644 index 0000000..e819f71 Binary files /dev/null and b/public/assets/img/item/wong.webp differ diff --git a/public/assets/img/texture/matcap.jpg b/public/assets/img/texture/matcap.jpg new file mode 100644 index 0000000..7079c09 Binary files /dev/null and b/public/assets/img/texture/matcap.jpg differ diff --git a/public/assets/img/texture/noise.png b/public/assets/img/texture/noise.png new file mode 100644 index 0000000..98bf343 Binary files /dev/null and b/public/assets/img/texture/noise.png differ diff --git a/public/assets/video/movie1.mp4 b/public/assets/video/movie1.mp4 deleted file mode 100644 index 709293c..0000000 Binary files a/public/assets/video/movie1.mp4 and /dev/null differ diff --git a/public/assets/video/movie2.mp4 b/public/assets/video/movie2.mp4 deleted file mode 100644 index 6e58709..0000000 Binary files a/public/assets/video/movie2.mp4 and /dev/null differ diff --git a/public/assets/video/movie3.mp4 b/public/assets/video/movie3.mp4 deleted file mode 100644 index d6acbc8..0000000 Binary files a/public/assets/video/movie3.mp4 and /dev/null differ diff --git a/sample_sine.gif b/sample_sine.gif deleted file mode 100644 index f5d50d9..0000000 Binary files a/sample_sine.gif and /dev/null differ diff --git a/screenshot1.webp b/screenshot1.webp new file mode 100644 index 0000000..dd1e732 Binary files /dev/null and b/screenshot1.webp differ diff --git a/screenshot2.webp b/screenshot2.webp index 4cbc22b..6d51690 100644 Binary files a/screenshot2.webp and b/screenshot2.webp differ diff --git a/screenshot3.webp b/screenshot3.webp new file mode 100644 index 0000000..630746f Binary files /dev/null and b/screenshot3.webp differ diff --git a/src/assets/js/app.js b/src/assets/js/app.js index 37e5f39..1b9e7b1 100644 --- a/src/assets/js/app.js +++ b/src/assets/js/app.js @@ -11,124 +11,63 @@ import "../scss/app.scss"; // -------------------------- import gsap from "gsap"; -import { ScrollTrigger } from "gsap/ScrollTrigger"; -gsap.registerPlugin(ScrollTrigger); // -------------------------- // module // -------------------------- -import { Global } from "./module/Global"; -import { Ua } from "./module/Ua"; -import { SetPropertySize } from "./module/SetPropertySize"; - -// -------------------------- - -// WebGL - -// -------------------------- +import { SetGui } from "./lib/setGui"; import { WebGL } from "./webgl/WebGL"; // -------------------------- -// windows +// window // -------------------------- window.MODE = process.env.NODE_ENV === "development"; window.GSAP = gsap; -window.ScrollTrigger = ScrollTrigger; -window.G = new Global(); window.addEventListener("DOMContentLoaded", (e) => { - const BREAK_POINT = 768; + new SetGui(); - const body = document.body, - ua = new Ua(body); - - const params = { - w: window.innerWidth, - h: window.innerHeight, - beforeWidth: window.innerWidth, - longer: 0, - shorter: 0, - aspect: 0, - }; - params.aspect = params.w / params.h; - params.longer = params.w > params.h ? params.w : params.h; - params.shorter = params.w < params.h ? params.w : params.h; + const world = document.getElementById("world"); + const worldRect = world.getBoundingClientRect(); const bool = { - isMatchMediaWidth: window.matchMedia("(max-width: 768px)").matches, isMatchMediaHover: window.matchMedia("(hover: hover)").matches, - isPc: ua.data.device === "pc", - isIphone: ua.data.iphone === "iphone", - isDeve: MODE, // false }; - const timer = { - resize: null, - orientation: null, + const params = { + w: window.innerWidth, + h: bool.isMatchMediaHover ? window.innerHeight : worldRect.height, }; - SetPropertySize(params.w, params.h); - - const webgl = new WebGL(body, params, bool); + const webgl = new WebGL(params); + webgl.init(); - const raf = () => { - const time = performance.now() / 1000; - webgl.raf(time); - }; + GSAP.ticker.add(webgl.raf); + GSAP.ticker.fps(30); const resize = () => { - bool.isMatchMediaWidth = window.matchMedia("(max-width: 768px)").matches; params.w = window.innerWidth; - params.h = window.innerHeight; - params.aspect = params.w / params.h; - params.longer = params.w > params.h ? params.w : params.h; - params.shorter = params.w < params.h ? params.w : params.h; - - const props = { - isMatchMediaWidth: bool.isMatchMediaWidth, - w: params.w, - h: params.h, - aspect: params.aspect, - longer: params.longer, - shorter: params.shorter, - }; + params.h = bool.isMatchMediaHover ? window.innerHeight : world.getBoundingClientRect().height; - SetPropertySize(params.w, params.h); - webgl.resize(props); - - clearTimeout(timer.resize); - timer.resize = setTimeout(() => { - const threshold = () => { - const w = window.innerWidth; - if (w > BREAK_POINT) if (params.beforeWidth < BREAK_POINT + 1) window.location.reload(); - if (w < BREAK_POINT + 1) if (params.beforeWidth > BREAK_POINT + 1) window.location.reload(); - params.beforeWidth = w; - }; - threshold(); - }, 100); + webgl.resize(params); }; + resize(); + window.addEventListener("resize", resize, { passive: true }); - const orientation = () => { - if (window.orientation != 0) { - if (params.w < params.h) { - clearTimeout(timer.orientation); - timer.orientation = setTimeout(() => { - window.location.reload(); - }, 300); - } - } - }; - - document.fonts.ready.then((e) => { - webgl.init(); - GSAP.ticker.add(raf); - GSAP.ticker.fps(30); - resize(); - window.addEventListener("resize", resize, { passive: true }); - if (!bool.isPc) window.addEventListener("orientationchange", orientation); - }); + if (bool.isMatchMediaHover) { + // 右クリック禁止 + document.oncontextmenu = function () { + return false; + }; + document.getElementsByTagName("html")[0].oncontextmenu = function () { + return false; + }; + document.body.oncontextmenu = function () { + return false; + }; + } }); diff --git a/src/assets/js/webgl/lib/SetGui.js b/src/assets/js/lib/setGui.js similarity index 61% rename from src/assets/js/webgl/lib/SetGui.js rename to src/assets/js/lib/setGui.js index 19551a3..fc66504 100644 --- a/src/assets/js/webgl/lib/SetGui.js +++ b/src/assets/js/lib/setGui.js @@ -1,14 +1,14 @@ -import GUI from "three/examples/jsm/libs/lil-gui.module.min"; +import GUI from "lil-gui"; export class SetGui { constructor() { this.gui = null; window.GUI = null; // if (MODE) { - this.gui = new GUI(); - window.GUI = this.gui; - this.toOpen(); - // this.toClose(); + // this.gui = new GUI(); + // window.GUI = this.gui; + // this.toOpen(); + // // this.toClose(); // } } diff --git a/src/assets/js/module/Global.js b/src/assets/js/module/Global.js deleted file mode 100644 index b557efd..0000000 --- a/src/assets/js/module/Global.js +++ /dev/null @@ -1,89 +0,0 @@ -export class Global { - /** - * 線形補間 - * リファレンス:https://ja.wikipedia.org/wiki/%E7%B7%9A%E5%BD%A2%E8%A3%9C%E9%96%93 - * @param {number} start - * @param {number} end - * @param {number} ease - * @returns {number} startとendを補完した数値 - */ - lerp(start, end, ease) { - return start * (1 - ease) + end * ease; - } - - /** - * 範囲を超えさせない - * @param {number} num // 指定値 - * @param {number} min // 最小値 - * @param {number} max // 最大値 - * @return {number} - */ - clamp(num, min, max) { - // console.log(num, min, max); - return min > num ? min : max < num ? max : num; - } - - /** - * 度数からラジアンに変換 - * @param {number} degree // 度数 - * @returns 弧度法のラジアンを返す - */ - getDegreeToRadian(degree) { - const radian = (degree * Math.PI) / 180; - return radian; - } - - /** - * ラジアンから度数に変換 - * @param {number} radians // 角度 - * @returns 弧度法のラジアンを返す - */ - getRadianToDegree(radian) { - const degree = (radian * 180) / Math.PI; - return degree; - } - - /** - * 範囲を超えると反対の端点にする - * @param {number} num // 指定値 - * @param {number} min // 最小値 - * @param {number} max // 最大値 - * @return {number} - */ - hoop(num, min, max) { - const range = max - min + 1; - let mod = (num - min) % range; - if (0 > mod) { - mod = range + mod; - } - return mod + min; - } - - /** - * 遅延 (await) - * @param {number} time 遅延時間 - * @returns - */ - delay(time) { - return new Promise((resolve) => { - setTimeout(() => { - resolve(); - }, time); - }); - } - - /** - * GETパラメータのキーから値を取得し返す - * 参考サイト:https://www-creators.com/archives/4463 - * @param {string} name // 取得したいGETパラメータのキー - * @returns {string} // GETパラメータ値 - */ - getParameter(name) { - name = name.replace(/[\[\]]/g, "\\$&"); - let regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"), - results = regex.exec(window.location.href); - if (!results) return null; - if (!results[2]) return ""; - return decodeURIComponent(results[2].replace(/\+/g, " ")); - } -} diff --git a/src/assets/js/module/SetPropertySize.js b/src/assets/js/module/SetPropertySize.js deleted file mode 100644 index 8c8476e..0000000 --- a/src/assets/js/module/SetPropertySize.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @param {number} w // window.innerWidth - * @param {number} h // window.innerHeight - */ -export function SetPropertySize(w, h) { - const vh = h * 0.01, - longer = w > h ? w : h, - shorter = w > h ? h : w; - - document.documentElement.style.setProperty("--vh", vh + "px"); // height: calc(var(--vh, 1vh) * 100); - document.documentElement.style.setProperty("--longer", longer + "px"); - document.documentElement.style.setProperty("--shorter", shorter + "px"); -} diff --git a/src/assets/js/module/Ua.js b/src/assets/js/module/Ua.js deleted file mode 100644 index 096792f..0000000 --- a/src/assets/js/module/Ua.js +++ /dev/null @@ -1,102 +0,0 @@ -export class Ua { - constructor(body) { - this.body = body; - this.bodyClassList = this.body.classList; - this.ua = window.navigator.userAgent.toLowerCase(); - this.data = { - browser: "", - os: "", - device: "", - iphone: "", - }; - - this.checkBrowser(); - this.checkOs(); - this.checkDevice(); - this.checkiPhone(); - } - - checkBrowser() { - if (this.ua.indexOf("edge") !== -1 || this.ua.indexOf("edga") !== -1 || this.ua.indexOf("edgios") !== -1) { - console.log("🚀 ~ This is Edge"); - this.data.browser = "edge"; - } else if (this.ua.indexOf("opera") !== -1 || this.ua.indexOf("opr") !== -1) { - console.log("🚀 ~ This is Opera"); - this.data.browser = "opera"; - } else if (this.ua.indexOf("samsungbrowser") !== -1) { - console.log("🚀 ~ This is SamsungInternetBrowser"); - this.data.browser = "samsung"; - } else if (this.ua.indexOf("ucbrowser") !== -1) { - console.log("🚀 ~ This is UcBrowser"); - this.data.browser = "uc"; - } else if (this.ua.indexOf("chrome") !== -1 || this.ua.indexOf("crios") !== -1) { - console.log("🚀 ~ This is Chrome"); - this.data.browser = "chrome"; - } else if (this.ua.indexOf("firefox") !== -1 || this.ua.indexOf("fxios") !== -1) { - console.log("🚀 ~ This is Firefox"); - this.data.browser = "firefox"; - } else if (this.ua.indexOf("safari") !== -1) { - console.log("🚀 ~ This is Safari"); - this.data.browser = "safari"; - } else if (this.ua.indexOf("msie") !== -1 || this.ua.indexOf("trident") !== -1) { - console.log("🚀 ~ This is IE"); - this.data.browser = "ie"; - alert("このブラウザは現在サポートされておりません。"); - } else { - console.log("🚀 ~ This is An unknown browser"); - this.data.browser = ""; - } - - if (this.data.browser != "") this.bodyClassList.add(this.data.browser); - } - - checkOs() { - if (this.ua.indexOf("windows nt") !== -1) { - console.log("🚀 ~ This is Windows"); - this.data.os = "windows"; - } else if (this.ua.indexOf("android") !== -1) { - console.log("🚀 ~ This is Android"); - this.data.os = "android"; - } else if (this.ua.indexOf("iphone") !== -1 || this.ua.indexOf("ipad") !== -1) { - console.log("🚀 ~ This is iOS"); - this.data.os = "ios"; - } else if (this.ua.indexOf("mac os x") !== -1) { - console.log("🚀 ~ This is macOS"); - this.data.os = "macos"; - } else { - console.log("🚀 ~ This is An unknown OS"); - this.data.os = ""; - } - - if (this.data.os != "") this.bodyClassList.add(this.data.os); - } - - checkDevice() { - if (this.ua.indexOf("iphone") !== -1 || (this.ua.indexOf("android") !== -1 && this.ua.indexOf("Mobile") > 0)) { - console.log("🚀 ~ This is Mobile"); - this.data.device = "mobile"; - } else if (this.ua.indexOf("ipad") !== -1 || this.ua.indexOf("android") !== -1) { - console.log("🚀 ~ This is Tablet"); - this.data.device = "tablet"; - } else if (this.ua.indexOf("ipad") > -1 || (this.ua.indexOf("macintosh") > -1 && "ontouchend" in document)) { - console.log("🚀 ~ This is iPad"); - this.data.device = "tablet"; - } else { - console.log("🚀 ~ This is PC"); - this.data.device = "pc"; - } - - if (this.data.device != "") this.bodyClassList.add(this.data.device); - } - - checkiPhone() { - if (this.ua.indexOf("iphone") !== -1) { - console.log("🚀 ~ This is iPhone"); - this.data.iphone = "iphone"; - } else { - this.data.iphone = ""; - } - - if (this.data.iphone != "") this.bodyClassList.add(this.data.iphone); - } -} diff --git a/src/assets/js/webgl/Mesh.js b/src/assets/js/webgl/Mesh.js deleted file mode 100644 index f48923e..0000000 --- a/src/assets/js/webgl/Mesh.js +++ /dev/null @@ -1,764 +0,0 @@ -// -------------------------- - -// lib - -// -------------------------- -import * as THREE from "three"; - -// -------------------------- - -// shaders - -// -------------------------- -import fragmentShader from "../../shaders/fragment.glsl"; -import vertexShader from "../../shaders/vertex.glsl"; - -// -------------------------- - -// module - -// -------------------------- -import { TextureLoad } from "./utility/TextureLoad"; - -const DURATION = 2.4; -const EASE = "power2.inOut"; - -export class Mesh { - constructor(body, params, bool, stage) { - this.body = body; - this.stage = stage; - this.params = params; - this.bool = bool; - - this.isInit = false; - - this.group = null; - this.mesh = null; - - this.isAnime = true; - - this.init(); - } - - TextureLoader(src) { - return new THREE.TextureLoader().loadAsync(src); - } - - /** - * - * @param {element} ele // imgタグ - * @returns objデータを返す - */ - loadImg(ele) { - const src = ele.getAttribute("src"); - const w = ele.getAttribute("width"); - const h = ele.getAttribute("height"); - - return new Promise((resolve) => { - const img = new Image(); - img.src = src; - img.addEventListener("load", (e) => { - const data = { - img: img, - src: src, - texture: TextureLoad(src), - w: w, - h: h, - aspect: w / h, - }; - return resolve(data); - }); - }); - } - - /** - * - * @param {element} ele // imgタグ - * @returns objデータを返す - */ - loadVideo(ele) { - const src = ele.getAttribute("src"); - const w = ele.getAttribute("width"); - const h = ele.getAttribute("height"); - - return new Promise((resolve) => { - ele.play(); - const data = { - ele: ele, - src: src, - texture: new THREE.VideoTexture(ele), - w: w, - h: h, - aspect: w / h, - }; - data.texture.encoding = THREE.sRGBEncoding; - return resolve(data); - }); - } - - async init() { - // 画像データ作成 - // this.imgDataList = []; - // this.imgList = [...document.querySelectorAll(".js-img")]; - // console.log(this.imgList); - // this.imgDataList = await Promise.all( - // this.imgList.map((ele) => { - // return this.loadImg(ele); - // }), - // ); - - this.imgDataList = []; - this.imgList = [...document.querySelectorAll(".js-video")]; - this.imgDataList = await Promise.all( - this.imgList.map((ele) => { - return this.loadVideo(ele); - }), - ); - - await G.delay(0); - this.slideConfig = { - current: 0, - max: this.imgDataList.length - 1, - }; - - this.createGroup(); - this.createPlaneGeometry(); - this.createMesh(); - - this.setDomSystem(); - this.setInteractive(); - - this.setAutoPlay(); - - await G.delay(300); - this.body.setAttribute("data-status", "enter"); - } - - toDown(e) { - if (!this.isDown && this.isAnime) { - clearTimeout(this.timerDown); - this.isDown = true; - this.vector.start.x = e.touches ? e.touches[0].clientX : e.clientX; - // this.vector.start.y = e.touches ? e.touches[0].clientY : e.clientY; - } - } - - toDownMove(e) { - const DURATION_DOWN = 50; - const THRESHOLD = 0.5; - - let nextIndex; - - if (this.isDown && this.isAnime) { - const x = e.touches ? e.touches[0].clientX : e.clientX; - // const y = e.touches ? e.touches[0].clientY : e.clientY; - - this.vector.target.x = this.vector.start.x - x; - // this.vector.target.y = this.vector.start.x - y; - - if (this.vector.target.x > 10 || this.vector.target.x < -10) { - // アニメーションのディレクションを決める - if (this.isDirectionOnced) { - this.isDirectionOnced = false; - - // 現在のナビゲーションの`is-active`を解除 - if (this.naviList[this.slideConfig.current].classList.contains("is-active")) { - this.naviList[this.slideConfig.current].classList.remove("is-active"); - } - - if (this.vector.target.x > 0) { - // console.log("+ : 右 → 左"); - this.isDirectionNext = true; - - // 次のindex番号を設定 - nextIndex = this.slideConfig.current - 1; - if (nextIndex < 0) nextIndex = this.imgDataList.length - 2; - - const current = this.group.children[this.slideConfig.current]; - const next = this.group.children[nextIndex]; - - // uniform変数更新 - current.material.uniforms.uAnime.value = 1.0; - current.renderOrder = 2; - current.material.uniforms.uTexture.value = this.imgDataList[this.slideConfig.current].texture; - current.material.uniforms.uTextureAspect.value = this.imgDataList[this.slideConfig.current].aspect; - - next.material.uniforms.uAnime.value = 1.0; - next.renderOrder = 1; - next.material.uniforms.uTexture.value = this.imgDataList[nextIndex].texture; - next.material.uniforms.uTextureAspect.value = this.imgDataList[nextIndex].aspect; - - // 動画再生時間を0にする - this.imgDataList[nextIndex].ele.currentTime = 0; - } else { - // console.log("- 左 → 右"); - this.isDirectionNext = false; - - // 次のindex番号を設定 - nextIndex = this.slideConfig.current + 1; - if (nextIndex > this.slideConfig.max) nextIndex = 0; - - const current = this.group.children[this.slideConfig.current]; - const next = this.group.children[nextIndex]; - - // uniform変数更新 - current.material.uniforms.uAnime.value = 1.0; - current.renderOrder = 1; - current.material.uniforms.uTexture.value = this.imgDataList[this.slideConfig.current].texture; - current.material.uniforms.uTextureAspect.value = this.imgDataList[this.slideConfig.current].aspect; - - next.material.uniforms.uAnime.value = 0.0; - next.renderOrder = 2; - next.material.uniforms.uTexture.value = this.imgDataList[nextIndex].texture; - next.material.uniforms.uTextureAspect.value = this.imgDataList[nextIndex].aspect; - - // 動画再生時間を0にする - this.imgDataList[nextIndex].ele.currentTime = 0; - console.log(nextIndex); - - } - } - - // 進捗アニメーション値を格納する - this.vector.current.x = G.clamp(Math.abs(this.vector.target.x / this.params.w) * 3, 0.0, THRESHOLD); - - if (this.isDirectionNext) { - nextIndex = this.slideConfig.current - 1; - if (nextIndex < 0) nextIndex = this.imgDataList.length - 2; - GSAP.to(this.group.children[this.slideConfig.current].material.uniforms.uAnime, { - duration: 1, - value: 1.0 - this.vector.current.x, - }); - } else { - nextIndex = this.slideConfig.current + 1; - if (nextIndex > this.slideConfig.max) nextIndex = 0; - GSAP.to(this.group.children[nextIndex].material.uniforms.uAnime, { - duration: 1, - value: this.vector.current.x, - }); - } - - // 自動再生を解除 - clearTimeout(this.timerAutoPlay); - // nextボタンの進捗を解除 - if (this.nextBtn.classList.contains("is-active")) { - this.nextBtn.classList.remove("is-active"); - } - - clearTimeout(this.timerDown); - this.timerDown = setTimeout(() => { - this.isDown = false; - this.isAnime = false; - - if (this.isDirectionNext) { - const current = this.group.children[this.slideConfig.current]; - console.log(current.material.uniforms.uAnime.value, THRESHOLD); - if (current.material.uniforms.uAnime.value < THRESHOLD) { - clearTimeout(this.timerAutoPlay); - this.naviList[this.slideConfig.current].classList.add("is-active"); - this.updateBodyData(this.slideConfig.current); - - GSAP.to(current.material.uniforms.uAnime, { - duration: DURATION, - value: 1.0, - ease: EASE, - onComplete: () => { - this.isAnime = true; - this.isDown = false; - this.isDirectionOnced = true; - - this.setAutoPlay(); - }, - }); - } else { - console.log("timer next before"); - // 戻す - - GSAP.to(current.material.uniforms.uAnime, { - duration: DURATION, - value: 0.0, - ease: EASE, - onComplete: () => { - nextIndex = this.slideConfig.current - 1; - if (nextIndex < 0) nextIndex = this.slideConfig.max; - - const current = this.group.children[this.slideConfig.current]; - const next = this.group.children[nextIndex]; - - // uniform変数更新 - current.material.uniforms.uAnime.value = 0.0; - current.renderOrder = 2; - current.material.uniforms.uTexture.value = this.imgDataList[this.slideConfig.current].texture; - current.material.uniforms.uTextureAspect.value = this.imgDataList[this.slideConfig.current].aspect; - - next.material.uniforms.uAnime.value = 1.0; - next.renderOrder = 1; - next.material.uniforms.uTexture.value = this.imgDataList[nextIndex].texture; - next.material.uniforms.uTextureAspect.value = this.imgDataList[nextIndex].aspect; - - // shaderのテクスチャ情報更新 - // current.material.uniforms.uTexture2.value = this.imgDataList[this.slideConfig.current].texture; - // current.material.uniforms.uTexture1.value = this.imgDataList[nextIndex].texture; - // current.material.uniforms.uTextureAspect2.value = this.imgDataList[this.slideConfig.current].aspect; - // current.material.uniforms.uTextureAspect1.value = this.imgDataList[nextIndex].aspect; - - this.slideConfig.current--; - if (this.slideConfig.current < 0) this.slideConfig.current = this.slideConfig.max; - - this.isAnime = true; - this.isDown = false; - this.isDirectionOnced = true; - this.naviList[this.slideConfig.current].classList.add("is-active"); - this.updateBodyData(this.slideConfig.current); - - this.setAutoPlay(); - }, - }); - } - } else { - const next = this.group.children[nextIndex]; - console.log(next.material.uniforms.uAnime.value , 1.0 - THRESHOLD); - if (next.material.uniforms.uAnime.value + 0.1 < 1.0 - THRESHOLD) { - console.log("timer prev after"); - this.naviList[this.slideConfig.current].classList.add("is-active"); - this.updateBodyData(this.slideConfig.current); - - GSAP.to(next.material.uniforms.uAnime, { - duration: DURATION, - value: 0.0, - ease: EASE, - onComplete: () => { - this.isAnime = true; - this.isDown = false; - this.isDirectionOnced = true; - - this.setAutoPlay(); - }, - }); - } else { - // 戻す - console.log("timer prev before"); - - GSAP.to(next.material.uniforms.uAnime, { - duration: DURATION, - value: 1.0, - ease: EASE, - onComplete: () => { - this.isAnime = true; - this.isDown = false; - this.isDirectionOnced = true; - - nextIndex = this.slideConfig.current + 1; - if (nextIndex > this.slideConfig.max) nextIndex = 0; - - const current = this.group.children[this.slideConfig.current]; - const next = this.group.children[nextIndex]; - - // // shaderのテクスチャ情報更新 - // current.material.uniforms.uTexture1.value = this.imgDataList[this.slideConfig.current].texture; - // current.material.uniforms.uTexture2.value = this.imgDataList[nextIndex].texture; - // current.material.uniforms.uTextureAspect1.value = this.imgDataList[this.slideConfig.current].aspect; - // current.material.uniforms.uTextureAspect2.value = this.imgDataList[nextIndex].aspect; - - // uniform変数更新 - current.material.uniforms.uAnime.value = 1.0; - current.renderOrder = 1; - current.material.uniforms.uTexture.value = this.imgDataList[this.slideConfig.current].texture; - current.material.uniforms.uTextureAspect.value = this.imgDataList[this.slideConfig.current].aspect; - - next.material.uniforms.uAnime.value = 1.0; - next.renderOrder = 2; - next.material.uniforms.uTexture.value = this.imgDataList[nextIndex].texture; - next.material.uniforms.uTextureAspect.value = this.imgDataList[nextIndex].aspect; - - // 現在地の更新 - this.slideConfig.current++; - if (this.slideConfig.current > this.slideConfig.max) this.slideConfig.current = 0; - this.naviList[this.slideConfig.current].classList.add("is-active"); - - this.updateBodyData(this.slideConfig.current); - - this.setAutoPlay(); - }, - }); - } - } - }, DURATION_DOWN); - } - } - } - - toUp(e) { - this.isDown = false; - } - - setInteractive() { - const DURATION_NEXT_SLIDE = 2000; - this.timerNextSlide = null; - this.isNextSlide = true; - window.addEventListener("wheel", (e) => { - const y = e.deltaY; - - if (this.isNextSlide && this.isAnime) { - this.isAnime = false; - this.isNextSlide = false; - if (y > 0) { - // console.log("down"); - this.updateSlide("+"); - } else { - // console.log("up"); - this.updateSlide("-"); - } - clearTimeout(this.timerNextSlide); - this.timerNextSlide = setTimeout(() => { - clearTimeout(this.timerNextSlide); - this.isNextSlide = true; - }, DURATION_NEXT_SLIDE); - } - }); - - this.isDown = false; - this.timerDown = null; - this.isDirectionOnced = true; - this.isDirectionNext = true; - this.nextIndex = 0; - - this.vector = { - start: { - x: 0, - y: 0, - }, - target: { - x: 0, - y: 0, - }, - current: { - x: 0, - y: 0, - }, - }; - - if (this.bool.isMatchMediaHover) { - window.addEventListener("mousedown", this.toDown.bind(this), { passive: true }); - window.addEventListener("mousemove", this.toDownMove.bind(this), { passive: true }); - window.addEventListener("mouseup", this.toUp.bind(this)); - } else { - window.addEventListener("touchstart", this.toDown.bind(this), { passive: true }); - window.addEventListener("touchmove", this.toDownMove.bind(this), { passive: true }); - window.addEventListener("touchend", this.toUp.bind(this)); - } - } - - updateBodyData(value) { - this.body.setAttribute("data-webgl-carousel-current", value); - } - - /** - * - * @param {string} direction // 進行方向: "+" or "-" - * @param {number} nextIndex // 次のスライドindex番号を指定する - */ - updateSlide(direction = "+", nextIndex = null) { - // 自動再生を解除 - clearTimeout(this.timerAutoPlay); - - // 現在のナビゲーションの`is-active`を解除 - if (this.naviList[this.slideConfig.current].classList.contains("is-active")) { - this.naviList[this.slideConfig.current].classList.remove("is-active"); - } - - // 進行方向によって処理を分ける - if (direction === "+") { - // 次の指定がなければ`+1`する - if (nextIndex === null) { - nextIndex = this.slideConfig.current + 1; - if (nextIndex > this.slideConfig.max) nextIndex = 0; - } - - const current = this.group.children[this.slideConfig.current]; - const next = this.group.children[nextIndex]; - - // uniform変数更新 - current.material.uniforms.uAnime.value = 1.0; - current.renderOrder = 2; - current.material.uniforms.uTexture.value = this.imgDataList[this.slideConfig.current].texture; - current.material.uniforms.uTextureAspect.value = this.imgDataList[this.slideConfig.current].aspect; - - next.material.uniforms.uAnime.value = 1.0; - next.renderOrder = 1; - next.material.uniforms.uTexture.value = this.imgDataList[nextIndex].texture; - next.material.uniforms.uTextureAspect.value = this.imgDataList[nextIndex].aspect; - - // 動画再生時間を0にする - this.imgDataList[nextIndex].ele.currentTime = 0; - - // shaderの補完値を更新、その後クリックを許可する - GSAP.to(current.material.uniforms.uAnime, { - duration: DURATION, - value: 0.0, - ease: EASE, - onComplete: () => { - this.isAnime = true; - this.isClickUI = true; - - // 自動再生を有効化 - this.setAutoPlay(); - }, - }); - - // 現在地の更新 - this.slideConfig.current++; - if (this.slideConfig.current > this.slideConfig.max) this.slideConfig.current = 0; - } else { - // 次の指定がなければ`-1`する - if (nextIndex === null) { - nextIndex = this.slideConfig.current - 1; - if (nextIndex < 0) nextIndex = this.slideConfig.max; - } - - const current = this.group.children[this.slideConfig.current]; - const next = this.group.children[nextIndex]; - - // uniform変数更新 - current.material.uniforms.uAnime.value = 1.0; - current.renderOrder = 1; - current.material.uniforms.uTexture.value = this.imgDataList[this.slideConfig.current].texture; - current.material.uniforms.uTextureAspect.value = this.imgDataList[this.slideConfig.current].aspect; - - next.material.uniforms.uAnime.value = 0.0; - next.renderOrder = 2; - next.material.uniforms.uTexture.value = this.imgDataList[nextIndex].texture; - next.material.uniforms.uTextureAspect.value = this.imgDataList[nextIndex].aspect; - - // 動画再生時間を0にする - this.imgDataList[nextIndex].ele.currentTime = 0; - - GSAP.to(next.material.uniforms.uAnime, { - duration: DURATION, - value: 1.0, - ease: EASE, - onComplete: () => { - this.isAnime = true; - this.isClickUI = true; - - // 自動再生を有効化 - this.setAutoPlay(); - }, - }); - - this.slideConfig.current--; - if (this.slideConfig.current < 0) this.slideConfig.current = this.slideConfig.max; - } - - if (nextIndex != null) { - this.slideConfig.current = nextIndex; - } - this.naviList[this.slideConfig.current].classList.add("is-active"); - this.updateBodyData(this.slideConfig.current); - - // nextボタンの進捗を解除 - if (this.nextBtn.classList.contains("is-active")) { - this.nextBtn.classList.remove("is-active"); - } - } - - setDomSystem() { - this.isClickUI = true; - // prevボタン - this.prevBtn = document.getElementById("prevBtn"); - this.prevBtn.addEventListener("click", (e) => { - if (this.isClickUI && this.isAnime) { - this.isAnime = false; - this.isClickUI = false; - this.updateSlide("-"); - } - }); - - // nextボタン - this.nextBtn = document.getElementById("nextBtn"); - this.nextBtn.addEventListener("click", (e) => { - if (this.isClickUI && this.isAnime) { - this.isAnime = false; - this.isClickUI = false; - this.updateSlide("+"); - } - }); - - // ナビゲーション - this.naviList = [...document.querySelectorAll(".js-navi")]; - for (let i = 0; i < this.naviList.length; i++) { - const navi = this.naviList[i]; - navi.addEventListener("click", (e) => { - console.log(this.slideConfig.current, i); - if (this.slideConfig.current != i) { - if (this.isClickUI && this.isAnime) { - this.isAnime = false; - this.isClickUI = false; - if (this.slideConfig.current < i) { - this.updateSlide("+", i); - } else if (this.slideConfig.current > i) { - this.updateSlide("-", i); - } - } - } - }); - } - } - - toAutoPlay() { - this.isAnime = false; - this.isClickUI = false; - this.updateSlide("+"); - } - - setAutoPlay() { - const INTERVAL = 3000; - this.timerAutoPlay = null; - - // nextボタンの進捗を有効化 - this.nextBtn.classList.add("is-active"); - - clearTimeout(this.timerAutoPlay); - this.timerAutoPlay = setTimeout(() => { - this.toAutoPlay(); - }, INTERVAL); - } - - createPlaneGeometry() { - const depth = 100; - this.planeGeometry = new THREE.PlaneBufferGeometry(1, 1, depth, depth); - } - - createGroup() { - this.group = new THREE.Group(); - this.stage.scene.add(this.group); - } - - updateMesh(mesh) { - // scale - mesh.scale.x = this.params.w; - mesh.scale.y = this.params.h; - mesh.scale.z = this.params.shorter; - - // shader - mesh.material.uniforms.uPlaneAspect.value = this.params.aspect; - } - - createMesh() { - const material = new THREE.ShaderMaterial({ - transparent: true, - opacity: 1, - side: THREE.DoubleSide, - fragmentShader: fragmentShader, - vertexShader: vertexShader, - uniforms: { - uTime: { type: "f", value: 0.0 }, - uScale: { type: "f", value: 1.0 }, - uPlaneAspect: { type: "f", value: this.params.aspect }, - - // img - uTexture: { type: "t", value: this.imgDataList[0].texture }, - uTextureAspect: { type: "f", value: this.imgDataList[0].aspect }, - - // duration && easing - uAnime: { type: "f", value: 0.0 }, - - uAngle: { - type: "f", - value: G.getDegreeToRadian(45), - }, - // uTwist: { type: "f", value: 0.0 }, - - // debug - uProgress: { type: "f", value: 0. }, - // uProgress2: { type: "f", value: 0.0 }, - }, - }); - - for (let i = 0; i < this.imgDataList.length; i++) { - const m = material.clone(); - m.uniforms.uTexture.value = this.imgDataList[i].texture; - if (i === 0) { - m.uniforms.uAnime.value = 1.0; - } - - const mesh = new THREE.Mesh(this.planeGeometry, m); - mesh.name = `plane${i}`; - mesh.renderOrder = 0; - this.updateMesh(mesh); - this.group.add(mesh); - - // if (GUI != null) { - // const folder = GUI.addFolder("mesh"); - // folder - // .add(mesh.material.uniforms.uProgress, "value", 0.0, 1.0) - // .name("uProgress") - // .onChange((value) => { - // mesh.material.uniforms.uProgress.value = value; - // }); - // } - } - - if (GUI) { - let params = { - // progress: 0.5, - // progress2: 0.0, - angle: G.getRadianToDegree(this.group.children[0].material.uniforms.uAngle.value), - // twist: G.getRadianToDegree(this.group.children[0].material.uniforms.uTwist.value), - }; - const folder = GUI.addFolder("shader"); - // folder - // .add(params, "progress", 0, 1) - // .name("uProgress") - // .onChange((value) => { - // for (let i = 0; i < this.group.children.length; i++) { - // const mesh = this.group.children[i]; - // mesh.material.uniforms.uProgress.value = value; - // } - // }); - folder - .add(params, "angle", 0, 90) - .name("uAngle") - .onChange((value) => { - for (let i = 0; i < this.group.children.length; i++) { - const mesh = this.group.children[i]; - mesh.material.uniforms.uAngle.value = G.getDegreeToRadian(value); - } - }); - // folder - // .add(params, "twist", 0, 90) - // .name("uTwist") - // .onChange((value) => { - // for (let i = 0; i < this.group.children.length; i++) { - // const mesh = this.group.children[i]; - // mesh.material.uniforms.uTwist.value = G.getDegreeToRadian(value); - // } - // }); - } - } - - resize(props) { - this.bool.isMatchMediaWidth = props.isMatchMediaWidth; - this.params.w = props.w; - this.params.h = props.h; - this.params.aspect = props.aspect; - this.params.shorter = props.shorter; - // this.params.longer = props.longer; - if (this.group != null) { - for (let i = 0; i < this.group.children.length; i++) { - const mesh = this.group.children[i]; - this.updateMesh(mesh); - } - } - } - - raf(time) { - if (this.group != null) { - for (let i = 0; i < this.group.children.length; i++) { - const mesh = this.group.children[i]; - mesh.material.uniforms.uTime.value = time; - } - } - this.stage.renderer.render(this.stage.scene, this.stage.camera); - } -} diff --git a/src/assets/js/webgl/Object.js b/src/assets/js/webgl/Object.js new file mode 100644 index 0000000..d509fa9 --- /dev/null +++ b/src/assets/js/webgl/Object.js @@ -0,0 +1,335 @@ +import { WebGLMath } from "./doxas/WebGLMath"; + +/** + * @class プログラムオブジェクトを作成する継承元 + */ +export class Object { + /** + * @param {WebGLRenderingContext} gl WebGLコンテキスト + * @param {source} fragment ピクセルシェーダ + * @param {source} vertex 頂点シェーダ + */ + constructor(stage, fragment, vertex) { + this.gl = stage.gl; + this.canvas = stage.canvas; + this.isOrbitCamera = stage.isOrbitCamera; + this.camera = stage.camera; + + this.drawCount = null; + this.uniforms = {}; + + const vs = this.createFragmentShader(fragment); + const fs = this.createVertexShader(vertex); + this.program = this.createProgramObject(vs, fs); + + // バックフェイスカリングと深度テストは初期状態で有効 + this.gl.enable(this.gl.CULL_FACE); + this.gl.enable(this.gl.DEPTH_TEST); + + this.v2 = WebGLMath.Vec2; + this.v3 = WebGLMath.Vec3; + this.m4 = WebGLMath.Mat4; + this.qtn = WebGLMath.Qtn; + } + + /** + * シェーダオブジェクトを生成 + * @param {WebGLRenderingContext} gl WebGLコンテキスト + * @param {source} source シェーダ + * @param {number} type gl.VERTEX_SHADER or gl.FRAGMENT_SHADER + * @returns {WebGLShader} + */ + createShaderObject(gl, source, type) { + const shader = gl.createShader(type); + gl.shaderSource(shader, source); + gl.compileShader(shader); + if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + return shader; + } else { + throw new Error(gl.getShaderInfoLog(shader)); + return null; + } + } + + /** + * ピクセルシェーダを生成 + * @param {source} source ピクセルシェーダ + * @returns {WebGLShader} + */ + createFragmentShader(source) { + console.log("🙌 ~ create fragment"); + const gl = this.gl; + return this.createShaderObject(gl, source, gl.FRAGMENT_SHADER); + } + + /** + * 頂点シェーダを生成 + * @param {souce} source 頂点シェーダ + * @returns {WebGLShader} + */ + createVertexShader(source) { + console.log("🙌 ~ create vertex"); + const gl = this.gl; + return this.createShaderObject(gl, source, gl.VERTEX_SHADER); + } + + /** + * プログラムオブジェクトを生成 + * @param {WebGLShader} vs 頂点シェーダ + * @param {WebGLShader} fs ピクセルシェーダ + * @returns {WebGLProgram} + */ + createProgramObject(vs, fs) { + const gl = this.gl; + const program = gl.createProgram(); + + // シェーダをアタッチ(関連付け)する + gl.attachShader(program, vs); + gl.attachShader(program, fs); + + // シェーダオブジェクトをリンクする + gl.linkProgram(program); + + // リンクが完了するとシェーダオブジェクトは不要になるので削除する + gl.deleteShader(vs); + gl.deleteShader(fs); + + if (gl.getProgramParameter(program, gl.LINK_STATUS)) { + gl.useProgram(program); + return program; + } else { + throw new Error(gl.getProgramInfoLog(program)); + return null; + } + } + + /** + * IBOを生成 + * @param {Array} indexArray 頂点インデックスの結び順の配列 + * @return {WebGLBuffer} + */ + createIBO(indexArray) { + const gl = this.gl; + // 空のバッファオブジェクトを生成する + const ibo = gl.createBuffer(); + // バッファを gl.ELEMENT_ARRAY_BUFFER としてバインドする + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo); + // バインドしたバッファに Int16Array オブジェクトに変換した配列を設定する + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Int16Array(indexArray), gl.STATIC_DRAW); + // 安全のために最後にバインドを解除してからバッファオブジェクトを返す + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); + return ibo; + } + + /** + * IBOを更新 + * @param {WebGLBuffer} ibo - インデックスバッファ + */ + updateIBO(ibo) { + const gl = this.gl; + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo); + } + + /** + * 配列から VBO(Vertex Buffer Object)を生成する + * @param {Array.} vertexArray - 頂点属性情報の配列 + * @return {WebGLBuffer} + */ + createVBO(vertexArray) { + const gl = this.gl; + // 空のバッファオブジェクトを生成する + const vbo = gl.createBuffer(); + // バッファを gl.ARRAY_BUFFER としてバインドする + gl.bindBuffer(gl.ARRAY_BUFFER, vbo); + // バインドしたバッファに Float32Array オブジェクトに変換した配列を設定する + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexArray), gl.STATIC_DRAW); + // 安全のために最後にバインドを解除してからバッファオブジェクトを返す + gl.bindBuffer(gl.ARRAY_BUFFER, null); + return vbo; + } + + /** + * VBOを有効化 + * @param {WebGLBuffer} vbo 頂点属性を格納した頂点バッファの配列 + * @param {number} location 頂点属性ロケーション + * @param {number} stride 分割数 + */ + updateVBO(vbo, location, stride) { + const gl = this.gl; + // 有効化したいバッファをまずバインドする + gl.bindBuffer(gl.ARRAY_BUFFER, vbo); + // 頂点属性ロケーションの有効化を行う + gl.enableVertexAttribArray(location); + // 対象のロケーションのストライドやデータ型を設定する + gl.vertexAttribPointer(location, stride, gl.FLOAT, false, 0, 0); + } + + getUniform(name) { + const gl = this.gl; + const program = this.program; + const location = gl.getUniformLocation(program, name); + return gl.getUniform(program, location); + } + + /** + * unifrom値を設定 + * @param {string} name 変数名 + * @param {string} type 型タイプ + * @param {any} value 値 + */ + createUniform(name, type, value) { + const gl = this.gl; + const program = this.program; + this.uniforms[name] = gl.getUniformLocation(program, name); + } + + /** + * unifrom値を更新 + * @param {string} name 変数名 + * @param {string} type 型タイプ + * @param {any} value 値 + * 変数の文字列タイプ(少し前の three.js 文字列変数): https://qiita.com/kitasenjudesign/items/1657d9556591284a43c8 + * uniformで利用するデータの型: https://webglfundamentals.org/webgl/lessons/ja/webgl-shaders-and-glsl.html + */ + updateUniform(name, type, value, transpose = false) { + const gl = this.gl; + switch (type) { + case "t": + gl.uniform1i(this.uniforms[name], value); // sampler2D (テクスチャ) + break; + case "i": + gl.uniform1i(this.uniforms[name], value); // int:1つの整数 + break; + case "f": + gl.uniform1f(this.uniforms[name], value); // float: 1つの浮動小数点 + break; + case "v1": + gl.uniform1fv(this.uniforms[name], value); // vec1: 1つの浮動小数点を配列に入れたもの + break; + case "v2": + gl.uniform2fv(this.uniforms[name], value); // vec2: 2つの浮動小数点を配列にいれたもの + break; + case "v3": + gl.uniform3fv(this.uniforms[name], value); // vec3: 3つの浮動小数点を配列にいれたもの + break; + case "v4": + gl.uniform4fv(this.uniforms[name], value); // vec4: 4つの浮動小数点を配列にいれたもの + break; + case "m2": + gl.uniformMatrix2fv(this.uniforms[name], transpose, value); // mat2: 配列で表現された 2x2 の行列 + break; + case "m3": + gl.uniformMatrix3fv(this.uniforms[name], transpose, value); // mat3: 配列で表現された 3x3 の行列 + break; + case "m4": + gl.uniformMatrix4fv(this.uniforms[name], transpose, value); // mat4: 配列で表現された 4x4 の行列 + break; + default: + throw new Error("type is not defined"); + break; + } + } + + /** + * + * @param {number} fov field of view 垂直視野 + * @param {number} aspect 画面のアスペクト比 + * @param {number} near 一番近い距離 + * @param {number} far 一番遠い距離 + * @returns + */ + createProjection(fov = 45, aspect = window.innerWidth / window.innerHeight, near = 0.1, far = 10.0) { + return this.m4.perspective(fov, aspect, near, far); + } + + /** + * + * @param {element} ele // imgタグ + * @returns {Promise} objデータを返す + */ + loadEleImg(ele) { + return new Promise((resolve) => { + const src = ele.getAttribute("src"); + const w = ele.getAttribute("width"); + const h = ele.getAttribute("height"); + + const img = new Image(); + img.src = src; + img.addEventListener("load", (e) => { + const data = { + img: img, + src: src, + w: w, + h: h, + aspect: w / h, + }; + return resolve(data); + }); + }); + } + + /** + * + * @param {path} path // 画像パス + * @returns {Promise} objデータを返す + */ + loadImg(path) { + return new Promise((resolve) => { + const img = new Image(); + img.src = path; + img.addEventListener("load", (e) => { + return resolve(img); + }); + }); + } + + /** + * テクスチャ用のリソースからテクスチャを生成する + * @param {any} resource - 画像や HTMLCanvasElement などのテクスチャ用リソース + * @return {WebGLTexture} + */ + createTexture(resource) { + const gl = this.gl; + // テクスチャオブジェクトを生成 + const texture = gl.createTexture(); + // アクティブなテクスチャユニット番号を指定する + gl.activeTexture(gl.TEXTURE0); + // テクスチャをアクティブなユニットにバインドする + gl.bindTexture(gl.TEXTURE_2D, texture); + // バインドしたテクスチャにデータを割り当て + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, resource); + // ミップマップを自動生成する + gl.generateMipmap(gl.TEXTURE_2D); + // テクスチャパラメータを設定する + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + // 安全の為にテクスチャのバインドを解除してから返す + gl.bindTexture(gl.TEXTURE_2D, null); + return texture; + } + + /** + * バックフェイスカリングを設定する + * @param {boolean} bool + * @returns + */ + setCulling(bool = true) { + const gl = this.gl; + return bool ? gl.enable(gl.CULL_FACE) : gl.disable(gl.CULL_FACE); + } + + /** + * 深度テストを設定する + * @param {boolean} bool - 設定する値 + */ + setDepthTest(bool = true) { + const gl = this.gl; + bool ? gl.enable(gl.DEPTH_TEST) : gl.disable(gl.DEPTH_TEST); + } + + raf() { + if (this.program != null) this.gl.useProgram(this.program); + } +} diff --git a/src/assets/js/webgl/ObjectPlane.js b/src/assets/js/webgl/ObjectPlane.js new file mode 100644 index 0000000..f8ccff6 --- /dev/null +++ b/src/assets/js/webgl/ObjectPlane.js @@ -0,0 +1,405 @@ +// module +import { Object } from "./Object"; + +// shader +import fragmentShader from "../../shader/frag/plane.glsl"; +import vertexShader from "../../shader/vert/plane.glsl"; + +export class ObjectPlane extends Object { + constructor(params, stage) { + super(stage, fragmentShader, vertexShader); + this.stage = stage; + this.params = params; + + this.isCreated = false; + this.isOpened = false; + this.isClicked = false; + this.isChange = true; + this.isMatchMediaHover = window.matchMedia("(hover: hover)").matches; + + this.mesh = {}; + + this.curve = { + x: { + target: 0, + current: 0, + }, + y: { + target: 0, + current: 0, + }, + power: 0.3, + }; + + this.variable = { + progress: 0.0, + scale: 0.0, + change: 0.0, + status: { + before: 1, + after: 0, + }, + }; + } + + /** + * @param {number} width 板ポリの横幅 + * @param {number} height 板ポリの縦幅 + * @param {number} widthSegments 横の1辺を分割する数 + * @param {number} heightSegments 縦の1辺を分割する数 + */ + getPlaneGeometry(width = 1, height = 1, widthSegments = 1, heightSegments = 1) { + const w = width / 2; + const h = height / 2; + + const gridX = Math.floor(widthSegments); + const gridY = Math.floor(heightSegments); + + const limitGridX = gridX + 1; + const limitGridY = gridY + 1; + + const segmentWidth = width / gridX; + const segmentHeight = height / gridY; + + const indexList = []; + const positionList = []; + const normalList = []; + const uvList = []; + + for (let iy = 0; iy < limitGridY; iy++) { + const y = iy * segmentHeight - h; + + for (let ix = 0; ix < limitGridX; ix++) { + const x = ix * segmentWidth - w; + + positionList.push(x, -y, 0); + + normalList.push(0, 0, 1); + + uvList.push(ix / gridX); + uvList.push(1 - iy / gridY); + } + } + + for (let iy = 0; iy < gridY; iy++) { + for (let ix = 0; ix < gridX; ix++) { + const a = ix + limitGridX * iy; + const b = ix + limitGridX * (iy + 1); + const c = ix + 1 + limitGridX * (iy + 1); + const d = ix + 1 + limitGridX * iy; + + indexList.push(a, b, d); + indexList.push(b, c, d); + } + } + + // prettier-ignore + return { + position: positionList, + normal: normalList, + uv: uvList, + index: indexList + }; + } + + createMesh() { + const gl = this.gl; + + // geometry作成 + this.mesh.geometry = this.getPlaneGeometry(1, 1, 32, 32); + + // BVO作成 + this.mesh.position = { + array: this.createVBO(this.mesh.geometry.position), + location: gl.getAttribLocation(this.program, "position"), + stride: 3, + }; + this.mesh.uv = { + array: this.createVBO(this.mesh.geometry.uv), + location: gl.getAttribLocation(this.program, "uv"), + stride: 2, + }; + this.mesh.normal = { + array: this.createVBO(this.mesh.geometry.normal), + location: gl.getAttribLocation(this.program, "normal"), + stride: 3, + }; + + // IBO作成 + this.mesh.ibo = { + data: this.createIBO(this.mesh.geometry.index), + length: this.mesh.geometry.index.length, + }; + + // uniform作成 + this.createUniform("uMvpMatrix"); + this.createUniform("uCurve"); + this.createUniform("uTime"); + this.createUniform("uNormalMatrix"); + this.createUniform("uModelMatrix"); + this.createUniform("uEyePosition"); + this.createUniform("uPlaneAspect"); + this.createUniform("uTextureAspect"); + this.createUniform("uMatcap"); + this.createUniform("uTexture1"); + this.createUniform("uTexture2"); + this.createUniform("uProgress"); + this.createUniform("uNoise"); + this.createUniform("uScale"); + this.createUniform("uChange"); + this.createUniform("uFullScale"); + + this.isCreated = true; + } + + onMove(vector) { + this.curve.x.target = vector.x.target; + this.curve.y.target = vector.y.target; + } + + resize(params) {} + + raf(time, vector) { + const v = vector; + const gl = this.stage.gl; + if (this.isCreated) { + super.raf(time); + + const m4 = this.m4; + const v3 = this.v3; + + // ビュー座標変換行列 + const view = this.isOrbitCamera ? this.camera.update() : this.camera; + + // プロジェクション座標変換行列 + const fov = 45; + const aspect = this.params.w / this.params.h; + const near = 0.01; + const far = 5000; + const projection = this.createProjection(fov, aspect, near, far); + + // scale + const rect = this.rectItem.getBoundingClientRect(); + const scaleX = rect.width; + const scaleY = rect.height; + const scaleZ = 1.0; + const scale = v3.create(scaleX, scaleY, scaleZ); + + // translate + const translateX = + v.x.current * this.params.w * 0.5 * this.variable.status.before + 0 * this.variable.status.after; + const translateY = + v.y.current * this.params.h * 0.5 * this.variable.status.before + 0 * this.variable.status.after; + const translateZ = (this.params.h / Math.tan((fov * Math.PI) / 360)) * 0.49 * -1; // 0.49: 0.5だとアスペクト比によっては1 ~ 2px隙間ができる... + const translate = v3.create(translateX, translateY, translateZ); + + // モデル座標変換行列 + const rotateAxis = v3.create(1.0, 0.0, 0.0); + let model = m4.translate(m4.identity(), translate); // 移動 + model = m4.scale(model, scale); + model = m4.rotate(model, 0, rotateAxis); + + // 行列を乗算して MVP 行列を生成する(掛ける順序に注意) + const vp = m4.multiply(projection, view); + const mvp = m4.multiply(vp, model); + + // モデル座標行列の逆行列を作成 + const normalMatrix = m4.transpose(m4.inverse(model)); + + const updateCurveValue = () => { + const x = v.x.current; + const y = v.y.current; + + // subtracts vector + this.curve.x.current = x - this.curve.x.target; + this.curve.y.current = y - this.curve.y.target; + + // multiply scalar + this.curve.x.current *= this.curve.power * -1; + this.curve.y.current *= this.curve.power * -1; + + this.updateUniform("uCurve", "v2", [this.curve.x.current, this.curve.y.current]); + }; + updateCurveValue(); + + // uniform更新 + this.updateUniform("uProgress", "f", this.variable.progress); + this.updateUniform("uMvpMatrix", "m4", mvp); + this.updateUniform("uNormalMatrix", "m4", normalMatrix); + this.updateUniform("uModelMatrix", "m4", model); + this.updateUniform("uEyePosition", "v3", this.camera.position); + this.updateUniform("uTime", "f", time); + this.updateUniform("uScale", "f", this.variable.scale); + this.updateUniform("uChange", "f", this.variable.change); + + const fullScaleX = 1.0 * this.variable.status.before + (this.params.w / scaleX) * this.variable.status.after; + const fullScaleY = 1.0 * this.variable.status.before + (this.params.h / scaleY) * this.variable.status.after; + this.updateUniform("uFullScale", "v2", [fullScaleX, fullScaleY]); + + const textureAspect = scaleX / scaleY; + const planeAspect = + textureAspect * this.variable.status.before + (this.params.w / this.params.h) * this.variable.status.after; + this.updateUniform("uPlaneAspect", "f", planeAspect); + this.updateUniform("uTextureAspect", "f", textureAspect); + + // VBO設定 + this.updateVBO(this.mesh.position.array, this.mesh.position.location, this.mesh.position.stride); + this.updateVBO(this.mesh.normal.array, this.mesh.normal.location, this.mesh.normal.stride); + this.updateVBO(this.mesh.uv.array, this.mesh.uv.location, this.mesh.uv.stride); + + // IBO設定 + this.updateIBO(this.mesh.ibo.data); + + // テクスチャ設定 + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, this.texture.current.img); + this.updateUniform("uTexture1", "t", 0); + + gl.activeTexture(gl.TEXTURE1); + gl.bindTexture(gl.TEXTURE_2D, this.texture.before.img); + this.updateUniform("uTexture2", "t", 1); + + gl.activeTexture(gl.TEXTURE2); + gl.bindTexture(gl.TEXTURE_2D, this.matcap); + this.updateUniform("uMatcap", "t", 2); + + gl.activeTexture(gl.TEXTURE3); + gl.bindTexture(gl.TEXTURE_2D, this.noise); + this.updateUniform("uNoise", "t", 3); + + // 描画 + gl.drawElements(gl.TRIANGLES, this.mesh.ibo.length, gl.UNSIGNED_SHORT, 0); + // gl.drawElements(gl.LINE_LOOP, this.mesh.ibo.length, gl.UNSIGNED_SHORT, 0); // debug + } + } + + toClickItem(ele, i) { + const DURATION = 1; + if (ele.classList.contains("is-active")) { + // 閉じる + ele.classList.remove("is-active"); + GSAP.to(this.variable.status, { + duration: DURATION, + before: 1, + after: 0, + }); + GSAP.to(this.variable, { + duration: DURATION, + scale: 0, + onComplete: () => { + this.isOpened = false; + }, + }); + } else { + if (this.isChange) { + this.itemList.forEach((element) => { + element.classList.remove("is-active"); + }); + ele.classList.add("is-active"); + + if (this.isOpened) { + // すでに開いている + this.isChange = false; + this.variable.change = 1.0; + const current = this.texture.current; + this.texture.before.img = current.img; + this.texture.before.aspect = current.aspect; + this.texture.current.img = this.createTexture(this.textureList[i].img); + this.texture.current.aspect = this.textureList[i].aspect; + + GSAP.to(this.variable, { + duration: DURATION, + change: 0.0, + onComplete: () => { + this.isChange = true; + }, + }); + } else { + // 今から開く + this.isOpened = true; + GSAP.to(this.variable.status, { + duration: DURATION, + before: 0, + after: 1, + }); + GSAP.to(this.variable, { + duration: DURATION, + scale: 1, + }); + } + } + } + } + + toEnterItem(i) { + if (!this.isOpened) { + const current = this.texture.current; + this.texture.before.img = current.img; + this.texture.before.aspect = current.aspect; + this.texture.current.img = this.createTexture(this.textureList[i].img); + this.texture.current.aspect = this.textureList[i].aspect; + } + } + + async init() { + console.log("🚀 ~ Plane init"); + + this.matcap = await this.loadImg("assets/img/texture/matcap.jpg"); + this.matcap = this.createTexture(this.matcap); + + this.noise = await this.loadImg("assets/img/texture/noise.png"); + this.noise = this.createTexture(this.noise); + + this.imgList = [...document.querySelectorAll(".js-img")]; + this.textureList = []; + this.textureList = await Promise.all( + this.imgList.map((ele) => { + return this.loadEleImg(ele); + }), + ); + + this.texture = { + before: { + img: this.createTexture(this.textureList[0].img), + aspect: this.textureList[0].aspect, + }, + current: { + img: this.createTexture(this.textureList[1].img), + aspect: this.textureList[1].aspect, + }, + }; + + this.itemList = [...document.querySelectorAll(".js-item")]; + this.itemList.forEach((ele, i) => { + if (this.isMatchMediaHover) { + ele.addEventListener("mouseenter", (e) => { + this.toEnterItem(i); + }); + } + ele.addEventListener("click", (e) => { + this.toClickItem(ele, i); + }); + }); + + this.rectItem = document.getElementById("js-rect"); + + this.setCulling(); + this.setDepthTest(); + this.createMesh(); + + setTimeout(() => { + const body = document.body; + body.setAttribute("data-status", "enter"); + }, 300); + + if (GUI != null) { + const gui = GUI.addFolder("plane"); + gui + .add(this.variable, "progress", 0.0, 1.0) + .name("uProgress") + .onChange((value) => { + this.variable.progress = value; + }); + } + } +} diff --git a/src/assets/js/webgl/Stage.js b/src/assets/js/webgl/Stage.js index 2693682..41a5533 100644 --- a/src/assets/js/webgl/Stage.js +++ b/src/assets/js/webgl/Stage.js @@ -1,151 +1,117 @@ -import * as THREE from "three"; +// lib +import { WebGLMath } from "./doxas/WebGLMath.js"; +import { WebGLOrbitCamera } from "./doxas/WebGLOrbitCamera"; export class Stage { - constructor(params, bool) { - // props - this.params = params; - this.bool = bool; - - // init - this.scene = null; + constructor(params, isClearColor = true, isOrbitCamera = true) { + this.gl = null; // WebGLRenderingContext + this.canvas = null; // HTMLCanvasElement this.camera = null; - this.renderer = null; - this.controls = null; - this.stats = null; - - this.init(); - } - - init() { - this.setRenderer(); - this.setScene(); - this.setCamera(); - // this.setFog(); - } + this.isClearColor = isClearColor; + this.isOrbitCamera = isOrbitCamera; + this.params = params; + this.params.color = { + r: 1, + g: 1, + b: 1, + a: 1, + }; - updateRenderer() { - this.renderer.setSize(this.params.w, this.params.h); - this.renderer.setPixelRatio(Math.min(2, window.devicePixelRatio)); + this.v3 = WebGLMath.Vec3; + this.m4 = WebGLMath.Mat4; } - setRendererLight() { - this.renderer.shadowMap.enabled = true; - this.renderer.shadowMap.needsUpdate = true; - this.renderer.shadowMap.autoUpdate = true; - this.renderer.shadowMap.type = THREE.PCFSoftShadowMap; - // this.renderer.toneMapping = THREE.CineonToneMapping; - // this.renderer.shadowMap.type = THREE.BasicShadowMap - // this.renderer.shadowMap.type = THREE.PCFShadowMap - // this.renderer.shadowMap.type = THREE.PCFSoftShadowMap - // this.renderer.shadowMap.type = THREE.VSMShadowMap - this.renderer.outputEncoding = THREE.sRGBEncoding; - this.renderer.toneMapping = THREE.ACESFilmicToneMapping; - this.renderer.toneMappingExposure = 1; //1.75 - // this.renderer.physicallyCorrectLights = true; + createWebGLContext() { + // WebGL コンテキストを初期化する + const gl = this.canvas.getContext("webgl"); + if (gl == null) { + throw new Error("webgl not supported"); + return null; + } else { + return gl; + } } - setRenderer() { - this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); - this.renderer.shadowMap.enabled = true; - // this.setRendererLight(); - this.updateRenderer(); - - const wrap = document.getElementById("world"); - wrap.appendChild(this.renderer.domElement); + /** + * canvasのサイズを設定 + * @param {number} w + * @param {number} h + */ + setSize(w = window.innerWidth, h = window.innerHeight) { + this.canvas.width = w; + this.canvas.height = h; } - setScene() { - this.scene = new THREE.Scene(); - this.scene.background = new THREE.Color("#161616"); - // if (GUI != null) { - // const scene = GUI.addFolder("scene"); - // // scene.close(); - // scene - // .addColor(this.scene, "background") - // .name("background") - // .onChange((value) => { - // this.scene.background = new THREE.Color(value); - // }); - // } - - // SceneHelper - // if (MODE) { - // this.scene.add(new THREE.GridHelper(1000, 100)); - // this.scene.add(new THREE.AxesHelper(100)); - // } + /** + * canvas内でのWebGLのviewportの設定 + * @param {number} x + * @param {number} y + * @param {number} w + * @param {number} h + */ + setViewport(x = 0, y = 0, w = this.canvas.width, h = this.canvas.height) { + this.gl.viewport(x, y, w, h); } - updateFog() { - this.scene.fog.far = this.params.shorter * 3; + /** + * クリアする色を設定 + * @param {object} color {r, g, b, a}; + */ + setClearColor(color = { r: 1, g: 1, b: 1, a: 1 }) { + this.params.color = color; + this.gl.clearColor(this.params.color.r, this.params.color.g, this.params.color.b, this.params.color.a); + this.gl.clearDepth(1.0); + // this.gl.clear(this.gl.COLOR_BUFFER_BIT); + this.gl.clear(gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT); } - setFog() { - this.scene.fog = new THREE.Fog(0x1e0101, 10, this.params.shorter * 3); - if (GUI != null) { - const fog = GUI.addFolder("fog"); - fog - .addColor(this.scene.fog, "color") - .name("color") - .onChange((value) => { - this.scene.fog.color = new THREE.Color(value); - }); - fog - .add(this.scene.fog, "near", 0, 100) - .name("near") - .onChange((value) => { - this.scene.fog.near = value; - }); - fog - .add(this.scene.fog, "far", 1, this.params.shorter * 10) - .name("far") - .onChange((value) => { - this.scene.fog.far = value; - }); + setCamera() { + if (this.isOrbitCamera) { + this.camera = new WebGLOrbitCamera(this.canvas, { + distance: 5.0, // Z 軸上の初期位置までの距離 + min: 0.1, // カメラが寄れる最小距離 + max: 10.0, // カメラが離れられる最大距離 + move: 2.0, // 右ボタンで平行移動する際の速度係数 + }); + } else { + const eye = this.v3.create(0.0, 0.0, 5.0); // カメラの位置 + const center = this.v3.create(0.0, 0.0, 0.0); // カメラの注視点 + const upDirection = this.v3.create(0.0, 1.0, 0.0); // カメラの天面の向き + this.camera = this.m4.lookAt(eye, center, upDirection); + this.camera.position = eye; } } - updateCamera() { - this.configCamera.far = (this.params.h * 0.5) / Math.tan(this.configCamera.fov * 0.5 * (Math.PI / 180)); - - this.camera.lookAt(new THREE.Vector3(0, 0, 0)); - this.camera.aspect = this.params.w / this.params.h; - this.camera.position.z = this.configCamera.far; - this.camera.far = this.configCamera.far * 4; - - this.camera.updateProjectionMatrix(); - } - - setCamera() { - this.configCamera = { - fov: 60, - aspect: this.params.w / this.params.h, - near: 1, - far: (this.params.h * 0.5) / Math.tan(60 * 0.5 * (Math.PI / 180)), - }; - - this.camera = new THREE.PerspectiveCamera( - this.configCamera.fov, - this.configCamera.aspect, - this.configCamera.near, - this.configCamera.far * 4, - ); - - this.updateCamera(); + /** + * @param {number} w + * @param {number} h + */ + resize(w = window.innerWidth, h = window.innerHeight) { + this.setSize(w, h); + this.setViewport(); } raf() { - // this.renderer.render(this.scene, this.camera); - } + if (this.isClearColor) { + this.setClearColor(); + } else { + this.gl.clearDepth(1.0); + this.gl.clear(this.gl.DEPTH_BUFFER_BIT); + } - resize(props) { - this.bool.isMatchMediaWidth = props.isMatchMediaWidth; - this.params.w = props.w; - this.params.h = props.h; - this.params.aspect = props.aspect; - this.params.shorter = props.shorter; - this.params.longer = props.longer; + this.setViewport(0, 0, this.canvas.width, this.canvas.height); + } - this.updateRenderer(); - this.updateCamera(); + /** + * @param {HTMLElement} canvas WebGLを内包するcanvas要素 + */ + init(canvas, w = window.innerWidth, h = window.innerHeight) { + console.log("🚀 ~ Stage init"); + this.canvas = canvas; + this.gl = this.createWebGLContext(this.canvas); + this.setSize(w, h); + this.setViewport(0, 0, this.canvas.width, this.canvas.height); + if (this.isClearColor) this.setClearColor(); + this.setCamera(); } } diff --git a/src/assets/js/webgl/WebGL.js b/src/assets/js/webgl/WebGL.js index e26f3f5..568ce5d 100644 --- a/src/assets/js/webgl/WebGL.js +++ b/src/assets/js/webgl/WebGL.js @@ -1,65 +1,82 @@ -// -------------------------- +// module +import { Stage } from "./Stage"; +import { ObjectPlane } from "./ObjectPlane"; -// lib +export class WebGL { + constructor(params) { + this.params = params; -// -------------------------- -import { SetControls } from "./lib/SetControls"; -import { SetStats } from "./lib/SetStats"; -import { SetGui } from "./lib/SetGui"; + this.vector = { + x: { + target: 0, + current: 0, + }, + y: { + target: 0, + current: 0, + }, + ease: 0.2, + }; -// -------------------------- + this.stage = new Stage(params, false, false); + this.stage.init(document.getElementById("webgl"), params.w, params.h); + this.plane = new ObjectPlane(params, this.stage); -// module + this.raf = this.raf.bind(this); -// -------------------------- -import { Stage } from "./Stage"; -import { Mesh } from "./Mesh"; + if (window.matchMedia("(hover: hover)").matches) { + window.addEventListener("mousemove", this.onMove.bind(this), { + passive: true, + }); + } else { + window.addEventListener("touchmove", this.onMove.bind(this), { + passive: true, + }); + } + } -export class WebGL { - constructor(body, params, bool) { - // props - this.body = body; - this.params = params; - this.bool = bool; + /** + * 線形補間 + * https://ja.wikipedia.org/wiki/%E7%B7%9A%E5%BD%A2%E8%A3%9C%E9%96%93 + * @param {number} start + * @param {number} end + * @param {number} ease + * @returns {number} 補完した値 + */ + lerp(start, end, ease) { + return start * (1 - ease) + end * ease; + } - // bool - this.isInit = false; + onMove(e) { + const x = e.touches ? e.touches[0].clientX : e.clientX; + const y = e.touches ? e.touches[0].clientY : e.clientY; - // lib - this.gui = new SetGui(); - this.stats = new SetStats(body); + this.vector.x.target = (x / this.params.w) * 2 - 1; + this.vector.y.target = -(y / this.params.h) * 2 + 1; - // module - this.stage = new Stage(params, bool); - this.mesh = new Mesh(body, params, bool, this.stage); - this.controls = new SetControls(this.stage); + this.plane.onMove(this.vector); } - raf(time) { - if (this.isInit) { - this.mesh.raf(time); - this.stage.raf(); - this.controls.update(); - this.stats.raf(); - } + raf() { + const time = performance.now() * 0.001; + + this.vector.x.current = this.lerp(this.vector.x.current, this.vector.x.target, this.vector.ease); + this.vector.y.current = this.lerp(this.vector.y.current, this.vector.y.target, this.vector.ease); + + this.stage.raf(); + this.plane.raf(time, this.vector); } - resize(props) { - if (this.isInit) { - this.bool.isMatchMediaWidth = props.isMatchMediaWidth; - this.params.w = props.w; - this.params.h = props.h; - this.params.aspect = props.aspect; - this.params.shorter = props.shorter; - this.params.longer = props.longer; + resize(params) { + this.params.w = this.params.w; + this.params.h = this.params.h; - this.mesh.resize(props); - this.stage.resize(props); - } + this.stage.resize(params.w, params.h); + this.plane.resize(params); } init() { - console.log("🚀 ~ WebGL"); - this.isInit = true; + console.log("🚀 ~ WebGL init"); + this.plane.init(); } } diff --git a/src/assets/js/webgl/doxas/WebGLMath.js b/src/assets/js/webgl/doxas/WebGLMath.js new file mode 100644 index 0000000..2574784 --- /dev/null +++ b/src/assets/js/webgl/doxas/WebGLMath.js @@ -0,0 +1,742 @@ + +/** + * ベクトルや行列演算の機能を提供する + * @class + */ +export class WebGLMath { + /** + * @static + * @type {Vec2} + */ + static get Vec2() {return Vec2;} + /** + * @static + * @type {Vec3} + */ + static get Vec3() {return Vec3;} + /** + * @static + * @type {Mat4} + */ + static get Mat4() {return Mat4;} + /** + * @static + * @type {Qtn} + */ + static get Qtn() {return Qtn;} +} + +/** + * Vec2 + * @class Vec2 + */ +class Vec2 { + /** + * 2つの要素を持つベクトルを生成する + * @param {number} [x=0] - X 要素の値 + * @param {number} [y=0] - Y 要素の値 + * @return {Float32Array} ベクトル格納用の配列 + */ + static create(x = 0, y = 0) { + const out = new Float32Array(2); + out[0] = x; + out[1] = y; + return out; + } + /** + * ベクトルの長さ(大きさ)を返す + * @param {Vec2} v - 2つの要素を持つベクトル + * @return {number} ベクトルの長さ(大きさ) + */ + static length(v) { + return Math.sqrt(v[0] * v[0] + v[1] * v[1]); + } + /** + * ベクトルを正規化した結果を返す + * @param {Vec2} v - 2つの要素を持つベクトル + * @return {Vec2} 正規化したベクトル + */ + static normalize(v) { + const n = Vec2.create(); + const l = Vec2.length(v); + if (l > 0) { + const i = 1 / l; + n[0] = v[0] * i; + n[1] = v[1] * i; + } + return n; + } + /** + * 2つのベクトルの内積の結果を返す + * @param {Vec2} v0 - 2つの要素を持つベクトル + * @param {Vec2} v1 - 2つの要素を持つベクトル + * @return {number} 内積の結果 + */ + static dot(v0, v1) { + return v0[0] * v1[0] + v0[1] * v1[1]; + } + /** + * 2つのベクトルの外積の結果を返す + * @param {Vec2} v0 - 2つの要素を持つベクトル + * @param {Vec2} v1 - 2つの要素を持つベクトル + * @return {number} 外積の結果 + */ + static cross(v0, v1) { + const n = Vec2.create(); + return v0[0] * v1[1] - v0[1] * v1[0]; + } +} + +/** + * Vec3 + * @class Vec3 + */ +class Vec3 { + /** + * 3つの要素を持つベクトルを生成する + * @param {number} [x=0] - X 要素の値 + * @param {number} [y=0] - Y 要素の値 + * @param {number} [z=0] - Z 要素の値 + * @return {Float32Array} ベクトル格納用の配列 + */ + static create(x = 0, y = 0, z = 0) { + const out = new Float32Array(3); + out[0] = x; + out[1] = y; + out[2] = z; + return out; + } + /** + * ベクトルの長さ(大きさ)を返す + * @param {Vec3} v - 3つの要素を持つベクトル + * @return {number} ベクトルの長さ(大きさ) + */ + static length(v) { + return Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); + } + /** + * ベクトルを正規化した結果を返す + * @param {Vec3} v - 3つの要素を持つベクトル + * @return {Vec3} 正規化したベクトル + */ + static normalize(v) { + const n = Vec3.create(); + const l = Vec3.length(v); + if (l > 0) { + const i = 1 / l; + n[0] = v[0] * i; + n[1] = v[1] * i; + n[2] = v[2] * i; + } + return n; + } + /** + * 2つのベクトルの内積の結果を返す + * @param {Vec3} v0 - 3つの要素を持つベクトル + * @param {Vec3} v1 - 3つの要素を持つベクトル + * @return {number} 内積の結果 + */ + static dot(v0, v1) { + return v0[0] * v1[0] + v0[1] * v1[1] + v0[2] * v1[2]; + } + /** + * 2つのベクトルの外積の結果を返す + * @param {Vec3} v0 - 3つの要素を持つベクトル + * @param {Vec3} v1 - 3つの要素を持つベクトル + * @return {Vec3} 外積の結果 + */ + static cross(v0, v1) { + return Vec3.create( + v0[1] * v1[2] - v0[2] * v1[1], + v0[2] * v1[0] - v0[0] * v1[2], + v0[0] * v1[1] - v0[1] * v1[0], + ); + } + /** + * 3つのベクトルから面法線を求めて返す + * @param {Vec3} v0 - 3つの要素を持つベクトル + * @param {Vec3} v1 - 3つの要素を持つベクトル + * @param {Vec3} v2 - 3つの要素を持つベクトル + * @return {Vec3} 面法線ベクトル + */ + static faceNormal(v0, v1, v2) { + const vec0 = Vec3.create(v1[0] - v0[0], v1[1] - v0[1], v1[2] - v0[2]); + const vec1 = Vec3.create(v2[0] - v0[0], v2[1] - v0[1], v2[2] - v0[2]); + const n = Vec3.create( + vec0[1] * vec1[2] - vec0[2] * vec1[1], + vec0[2] * vec1[0] - vec0[0] * vec1[2], + vec0[0] * vec1[1] - vec0[1] * vec1[0], + ); + return Vec3.normalize(n); + } +} + +/** + * Mat4 + * @class Mat4 + */ +class Mat4 { + /** + * 4x4 の正方行列を生成する + * @return {Float32Array} 行列格納用の配列 + */ + static create() { + return new Float32Array(16); + } + /** + * 行列を単位化する(参照に注意) + * @param {Mat4} dest - 単位化する行列 + * @return {Mat4} 単位化した行列 + */ + static identity(dest) { + const out = dest == null ? Mat4.create() : dest; + out[0] = 1; out[1] = 0; out[2] = 0; out[3] = 0; + out[4] = 0; out[5] = 1; out[6] = 0; out[7] = 0; + out[8] = 0; out[9] = 0; out[10] = 1; out[11] = 0; + out[12] = 0; out[13] = 0; out[14] = 0; out[15] = 1; + return out; + } + /** + * 行列を乗算する(参照に注意・戻り値としても結果を返す) + * @param {Mat4} mat0 - 乗算される行列 + * @param {Mat4} mat1 - 乗算する行列 + * @param {Mat4} [dest] - 乗算結果を格納する行列 + * @return {Mat4} 乗算結果の行列 + */ + static multiply(mat0, mat1, dest) { + const out = dest == null ? Mat4.create() : dest; + const a = mat0[0], b = mat0[1], c = mat0[2], d = mat0[3], + e = mat0[4], f = mat0[5], g = mat0[6], h = mat0[7], + i = mat0[8], j = mat0[9], k = mat0[10], l = mat0[11], + m = mat0[12], n = mat0[13], o = mat0[14], p = mat0[15], + A = mat1[0], B = mat1[1], C = mat1[2], D = mat1[3], + E = mat1[4], F = mat1[5], G = mat1[6], H = mat1[7], + I = mat1[8], J = mat1[9], K = mat1[10], L = mat1[11], + M = mat1[12], N = mat1[13], O = mat1[14], P = mat1[15]; + out[0] = A * a + B * e + C * i + D * m; + out[1] = A * b + B * f + C * j + D * n; + out[2] = A * c + B * g + C * k + D * o; + out[3] = A * d + B * h + C * l + D * p; + out[4] = E * a + F * e + G * i + H * m; + out[5] = E * b + F * f + G * j + H * n; + out[6] = E * c + F * g + G * k + H * o; + out[7] = E * d + F * h + G * l + H * p; + out[8] = I * a + J * e + K * i + L * m; + out[9] = I * b + J * f + K * j + L * n; + out[10] = I * c + J * g + K * k + L * o; + out[11] = I * d + J * h + K * l + L * p; + out[12] = M * a + N * e + O * i + P * m; + out[13] = M * b + N * f + O * j + P * n; + out[14] = M * c + N * g + O * k + P * o; + out[15] = M * d + N * h + O * l + P * p; + return out; + } + /** + * 行列に拡大縮小を適用する(参照に注意・戻り値としても結果を返す) + * @param {Mat4} mat - 適用を受ける行列 + * @param {Vec3} vec - XYZ の各軸に対して拡縮を適用する値の行列 + * @param {Mat4} [dest] - 結果を格納する行列 + * @return {Mat4} 結果の行列 + */ + static scale(mat, vec, dest) { + const out = dest == null ? Mat4.create() : dest; + out[0] = mat[0] * vec[0]; + out[1] = mat[1] * vec[0]; + out[2] = mat[2] * vec[0]; + out[3] = mat[3] * vec[0]; + out[4] = mat[4] * vec[1]; + out[5] = mat[5] * vec[1]; + out[6] = mat[6] * vec[1]; + out[7] = mat[7] * vec[1]; + out[8] = mat[8] * vec[2]; + out[9] = mat[9] * vec[2]; + out[10] = mat[10] * vec[2]; + out[11] = mat[11] * vec[2]; + out[12] = mat[12]; + out[13] = mat[13]; + out[14] = mat[14]; + out[15] = mat[15]; + return out; + } + /** + * 行列に平行移動を適用する(参照に注意・戻り値としても結果を返す) + * @param {Mat4} mat - 適用を受ける行列 + * @param {Vec3} vec - XYZ の各軸に対して平行移動を適用する値の行列 + * @param {Mat4} [dest] - 結果を格納する行列 + * @return {Mat4} 結果の行列 + */ + static translate(mat, vec, dest) { + const out = dest == null ? Mat4.create() : dest; + out[0] = mat[0]; out[1] = mat[1]; out[2] = mat[2]; out[3] = mat[3]; + out[4] = mat[4]; out[5] = mat[5]; out[6] = mat[6]; out[7] = mat[7]; + out[8] = mat[8]; out[9] = mat[9]; out[10] = mat[10]; out[11] = mat[11]; + out[12] = mat[0] * vec[0] + mat[4] * vec[1] + mat[8] * vec[2] + mat[12]; + out[13] = mat[1] * vec[0] + mat[5] * vec[1] + mat[9] * vec[2] + mat[13]; + out[14] = mat[2] * vec[0] + mat[6] * vec[1] + mat[10] * vec[2] + mat[14]; + out[15] = mat[3] * vec[0] + mat[7] * vec[1] + mat[11] * vec[2] + mat[15]; + return out; + } + /** + * 行列に回転を適用する(参照に注意・戻り値としても結果を返す) + * @param {Mat4} mat - 適用を受ける行列 + * @param {number} angle - 回転量を表す値(ラジアン) + * @param {Vec3} axis - 回転の軸 + * @param {Mat4} [dest] - 結果を格納する行列 + * @return {Mat4} 結果の行列 + */ + static rotate(mat, angle, axis, dest) { + let out = dest == null ? Mat4.create() : dest; + const sq = Math.sqrt(axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]); + if (!sq) { + return null; + } + let a = axis[0], b = axis[1], c = axis[2]; + if (sq != 1) { + const inv = 1 / sq; + a *= inv; + b *= inv; + c *= inv; + } + const d = Math.sin(angle), e = Math.cos(angle), f = 1 - e, + g = mat[0], h = mat[1], i = mat[2], j = mat[3], + k = mat[4], l = mat[5], m = mat[6], n = mat[7], + o = mat[8], p = mat[9], q = mat[10], r = mat[11], + s = a * a * f + e, + t = b * a * f + c * d, + u = c * a * f - b * d, + v = a * b * f - c * d, + w = b * b * f + e, + x = c * b * f + a * d, + y = a * c * f + b * d, + z = b * c * f - a * d, + A = c * c * f + e; + if (angle) { + if (mat != out) { + out[12] = mat[12]; + out[13] = mat[13]; + out[14] = mat[14]; + out[15] = mat[15]; + } + } else { + out = mat; + } + out[0] = g * s + k * t + o * u; + out[1] = h * s + l * t + p * u; + out[2] = i * s + m * t + q * u; + out[3] = j * s + n * t + r * u; + out[4] = g * v + k * w + o * x; + out[5] = h * v + l * w + p * x; + out[6] = i * v + m * w + q * x; + out[7] = j * v + n * w + r * x; + out[8] = g * y + k * z + o * A; + out[9] = h * y + l * z + p * A; + out[10] = i * y + m * z + q * A; + out[11] = j * y + n * z + r * A; + return out; + } + /** + * ビュー座標変換行列を生成する(参照に注意・戻り値としても結果を返す) + * @param {Vec3} eye - 視点位置 + * @param {Vec3} center - 注視点 + * @param {Vec3} up - 上方向を示すベクトル + * @param {Mat4} [dest] - 結果を格納する行列 + * @return {Mat4} 結果の行列 + */ + static lookAt(eye, center, up, dest) { + const out = dest == null ? Mat4.create() : dest; + const eyeX = eye[0], eyeY = eye[1], eyeZ = eye[2], + centerX = center[0], centerY = center[1], centerZ = center[2], + upX = up[0], upY = up[1], upZ = up[2]; + if (eyeX == centerX && eyeY == centerY && eyeZ == centerZ) { + return Mat4.identity(out); + } + let x0, x1, x2, y0, y1, y2, z0, z1, z2, l; + z0 = eyeX - centerX; + z1 = eyeY - centerY; + z2 = eyeZ - centerZ; + l = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2); + z0 *= l; + z1 *= l; + z2 *= l; + x0 = upY * z2 - upZ * z1; + x1 = upZ * z0 - upX * z2; + x2 = upX * z1 - upY * z0; + l = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2); + if (!l) { + x0 = 0; x1 = 0; x2 = 0; + } else { + l = 1 / l; + x0 *= l; x1 *= l; x2 *= l; + } + y0 = z1 * x2 - z2 * x1; y1 = z2 * x0 - z0 * x2; y2 = z0 * x1 - z1 * x0; + l = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2); + if (!l) { + y0 = 0; y1 = 0; y2 = 0; + } else { + l = 1 / l; + y0 *= l; y1 *= l; y2 *= l; + } + out[0] = x0; out[1] = y0; out[2] = z0; out[3] = 0; + out[4] = x1; out[5] = y1; out[6] = z1; out[7] = 0; + out[8] = x2; out[9] = y2; out[10] = z2; out[11] = 0; + out[12] = -(x0 * eyeX + x1 * eyeY + x2 * eyeZ); + out[13] = -(y0 * eyeX + y1 * eyeY + y2 * eyeZ); + out[14] = -(z0 * eyeX + z1 * eyeY + z2 * eyeZ); + out[15] = 1; + return out; + } + /** + * 透視投影変換行列を生成する(参照に注意・戻り値としても結果を返す) + * @param {number} fovy - 視野角(度数法) + * @param {number} aspect - アスペクト比(幅 / 高さ) + * @param {number} near - ニアクリップ面までの距離 + * @param {number} far - ファークリップ面までの距離 + * @param {Mat4} [dest] - 結果を格納する行列 + * @return {Mat4} 結果の行列 + */ + static perspective(fovy, aspect, near, far, dest) { + const out = dest == null ? Mat4.create() : dest; + const t = near * Math.tan(fovy * Math.PI / 360); + const r = t * aspect; + const a = r * 2, b = t * 2, c = far - near; + out[0] = near * 2 / a; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = near * 2 / b; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = -(far + near) / c; + out[11] = -1; + out[12] = 0; + out[13] = 0; + out[14] = -(far * near * 2) / c; + out[15] = 0; + return out; + } + /** + * 正射影投影変換行列を生成する(参照に注意・戻り値としても結果を返す) + * @param {number} left - 左端 + * @param {number} right - 右端 + * @param {number} top - 上端 + * @param {number} bottom - 下端 + * @param {number} near - ニアクリップ面までの距離 + * @param {number} far - ファークリップ面までの距離 + * @param {Mat4} [dest] - 結果を格納する行列 + * @return {Mat4} 結果の行列 + */ + static ortho(left, right, top, bottom, near, far, dest) { + const out = dest == null ? Mat4.create() : dest; + const h = right - left; + const v = top - bottom; + const d = far - near; + out[0] = 2 / h; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = 2 / v; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = -2 / d; + out[11] = 0; + out[12] = -(left + right) / h; + out[13] = -(top + bottom) / v; + out[14] = -(far + near) / d; + out[15] = 1; + return out; + } + /** + * 転置行列を生成する(参照に注意・戻り値としても結果を返す) + * @param {Mat4} mat - 適用する行列 + * @param {Mat4} [dest] - 結果を格納する行列 + * @return {Mat4} 結果の行列 + */ + static transpose(mat, dest) { + const out = dest == null ? Mat4.create() : dest; + out[0] = mat[0]; out[1] = mat[4]; + out[2] = mat[8]; out[3] = mat[12]; + out[4] = mat[1]; out[5] = mat[5]; + out[6] = mat[9]; out[7] = mat[13]; + out[8] = mat[2]; out[9] = mat[6]; + out[10] = mat[10]; out[11] = mat[14]; + out[12] = mat[3]; out[13] = mat[7]; + out[14] = mat[11]; out[15] = mat[15]; + return out; + } + /** + * 逆行列を生成する(参照に注意・戻り値としても結果を返す) + * @param {Mat4} mat - 適用する行列 + * @param {Mat4} [dest] - 結果を格納する行列 + * @return {Mat4} 結果の行列 + */ + static inverse(mat, dest) { + const out = dest == null ? Mat4.create() : dest; + const a = mat[0], b = mat[1], c = mat[2], d = mat[3], + e = mat[4], f = mat[5], g = mat[6], h = mat[7], + i = mat[8], j = mat[9], k = mat[10], l = mat[11], + m = mat[12], n = mat[13], o = mat[14], p = mat[15], + q = a * f - b * e, r = a * g - c * e, + s = a * h - d * e, t = b * g - c * f, + u = b * h - d * f, v = c * h - d * g, + w = i * n - j * m, x = i * o - k * m, + y = i * p - l * m, z = j * o - k * n, + A = j * p - l * n, B = k * p - l * o, + ivd = 1 / (q * B - r * A + s * z + t * y - u * x + v * w); + out[0] = ( f * B - g * A + h * z) * ivd; + out[1] = (-b * B + c * A - d * z) * ivd; + out[2] = ( n * v - o * u + p * t) * ivd; + out[3] = (-j * v + k * u - l * t) * ivd; + out[4] = (-e * B + g * y - h * x) * ivd; + out[5] = ( a * B - c * y + d * x) * ivd; + out[6] = (-m * v + o * s - p * r) * ivd; + out[7] = ( i * v - k * s + l * r) * ivd; + out[8] = ( e * A - f * y + h * w) * ivd; + out[9] = (-a * A + b * y - d * w) * ivd; + out[10] = ( m * u - n * s + p * q) * ivd; + out[11] = (-i * u + j * s - l * q) * ivd; + out[12] = (-e * z + f * x - g * w) * ivd; + out[13] = ( a * z - b * x + c * w) * ivd; + out[14] = (-m * t + n * r - o * q) * ivd; + out[15] = ( i * t - j * r + k * q) * ivd; + return out; + } + /** + * 行列にベクトルを乗算する(ベクトルに行列を適用する) + * @param {Mat4} mat - 適用する行列 + * @param {Array.} vec - 乗算するベクトル(4 つの要素を持つ配列) + * @return {Float32Array} 結果のベクトル + */ + static toVecIV(mat, vec) { + const a = mat[0], b = mat[1], c = mat[2], d = mat[3], + e = mat[4], f = mat[5], g = mat[6], h = mat[7], + i = mat[8], j = mat[9], k = mat[10], l = mat[11], + m = mat[12], n = mat[13], o = mat[14], p = mat[15], + x = vec[0], y = vec[1], z = vec[2], w = vec[3]; + const out = new Float32Array(4); + out[0] = x * a + y * e + z * i + w * m; + out[1] = x * b + y * f + z * j + w * n; + out[2] = x * c + y * g + z * k + w * o; + out[3] = x * d + y * h + z * l + w * p; + return out; + } + /** + * MVP 行列に相当する行列を受け取りベクトルを変換して返す + * @param {Mat4} mat - MVP 行列 + * @param {Vec3} vec - MVP 行列と乗算するベクトル + * @param {number} width - ビューポートの幅 + * @param {number} height - ビューポートの高さ + * @return {Vec2} 結果のベクトル + */ + static screenPositionFromMvp(mat, vec, width, height) { + const halfWidth = width * 0.5; + const halfHeight = height * 0.5; + const v = Mat4.toVecIV(mat, [vec[0], vec[1], vec[2], 1.0]); + if (v[3] <= 0.0) { + return [NaN, NaN]; + } + v[0] /= v[3]; + v[1] /= v[3]; + v[2] /= v[3]; + const out = Vec2.create(); + out[0] = halfWidth + v[0] * halfWidth, + out[1] = halfHeight - v[1] * halfHeight + return out; + } +} + +/** + * Qtn + * @class Qtn + */ +class Qtn { + /** + * 4 つの要素からなるクォータニオンのデータ構造を生成する(虚部 x, y, z, 実部 w の順序で定義) + * @return {Float32Array} クォータニオンデータ格納用の配列 + */ + static create() { + return new Float32Array(4); + } + /** + * クォータニオンを初期化する(参照に注意) + * @param {Qtn} dest - 初期化するクォータニオン + * @return {Qtn} 結果のクォータニオン + */ + static identity(dest) { + const out = dest == null ? Qtn.create() : dest; + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; + } + /** + * 共役四元数を生成して返す(参照に注意・戻り値としても結果を返す) + * @param {Qtn} qtn - 元となるクォータニオン + * @param {Qtn} [dest] - 結果を格納するクォータニオン + * @return {Qtn} 結果のクォータニオン + */ + static inverse(qtn, dest) { + const out = dest == null ? Qtn.create() : dest; + out[0] = -qtn[0]; + out[1] = -qtn[1]; + out[2] = -qtn[2]; + out[3] = qtn[3]; + return out; + } + /** + * 虚部を正規化した結果を返す + * @param {Qtn} qtn - 元となるクォータニオン + * @return {Qtn} 結果のクォータニオン + */ + static normalize(qtn) { + const out = Qtn.create(); + const x = qtn[0], y = qtn[1], z = qtn[2]; + const l = Math.sqrt(x * x + y * y + z * z); + if (l > 0) { + const i = 1 / l; + out[0] = x * i; + out[1] = y * i; + out[2] = z * i; + } + return out; + } + /** + * クォータニオンを乗算した結果を返す(参照に注意・戻り値としても結果を返す) + * @param {Qtn} qtn0 - 乗算されるクォータニオン + * @param {Qtn} qtn1 - 乗算するクォータニオン + * @param {Qtn} [dest] - 結果を格納するクォータニオン + * @return {Qtn} 結果のクォータニオン + */ + static multiply(qtn0, qtn1, dest) { + const out = dest == null ? Qtn.create() : dest; + const ax = qtn0[0], ay = qtn0[1], az = qtn0[2], aw = qtn0[3]; + const bx = qtn1[0], by = qtn1[1], bz = qtn1[2], bw = qtn1[3]; + out[0] = ax * bw + aw * bx + ay * bz - az * by; + out[1] = ay * bw + aw * by + az * bx - ax * bz; + out[2] = az * bw + aw * bz + ax * by - ay * bx; + out[3] = aw * bw - ax * bx - ay * by - az * bz; + return out; + } + /** + * クォータニオンに回転を適用し返す(参照に注意・戻り値としても結果を返す) + * @param {number} angle - 回転する量(ラジアン) + * @param {Vec3} axis - 3つの要素を持つ軸ベクトル + * @param {Qtn} [dest] - 結果を格納するクォータニオン + * @return {Qtn} 結果のクォータニオン + */ + static rotate(angle, axis, dest) { + const out = dest == null ? Qtn.create() : dest; + let a = axis[0], b = axis[1], c = axis[2]; + const sq = Math.sqrt(axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]); + if (sq !== 0) { + const l = 1 / sq; + a *= l; + b *= l; + c *= l; + } + const s = Math.sin(angle * 0.5); + out[0] = a * s; + out[1] = b * s; + out[2] = c * s; + out[3] = Math.cos(angle * 0.5); + return out; + } + /** + * ベクトルにクォータニオンを適用し返す(参照に注意・戻り値としても結果を返す) + * @param {Vec3} vec - 3つの要素を持つベクトル + * @param {Qtn} qtn - クォータニオン + * @param {Vec3} [dest] - 3つの要素を持つベクトル + * @return {Vec3} 結果のベクトル + */ + static toVecIII(vec, qtn, dest) { + const out = dest == null ? Vec3.create() : dest; + const qp = Qtn.create(); + const qq = Qtn.create(); + const qr = Qtn.create(); + Qtn.inverse(qtn, qr); + qp[0] = vec[0]; + qp[1] = vec[1]; + qp[2] = vec[2]; + Qtn.multiply(qr, qp, qq); + Qtn.multiply(qq, qtn, qr); + out[0] = qr[0]; + out[1] = qr[1]; + out[2] = qr[2]; + return out; + } + /** + * 4x4 行列にクォータニオンを適用し返す(参照に注意・戻り値としても結果を返す) + * @param {Qtn} qtn - クォータニオン + * @param {Mat4} [dest] - 4x4 行列 + * @return {Mat4} 結果の行列 + */ + static toMatIV(qtn, dest) { + const out = dest == null ? Mat4.create() : dest; + const x = qtn[0], y = qtn[1], z = qtn[2], w = qtn[3]; + const x2 = x + x, y2 = y + y, z2 = z + z; + const xx = x * x2, xy = x * y2, xz = x * z2; + const yy = y * y2, yz = y * z2, zz = z * z2; + const wx = w * x2, wy = w * y2, wz = w * z2; + out[0] = 1 - (yy + zz); + out[1] = xy - wz; + out[2] = xz + wy; + out[3] = 0; + out[4] = xy + wz; + out[5] = 1 - (xx + zz); + out[6] = yz - wx; + out[7] = 0; + out[8] = xz - wy; + out[9] = yz + wx; + out[10] = 1 - (xx + yy); + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; + } + /** + * 2つのクォータニオンの球面線形補間を行った結果を返す(参照に注意・戻り値としても結果を返す) + * @param {Qtn} qtn0 - クォータニオン + * @param {Qtn} qtn1 - クォータニオン + * @param {number} time - 補間係数(0.0 から 1.0 で指定) + * @param {Qtn} [dest] - 結果を格納するクォータニオン + * @return {Qtn} 結果のクォータニオン + */ + static slerp(qtn0, qtn1, time, dest) { + const out = dest == null ? Qtn.create() : dest; + const ht = qtn0[0] * qtn1[0] + qtn0[1] * qtn1[1] + qtn0[2] * qtn1[2] + qtn0[3] * qtn1[3]; + let hs = 1.0 - ht * ht; + if (hs <= 0.0) { + out[0] = qtn0[0]; + out[1] = qtn0[1]; + out[2] = qtn0[2]; + out[3] = qtn0[3]; + } else { + hs = Math.sqrt(hs); + if (Math.abs(hs) < 0.0001) { + out[0] = (qtn0[0] * 0.5 + qtn1[0] * 0.5); + out[1] = (qtn0[1] * 0.5 + qtn1[1] * 0.5); + out[2] = (qtn0[2] * 0.5 + qtn1[2] * 0.5); + out[3] = (qtn0[3] * 0.5 + qtn1[3] * 0.5); + } else { + const ph = Math.acos(ht); + const pt = ph * time; + const t0 = Math.sin(ph - pt) / hs; + const t1 = Math.sin(pt) / hs; + out[0] = qtn0[0] * t0 + qtn1[0] * t1; + out[1] = qtn0[1] * t0 + qtn1[1] * t1; + out[2] = qtn0[2] * t0 + qtn1[2] * t1; + out[3] = qtn0[3] * t0 + qtn1[3] * t1; + } + } + return out; + } +} + diff --git a/src/assets/js/webgl/doxas/WebGLOrbitCamera.js b/src/assets/js/webgl/doxas/WebGLOrbitCamera.js new file mode 100644 index 0000000..423b718 --- /dev/null +++ b/src/assets/js/webgl/doxas/WebGLOrbitCamera.js @@ -0,0 +1,193 @@ +import { WebGLMath } from "./WebGLMath.js"; + +// 短く書けるようにローカル変数に入れておく +const Vec2 = WebGLMath.Vec2; +const Vec3 = WebGLMath.Vec3; +const Mat4 = WebGLMath.Mat4; +const Qtn = WebGLMath.Qtn; + +/** + * three.js の OrbitControls に似た挙動のカメラ操作用ユーティリティクラス + * @class + */ +export class WebGLOrbitCamera { + /** @type {number} */ + static get DEFAULT_DISTANCE() { + return 5.0; + } + /** @type {number} */ + static get DEFAULT_MIN_DISTANCE() { + return 1.0; + } + /** @type {number} */ + static get DEFAULT_MAX_DISTANCE() { + return 10.0; + } + /** @type {number} */ + static get DEFAULT_MOVE_SCALE() { + return 2.0; + } + + /** + * @constructor + * @param {HTMLElement} target - イベントを設定するターゲットエレメント + * @param {object} [option={}] + * @property {number} option.distance - カメラの原点からの距離 + * @property {number} option.min - カメラが原点に寄れる最小距離 + * @property {number} option.max - カメラが原点から離れられる最大距離 + * @property {number} option.move - カメラが平行移動する際のスケール + */ + constructor(target, option = {}) { + this.target = target; + this.distance = option.distance || WebGLOrbitCamera.DEFAULT_DISTANCE; + this.minDistance = option.min || WebGLOrbitCamera.DEFAULT_MIN_DISTANCE; + this.maxDistance = option.max || WebGLOrbitCamera.DEFAULT_MAX_DISTANCE; + this.moveScale = option.move || WebGLOrbitCamera.DEFAULT_MOVE_SCALE; + this.position = Vec3.create(0.0, 0.0, this.distance); + this.center = Vec3.create(0.0, 0.0, 0.0); + this.upDirection = Vec3.create(0.0, 1.0, 0.0); + this.defaultPosition = Vec3.create(0.0, 0.0, this.distance); + this.defaultCenter = Vec3.create(0.0, 0.0, 0.0); + this.defaultUpDirection = Vec3.create(0.0, 1.0, 0.0); + this.movePosition = Vec3.create(0.0, 0.0, 0.0); + this.rotateX = 0.0; + this.rotateY = 0.0; + this.scale = 0.0; + this.isDown = false; + this.prevPosition = Vec2.create(0, 0); + this.offsetPosition = Vec2.create(0, 0); + this.qt = Qtn.create(); + this.qtx = Qtn.create(); + this.qty = Qtn.create(); + + // self binding + this.mouseInteractionStart = this.mouseInteractionStart.bind(this); + this.mouseInteractionMove = this.mouseInteractionMove.bind(this); + this.mouseInteractionEnd = this.mouseInteractionEnd.bind(this); + this.wheelScroll = this.wheelScroll.bind(this); + + // event + this.target.addEventListener( + "mousedown", + this.mouseInteractionStart, + false + ); + this.target.addEventListener("mousemove", this.mouseInteractionMove, false); + this.target.addEventListener("mouseup", this.mouseInteractionEnd, false); + this.target.addEventListener("wheel", this.wheelScroll, false); + this.target.addEventListener( + "contextmenu", + (event) => { + event.preventDefault(); + }, + false + ); + } + + /** + * マウスボタンが押された際のイベント + */ + mouseInteractionStart(event) { + this.isDown = true; + const bound = this.target.getBoundingClientRect(); + this.prevPosition = Vec2.create( + event.clientX - bound.left, + event.clientY - bound.top + ); + } + + /** + * マウスが移動した際のイベント + */ + mouseInteractionMove(event) { + if (this.isDown !== true) { + return; + } + const bound = this.target.getBoundingClientRect(); + const w = bound.width; + const h = bound.height; + const x = event.clientX - bound.left; + const y = event.clientY - bound.top; + const s = 1.0 / Math.min(w, h); + this.offsetPosition = Vec2.create( + x - this.prevPosition[0], + y - this.prevPosition[1] + ); + this.prevPosition = Vec2.create(x, y); + switch (event.buttons) { + case 1: // 左ボタン + this.rotateX += this.offsetPosition[0] * s; + this.rotateY += this.offsetPosition[1] * s; + this.rotateX = this.rotateX % 1.0; + this.rotateY = Math.min(Math.max(this.rotateY % 1.0, -0.25), 0.25); + break; + case 2: // 右ボタン + const eyeOffset = Vec3.create( + this.offsetPosition[0], + -this.offsetPosition[1], + 0.0 + ); + const rotateEye = Qtn.toVecIII(eyeOffset, this.qt); + this.movePosition[0] -= rotateEye[0] * s * this.moveScale; + this.movePosition[1] -= rotateEye[1] * s * this.moveScale; + this.movePosition[2] -= rotateEye[2] * s * this.moveScale; + break; + } + } + + /** + * マウスボタンが離された際のイベント + */ + mouseInteractionEnd(event) { + this.isDown = false; + } + + /** + * スクロール操作に対するイベント + */ + wheelScroll(event) { + const w = event.wheelDelta; + if (w > 0) { + this.scale = -0.5; + } else if (w < 0) { + this.scale = 0.5; + } + } + + /** + * 現在のパラメータからビュー行列を生成して返す + * @return {Mat4} + */ + update() { + const PI2 = Math.PI * 2.0; + const v = Vec3.create(1.0, 0.0, 0.0); + const u = Vec3.create(0.0, 1.0, 0.0); + // scale + this.scale *= 0.7; + this.distance += this.scale; + this.distance = Math.min( + Math.max(this.distance, this.minDistance), + this.maxDistance + ); + this.defaultPosition[2] = this.distance; + // rotate + Qtn.identity(this.qt); + Qtn.identity(this.qtx); + Qtn.identity(this.qty); + Qtn.rotate(this.rotateX * PI2, u, this.qtx); + Qtn.toVecIII(v, this.qtx, v); + Qtn.rotate(this.rotateY * PI2, v, this.qty); + Qtn.multiply(this.qtx, this.qty, this.qt); + Qtn.toVecIII(this.defaultPosition, this.qt, this.position); + Qtn.toVecIII(this.defaultUpDirection, this.qt, this.upDirection); + // translate + this.position[0] += this.movePosition[0]; + this.position[1] += this.movePosition[1]; + this.position[2] += this.movePosition[2]; + this.center[0] = this.defaultCenter[0] + this.movePosition[0]; + this.center[1] = this.defaultCenter[1] + this.movePosition[1]; + this.center[2] = this.defaultCenter[2] + this.movePosition[2]; + + return Mat4.lookAt(this.position, this.center, this.upDirection); + } +} diff --git a/src/assets/js/webgl/lib/SetControls.js b/src/assets/js/webgl/lib/SetControls.js deleted file mode 100644 index c16b8d4..0000000 --- a/src/assets/js/webgl/lib/SetControls.js +++ /dev/null @@ -1,26 +0,0 @@ -import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; - -export class SetControls { - constructor(stage) { - // this.controls = new OrbitControls(stage.camera, stage.renderer.domElement); - // this.controls.enableDamping = true; - // this.controls.dampingFactor = 0.2; - // if (GUI != null && this.controls != null) this.addGui(); - } - - addGui() { - const controls = GUI.addFolder("controls"); - controls.close(); - controls.add(this.controls, "enabled").onChange((value) => { - this.controls.enabled = value; - }); - } - - disableDamping() { - this.controls.enableDamping = false; - } - - update() { - if (this.controls != null) this.controls.update(); - } -} diff --git a/src/assets/js/webgl/lib/SetStats.js b/src/assets/js/webgl/lib/SetStats.js deleted file mode 100644 index 9582c42..0000000 --- a/src/assets/js/webgl/lib/SetStats.js +++ /dev/null @@ -1,26 +0,0 @@ -import Stats from "three/examples/jsm/libs/stats.module"; - -export class SetStats { - constructor(body = document.body) { - this.body = body; - - this.stats = null; - // if (MODE) { - // this.stats = new Stats(); - - // const ele = this.stats.domElement; - // const eleStyle = ele.style; - // eleStyle.position = "fixed"; - // eleStyle.top = "0px"; - // eleStyle.left = "0px"; - // eleStyle.right = "initial"; - // eleStyle.bottom = "initial"; - // eleStyle.zIndex = "9999"; - // this.body.appendChild(ele); - // } - } - - raf() { - if (this.stats != null) this.stats.update(); - } -} diff --git a/src/assets/js/webgl/utility/TextureLoad.js b/src/assets/js/webgl/utility/TextureLoad.js deleted file mode 100644 index 90a8f19..0000000 --- a/src/assets/js/webgl/utility/TextureLoad.js +++ /dev/null @@ -1,9 +0,0 @@ -import * as THREE from "three"; - -export function TextureLoad(src) { - const texture = new THREE.TextureLoader().load(src); - // texture.encoding = THREE.GammaEncoding; - // texture.encoding = THREE.sRGBEncoding; - // texture.encoding = THREE.LinearEncoding; - return texture; -} diff --git a/src/assets/scss/app.scss b/src/assets/scss/app.scss index 0beff03..c35c8c8 100644 --- a/src/assets/scss/app.scss +++ b/src/assets/scss/app.scss @@ -11,7 +11,6 @@ html, body { - overflow: hidden; background: var(--black); } @@ -36,7 +35,6 @@ body { z-index: 0; width: 100vw; height: 100vh; - height: calc(var(--vh, 1vh) * 100); canvas { cursor: grab; &:active { @@ -55,369 +53,188 @@ body { // -------------------------- -// wheel示唆 +// コンテナ // -------------------------- -.c-wheelSuggestion { - pointer-events: none; - user-select: none; - position: fixed; - left: max(16px, liquid(16)); - bottom: max(48px, liquid(48)); - z-index: 100; - width: max-content; - height: max-content; - padding-left: max(8px, liquid(8)); - @include sp_w() { - right: min(16px, liquid(16)); - padding-left: min(8px, liquid(8)); - } - @media (hover: none) { - display: none; - } - +.l-container { + position: relative; + z-index: 10; opacity: 0; body[data-status="enter"] & { - transition: 0.6s 0.4s ease opacity; opacity: 1; + transition: 0.3s ease opacity; + } +} +.l-container__head { + border-left: solid 2px var(--white-solid); + border-right: solid 2px var(--white-solid); + border-top: solid 2px var(--white-solid); + border-bottom: solid 1px var(--white-solid); + box-sizing: border-box; + padding: 32px; + display: flex; + flex-wrap: wrap; + justify-content: space-between; + align-items: flex-end; + @include sp_w() { + padding: 24px 24px; } } -.c-wheelSuggestion__text { +.c-title { + width: 100%; color: var(--white); - font-family: var(--ja); - line-height: 100%; - font-size: max(12px, liquid(12)); + font-size: 84px; + font-weight: 700; + -webkit-text-stroke: 4px var(--white); + text-stroke: 4px var(--white); line-height: 100%; - font-weight: bold; - writing-mode: vertical-rl; @include sp_w() { - font-size: min(12px, liquid(12)); + font-size: 64px; } } -.c-wheelSuggestion__line { - position: absolute; - top: 0; - left: 0; - bottom: 0; - margin: auto; - height: 100%; - width: 2px; - background: var(--white); - animation: 3s $easeinout isLoopY infinite; - transform: scale(1, 1); - transform-origin: top; -} -@keyframes isLoopY { - 0% { - transform: scale(1, 0); - transform-origin: top; - } - 49% { - transform: scale(1, 1); - transform-origin: top; - } - 51% { - transform: scale(1, 1); - transform-origin: bottom; - } - 100% { - transform: scale(1, 0); - transform-origin: bottom; +.c-text { + margin-top: 8px; + color: var(--white); + font-size: 14px; + font-family: 100; + line-height: 160%; + @include sp_w() { + font-size: 12px; + margin-top: 12px; } } +.c-text-right { + text-align: right; +} // -------------------------- -// drag示唆 +// アイテムサイズ // -------------------------- -.c-dragSuggestion { +#js-rect { pointer-events: none; user-select: none; - position: fixed; - left: max(48px, liquid(48)); - bottom: max(20px, liquid(20)); - z-index: 100; - width: max-content; - height: max-content; - padding-bottom: max(8px, liquid(8)); - @include pc_w() { - body:not(.pc) & { - left: max(20px, liquid(20)); - } - } - @include sp_w() { - left: 0; - right: 0; - margin: auto; - // bottom: min(40px, liquid(40)); - bottom: min(80px, liquid(80)); - } - - opacity: 0; - body[data-status="enter"] & { - transition: 0.6s 0.4s ease opacity; - opacity: 1; - } -} -.c-dragSuggestion__text { - color: var(--white); - font-family: var(--ja); - line-height: 100%; - font-size: max(12px, liquid(12)); - line-height: 100%; - font-weight: bold; - @include sp_w() { - font-size: min(12px, liquid(12)); - } -} -.c-dragSuggestion__line { position: absolute; + top: 0; left: 0; - right: 0; - bottom: 0; - margin: auto; - height: 2px; - width: 100%; - background: var(--white); - animation: 3s $easeinout isLoopX infinite; - transform: scale(1, 1); - transform-origin: left; -} -@keyframes isLoopX { - 0% { - transform: scale(0, 1); - transform-origin: left; - } - 49% { - transform: scale(1, 1); - transform-origin: left; - } - 51% { - transform: scale(1, 1); - transform-origin: right; - } - 100% { - transform: scale(0, 1); - transform-origin: right; + opacity: 0; + width: liquid(900 * 0.5); + height: liquid(540 * 0.5); + @include sp_w() { + width: liquid(900 * 0.3); + height: liquid(540 * 0.3); } } // -------------------------- -// ナビゲーション +// アイテムリスト // -------------------------- -button { - outline: none; - margin: 0; - padding: 0; -} - -.l-navi { - user-select: none; - position: fixed; - top: 0; - right: max(16px, liquid(16)); - bottom: 0; - z-index: 9999; - margin: auto; - width: max-content; - height: max-content; - @include sp_w() { - display: flex; - align-items: center; - top: initial; - bottom: min(40px, liquid(40)); - right: 0; - left: 0; - margin: auto; - width: max-content; - gap: min(8px, liquid(8)); - } - .c-btn { - @include pc_w() { - &:nth-of-type(1) { - margin-bottom: max(16px, liquid(16)); - } - &:nth-last-of-type(1) { - margin-top: max(16px, liquid(16)); - } +.c-itemList { + @include hover() { + .c-item__number, + .c-item__label, + .c-item__arrow { + opacity: 0.3; } - @include sp_w() { - .c-btn__text { - transform: rotateZ(-90deg); + .c-item.is-active { + .c-item__number, + .c-item__label, + .c-item__arrow { + opacity: 1; } } } - - opacity: 0; - body[data-status="enter"] & { - transition: 0.6s 0.4s ease opacity; - opacity: 1; - } } - -// ボタン -.c-btn { +.c-itemList__box { +} +.c-item { cursor: pointer; position: relative; z-index: 0; display: flex; align-items: center; - justify-content: center; - background: initial; - width: max(24px, liquid(24)); - height: max(24px, liquid(24)); - border: solid max(2px, liquid(2)) var(--white); - font-size: max(10px, liquid(10)); + gap: 12px; + padding: 64px 32px; + border-left: solid 2px var(--white-solid); + border-right: solid 2px var(--white-solid); + border-top: solid 1px var(--white-solid); + border-bottom: solid 1px var(--white-solid); + box-sizing: border-box; @include sp_w() { - width: min(32px, liquid(32)); - height: min(32px, liquid(32)); - border: solid min(2px, liquid(2)) var(--white); + padding: 54px 24px; } - - opacity: 1; @include hover() { - transition: 0.4s ease opacity; - opacity: 0.5; + .c-item__number, + .c-item__label, + .c-item__arrow { + opacity: 1; + } + } + + &.is-active { + .c-item__number, + .c-item__label, + .c-item__arrow { + opacity: 1; + } + .c-item__arrow { + transform: rotateZ(45deg); + } } } -.c-btn__bg { +.c-item__number, +.c-item__label, +.c-item__arrow { pointer-events: none; user-select: none; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - z-index: 0; - margin: auto; - width: 101%; - height: 101%; - transform: scale(1, 0); - transform-origin: bottom; - background: var(--white); - transition: 0.4s $easeinout transform; } -.c-btn__text { - pointer-events: none; - user-select: none; - position: relative; - z-index: 2; +.c-item__number { color: var(--white); - font-size: max(10px, liquid(10)); - width: max-content; - height: max-content; - margin: 0; - mix-blend-mode: difference; - @include sp_w() { - font-size: min(10px, liquid(10)); - } + font-size: 16px; + font-weight: 700; } - -// ボタン next -.c-btn-next { - &.is-active { - .c-btn__bg { - transform: scale(1, 1); - transition: 3s linear transform; - } - } +.c-item__label { + color: var(--white); + font-size: 16px; + font-weight: 700; } - -// ナビ -.c-navi { - position: relative; - cursor: pointer; - width: max(24px, liquid(24)); - height: max(8px, liquid(8)); - border: solid max(1px, liquid(1)) var(--white); - box-sizing: border-box; - transition: 0.4s ease opacity; - background: rgba(#fff, 0); - @include pc_w() { - margin: auto; - margin-top: max(8px, liquid(8)); - - &:nth-of-type(1) { - margin-top: 0; - } - } - @include sp_w() { - width: min(32px, liquid(32)); - height: min(32px, liquid(32)); - border: solid min(2px, liquid(2)) var(--white); - } - &::before { - pointer-events: none; - user-select: none; - content: ""; - position: absolute; - top: 0%; - left: 0%; - right: 0; - bottom: 0; - z-index: 0; - margin: auto; - width: 102%; - height: 102%; - background: var(--white); - transform: scale(1, 0); - transform-origin: bottom; - transition: 1.2s $easeinout transform; - } - - &.is-active { - &::before { - transform: scale(1, 1); - } - } - @include hover() { - opacity: 0.5; +.c-item__arrow { + color: var(--white); + font-size: 28px; + font-weight: 700; + margin-left: auto; + transition: 0.2s ease opacity, 0.2s ease transform; +} +.c-item__number, +.c-item__label { + opacity: 1; + transition: 0.2s ease opacity; +} +.c-item__img { + display: none; + visibility: hidden; + img { } } // -------------------------- -// タイトル +// footer // -------------------------- -.c-title { - pointer-events: none; - user-select: none; - position: fixed; - top: max(20px, liquid(20)); - left: max(20px, liquid(20)); - z-index: 5000; - @include sp_w() { - top: min(12px, liquid(12)); - left: min(12px, liquid(12)); - } - span { - display: inline-block; - font-family: var(--ja); - line-height: 100%; - font-weight: bold; - width: max-content; - color: var(--white); - - &:nth-of-type(1) { - font-size: max(54px, liquid(54)); - letter-spacing: max(-2px, liquid(-2)); - @include sp_w() { - font-size: min(32px, liquid(32)); - letter-spacing: max(-2px, liquid(-2)); - } - } - &:nth-of-type(2) { - font-size: max(24px, liquid(24)); - line-height: 160%; - @include sp_w() { - font-size: min(20px, liquid(20)); - } - } - } +.l-footer { + position: relative; + z-index: 10; + border-left: solid 2px var(--white-solid); + border-right: solid 2px var(--white-solid); + border-top: solid 1px var(--white-solid); + border-bottom: solid 2px var(--white-solid); + box-sizing: border-box; + width: 100vw; + height: 64px; } // -------------------------- @@ -428,13 +245,13 @@ button { .c-copyright { user-select: none; position: fixed; - bottom: max(16px, liquid(16)); + bottom: 24px; left: 0; right: 0; margin: auto; z-index: 2000; display: block; - font-size: max(12px, liquid(12)); + font-size: 12px; font-family: var(--ja); line-height: 100%; font-weight: bold; @@ -444,8 +261,6 @@ button { @include sp_w() { right: 0; left: 0; - bottom: min(16px, liquid(16)); - font-size: min(12px, liquid(12)); margin: auto; } &::before { @@ -453,7 +268,7 @@ button { user-select: none; content: ""; position: absolute; - bottom: max(-6px, liquid(-6)); + bottom: -6px; left: 0; z-index: 0; transform: translate3d(0, 0, 0px); @@ -464,7 +279,7 @@ button { transform-origin: left; transition: 0.4s $easeinout transform; @include sp_w() { - bottom: min(-4px, liquid(-4)); + bottom: -4px; } } @include hover() { @@ -486,18 +301,10 @@ button { // -------------------------- .c-github { user-select: none; - position: fixed; - right: max(16px, liquid(16)); - bottom: max(16px, liquid(20)); - z-index: 2000; - width: max(20px, liquid(20)); - height: max(20px, liquid(20)); + width: 20px; + height: 20px; display: flex; align-items: center; - @include sp_w() { - bottom: min(12px, liquid(12)); - right: min(12px, liquid(12)); - } svg { pointer-events: none; user-select: none; @@ -510,5 +317,8 @@ button { body[data-status="enter"] & { transition: 0.4s ease opacity; opacity: 1; + @include hover() { + opacity: 0.5; + } } } diff --git a/src/assets/scss/foundation/_root.scss b/src/assets/scss/foundation/_root.scss index 27cf42f..6d05ee3 100644 --- a/src/assets/scss/foundation/_root.scss +++ b/src/assets/scss/foundation/_root.scss @@ -7,5 +7,6 @@ $gothic: "游ゴシック", YuGothic, "ヒラギノ角ゴ ProN W3", "Hiragino Ka // color --white: #fff; + --white-solid: rgba(255, 255, 255, 0.2); --black: #161616; } diff --git a/src/assets/scss/global/_function.scss b/src/assets/scss/global/_function.scss index 1aec4f6..f1b0536 100644 --- a/src/assets/scss/global/_function.scss +++ b/src/assets/scss/global/_function.scss @@ -81,58 +81,3 @@ } } } - -// -------------------------- - -// ホバーアニメーション - -// -------------------------- -// @mixin setHoverAlpha($after: 0.5) { -// @media (hover: hover) { -// opacity: 1; -// transition: $hoverTime $hoverEase opacity; -// &:hover { -// opacity: $after; -// } -// } -// } - -// -------------------------- - -// 出現アニメーション - -// -------------------------- -// フェードスライドイン -// @mixin setFadeSlideInBefore($time: 0.6s, $ease: ease, $yPc: 50%, $ySp: 40%) { -// opacity: 0; -// transform: translate3d(0, $yPc, 0); -// transition: $time $ease opacity, $time $ease transform; -// @include sp_w() { -// transform: translate3d(0, $ySp, 0); -// } -// } -// @mixin setFadeSlideInAfter() { -// opacity: 1; -// transform: translate3d(0, 0, 0); -// } - -// // スライドイン -// @mixin setSlideInBefore($time: 0.6s, $ease: ease, $yPc: 50%, $ySp: 40%) { -// transform: translate3d(0, $yPc, 0); -// transition: $time $ease transform; -// @include sp_w() { -// transform: translate3d(0, $ySp, 0); -// } -// } -// @mixin setSlideInAfter() { -// transform: translate3d(0, 0, 0); -// } - -// // フェードイン -// @mixin setFadeInBefore($time: 0.6s, $ease: ease) { -// opacity: 0; -// transition: $time $ease opacity; -// } -// @mixin setFadeInAfter() { -// opacity: 1; -// } diff --git a/src/assets/scss/global/_variable.scss b/src/assets/scss/global/_variable.scss index 474e2f3..e16ab93 100644 --- a/src/assets/scss/global/_variable.scss +++ b/src/assets/scss/global/_variable.scss @@ -1,7 +1,7 @@ // --------------------- -// + // screen -// + // --------------------- $screen1: 320; $screen2: 375; @@ -15,17 +15,17 @@ $screen9: 1680; $screen10: 1920; // --------------------- -// + // responsive -// + // --------------------- $maxWidth: #{$screen4}px; $minWidth: #{$screen4 + 1}px; // --------------------------------- -// + // easing //https://easings.net/ja -// + // --------------------------------- // ease in $easeInSine: cubic-bezier(0.12, 0, 0.39, 0); @@ -61,9 +61,9 @@ $easeout: $easeOutExpo; $easeinout: $easeInOutExpo; // --------------------- -// + // hover -// + // --------------------- $hoverTime: 0.4s; $hoverEase: $easeOutQuart; diff --git a/src/assets/scss/other/_utility.scss b/src/assets/scss/other/_utility.scss index d70e83f..bfe2e74 100644 --- a/src/assets/scss/other/_utility.scss +++ b/src/assets/scss/other/_utility.scss @@ -1,12 +1,6 @@ @use "sass:math"; // math.div(a,b); => a / b @use "../global/app" as *; -// ---------------------------------- -// -// 非表示 -// -// ---------------------------------- -// ブレイクポイント @include pc_w() { .u-pc-hide { display: none !important; @@ -18,145 +12,6 @@ } } -// 非表示 .u-hidden { display: none !important; } - -// ---------------------------------- -// -// transition delay | +.05s | min: .1s ~ max: 2.05s -// -// ---------------------------------- -// $max: 40; -// @for $i from 1 through 40 { -// .u-delay-#{50+(50 * $i)} { -// transition-delay: 0.05s + (0.05s * $i); -// } -// } - -// ---------------------------------- -// -// animation delay | +.05s | min: .1s ~ max: 2.05s -// -// ---------------------------------- -// $max: 40; -// @for $i from 1 through 40 { -// .u-delay-anime-#{50+(50 * $i)} { -// animation-delay: 0.05s + (0.05s * $i); -// } -// } - -// ---------------------------------- -// -// margin | 4の倍数 | max: 80 -// -// ---------------------------------- -// $max: 20; -// auto -// .u-mg-auto { -// margin: auto; -// } - -// margin -// @for $i from 1 through $max { -// .u-mg-#{$i * 4} { -// margin: min(4px * $i, vw(4 * $i)) auto; -// @include sp_w() { -// // margin: min(4px * $i, vw(4 * $i, 375)) auto; -// margin: vw_sp(4 * $i) auto; -// } -// } -// } - -// margin-top -// @for $i from 1 through $max { -// .u-mgt-#{$i * 4} { -// margin-top: min(4px * $i, vw(4 * $i)); -// @include sp_w() { -// // margin-top: min(4px * $i, vw(4 * $i, 375)); -// margin-top: vw_sp(4 * $i); -// } -// } -// } - -// margin-bottom -// @for $i from 1 through $max { -// .u-mgb-#{$i * 4} { -// margin-bottom: min(4px * $i, vw(4 * $i)); -// @include sp_w() { -// // margin-bottom: min(4px * $i, vw(4 * $i, 375)); -// margin-bottom: vw_sp(4 * $i); -// } -// } -// } - -// ---------------------------------- -// -// padding | 4の倍数 | max: 80 -// -// ---------------------------------- -// $max: 20; -// padding -// @for $i from 1 through $max { -// .u-pd-#{$i * 4} { -// padding: min(4px * $i, vw(4 * $i)) 0; -// @include sp_w() { -// // padding: min(4px * $i, vw(4 * $i, 375)) 0; -// padding: vw(4 * $i, 375) 0; -// } -// } -// } - -// // padding-top -// @for $i from 1 through $max { -// .u-pdt-#{$i * 4} { -// padding-top: min(4px * $i, vw(4 * $i)); -// @include sp_w() { -// // padding-top: min(4px * $i, vw(4 * $i, 375)); -// padding-top: vw(4 * $i, 375); -// } -// } -// } - -// padding-bottom -// @for $i from 1 through $max { -// .u-pdb-#{$i * 4} { -// padding-bottom: min(4px * $i, vw(4 * $i)); -// @include sp_w() { -// // padding-bottom: min(4px * $i, vw(4 * $i, 375)); -// padding-bottom: vw(4 * $i, 375); -// } -// } -// } - -// ---------------------------------- -// -// テキスト -// -// ---------------------------------- -// // 改行しない -// .u-text-nowrap { -// white-space: nowrap; -// } -// @include pc_w() { -// .u-pc-text-nowrap { -// white-space: nowrap; -// } -// } -// @include sp_w() { -// .u-sp-text-nowrap { -// white-space: nowrap; -// } -// } - -// ---------------------------------- -// -// その他 -// -// ---------------------------------- -// クリックできない -// .u-noClick { -// pointer-events: none; -// user-select: none; -// } diff --git a/src/assets/shader/_inc/matcap.glsl b/src/assets/shader/_inc/matcap.glsl new file mode 100644 index 0000000..ddf2f45 --- /dev/null +++ b/src/assets/shader/_inc/matcap.glsl @@ -0,0 +1,5 @@ +vec2 matcap(vec3 eye, vec3 normal) { + vec3 reflected = reflect(eye, normal); + float m = 2.8284271247461903 * sqrt( reflected.z+1.0 ); + return reflected.xy / m + 0.5; +} \ No newline at end of file diff --git a/src/assets/shader/_inc/optimizationUv.glsl b/src/assets/shader/_inc/optimizationUv.glsl new file mode 100644 index 0000000..c3a9c94 --- /dev/null +++ b/src/assets/shader/_inc/optimizationUv.glsl @@ -0,0 +1,6 @@ +vec2 optimizationUv(vec2 uv, vec2 ratio){ + return vec2( + ((uv.x - 0.5) * ratio.x + 0.5), + ((uv.y - 0.5) * ratio.y + 0.5) + ); +} \ No newline at end of file diff --git a/src/assets/shader/_inc/ratio.glsl b/src/assets/shader/_inc/ratio.glsl new file mode 100644 index 0000000..f834d8b --- /dev/null +++ b/src/assets/shader/_inc/ratio.glsl @@ -0,0 +1,6 @@ +vec2 ratio(float p, float t, float s){ + return vec2( + min(p / t, 1.0) * s, + (min((1.0 / p) / (1.0 / t), 1.0)) * s + ); +} \ No newline at end of file diff --git a/src/assets/shader/frag/plane.glsl b/src/assets/shader/frag/plane.glsl new file mode 100644 index 0000000..e8a5601 --- /dev/null +++ b/src/assets/shader/frag/plane.glsl @@ -0,0 +1,75 @@ +precision mediump float; +varying float vScale; +varying vec2 vUv; +varying vec2 vCurve; +varying vec3 vNormal; +uniform float uChange; +uniform float uPlaneAspect; +uniform float uTextureAspect; +uniform sampler2D uTexture1; +uniform sampler2D uTexture2; +uniform sampler2D uNoise; +uniform sampler2D uMatcap; +uniform vec3 uEyePosition; +varying vec3 vPosition; + +uniform float uTime; +uniform float uProgress; + +const vec3 LIGTH = vec3(0.0, 0.0, 5.0); + +#include ../_inc/matcap.glsl +#include ../_inc/ratio.glsl +#include ../_inc/optimizationUv.glsl + +void main() { + float progress = uChange; + float scaleProgress = 1.0 - vScale; + vec2 uv = vec2(vUv.x, 1.0 - vUv.y); + + // モデルの頂点座標とカメラの位置から視線ベクトルを求める + vec3 eyeDirection = normalize(vPosition - uEyePosition); + + // matcap + vec2 matcapUv = matcap(eyeDirection, vNormal); + vec4 matcapTexture = texture2D(uMatcap, matcapUv); + + // ノイズ(歪み) + vec4 noise = texture2D(uNoise, optimizationUv(uv, vec2(1.0))); + vec2 dispUv = noise.xy; + + vec2 textureUv = optimizationUv(uv, ratio(uPlaneAspect, uTextureAspect, 1.0)); + + float interpolation = pow( + smoothstep( + 0.0, + 1.0, + (progress * 0.95 + dispUv.x * 0.05 ) * 2.0 - textureUv.x + ), + 5.0 + ); + + vec2 uv1 = (textureUv - 0.5) * (1.0 - interpolation) + 0.5; + vec4 t1 = vec4( + texture2D(uTexture1, uv1).r, + texture2D(uTexture1, uv1 + (vCurve.x + vCurve.y) * 0.4 * scaleProgress).g, + texture2D(uTexture1, uv1 + (vCurve.x + vCurve.y) * 0.4 * scaleProgress).b, + 1.0 + ); + t1.r = t1.r * (1.0 + interpolation * (20.0 - 19.0 * progress)); + t1.g = t1.g * (1.0 - interpolation); + t1.b = t1.b * (1.0 - interpolation * (10.0 - 9.0 * progress)); + + vec2 uv2 = (textureUv - 0.5) * (interpolation) + 0.5; + vec4 t2 = vec4( + texture2D(uTexture2, uv2).r, + texture2D(uTexture2, uv2 + (vCurve.x + vCurve.y) * 0.4 * scaleProgress).g, + texture2D(uTexture2, uv2 + (vCurve.x + vCurve.y) * 0.4 * scaleProgress).b, + 1.0 + ); + t2.rgb = t2.rgb * interpolation; + + vec4 texture = mix(t1,t2,interpolation); + vec4 dist = vec4(texture.rgb * matcapTexture.rgb, 1.0); + gl_FragColor = dist; +} diff --git a/src/assets/shader/vert/plane.glsl b/src/assets/shader/vert/plane.glsl new file mode 100644 index 0000000..e578498 --- /dev/null +++ b/src/assets/shader/vert/plane.glsl @@ -0,0 +1,58 @@ +attribute vec3 position; +attribute vec3 normal; +attribute vec2 uv; +varying float vScale; +varying vec2 vUv; +uniform float uScale; +uniform vec2 uFullScale; +varying vec2 vCurve; +varying vec3 vNormal; +varying vec3 vPosition; +uniform vec2 uCurve; +uniform mat4 uMvpMatrix; +uniform mat4 uModelMatrix; +uniform mat4 uNormalMatrix; + +const float PI = 3.1415925; + +void main() { + vUv = uv; + vCurve = uCurve; + vScale = uScale; + + // ワールド空間上でのモデルの頂点を求める + vPosition = (uModelMatrix * vec4(position, 1.0)).xyz; + + vNormal = normalize((uNormalMatrix * vec4(normal, 0.0)).xyz); + + // animation progress + float transform = 1.0 - uv.y; + float progressStartValue = 0.5; + float progress = clamp( + progressStartValue, + 1.0, + smoothstep( + transform * progressStartValue, + 1.0, + uScale + ) + ); + + float x = position.x; + float y = position.y; + float z = position.z; + + // curve effects + x = x + (sin(uv.y * PI) * uCurve.x) * (1.0 - uScale); + y = y + (sin(uv.x * PI) * uCurve.y) * (1.0 - uScale); + + // plane size → fullscreen size + x = x * uFullScale.x; + y = y * uFullScale.y; + + // position adjustment + x = x + (x * progress) - (x * uScale); + y = y + (y * progress) - (y * uScale); + + gl_Position = uMvpMatrix * vec4(vec3(x, y, z), 1.0); +} diff --git a/src/assets/shaders/_inc/glsl-noise/classic/2d.glsl b/src/assets/shaders/_inc/glsl-noise/classic/2d.glsl deleted file mode 100644 index 20b6e3e..0000000 --- a/src/assets/shaders/_inc/glsl-noise/classic/2d.glsl +++ /dev/null @@ -1,74 +0,0 @@ -// -// GLSL textureless classic 2D noise "cnoise", -// with an RSL-style periodic variant "pnoise". -// Author: Stefan Gustavson (stefan.gustavson@liu.se) -// Version: 2011-08-22 -// -// Many thanks to Ian McEwan of Ashima Arts for the -// ideas for permutation and gradient selection. -// -// Copyright (c) 2011 Stefan Gustavson. All rights reserved. -// Distributed under the MIT license. See LICENSE file. -// https://github.com/ashima/webgl-noise -// - -vec4 mod289(vec4 x) -{ - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -vec4 permute(vec4 x) -{ - return mod289(((x*34.0)+1.0)*x); -} - -vec4 taylorInvSqrt(vec4 r) -{ - return 1.79284291400159 - 0.85373472095314 * r; -} - -vec2 fade(vec2 t) { - return t*t*t*(t*(t*6.0-15.0)+10.0); -} - -// Classic Perlin noise -float cnoise(vec2 P) -{ - vec4 Pi = floor(P.xyxy) + vec4(0.0, 0.0, 1.0, 1.0); - vec4 Pf = fract(P.xyxy) - vec4(0.0, 0.0, 1.0, 1.0); - Pi = mod289(Pi); // To avoid truncation effects in permutation - vec4 ix = Pi.xzxz; - vec4 iy = Pi.yyww; - vec4 fx = Pf.xzxz; - vec4 fy = Pf.yyww; - - vec4 i = permute(permute(ix) + iy); - - vec4 gx = fract(i * (1.0 / 41.0)) * 2.0 - 1.0 ; - vec4 gy = abs(gx) - 0.5 ; - vec4 tx = floor(gx + 0.5); - gx = gx - tx; - - vec2 g00 = vec2(gx.x,gy.x); - vec2 g10 = vec2(gx.y,gy.y); - vec2 g01 = vec2(gx.z,gy.z); - vec2 g11 = vec2(gx.w,gy.w); - - vec4 norm = taylorInvSqrt(vec4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11))); - g00 *= norm.x; - g01 *= norm.y; - g10 *= norm.z; - g11 *= norm.w; - - float n00 = dot(g00, vec2(fx.x, fy.x)); - float n10 = dot(g10, vec2(fx.y, fy.y)); - float n01 = dot(g01, vec2(fx.z, fy.z)); - float n11 = dot(g11, vec2(fx.w, fy.w)); - - vec2 fade_xy = fade(Pf.xy); - vec2 n_x = mix(vec2(n00, n01), vec2(n10, n11), fade_xy.x); - float n_xy = mix(n_x.x, n_x.y, fade_xy.y); - return 2.3 * n_xy; -} - -#pragma glslify: export(cnoise) diff --git a/src/assets/shaders/_inc/glsl-noise/classic/3d.glsl b/src/assets/shaders/_inc/glsl-noise/classic/3d.glsl deleted file mode 100644 index 6fe889a..0000000 --- a/src/assets/shaders/_inc/glsl-noise/classic/3d.glsl +++ /dev/null @@ -1,109 +0,0 @@ -// -// GLSL textureless classic 3D noise "cnoise", -// with an RSL-style periodic variant "pnoise". -// Author: Stefan Gustavson (stefan.gustavson@liu.se) -// Version: 2011-10-11 -// -// Many thanks to Ian McEwan of Ashima Arts for the -// ideas for permutation and gradient selection. -// -// Copyright (c) 2011 Stefan Gustavson. All rights reserved. -// Distributed under the MIT license. See LICENSE file. -// https://github.com/ashima/webgl-noise -// - -vec3 mod289(vec3 x) -{ - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -vec4 mod289(vec4 x) -{ - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -vec4 permute(vec4 x) -{ - return mod289(((x*34.0)+1.0)*x); -} - -vec4 taylorInvSqrt(vec4 r) -{ - return 1.79284291400159 - 0.85373472095314 * r; -} - -vec3 fade(vec3 t) { - return t*t*t*(t*(t*6.0-15.0)+10.0); -} - -// Classic Perlin noise -float cnoise(vec3 P) -{ - vec3 Pi0 = floor(P); // Integer part for indexing - vec3 Pi1 = Pi0 + vec3(1.0); // Integer part + 1 - Pi0 = mod289(Pi0); - Pi1 = mod289(Pi1); - vec3 Pf0 = fract(P); // Fractional part for interpolation - vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0 - vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x); - vec4 iy = vec4(Pi0.yy, Pi1.yy); - vec4 iz0 = Pi0.zzzz; - vec4 iz1 = Pi1.zzzz; - - vec4 ixy = permute(permute(ix) + iy); - vec4 ixy0 = permute(ixy + iz0); - vec4 ixy1 = permute(ixy + iz1); - - vec4 gx0 = ixy0 * (1.0 / 7.0); - vec4 gy0 = fract(floor(gx0) * (1.0 / 7.0)) - 0.5; - gx0 = fract(gx0); - vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0); - vec4 sz0 = step(gz0, vec4(0.0)); - gx0 -= sz0 * (step(0.0, gx0) - 0.5); - gy0 -= sz0 * (step(0.0, gy0) - 0.5); - - vec4 gx1 = ixy1 * (1.0 / 7.0); - vec4 gy1 = fract(floor(gx1) * (1.0 / 7.0)) - 0.5; - gx1 = fract(gx1); - vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1); - vec4 sz1 = step(gz1, vec4(0.0)); - gx1 -= sz1 * (step(0.0, gx1) - 0.5); - gy1 -= sz1 * (step(0.0, gy1) - 0.5); - - vec3 g000 = vec3(gx0.x,gy0.x,gz0.x); - vec3 g100 = vec3(gx0.y,gy0.y,gz0.y); - vec3 g010 = vec3(gx0.z,gy0.z,gz0.z); - vec3 g110 = vec3(gx0.w,gy0.w,gz0.w); - vec3 g001 = vec3(gx1.x,gy1.x,gz1.x); - vec3 g101 = vec3(gx1.y,gy1.y,gz1.y); - vec3 g011 = vec3(gx1.z,gy1.z,gz1.z); - vec3 g111 = vec3(gx1.w,gy1.w,gz1.w); - - vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110))); - g000 *= norm0.x; - g010 *= norm0.y; - g100 *= norm0.z; - g110 *= norm0.w; - vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111))); - g001 *= norm1.x; - g011 *= norm1.y; - g101 *= norm1.z; - g111 *= norm1.w; - - float n000 = dot(g000, Pf0); - float n100 = dot(g100, vec3(Pf1.x, Pf0.yz)); - float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z)); - float n110 = dot(g110, vec3(Pf1.xy, Pf0.z)); - float n001 = dot(g001, vec3(Pf0.xy, Pf1.z)); - float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z)); - float n011 = dot(g011, vec3(Pf0.x, Pf1.yz)); - float n111 = dot(g111, Pf1); - - vec3 fade_xyz = fade(Pf0); - vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z); - vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y); - float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); - return 2.2 * n_xyz; -} - -#pragma glslify: export(cnoise) diff --git a/src/assets/shaders/_inc/glsl-noise/classic/4d.glsl b/src/assets/shaders/_inc/glsl-noise/classic/4d.glsl deleted file mode 100644 index 3c90879..0000000 --- a/src/assets/shaders/_inc/glsl-noise/classic/4d.glsl +++ /dev/null @@ -1,169 +0,0 @@ -// -// GLSL textureless classic 4D noise "cnoise", -// with an RSL-style periodic variant "pnoise". -// Author: Stefan Gustavson (stefan.gustavson@liu.se) -// Version: 2011-08-22 -// -// Many thanks to Ian McEwan of Ashima Arts for the -// ideas for permutation and gradient selection. -// -// Copyright (c) 2011 Stefan Gustavson. All rights reserved. -// Distributed under the MIT license. See LICENSE file. -// https://github.com/ashima/webgl-noise -// - -vec4 mod289(vec4 x) -{ - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -vec4 permute(vec4 x) -{ - return mod289(((x*34.0)+1.0)*x); -} - -vec4 taylorInvSqrt(vec4 r) -{ - return 1.79284291400159 - 0.85373472095314 * r; -} - -vec4 fade(vec4 t) { - return t*t*t*(t*(t*6.0-15.0)+10.0); -} - -// Classic Perlin noise -float cnoise(vec4 P) -{ - vec4 Pi0 = floor(P); // Integer part for indexing - vec4 Pi1 = Pi0 + 1.0; // Integer part + 1 - Pi0 = mod289(Pi0); - Pi1 = mod289(Pi1); - vec4 Pf0 = fract(P); // Fractional part for interpolation - vec4 Pf1 = Pf0 - 1.0; // Fractional part - 1.0 - vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x); - vec4 iy = vec4(Pi0.yy, Pi1.yy); - vec4 iz0 = vec4(Pi0.zzzz); - vec4 iz1 = vec4(Pi1.zzzz); - vec4 iw0 = vec4(Pi0.wwww); - vec4 iw1 = vec4(Pi1.wwww); - - vec4 ixy = permute(permute(ix) + iy); - vec4 ixy0 = permute(ixy + iz0); - vec4 ixy1 = permute(ixy + iz1); - vec4 ixy00 = permute(ixy0 + iw0); - vec4 ixy01 = permute(ixy0 + iw1); - vec4 ixy10 = permute(ixy1 + iw0); - vec4 ixy11 = permute(ixy1 + iw1); - - vec4 gx00 = ixy00 * (1.0 / 7.0); - vec4 gy00 = floor(gx00) * (1.0 / 7.0); - vec4 gz00 = floor(gy00) * (1.0 / 6.0); - gx00 = fract(gx00) - 0.5; - gy00 = fract(gy00) - 0.5; - gz00 = fract(gz00) - 0.5; - vec4 gw00 = vec4(0.75) - abs(gx00) - abs(gy00) - abs(gz00); - vec4 sw00 = step(gw00, vec4(0.0)); - gx00 -= sw00 * (step(0.0, gx00) - 0.5); - gy00 -= sw00 * (step(0.0, gy00) - 0.5); - - vec4 gx01 = ixy01 * (1.0 / 7.0); - vec4 gy01 = floor(gx01) * (1.0 / 7.0); - vec4 gz01 = floor(gy01) * (1.0 / 6.0); - gx01 = fract(gx01) - 0.5; - gy01 = fract(gy01) - 0.5; - gz01 = fract(gz01) - 0.5; - vec4 gw01 = vec4(0.75) - abs(gx01) - abs(gy01) - abs(gz01); - vec4 sw01 = step(gw01, vec4(0.0)); - gx01 -= sw01 * (step(0.0, gx01) - 0.5); - gy01 -= sw01 * (step(0.0, gy01) - 0.5); - - vec4 gx10 = ixy10 * (1.0 / 7.0); - vec4 gy10 = floor(gx10) * (1.0 / 7.0); - vec4 gz10 = floor(gy10) * (1.0 / 6.0); - gx10 = fract(gx10) - 0.5; - gy10 = fract(gy10) - 0.5; - gz10 = fract(gz10) - 0.5; - vec4 gw10 = vec4(0.75) - abs(gx10) - abs(gy10) - abs(gz10); - vec4 sw10 = step(gw10, vec4(0.0)); - gx10 -= sw10 * (step(0.0, gx10) - 0.5); - gy10 -= sw10 * (step(0.0, gy10) - 0.5); - - vec4 gx11 = ixy11 * (1.0 / 7.0); - vec4 gy11 = floor(gx11) * (1.0 / 7.0); - vec4 gz11 = floor(gy11) * (1.0 / 6.0); - gx11 = fract(gx11) - 0.5; - gy11 = fract(gy11) - 0.5; - gz11 = fract(gz11) - 0.5; - vec4 gw11 = vec4(0.75) - abs(gx11) - abs(gy11) - abs(gz11); - vec4 sw11 = step(gw11, vec4(0.0)); - gx11 -= sw11 * (step(0.0, gx11) - 0.5); - gy11 -= sw11 * (step(0.0, gy11) - 0.5); - - vec4 g0000 = vec4(gx00.x,gy00.x,gz00.x,gw00.x); - vec4 g1000 = vec4(gx00.y,gy00.y,gz00.y,gw00.y); - vec4 g0100 = vec4(gx00.z,gy00.z,gz00.z,gw00.z); - vec4 g1100 = vec4(gx00.w,gy00.w,gz00.w,gw00.w); - vec4 g0010 = vec4(gx10.x,gy10.x,gz10.x,gw10.x); - vec4 g1010 = vec4(gx10.y,gy10.y,gz10.y,gw10.y); - vec4 g0110 = vec4(gx10.z,gy10.z,gz10.z,gw10.z); - vec4 g1110 = vec4(gx10.w,gy10.w,gz10.w,gw10.w); - vec4 g0001 = vec4(gx01.x,gy01.x,gz01.x,gw01.x); - vec4 g1001 = vec4(gx01.y,gy01.y,gz01.y,gw01.y); - vec4 g0101 = vec4(gx01.z,gy01.z,gz01.z,gw01.z); - vec4 g1101 = vec4(gx01.w,gy01.w,gz01.w,gw01.w); - vec4 g0011 = vec4(gx11.x,gy11.x,gz11.x,gw11.x); - vec4 g1011 = vec4(gx11.y,gy11.y,gz11.y,gw11.y); - vec4 g0111 = vec4(gx11.z,gy11.z,gz11.z,gw11.z); - vec4 g1111 = vec4(gx11.w,gy11.w,gz11.w,gw11.w); - - vec4 norm00 = taylorInvSqrt(vec4(dot(g0000, g0000), dot(g0100, g0100), dot(g1000, g1000), dot(g1100, g1100))); - g0000 *= norm00.x; - g0100 *= norm00.y; - g1000 *= norm00.z; - g1100 *= norm00.w; - - vec4 norm01 = taylorInvSqrt(vec4(dot(g0001, g0001), dot(g0101, g0101), dot(g1001, g1001), dot(g1101, g1101))); - g0001 *= norm01.x; - g0101 *= norm01.y; - g1001 *= norm01.z; - g1101 *= norm01.w; - - vec4 norm10 = taylorInvSqrt(vec4(dot(g0010, g0010), dot(g0110, g0110), dot(g1010, g1010), dot(g1110, g1110))); - g0010 *= norm10.x; - g0110 *= norm10.y; - g1010 *= norm10.z; - g1110 *= norm10.w; - - vec4 norm11 = taylorInvSqrt(vec4(dot(g0011, g0011), dot(g0111, g0111), dot(g1011, g1011), dot(g1111, g1111))); - g0011 *= norm11.x; - g0111 *= norm11.y; - g1011 *= norm11.z; - g1111 *= norm11.w; - - float n0000 = dot(g0000, Pf0); - float n1000 = dot(g1000, vec4(Pf1.x, Pf0.yzw)); - float n0100 = dot(g0100, vec4(Pf0.x, Pf1.y, Pf0.zw)); - float n1100 = dot(g1100, vec4(Pf1.xy, Pf0.zw)); - float n0010 = dot(g0010, vec4(Pf0.xy, Pf1.z, Pf0.w)); - float n1010 = dot(g1010, vec4(Pf1.x, Pf0.y, Pf1.z, Pf0.w)); - float n0110 = dot(g0110, vec4(Pf0.x, Pf1.yz, Pf0.w)); - float n1110 = dot(g1110, vec4(Pf1.xyz, Pf0.w)); - float n0001 = dot(g0001, vec4(Pf0.xyz, Pf1.w)); - float n1001 = dot(g1001, vec4(Pf1.x, Pf0.yz, Pf1.w)); - float n0101 = dot(g0101, vec4(Pf0.x, Pf1.y, Pf0.z, Pf1.w)); - float n1101 = dot(g1101, vec4(Pf1.xy, Pf0.z, Pf1.w)); - float n0011 = dot(g0011, vec4(Pf0.xy, Pf1.zw)); - float n1011 = dot(g1011, vec4(Pf1.x, Pf0.y, Pf1.zw)); - float n0111 = dot(g0111, vec4(Pf0.x, Pf1.yzw)); - float n1111 = dot(g1111, Pf1); - - vec4 fade_xyzw = fade(Pf0); - vec4 n_0w = mix(vec4(n0000, n1000, n0100, n1100), vec4(n0001, n1001, n0101, n1101), fade_xyzw.w); - vec4 n_1w = mix(vec4(n0010, n1010, n0110, n1110), vec4(n0011, n1011, n0111, n1111), fade_xyzw.w); - vec4 n_zw = mix(n_0w, n_1w, fade_xyzw.z); - vec2 n_yzw = mix(n_zw.xy, n_zw.zw, fade_xyzw.y); - float n_xyzw = mix(n_yzw.x, n_yzw.y, fade_xyzw.x); - return 2.2 * n_xyzw; -} - -#pragma glslify: export(cnoise) diff --git a/src/assets/shaders/_inc/glsl-noise/periodic/2d.glsl b/src/assets/shaders/_inc/glsl-noise/periodic/2d.glsl deleted file mode 100644 index c267970..0000000 --- a/src/assets/shaders/_inc/glsl-noise/periodic/2d.glsl +++ /dev/null @@ -1,75 +0,0 @@ -// -// GLSL textureless classic 2D noise "cnoise", -// with an RSL-style periodic variant "pnoise". -// Author: Stefan Gustavson (stefan.gustavson@liu.se) -// Version: 2011-08-22 -// -// Many thanks to Ian McEwan of Ashima Arts for the -// ideas for permutation and gradient selection. -// -// Copyright (c) 2011 Stefan Gustavson. All rights reserved. -// Distributed under the MIT license. See LICENSE file. -// https://github.com/ashima/webgl-noise -// - -vec4 mod289(vec4 x) -{ - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -vec4 permute(vec4 x) -{ - return mod289(((x*34.0)+1.0)*x); -} - -vec4 taylorInvSqrt(vec4 r) -{ - return 1.79284291400159 - 0.85373472095314 * r; -} - -vec2 fade(vec2 t) { - return t*t*t*(t*(t*6.0-15.0)+10.0); -} - -// Classic Perlin noise, periodic variant -float pnoise(vec2 P, vec2 rep) -{ - vec4 Pi = floor(P.xyxy) + vec4(0.0, 0.0, 1.0, 1.0); - vec4 Pf = fract(P.xyxy) - vec4(0.0, 0.0, 1.0, 1.0); - Pi = mod(Pi, rep.xyxy); // To create noise with explicit period - Pi = mod289(Pi); // To avoid truncation effects in permutation - vec4 ix = Pi.xzxz; - vec4 iy = Pi.yyww; - vec4 fx = Pf.xzxz; - vec4 fy = Pf.yyww; - - vec4 i = permute(permute(ix) + iy); - - vec4 gx = fract(i * (1.0 / 41.0)) * 2.0 - 1.0 ; - vec4 gy = abs(gx) - 0.5 ; - vec4 tx = floor(gx + 0.5); - gx = gx - tx; - - vec2 g00 = vec2(gx.x,gy.x); - vec2 g10 = vec2(gx.y,gy.y); - vec2 g01 = vec2(gx.z,gy.z); - vec2 g11 = vec2(gx.w,gy.w); - - vec4 norm = taylorInvSqrt(vec4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11))); - g00 *= norm.x; - g01 *= norm.y; - g10 *= norm.z; - g11 *= norm.w; - - float n00 = dot(g00, vec2(fx.x, fy.x)); - float n10 = dot(g10, vec2(fx.y, fy.y)); - float n01 = dot(g01, vec2(fx.z, fy.z)); - float n11 = dot(g11, vec2(fx.w, fy.w)); - - vec2 fade_xy = fade(Pf.xy); - vec2 n_x = mix(vec2(n00, n01), vec2(n10, n11), fade_xy.x); - float n_xy = mix(n_x.x, n_x.y, fade_xy.y); - return 2.3 * n_xy; -} - -#pragma glslify: export(pnoise) diff --git a/src/assets/shaders/_inc/glsl-noise/periodic/3d.glsl b/src/assets/shaders/_inc/glsl-noise/periodic/3d.glsl deleted file mode 100644 index b88ffa6..0000000 --- a/src/assets/shaders/_inc/glsl-noise/periodic/3d.glsl +++ /dev/null @@ -1,109 +0,0 @@ -// -// GLSL textureless classic 3D noise "cnoise", -// with an RSL-style periodic variant "pnoise". -// Author: Stefan Gustavson (stefan.gustavson@liu.se) -// Version: 2011-10-11 -// -// Many thanks to Ian McEwan of Ashima Arts for the -// ideas for permutation and gradient selection. -// -// Copyright (c) 2011 Stefan Gustavson. All rights reserved. -// Distributed under the MIT license. See LICENSE file. -// https://github.com/ashima/webgl-noise -// - -vec3 mod289(vec3 x) -{ - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -vec4 mod289(vec4 x) -{ - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -vec4 permute(vec4 x) -{ - return mod289(((x*34.0)+1.0)*x); -} - -vec4 taylorInvSqrt(vec4 r) -{ - return 1.79284291400159 - 0.85373472095314 * r; -} - -vec3 fade(vec3 t) { - return t*t*t*(t*(t*6.0-15.0)+10.0); -} - -// Classic Perlin noise, periodic variant -float pnoise(vec3 P, vec3 rep) -{ - vec3 Pi0 = mod(floor(P), rep); // Integer part, modulo period - vec3 Pi1 = mod(Pi0 + vec3(1.0), rep); // Integer part + 1, mod period - Pi0 = mod289(Pi0); - Pi1 = mod289(Pi1); - vec3 Pf0 = fract(P); // Fractional part for interpolation - vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0 - vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x); - vec4 iy = vec4(Pi0.yy, Pi1.yy); - vec4 iz0 = Pi0.zzzz; - vec4 iz1 = Pi1.zzzz; - - vec4 ixy = permute(permute(ix) + iy); - vec4 ixy0 = permute(ixy + iz0); - vec4 ixy1 = permute(ixy + iz1); - - vec4 gx0 = ixy0 * (1.0 / 7.0); - vec4 gy0 = fract(floor(gx0) * (1.0 / 7.0)) - 0.5; - gx0 = fract(gx0); - vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0); - vec4 sz0 = step(gz0, vec4(0.0)); - gx0 -= sz0 * (step(0.0, gx0) - 0.5); - gy0 -= sz0 * (step(0.0, gy0) - 0.5); - - vec4 gx1 = ixy1 * (1.0 / 7.0); - vec4 gy1 = fract(floor(gx1) * (1.0 / 7.0)) - 0.5; - gx1 = fract(gx1); - vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1); - vec4 sz1 = step(gz1, vec4(0.0)); - gx1 -= sz1 * (step(0.0, gx1) - 0.5); - gy1 -= sz1 * (step(0.0, gy1) - 0.5); - - vec3 g000 = vec3(gx0.x,gy0.x,gz0.x); - vec3 g100 = vec3(gx0.y,gy0.y,gz0.y); - vec3 g010 = vec3(gx0.z,gy0.z,gz0.z); - vec3 g110 = vec3(gx0.w,gy0.w,gz0.w); - vec3 g001 = vec3(gx1.x,gy1.x,gz1.x); - vec3 g101 = vec3(gx1.y,gy1.y,gz1.y); - vec3 g011 = vec3(gx1.z,gy1.z,gz1.z); - vec3 g111 = vec3(gx1.w,gy1.w,gz1.w); - - vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110))); - g000 *= norm0.x; - g010 *= norm0.y; - g100 *= norm0.z; - g110 *= norm0.w; - vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111))); - g001 *= norm1.x; - g011 *= norm1.y; - g101 *= norm1.z; - g111 *= norm1.w; - - float n000 = dot(g000, Pf0); - float n100 = dot(g100, vec3(Pf1.x, Pf0.yz)); - float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z)); - float n110 = dot(g110, vec3(Pf1.xy, Pf0.z)); - float n001 = dot(g001, vec3(Pf0.xy, Pf1.z)); - float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z)); - float n011 = dot(g011, vec3(Pf0.x, Pf1.yz)); - float n111 = dot(g111, Pf1); - - vec3 fade_xyz = fade(Pf0); - vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z); - vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y); - float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); - return 2.2 * n_xyz; -} - -#pragma glslify: export(pnoise) diff --git a/src/assets/shaders/_inc/glsl-noise/periodic/4d.glsl b/src/assets/shaders/_inc/glsl-noise/periodic/4d.glsl deleted file mode 100644 index a754ba4..0000000 --- a/src/assets/shaders/_inc/glsl-noise/periodic/4d.glsl +++ /dev/null @@ -1,169 +0,0 @@ -// -// GLSL textureless classic 4D noise "cnoise", -// with an RSL-style periodic variant "pnoise". -// Author: Stefan Gustavson (stefan.gustavson@liu.se) -// Version: 2011-08-22 -// -// Many thanks to Ian McEwan of Ashima Arts for the -// ideas for permutation and gradient selection. -// -// Copyright (c) 2011 Stefan Gustavson. All rights reserved. -// Distributed under the MIT license. See LICENSE file. -// https://github.com/ashima/webgl-noise -// - -vec4 mod289(vec4 x) -{ - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -vec4 permute(vec4 x) -{ - return mod289(((x*34.0)+1.0)*x); -} - -vec4 taylorInvSqrt(vec4 r) -{ - return 1.79284291400159 - 0.85373472095314 * r; -} - -vec4 fade(vec4 t) { - return t*t*t*(t*(t*6.0-15.0)+10.0); -} - -// Classic Perlin noise, periodic version -float pnoise(vec4 P, vec4 rep) -{ - vec4 Pi0 = mod(floor(P), rep); // Integer part modulo rep - vec4 Pi1 = mod(Pi0 + 1.0, rep); // Integer part + 1 mod rep - Pi0 = mod289(Pi0); - Pi1 = mod289(Pi1); - vec4 Pf0 = fract(P); // Fractional part for interpolation - vec4 Pf1 = Pf0 - 1.0; // Fractional part - 1.0 - vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x); - vec4 iy = vec4(Pi0.yy, Pi1.yy); - vec4 iz0 = vec4(Pi0.zzzz); - vec4 iz1 = vec4(Pi1.zzzz); - vec4 iw0 = vec4(Pi0.wwww); - vec4 iw1 = vec4(Pi1.wwww); - - vec4 ixy = permute(permute(ix) + iy); - vec4 ixy0 = permute(ixy + iz0); - vec4 ixy1 = permute(ixy + iz1); - vec4 ixy00 = permute(ixy0 + iw0); - vec4 ixy01 = permute(ixy0 + iw1); - vec4 ixy10 = permute(ixy1 + iw0); - vec4 ixy11 = permute(ixy1 + iw1); - - vec4 gx00 = ixy00 * (1.0 / 7.0); - vec4 gy00 = floor(gx00) * (1.0 / 7.0); - vec4 gz00 = floor(gy00) * (1.0 / 6.0); - gx00 = fract(gx00) - 0.5; - gy00 = fract(gy00) - 0.5; - gz00 = fract(gz00) - 0.5; - vec4 gw00 = vec4(0.75) - abs(gx00) - abs(gy00) - abs(gz00); - vec4 sw00 = step(gw00, vec4(0.0)); - gx00 -= sw00 * (step(0.0, gx00) - 0.5); - gy00 -= sw00 * (step(0.0, gy00) - 0.5); - - vec4 gx01 = ixy01 * (1.0 / 7.0); - vec4 gy01 = floor(gx01) * (1.0 / 7.0); - vec4 gz01 = floor(gy01) * (1.0 / 6.0); - gx01 = fract(gx01) - 0.5; - gy01 = fract(gy01) - 0.5; - gz01 = fract(gz01) - 0.5; - vec4 gw01 = vec4(0.75) - abs(gx01) - abs(gy01) - abs(gz01); - vec4 sw01 = step(gw01, vec4(0.0)); - gx01 -= sw01 * (step(0.0, gx01) - 0.5); - gy01 -= sw01 * (step(0.0, gy01) - 0.5); - - vec4 gx10 = ixy10 * (1.0 / 7.0); - vec4 gy10 = floor(gx10) * (1.0 / 7.0); - vec4 gz10 = floor(gy10) * (1.0 / 6.0); - gx10 = fract(gx10) - 0.5; - gy10 = fract(gy10) - 0.5; - gz10 = fract(gz10) - 0.5; - vec4 gw10 = vec4(0.75) - abs(gx10) - abs(gy10) - abs(gz10); - vec4 sw10 = step(gw10, vec4(0.0)); - gx10 -= sw10 * (step(0.0, gx10) - 0.5); - gy10 -= sw10 * (step(0.0, gy10) - 0.5); - - vec4 gx11 = ixy11 * (1.0 / 7.0); - vec4 gy11 = floor(gx11) * (1.0 / 7.0); - vec4 gz11 = floor(gy11) * (1.0 / 6.0); - gx11 = fract(gx11) - 0.5; - gy11 = fract(gy11) - 0.5; - gz11 = fract(gz11) - 0.5; - vec4 gw11 = vec4(0.75) - abs(gx11) - abs(gy11) - abs(gz11); - vec4 sw11 = step(gw11, vec4(0.0)); - gx11 -= sw11 * (step(0.0, gx11) - 0.5); - gy11 -= sw11 * (step(0.0, gy11) - 0.5); - - vec4 g0000 = vec4(gx00.x,gy00.x,gz00.x,gw00.x); - vec4 g1000 = vec4(gx00.y,gy00.y,gz00.y,gw00.y); - vec4 g0100 = vec4(gx00.z,gy00.z,gz00.z,gw00.z); - vec4 g1100 = vec4(gx00.w,gy00.w,gz00.w,gw00.w); - vec4 g0010 = vec4(gx10.x,gy10.x,gz10.x,gw10.x); - vec4 g1010 = vec4(gx10.y,gy10.y,gz10.y,gw10.y); - vec4 g0110 = vec4(gx10.z,gy10.z,gz10.z,gw10.z); - vec4 g1110 = vec4(gx10.w,gy10.w,gz10.w,gw10.w); - vec4 g0001 = vec4(gx01.x,gy01.x,gz01.x,gw01.x); - vec4 g1001 = vec4(gx01.y,gy01.y,gz01.y,gw01.y); - vec4 g0101 = vec4(gx01.z,gy01.z,gz01.z,gw01.z); - vec4 g1101 = vec4(gx01.w,gy01.w,gz01.w,gw01.w); - vec4 g0011 = vec4(gx11.x,gy11.x,gz11.x,gw11.x); - vec4 g1011 = vec4(gx11.y,gy11.y,gz11.y,gw11.y); - vec4 g0111 = vec4(gx11.z,gy11.z,gz11.z,gw11.z); - vec4 g1111 = vec4(gx11.w,gy11.w,gz11.w,gw11.w); - - vec4 norm00 = taylorInvSqrt(vec4(dot(g0000, g0000), dot(g0100, g0100), dot(g1000, g1000), dot(g1100, g1100))); - g0000 *= norm00.x; - g0100 *= norm00.y; - g1000 *= norm00.z; - g1100 *= norm00.w; - - vec4 norm01 = taylorInvSqrt(vec4(dot(g0001, g0001), dot(g0101, g0101), dot(g1001, g1001), dot(g1101, g1101))); - g0001 *= norm01.x; - g0101 *= norm01.y; - g1001 *= norm01.z; - g1101 *= norm01.w; - - vec4 norm10 = taylorInvSqrt(vec4(dot(g0010, g0010), dot(g0110, g0110), dot(g1010, g1010), dot(g1110, g1110))); - g0010 *= norm10.x; - g0110 *= norm10.y; - g1010 *= norm10.z; - g1110 *= norm10.w; - - vec4 norm11 = taylorInvSqrt(vec4(dot(g0011, g0011), dot(g0111, g0111), dot(g1011, g1011), dot(g1111, g1111))); - g0011 *= norm11.x; - g0111 *= norm11.y; - g1011 *= norm11.z; - g1111 *= norm11.w; - - float n0000 = dot(g0000, Pf0); - float n1000 = dot(g1000, vec4(Pf1.x, Pf0.yzw)); - float n0100 = dot(g0100, vec4(Pf0.x, Pf1.y, Pf0.zw)); - float n1100 = dot(g1100, vec4(Pf1.xy, Pf0.zw)); - float n0010 = dot(g0010, vec4(Pf0.xy, Pf1.z, Pf0.w)); - float n1010 = dot(g1010, vec4(Pf1.x, Pf0.y, Pf1.z, Pf0.w)); - float n0110 = dot(g0110, vec4(Pf0.x, Pf1.yz, Pf0.w)); - float n1110 = dot(g1110, vec4(Pf1.xyz, Pf0.w)); - float n0001 = dot(g0001, vec4(Pf0.xyz, Pf1.w)); - float n1001 = dot(g1001, vec4(Pf1.x, Pf0.yz, Pf1.w)); - float n0101 = dot(g0101, vec4(Pf0.x, Pf1.y, Pf0.z, Pf1.w)); - float n1101 = dot(g1101, vec4(Pf1.xy, Pf0.z, Pf1.w)); - float n0011 = dot(g0011, vec4(Pf0.xy, Pf1.zw)); - float n1011 = dot(g1011, vec4(Pf1.x, Pf0.y, Pf1.zw)); - float n0111 = dot(g0111, vec4(Pf0.x, Pf1.yzw)); - float n1111 = dot(g1111, Pf1); - - vec4 fade_xyzw = fade(Pf0); - vec4 n_0w = mix(vec4(n0000, n1000, n0100, n1100), vec4(n0001, n1001, n0101, n1101), fade_xyzw.w); - vec4 n_1w = mix(vec4(n0010, n1010, n0110, n1110), vec4(n0011, n1011, n0111, n1111), fade_xyzw.w); - vec4 n_zw = mix(n_0w, n_1w, fade_xyzw.z); - vec2 n_yzw = mix(n_zw.xy, n_zw.zw, fade_xyzw.y); - float n_xyzw = mix(n_yzw.x, n_yzw.y, fade_xyzw.x); - return 2.2 * n_xyzw; -} - -#pragma glslify: export(pnoise) diff --git a/src/assets/shaders/_inc/glsl-noise/simplex/2d.glsl b/src/assets/shaders/_inc/glsl-noise/simplex/2d.glsl deleted file mode 100644 index 7c89a87..0000000 --- a/src/assets/shaders/_inc/glsl-noise/simplex/2d.glsl +++ /dev/null @@ -1,72 +0,0 @@ -// -// Description : Array and textureless GLSL 2D simplex noise function. -// Author : Ian McEwan, Ashima Arts. -// Maintainer : ijm -// Lastmod : 20110822 (ijm) -// License : Copyright (C) 2011 Ashima Arts. All rights reserved. -// Distributed under the MIT License. See LICENSE file. -// https://github.com/ashima/webgl-noise -// - -vec3 mod289(vec3 x) { - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -vec2 mod289(vec2 x) { - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -vec3 permute(vec3 x) { - return mod289(((x*34.0)+1.0)*x); -} - -float snoise(vec2 v) - { - const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0 - 0.366025403784439, // 0.5*(sqrt(3.0)-1.0) - -0.577350269189626, // -1.0 + 2.0 * C.x - 0.024390243902439); // 1.0 / 41.0 -// First corner - vec2 i = floor(v + dot(v, C.yy) ); - vec2 x0 = v - i + dot(i, C.xx); - -// Other corners - vec2 i1; - //i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0 - //i1.y = 1.0 - i1.x; - i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); - // x0 = x0 - 0.0 + 0.0 * C.xx ; - // x1 = x0 - i1 + 1.0 * C.xx ; - // x2 = x0 - 1.0 + 2.0 * C.xx ; - vec4 x12 = x0.xyxy + C.xxzz; - x12.xy -= i1; - -// Permutations - i = mod289(i); // Avoid truncation effects in permutation - vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 )) - + i.x + vec3(0.0, i1.x, 1.0 )); - - vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0); - m = m*m ; - m = m*m ; - -// Gradients: 41 points uniformly over a line, mapped onto a diamond. -// The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287) - - vec3 x = 2.0 * fract(p * C.www) - 1.0; - vec3 h = abs(x) - 0.5; - vec3 ox = floor(x + 0.5); - vec3 a0 = x - ox; - -// Normalise gradients implicitly by scaling m -// Approximation of: m *= inversesqrt( a0*a0 + h*h ); - m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h ); - -// Compute final noise value at P - vec3 g; - g.x = a0.x * x0.x + h.x * x0.y; - g.yz = a0.yz * x12.xz + h.yz * x12.yw; - return 130.0 * dot(m, g); -} - -#pragma glslify: export(snoise) diff --git a/src/assets/shaders/_inc/glsl-noise/simplex/3d.glsl b/src/assets/shaders/_inc/glsl-noise/simplex/3d.glsl deleted file mode 100644 index c9b8dcb..0000000 --- a/src/assets/shaders/_inc/glsl-noise/simplex/3d.glsl +++ /dev/null @@ -1,104 +0,0 @@ -// -// Description : Array and textureless GLSL 2D/3D/4D simplex -// noise functions. -// Author : Ian McEwan, Ashima Arts. -// Maintainer : ijm -// Lastmod : 20110822 (ijm) -// License : Copyright (C) 2011 Ashima Arts. All rights reserved. -// Distributed under the MIT License. See LICENSE file. -// https://github.com/ashima/webgl-noise -// - -vec3 mod289(vec3 x) { - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -vec4 mod289(vec4 x) { - return x - floor(x * (1.0 / 289.0)) * 289.0; -} - -vec4 permute(vec4 x) { - return mod289(((x*34.0)+1.0)*x); -} - -vec4 taylorInvSqrt(vec4 r) -{ - return 1.79284291400159 - 0.85373472095314 * r; -} - -float snoise(vec3 v) - { - const vec2 C = vec2(1.0/6.0, 1.0/3.0) ; - const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); - -// First corner - vec3 i = floor(v + dot(v, C.yyy) ); - vec3 x0 = v - i + dot(i, C.xxx) ; - -// Other corners - vec3 g = step(x0.yzx, x0.xyz); - vec3 l = 1.0 - g; - vec3 i1 = min( g.xyz, l.zxy ); - vec3 i2 = max( g.xyz, l.zxy ); - - // x0 = x0 - 0.0 + 0.0 * C.xxx; - // x1 = x0 - i1 + 1.0 * C.xxx; - // x2 = x0 - i2 + 2.0 * C.xxx; - // x3 = x0 - 1.0 + 3.0 * C.xxx; - vec3 x1 = x0 - i1 + C.xxx; - vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y - vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y - -// Permutations - i = mod289(i); - vec4 p = permute( permute( permute( - i.z + vec4(0.0, i1.z, i2.z, 1.0 )) - + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) - + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); - -// Gradients: 7x7 points over a square, mapped onto an octahedron. -// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) - float n_ = 0.142857142857; // 1.0/7.0 - vec3 ns = n_ * D.wyz - D.xzx; - - vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7) - - vec4 x_ = floor(j * ns.z); - vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N) - - vec4 x = x_ *ns.x + ns.yyyy; - vec4 y = y_ *ns.x + ns.yyyy; - vec4 h = 1.0 - abs(x) - abs(y); - - vec4 b0 = vec4( x.xy, y.xy ); - vec4 b1 = vec4( x.zw, y.zw ); - - //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; - //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; - vec4 s0 = floor(b0)*2.0 + 1.0; - vec4 s1 = floor(b1)*2.0 + 1.0; - vec4 sh = -step(h, vec4(0.0)); - - vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ; - vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ; - - vec3 p0 = vec3(a0.xy,h.x); - vec3 p1 = vec3(a0.zw,h.y); - vec3 p2 = vec3(a1.xy,h.z); - vec3 p3 = vec3(a1.zw,h.w); - -//Normalise gradients - vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); - p0 *= norm.x; - p1 *= norm.y; - p2 *= norm.z; - p3 *= norm.w; - -// Mix final noise value - vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); - m = m * m; - return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), - dot(p2,x2), dot(p3,x3) ) ); - } - -// #pragma glslify: export(snoise) diff --git a/src/assets/shaders/_inc/glsl-noise/simplex/4d.glsl b/src/assets/shaders/_inc/glsl-noise/simplex/4d.glsl deleted file mode 100644 index 76ee01c..0000000 --- a/src/assets/shaders/_inc/glsl-noise/simplex/4d.glsl +++ /dev/null @@ -1,130 +0,0 @@ -// -// Description : Array and textureless GLSL 2D/3D/4D simplex -// noise functions. -// Author : Ian McEwan, Ashima Arts. -// Maintainer : ijm -// Lastmod : 20110822 (ijm) -// License : Copyright (C) 2011 Ashima Arts. All rights reserved. -// Distributed under the MIT License. See LICENSE file. -// https://github.com/ashima/webgl-noise -// - -vec4 mod289(vec4 x) { - return x - floor(x * (1.0 / 289.0)) * 289.0; } - -float mod289(float x) { - return x - floor(x * (1.0 / 289.0)) * 289.0; } - -vec4 permute(vec4 x) { - return mod289(((x*34.0)+1.0)*x); -} - -float permute(float x) { - return mod289(((x*34.0)+1.0)*x); -} - -vec4 taylorInvSqrt(vec4 r) -{ - return 1.79284291400159 - 0.85373472095314 * r; -} - -float taylorInvSqrt(float r) -{ - return 1.79284291400159 - 0.85373472095314 * r; -} - -vec4 grad4(float j, vec4 ip) - { - const vec4 ones = vec4(1.0, 1.0, 1.0, -1.0); - vec4 p,s; - - p.xyz = floor( fract (vec3(j) * ip.xyz) * 7.0) * ip.z - 1.0; - p.w = 1.5 - dot(abs(p.xyz), ones.xyz); - s = vec4(lessThan(p, vec4(0.0))); - p.xyz = p.xyz + (s.xyz*2.0 - 1.0) * s.www; - - return p; - } - -// (sqrt(5) - 1)/4 = F4, used once below -#define F4 0.309016994374947451 - -float snoise(vec4 v) - { - const vec4 C = vec4( 0.138196601125011, // (5 - sqrt(5))/20 G4 - 0.276393202250021, // 2 * G4 - 0.414589803375032, // 3 * G4 - -0.447213595499958); // -1 + 4 * G4 - -// First corner - vec4 i = floor(v + dot(v, vec4(F4)) ); - vec4 x0 = v - i + dot(i, C.xxxx); - -// Other corners - -// Rank sorting originally contributed by Bill Licea-Kane, AMD (formerly ATI) - vec4 i0; - vec3 isX = step( x0.yzw, x0.xxx ); - vec3 isYZ = step( x0.zww, x0.yyz ); -// i0.x = dot( isX, vec3( 1.0 ) ); - i0.x = isX.x + isX.y + isX.z; - i0.yzw = 1.0 - isX; -// i0.y += dot( isYZ.xy, vec2( 1.0 ) ); - i0.y += isYZ.x + isYZ.y; - i0.zw += 1.0 - isYZ.xy; - i0.z += isYZ.z; - i0.w += 1.0 - isYZ.z; - - // i0 now contains the unique values 0,1,2,3 in each channel - vec4 i3 = clamp( i0, 0.0, 1.0 ); - vec4 i2 = clamp( i0-1.0, 0.0, 1.0 ); - vec4 i1 = clamp( i0-2.0, 0.0, 1.0 ); - - // x0 = x0 - 0.0 + 0.0 * C.xxxx - // x1 = x0 - i1 + 1.0 * C.xxxx - // x2 = x0 - i2 + 2.0 * C.xxxx - // x3 = x0 - i3 + 3.0 * C.xxxx - // x4 = x0 - 1.0 + 4.0 * C.xxxx - vec4 x1 = x0 - i1 + C.xxxx; - vec4 x2 = x0 - i2 + C.yyyy; - vec4 x3 = x0 - i3 + C.zzzz; - vec4 x4 = x0 + C.wwww; - -// Permutations - i = mod289(i); - float j0 = permute( permute( permute( permute(i.w) + i.z) + i.y) + i.x); - vec4 j1 = permute( permute( permute( permute ( - i.w + vec4(i1.w, i2.w, i3.w, 1.0 )) - + i.z + vec4(i1.z, i2.z, i3.z, 1.0 )) - + i.y + vec4(i1.y, i2.y, i3.y, 1.0 )) - + i.x + vec4(i1.x, i2.x, i3.x, 1.0 )); - -// Gradients: 7x7x6 points over a cube, mapped onto a 4-cross polytope -// 7*7*6 = 294, which is close to the ring size 17*17 = 289. - vec4 ip = vec4(1.0/294.0, 1.0/49.0, 1.0/7.0, 0.0) ; - - vec4 p0 = grad4(j0, ip); - vec4 p1 = grad4(j1.x, ip); - vec4 p2 = grad4(j1.y, ip); - vec4 p3 = grad4(j1.z, ip); - vec4 p4 = grad4(j1.w, ip); - -// Normalise gradients - vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); - p0 *= norm.x; - p1 *= norm.y; - p2 *= norm.z; - p3 *= norm.w; - p4 *= taylorInvSqrt(dot(p4,p4)); - -// Mix contributions from the five corners - vec3 m0 = max(0.6 - vec3(dot(x0,x0), dot(x1,x1), dot(x2,x2)), 0.0); - vec2 m1 = max(0.6 - vec2(dot(x3,x3), dot(x4,x4) ), 0.0); - m0 = m0 * m0; - m1 = m1 * m1; - return 49.0 * ( dot(m0*m0, vec3( dot( p0, x0 ), dot( p1, x1 ), dot( p2, x2 ))) - + dot(m1*m1, vec2( dot( p3, x3 ), dot( p4, x4 ) ) ) ) ; - - } - -#pragma glslify: export(snoise) diff --git a/src/assets/shaders/fragment.glsl b/src/assets/shaders/fragment.glsl deleted file mode 100644 index 743612b..0000000 --- a/src/assets/shaders/fragment.glsl +++ /dev/null @@ -1,46 +0,0 @@ -varying float vTime; -varying vec2 vUv; - -varying float vFrontShadow; -uniform sampler2D uTexture; -uniform float uTextureAspect; -uniform float uPlaneAspect; - -vec2 ratio(float p, float t, float s){ - return vec2( - min(p / t, 1.0) * s, - (min((1.0 / p) / (1.0 / t), 1.0)) * s - ); -} - -vec2 optimizationUv(vec2 uv, vec2 ratio){ - return vec2( - ((uv.x - 0.5) * ratio.x + 0.5), - ((uv.y - 0.5) * ratio.y + 0.5) - ); -} - -vec3 rgbToGrayscale(vec3 color) { - float average = (color.r + color.g + color.b) / 3.0; - return vec3(average); -} - -void main( void ) { - vec2 uv = vUv; - vec2 ratio1 = ratio(uPlaneAspect, uTextureAspect, 1.); - vec2 uv1 = optimizationUv(uv, ratio1); - vec4 texture = texture2D(uTexture, uv1); - - if (gl_FrontFacing) { - // 表 - texture.rgb *= vFrontShadow; - } else { - // 裏 - texture.rgb = rgbToGrayscale(texture.rgb); - texture = vec4( - texture.rgb, 1.0 - ); - }; - gl_FragColor = texture; -} - diff --git a/src/assets/shaders/vertex.glsl b/src/assets/shaders/vertex.glsl deleted file mode 100644 index 3338d9f..0000000 --- a/src/assets/shaders/vertex.glsl +++ /dev/null @@ -1,118 +0,0 @@ -varying float vTime; -varying float vFrontShadow; -varying vec2 vUv; - -uniform float uScale; -uniform float uTime; -uniform float uAnime; -uniform float uAngle; -// uniform float uTwist; -// uniform float uProgress; - -const float PI = 3.1415925; -const float RADIUS = 0.1; -const float ROLL = 8.0; - -mat4 rotationMatrix(vec3 axis, float angle) { - axis = normalize(axis); - float s = sin(angle); - float c = cos(angle); - float oc = 1.0 - c; - - return mat4( - oc * axis.x * axis.x + c, - oc * axis.x * axis.y - axis.z * s, - oc * axis.z * axis.x + axis.y * s, - 0.0, - oc * axis.x * axis.y + axis.z * s, - oc * axis.y * axis.y + c, - oc * axis.y * axis.z - axis.x * s, - 0.0, - oc * axis.z * axis.x - axis.y * s, - oc * axis.y * axis.z + axis.x * s, - oc * axis.z * axis.z + c, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0 - ); -} - -vec3 rotate(vec3 v, vec3 axis, float angle) { - mat4 m = rotationMatrix(axis, angle); - return (m * vec4(v, 1.0)).xyz; -} - -float map(float x, float a, float b, float c, float d) { - return (x - a) * (d - c) / (b - a) + c; -} - -void main(){ - vUv = uv; - vTime = uTime; - - // 進捗範囲を`0.0 ~ 1.0`から最小値を半径分マイナスにする - float progress = map(uAnime, 0.0, 1.0, RADIUS * -1.0, 1.0); - - // 回転量 - float angle = uAngle; - - vec3 pos = position; - // Z軸ベクトルを基準に回転させ位置を中心に調整する - pos = rotate( - pos - vec3(-0.5, 0.5, 0.0), - vec3(0.0, 0.0, 1.0), - angle * -1.0 - ) + vec3(-0.5, 0.5, 0.0); - - // ローカル原点を右端にする、移動する範囲をangleに合わせる - // `pos.x`の範囲`0.5 ~ 1.5`を`-1.9986 ≤ sin(angle) + cos(angle) ≤ 1.0016`にあわせる - // その結果、`0.49984797903 ≤ offset ≤ -0.75026367436`となる - float offset = (pos.x + 0.5) / (sin(angle) + cos(angle)); - - // ロールする位置を設定 - pos.z = RADIUS + RADIUS * (1.0 - offset * 0.5) * sin(-offset * ROLL * PI - 0.5 * PI); - pos.x = -0.5 + RADIUS * (1.0 - offset * 0.5) * cos(-offset * ROLL * PI + 0.5 * PI); - - // ローカル原点で回転する状態からz軸ベクトル中心に回転するように補正する - pos = rotate( - pos - vec3(-0.5,0.5,0.0), - vec3(0.0,0.0,1.0), - angle - ) + vec3(-0.5,0.5,0.0); - - // 原点(中点)からになるように補正する、Z軸(上下)には半径(ベクトル)に合わせて正しい回転が得られるようにする - pos = pos - vec3(-0.5,0.5, RADIUS); - - // ロールアニメーション - pos = rotate( - pos, - vec3(sin(angle), cos(angle), 0.0), - -PI * progress * ROLL - ); - - // 並行移動のアニメーション - pos += vec3( - -0.5 + progress * cos(angle) * (sin(angle) + cos(angle)), - 0.5 - progress * sin(angle) * (sin(angle) + cos(angle)), - RADIUS * (1.0 - progress * 0.5) - ); - - // 平面とロールの位置を補完する - float interpolationValue = (progress - offset * 0.95) * 100.0; - float interpolation = clamp( - interpolationValue, - 0.0, - 1.0 - ); - vec3 lastPosition = mix(pos, position, interpolation); - gl_Position = projectionMatrix * modelViewMatrix * vec4(lastPosition * 1.0, 1.0 ); - - // shadows - vFrontShadow = clamp( - interpolationValue, - 0.5, - 1.0 - ); -} diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro index abb7596..cad8317 100644 --- a/src/layouts/Layout.astro +++ b/src/layouts/Layout.astro @@ -14,8 +14,8 @@ export interface Props { const SITE = import.meta.env.SITE; const { - title = "WebGL Carousel Demo.06 ~ PaperAnimation | Toys.No.028 | ShoyaKajita.", - description = "WebGL Carousel Demo.06 ~ PaperAnimation | WebGL Three.js GLSL | Interactive toys created by ShoyaKajita.", + title = "WebGL School Task.07 ~ Plane geometry animation using pure WebGL. | Toys.No.029 | ShoyaKajita.", + description = "WebGL School Task.07 ~ Plane geometry animation using pure WebGL. | WebGL Three.js GLSL | Interactive toys created by ShoyaKajita.", themeColor = "#161616", ogType = "website", ogImg = "assets/img/head/screenshot.webp", @@ -61,6 +61,7 @@ const gtag = ` diff --git a/src/pages/index.astro b/src/pages/index.astro index 23b933f..ddf289d 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -1,74 +1,200 @@ --- import Layout from "../layouts/Layout.astro"; + +const itemList = [ + { + label: "Iron Man", + imgName: "ironman", + width: 900, + height: 540, + }, + { + label: "Spiderman", + imgName: "spiderman", + width: 900, + height: 540, + }, + { + label: "War machine", + imgName: "warmachine", + width: 900, + height: 540, + }, + { + label: "Captain America", + imgName: "captainamerica", + width: 900, + height: 540, + }, + { + label: "Falcon", + imgName: "falcon", + width: 900, + height: 540, + }, + { + label: "The Winter Soldier", + imgName: "wintersoldier", + width: 900, + height: 540, + }, + { + label: "Thor", + imgName: "thor", + width: 900, + height: 540, + }, + { + label: "Vision", + imgName: "vision", + width: 900, + height: 540, + }, + { + label: "Black Widow", + imgName: "blackwidow", + width: 900, + height: 540, + }, + { + label: "Doctor Strange", + imgName: "doctorstrange", + width: 900, + height: 540, + }, + { + label: "Wong", + imgName: "wong", + width: 900, + height: 540, + }, + { + label: "Drax the Destroyer", + imgName: "drax", + width: 900, + height: 540, + }, + { + label: "Hulk", + imgName: "hulk", + width: 900, + height: 540, + }, + { + label: "Black Panther", + imgName: "blackpanther", + width: 900, + height: 540, + }, + { + label: "Okoye", + imgName: "okoye", + width: 900, + height: 540, + }, + { + label: "Shuri", + imgName: "syuri", + width: 900, + height: 540, + }, + { + label: "Star Lord", + imgName: "starroad", + width: 900, + height: 540, + }, + { + label: "Rocket Raccoon", + imgName: "rocket", + width: 900, + height: 540, + }, + { + label: "Groot", + imgName: "groot", + width: 900, + height: 540, + }, + { + label: "Gamora", + imgName: "gamora", + width: 900, + height: 540, + }, + { + label: "Mantis", + imgName: "mantis", + width: 900, + height: 540, + }, + { + label: "Nebula", + imgName: "nebula", + width: 900, + height: 540, + }, + { + label: "Scarlet Witch", + imgName: "scarletwitch", + width: 900, + height: 540, + }, +]; --- -

- WebGL Carousel
- DEMO.06 -

-
-
-
WHEEL Y MOVE
-
-
-
-
DRAG X MOVE
-
-
-
- - - +
+
-