{"id":696,"date":"2024-02-08T13:35:46","date_gmt":"2024-02-08T13:35:46","guid":{"rendered":"https:\/\/shores.design\/?page_id=696"},"modified":"2024-02-13T02:47:06","modified_gmt":"2024-02-13T02:47:06","slug":"webgl-shaders","status":"publish","type":"page","link":"https:\/\/shores.design\/index.php\/webgl-shaders\/","title":{"rendered":"WebGL-Shaders"},"content":{"rendered":"<div data-colibri-id=\"696-c1\" class=\"style-415 style-local-696-c1 position-relative\">\n  <!---->\n  <div data-colibri-component=\"section\" data-colibri-id=\"696-c2\" id=\"custom\" class=\"h-section h-section-global-spacing d-flex align-items-lg-center align-items-md-center align-items-center style-416 style-local-696-c2 position-relative\">\n    <!---->\n    <!---->\n    <div class=\"h-section-grid-container h-section-fluid-container\">\n      <!---->\n      <div data-colibri-id=\"696-c3\" class=\"h-row-container gutters-row-lg-0 gutters-row-md-0 gutters-row-0 gutters-row-v-lg-0 gutters-row-v-md-0 gutters-row-v-0 style-417 style-local-696-c3 position-relative\">\n        <!---->\n        <div class=\"h-row justify-content-lg-center justify-content-md-center justify-content-center align-items-lg-start align-items-md-start align-items-start gutters-col-lg-0 gutters-col-md-0 gutters-col-0 gutters-col-v-lg-0 gutters-col-v-md-0 gutters-col-v-0\">\n          <!---->\n          <div class=\"h-column h-column-container d-flex h-col-lg h-col-md h-col-auto align-self-lg-start align-self-md-start align-self-start style-418-outer style-local-696-c4-outer\">\n            <div data-colibri-id=\"696-c4\" class=\"d-flex h-flex-basis h-column__inner h-px-lg-0 h-px-md-0 h-px-0 v-inner-lg-0 v-inner-md-0 v-inner-0 style-418 style-local-696-c4 position-relative\">\n              <!---->\n              <!---->\n              <div class=\"w-100 h-y-container h-column__content h-column__v-align flex-basis-100 align-self-lg-center align-self-md-center align-self-center\">\n                <!---->\n                <div data-colibri-id=\"696-c5\" class=\"style-419 style-local-696-c5 position-relative h-element\">\n                  <!---->\n                  <div class=\"\"><!DOCTYPE html>\r\n<html>\r\n<head>\r\n    <meta charset=\"UTF-8\" \/>\r\n    <title>Shader Examples<\/title>\r\n    <style>\r\n        html {\r\n            height: 100%;\r\n            width: 100%;\r\n        }\r\n        body {\r\n            overflow: hidden;\r\n            height: 100%;\r\n            width: 100%;\r\n            margin: 0;\r\n        }\r\n        .container {\r\n            position: absolute;\r\n            left: 10px;\r\n            top: 10px;        \r\n            width: 95px;\r\n            background-color: rgb(235, 235, 235);\r\n            border-radius: 10px;\r\n            padding: 10px;\r\n            box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);\r\n        }\r\n        .btn {\r\n            width: 100%;\r\n            padding: 5px;\r\n            margin-bottom: 5px;\r\n            border: none;\r\n            border-radius: 5px;\r\n            background-color: rgb(82, 82, 82);\r\n            color: rgb(235, 235, 235);\r\n            cursor: pointer;\r\n            transition: background-color 0.3s ease;\r\n        }\r\n        .btn:last-child {\r\n            margin-bottom: 0;\r\n        }\r\n        .btn:hover {\r\n            background-color: rgb(70, 70, 70);\r\n        }\r\n        .circle-btn {\r\n            width: 35px; \/* Adjust size as needed *\/\r\n            height: 35px; \/* Adjust size as needed *\/\r\n            border-radius: 50%;\r\n            background-color: rgb(82, 82, 82); \/* Button color *\/\r\n            color: rgb(235, 235, 235); \/* Text color *\/\r\n            font-size: 10px; \/* Adjust font size as needed *\/\r\n            line-height: 30px; \/* Adjust line-height to match the button height *\/\r\n            border: none;\r\n            cursor: pointer;\r\n            display: flex;\r\n            justify-content: center;\r\n            align-items: center;\r\n            margin-left: 20px;\r\n            outline: none; \/* Remove focus outline *\/\r\n            transition: background-color 0.3s ease;\r\n        }\r\n\r\n        .circle-btn:hover {\r\n            background-color: rgb(70, 70, 70); \/* Button color on hover *\/\r\n        }\r\n    <\/style>\r\n<\/head>\r\n<body>\r\n    <canvas id=\"webglCanvas\"><\/canvas> \r\n    <div class=\"container\">\r\n        <button class=\"btn\" onclick=\"changeShader('ribbons')\">Ribbons<\/button>\r\n        <button class=\"btn\" onclick=\"changeShader('orb')\">Orb<\/button>\r\n        <button class=\"circle-btn\" onclick=\"location='https:\/\/github.com\/dansh0\/webgl-fragment-shaders'\">&#60;&#47;&#62;<\/button>\r\n\r\n        <!-- <button class=\"btn\" onclick=\"changeShader('flakes')\">Flakes<\/button> -->\r\n    <\/div>\r\n    <script id=\"vertexShader\" type=\"x-shader\/x-vertex\">\r\n        attribute vec4 aPosition;\r\n        varying vec2 vUv;\r\n        void main() {\r\n            vUv = aPosition.xy\/2.0 + 0.5;\r\n            gl_Position = aPosition;\r\n        }\r\n    <\/script>\r\n    <script id=\"fragmentShaderRibbons\" type=\"x-shader\/x-fragment\">\r\n        #define MAX_STEPS_BOUNDS 10000\r\n        #define MAX_STEPS_FILL 8\r\n        #define SUBSTEPS 1\r\n        #define MAX_DIST 400.\r\n        #define MIN_DIST 0.01\r\n        #define DOTS_PER_MM 10.\r\n        #define NORM_EPS 0.001\r\n        #define PI 3.141592\r\n\r\n        precision mediump float;\r\n        uniform float uTime;\r\n        uniform vec2 uResolution;\r\n\r\n        \/\/ PARAMS\r\n        float tpmsDiv = 5.0; \/\/ # of periods within the volume\r\n        float cDist = 200.; \/\/ Camera distance from center\r\n        vec3 objCol = vec3(1.0, 1.0, 1.0); \/\/ Base material color\r\n        vec3 lCol = vec3(1.0, 1.0, 1.0); \/\/ Light color\r\n        vec3 lPos = vec3(0.); \/\/ Light source position\r\n        float alStr = 0.2; \/\/ Ambient light strength\r\n        float dlStr = 0.8; \/\/ Diffuse light strength\r\n\r\n        \/\/ Globals\r\n        float scl; \/\/ Part Size\r\n        float tpmsSc; \/\/ Fill Periodicity\r\n        float tpmsFac; \/\/ Fill Density (width only in this case)\r\n\r\n        \/\/ GEOMETRY\r\n            \r\n        \/\/ Sphere SDF\r\n        float dSphere(vec3 p, vec3 c, float r) {\r\n            vec3 transPoint = (p - c);\r\n            return length(transPoint) - r;\r\n        }\r\n\r\n        \/\/ Schwarz SDF\r\n        float dSchwarz(vec3 p) {\r\n            p *= tpmsSc;\r\n            float fac = 0.10 + 0.075*sin(2.0*PI*(mod(uTime,10.0)\/10.0 + 4.0*length(p)\/scl));\r\n            return abs(dot(cos(p), vec3(1.0))) - fac;\r\n        }\r\n            \r\n\r\n        \/\/ GEOMETRY COMBINATIONS\r\n\r\n        \/\/ Distance Function Combine\r\n        float dComb( vec3 p ) {\r\n            \r\n            \/\/ geometry\r\n            float sph = dSphere( p, vec3(0.), scl);\r\n            float tpms = dSchwarz(p);\r\n            \r\n            return max(tpms, sph);\r\n            \r\n        }     \r\n\r\n            \r\n        \/\/ RAY TOOLS\r\n            \r\n        \/\/ Ray March for boundary\r\n        float mrch(vec3 p, vec3 d) {\r\n            float dist = 0.;\r\n            for (int iStep=0; iStep<MAX_STEPS_BOUNDS; iStep++) {\r\n                float mDist = dSphere( p, vec3(0.), scl);\r\n                if (mDist > MIN_DIST && dist < MAX_DIST) {\r\n                    p += mDist * d;\r\n                    dist += mDist;\r\n                } else {\r\n                    return dist;\r\n                }\r\n            }\r\n            return MAX_DIST;\r\n        }\r\n\r\n        \/\/ Volumetric raymarch for fill\r\n        float mrchFixSt(vec3 p, vec3 d, float bDist, float step, out int iter) {\r\n                    \r\n            \/\/ start at start of bounding sphere\r\n            vec3 bPos = p + bDist * d;\r\n            float dist = bDist; \r\n            p = bPos;\r\n\r\n            for (int iStep=0; iStep<MAX_STEPS_FILL; iStep++) {\r\n                float sdfDist = dComb(p);\r\n                if (sdfDist>MIN_DIST && dist<MAX_DIST) {\r\n                    p += step * d;\r\n                    dist += step;\r\n                } else {\r\n                    iter = iStep;\r\n                    return dist;\r\n                }\r\n            }\r\n            return MAX_DIST;\r\n        }\r\n            \r\n        \/\/ tpmsGradient instead of normal (maybe the same??)\r\n        vec3 tpmsGrad(vec3 p) {\r\n            vec3 change;\r\n            change.x = dSchwarz(p + vec3(NORM_EPS, 0, 0)) - dSchwarz(p - vec3(NORM_EPS, 0, 0));\r\n            change.y = dSchwarz(p + vec3(0, NORM_EPS, 0)) - dSchwarz(p - vec3(0, NORM_EPS, 0)); \r\n            change.z = dSchwarz(p + vec3(0, 0, NORM_EPS)) - dSchwarz(p - vec3(0, 0, NORM_EPS)); \r\n            return normalize( change );\r\n        }\r\n\r\n\r\n        \/\/ CAMERA TOOLS\r\n\r\n        \/\/ Orbit Controls\r\n        vec3 orbitCtrl(float cDist, vec2 sphAngles) {\r\n            \/\/ spherical angles is x = theta -PI to PI and y = phi -PI\/2 to PI\/2\r\n            vec3 cPos;\r\n            cPos.x = cDist * cos(sphAngles.x) * sin(sphAngles.y);\r\n            cPos.z = cDist * sin(sphAngles.x) * sin(sphAngles.y);\r\n            cPos.y = cDist * cos(sphAngles.y);\r\n            return cPos;  \r\n        }    \r\n\r\n\r\n        \/\/ Camera Fragment Position (Orthographic)\r\n        vec3 orthoFragP(vec3 cPos, vec3 cDir, vec2 cSize) {\r\n            vec3 up = vec3(0.0, 1.0, 0.0);\r\n            if (cDir.x == 0.0 && cDir.z == 0.0 && cDir.y != 0.0) {\r\n                up = vec3(0.0, 0.0, 1.0);\r\n            }\r\n            vec2 off = ((gl_FragCoord.xy \/ uResolution.xy) * cSize) - (cSize * 0.5);\r\n            vec3 rCh = normalize(cross(cDir, up));\r\n            vec3 upCh = normalize(cross(rCh, cDir));\r\n            vec3 wrldOff = off.x * rCh + off.y * upCh;\r\n            return cPos + wrldOff;\r\n        }\r\n\r\n            \r\n        \/\/ MAIN\r\n        void main()\r\n        {\r\n            \/\/ Background color default\r\n            vec3 col = vec3(0.0);\r\n            \r\n            \/\/ Set Geometry Size\r\n            float hMargRg = (uResolution.y + 30.) \/ 2.0;\r\n            float marg = -uResolution.y + hMargRg * (1.0-cos(uTime\/50.0));\/\/-uResolution.y; \r\n            float sphRPx = min(uResolution.y, uResolution.x)\/2.0 - marg;\r\n            scl = sphRPx \/ DOTS_PER_MM;\r\n            tpmsSc = (2.0*PI)\/((2.0*scl)\/tpmsDiv);\r\n            \r\n            \/\/ Init camera\r\n            vec2 cSize = uResolution.xy \/ DOTS_PER_MM;\r\n            vec2 cAngles = vec2(sin(uTime\/20.0)*PI, (PI\/2.0)+(sin(uTime\/25.0-PI\/2.0))*0.999*(PI\/2.0));\r\n            \/\/fragColor = vec4(vec3(-1.0*cAngles.y\/(2.0*PI), cAngles.y\/(2.0*PI), 0.0), 1.0);\r\n            vec3 cPos = orbitCtrl(cDist, cAngles);\r\n            vec3 cDir = normalize(-cPos);\r\n            vec3 fragPos = orthoFragP(cPos, cDir, cSize);\r\n            \r\n            \/\/ Ray March Step Boundary\r\n            float objDist = mrch(fragPos.xyz, cDir);\r\n            vec3 objPos = fragPos + cDir * objDist;\r\n            \r\n            \/\/ Ray March Fixed Step Lattice\r\n            float step = 2.0*scl \/ float(MAX_STEPS_FILL);\r\n            int iter;\r\n            float tpmsDist = mrchFixSt(fragPos.xyz, cDir, objDist, step, iter);\r\n            vec3 tpmsPos = fragPos + cDir * tpmsDist;\r\n            \r\n            \r\n            if (tpmsDist < MAX_DIST) {\r\n                \/\/ Find gradient\r\n                vec3 grad = tpmsGrad(tpmsPos);\r\n                objCol = 1.0 - abs(grad)\/2.0;\r\n                \r\n                \/\/ Color Based on Iteration\r\n                float colMod = 3.0;\r\n                float iterVal = floor(abs(mod(float(iter),8.0)-3.9));\r\n                vec3 colMult = vec3(float(iterVal>2.0), float(iterVal<2.0), float(iterVal>0.0));\r\n                objCol *= colMult*colMod;\r\n                \r\n                \/\/ Ambient Lighting\r\n                vec3 ambiLight = lCol * alStr;\r\n                \r\n                \/\/ Diffuse Lighting\r\n                vec3 diffDir = normalize(lPos - tpmsPos);\r\n                vec3 diffLight = lCol * dlStr * max(dot(grad, diffDir), 0.0);\r\n                \r\n                \/\/ Combined Lighting\r\n                vec3 combLight = ambiLight + diffLight;\r\n                col = combLight * objCol;\r\n\r\n            } else {\r\n                \/\/ Background\r\n                    col = vec3(abs(dSchwarz(vec3(gl_FragCoord.xy*(5.0),uTime\/2.0)\/tpmsSc))*0.1);\r\n            \r\n            }\r\n\r\n            \/\/ Output to screen\r\n            gl_FragColor = vec4(col,1.0);\r\n            \r\n        }\r\n    <\/script>\r\n    <script id=\"fragmentShaderOrb\" type=\"x-shader\/x-fragment\">\r\n        #define PI 3.14159\r\n\r\n        precision mediump float;\r\n        uniform float uTime;\r\n        uniform vec2 uResolution;\r\n\r\n        float gyroid(vec3 point) {\r\n            return cos(point.x) * sin(point.y) + cos(point.y) * sin(point.z) + cos(point.z) * sin(point.x);\r\n        }\r\n\r\n        float sphereDepth(vec2 position) {\r\n            return sqrt(1.0 - length(position)); \r\n        }\r\n\r\n        void main()\r\n        {\r\n\r\n            \/\/ try: gyroidDivisor = 15.0, margin = -uResolution.y\r\n            \/\/ try: gyroidDivisor = 5.0, margin = 20.0\r\n\r\n            \/\/ input parameters\r\n            float gyroidDivisor = 5.0; \/\/ changes gyroid periodicity\r\n            float margin = 20.0; \/\/ margin of screen, determines sphere size (try negative for massive)\r\n            float timeConstant = 20.0; \/\/ controls animation speed (higher is slower)\r\n            float gyroidPeriodSwing = 0.1; \/\/ how much the period size changes (higher is more drastic change, try to avoid crossing 1.0 or else it gets weird)\r\n            float glowPower = 0.75; \/\/ general glow (higher increases overall sphere glow)\r\n            float edgeGlowPower = 5.0; \/\/ edge glow parameter 1 (higher increases fall-off from edge to center)\r\n            float edgeGlowStrength = 5.0; \/\/ edge glow parameter 2 (higher makes edge glow brighter)\r\n            float backgroundBrightness = 0.75; \/\/ 0.0-1.0 for background brightness\r\n            \r\n            \/\/ animated\r\n            float timePhase = sin(uTime\/timeConstant);\r\n            \r\n            \/\/ inits\r\n            vec3 col;\r\n\r\n            \/\/ solve depth\r\n            float minScreenEdge = min(uResolution.y, uResolution.x);\r\n            float sphereRadiusPix = minScreenEdge\/2.0 - margin;\r\n            vec2 fragCoordCentered = gl_FragCoord.xy - (0.5*uResolution.xy);\r\n            float depth = sphereDepth(fragCoordCentered\/sphereRadiusPix);\r\n            float inverseDepth = 1.0-depth;\r\n            \r\n            \/\/ inside sphere\r\n            if (depth > 0.0) {\r\n            \r\n                \/\/ position and \"normal\"\r\n                vec3 position = vec3(fragCoordCentered\/sphereRadiusPix, depth) + timePhase;\r\n                vec3 normal = abs(position);\r\n                \r\n                \/\/ solve gyroid\r\n                float gyroidDivisorAnimated = gyroidDivisor*(1.0-(gyroidPeriodSwing\/2.0)+timePhase\/(1.0\/gyroidPeriodSwing));\r\n                float gyroidFactor = gyroid(position*2.0*PI*gyroidDivisorAnimated);\r\n                float inverseGyroidAbs = 1.5-abs(gyroidFactor);\r\n                \r\n                \/\/ solve glow\r\n                float edgeGlow = pow(inverseDepth, edgeGlowPower) * edgeGlowStrength;\r\n                float glow = glowPower + edgeGlow;\r\n                \r\n                \/\/ color\r\n                col = vec3(normal*glow*inverseGyroidAbs);\r\n            } \r\n            \r\n            \/\/ background \r\n            else {\r\n                \r\n                float maxScreenEdge = max(uResolution.y, uResolution.x);\r\n                float cornerRadius = sqrt(pow(minScreenEdge\/2.0, 2.0) + pow(maxScreenEdge\/2.0, 2.0))*1.25;\r\n                float backgroundGradient = sphereDepth(fragCoordCentered\/cornerRadius);\r\n                col = vec3(backgroundGradient*backgroundBrightness);\r\n            }\r\n            \r\n            \/\/ output to screen\r\n            gl_FragColor = vec4(col,1.0);\r\n        }\r\n    <\/script>\r\n    <script>\r\n        const canvas = document.getElementById('webglCanvas')\r\n        const gl = canvas.getContext('webgl')\r\n        let topBar = 64\r\n        let width = window.innerWidth\r\n        let height = window.innerHeight\r\n        canvas.style.height = height-topBar + 'px'\r\n        canvas.style.width = width + 'px'\r\n        canvas.width = canvas.clientWidth \/\/ resize to client canvas\r\n        canvas.height = canvas.clientHeight \/\/ resize to client canvas\r\n\r\n        \/\/ Clear Canvas\r\n        gl.clearColor(0, 0, 0, 0)\r\n        gl.clear(gl.COLOR_BUFFER_BIT)\r\n\r\n        \/\/ Set Canvas Size\r\n        console.log(canvas.width, canvas.height)\r\n        gl.viewport(0, 0, canvas.width, canvas.height)\r\n\r\n        \/\/ Set up Attributes\r\n        const positionBuff = gl.createBuffer()\r\n        gl.bindBuffer(gl.ARRAY_BUFFER, positionBuff)\r\n        let positions = [\r\n            -1, -1, -1,\r\n            -1, 1, -1,\r\n            1, 1, -1,\r\n            -1, -1, -1,\r\n            1, 1, -1,\r\n            1, -1, -1\r\n        ]\r\n        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW)\r\n        const buffSize = 3\r\n        const buffType = gl.FLOAT\r\n\r\n        \/\/ Time Function\r\n        const startTime = Date.now();\r\n        const time = () => { return Date.now() - startTime }\r\n\r\n        \/\/ Load Shaders\r\n        const vertexShader = document.getElementById('vertexShader').textContent\r\n        const fragmentShaderRibbons = document.getElementById('fragmentShaderRibbons').textContent\r\n        const fragmentShaderOrb = document.getElementById('fragmentShaderOrb').textContent\r\n        \r\n        \/\/ Compile the vertex shader\r\n        const vShader = gl.createShader( gl['VERTEX_SHADER'] )\r\n        gl.shaderSource(vShader, vertexShader);\r\n        gl.compileShader(vShader);\r\n        console.log(gl.getShaderInfoLog(vShader));\r\n\r\n        \/\/ Compile the fragment shaders\r\n        const fShaderRibbons = gl.createShader( gl['FRAGMENT_SHADER'] )\r\n        gl.shaderSource(fShaderRibbons, fragmentShaderRibbons);\r\n        gl.compileShader(fShaderRibbons);\r\n        console.log(gl.getShaderInfoLog(fShaderRibbons));\r\n\r\n        const fShaderOrb = gl.createShader( gl['FRAGMENT_SHADER'] )\r\n        gl.shaderSource(fShaderOrb, fragmentShaderOrb);\r\n        gl.compileShader(fShaderOrb);\r\n        console.log(gl.getShaderInfoLog(fShaderOrb));\r\n\r\n        \/\/ Create Program\r\n        const setUpProgram = (fShader) => {\r\n\r\n            let program = gl.createProgram()\r\n            gl.attachShader(program, vShader)\r\n            gl.attachShader(program, fShader)\r\n            gl.linkProgram(program)\r\n            gl.useProgram(program)\r\n            \r\n            const posAttribLocation = gl.getAttribLocation(program, 'aPosition')\r\n\r\n            \/\/ Instruct Program how to use attribute data\r\n            gl.enableVertexAttribArray(posAttribLocation)\r\n            gl.bindBuffer(gl.ARRAY_BUFFER, positionBuff)\r\n            gl.vertexAttribPointer( posAttribLocation, buffSize, buffType, false, 0, 0)\r\n            \r\n            \/\/ Set up Uniforms\r\n            let timeUniformLocation = gl.getUniformLocation(program, \"uTime\")\r\n            gl.uniform1f(timeUniformLocation, time())\r\n\r\n            let resUniformLocation = gl.getUniformLocation(program, \"uResolution\")\r\n            gl.uniform2f(resUniformLocation, canvas.width, canvas.height)\r\n\r\n            return program\r\n        }\r\n\r\n        let programs = {\r\n            'ribbons': setUpProgram(fShaderRibbons),\r\n            'orb': setUpProgram(fShaderOrb)\r\n        }\r\n\r\n        let currentProgram = 'ribbons'\r\n        gl.useProgram(programs[currentProgram])\r\n\r\n        \/\/ Draw\r\n        const count = parseInt(positions.length\/3)\r\n        gl.drawArrays(gl.TRIANGLES, 0, count) \/\/primitive, offset, count\r\n\r\n        \/\/ Animate!\r\n        const animate = () => {\r\n            let timeUniformLocation = gl.getUniformLocation(programs[currentProgram], \"uTime\")\r\n            gl.uniform1f(timeUniformLocation, time()\/1000)\r\n            gl.drawArrays(gl.TRIANGLES, 0, count)\r\n            requestAnimationFrame(animate);\r\n        }\r\n\r\n        const changeShader = (shaderName) => {\r\n            currentProgram = shaderName\r\n            gl.useProgram(programs[currentProgram])\r\n\r\n            window.dispatchEvent(new Event('resize'));\r\n        } \r\n\r\n        window.addEventListener(\"resize\", () => {\r\n            let width = window.innerWidth\r\n            let height = window.innerHeight\r\n            canvas.style.height = height-topBar + 'px'\r\n            canvas.style.width = width + 'px'\r\n            canvas.width = canvas.clientWidth \/\/ resize to client canvas\r\n            canvas.height = canvas.clientHeight \/\/ resize to client canvas\r\n            let resUniformLocation = gl.getUniformLocation(programs[currentProgram], \"uResolution\")\r\n            gl.uniform2f(resUniformLocation, canvas.width, canvas.height)\r\n        });\r\n\r\n        animate()\r\n    <\/script>\r\n<\/body>\r\n<\/html><\/div>\n                <\/div>\n              <\/div>\n            <\/div>\n          <\/div>\n        <\/div>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"page-templates\/full-width-page.php","meta":{"footnotes":""},"class_list":["post-696","page","type-page","status-publish","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v25.6 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>WebGL-Shaders - Shores Design<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/shores.design\/index.php\/webgl-shaders\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"WebGL-Shaders - Shores Design\" \/>\n<meta property=\"og:url\" content=\"https:\/\/shores.design\/index.php\/webgl-shaders\/\" \/>\n<meta property=\"og:site_name\" content=\"Shores Design\" \/>\n<meta property=\"article:modified_time\" content=\"2024-02-13T02:47:06+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/shores.design\/index.php\/webgl-shaders\/\",\"url\":\"https:\/\/shores.design\/index.php\/webgl-shaders\/\",\"name\":\"WebGL-Shaders - Shores Design\",\"isPartOf\":{\"@id\":\"https:\/\/shores.design\/#website\"},\"datePublished\":\"2024-02-08T13:35:46+00:00\",\"dateModified\":\"2024-02-13T02:47:06+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/shores.design\/index.php\/webgl-shaders\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/shores.design\/index.php\/webgl-shaders\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/shores.design\/index.php\/webgl-shaders\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/shores.design\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"WebGL-Shaders\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/shores.design\/#website\",\"url\":\"https:\/\/shores.design\/\",\"name\":\"Shores Design\",\"description\":\"Graphics, Web, and Desktop Design Services\",\"publisher\":{\"@id\":\"https:\/\/shores.design\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/shores.design\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/shores.design\/#organization\",\"name\":\"Shores Design\",\"url\":\"https:\/\/shores.design\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/shores.design\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/shores.design\/wp-content\/uploads\/2023\/11\/LogoBackwardsWhite.png\",\"contentUrl\":\"https:\/\/shores.design\/wp-content\/uploads\/2023\/11\/LogoBackwardsWhite.png\",\"width\":480,\"height\":480,\"caption\":\"Shores Design\"},\"image\":{\"@id\":\"https:\/\/shores.design\/#\/schema\/logo\/image\/\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"WebGL-Shaders - Shores Design","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/shores.design\/index.php\/webgl-shaders\/","og_locale":"en_US","og_type":"article","og_title":"WebGL-Shaders - Shores Design","og_url":"https:\/\/shores.design\/index.php\/webgl-shaders\/","og_site_name":"Shores Design","article_modified_time":"2024-02-13T02:47:06+00:00","twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/shores.design\/index.php\/webgl-shaders\/","url":"https:\/\/shores.design\/index.php\/webgl-shaders\/","name":"WebGL-Shaders - Shores Design","isPartOf":{"@id":"https:\/\/shores.design\/#website"},"datePublished":"2024-02-08T13:35:46+00:00","dateModified":"2024-02-13T02:47:06+00:00","breadcrumb":{"@id":"https:\/\/shores.design\/index.php\/webgl-shaders\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/shores.design\/index.php\/webgl-shaders\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/shores.design\/index.php\/webgl-shaders\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/shores.design\/"},{"@type":"ListItem","position":2,"name":"WebGL-Shaders"}]},{"@type":"WebSite","@id":"https:\/\/shores.design\/#website","url":"https:\/\/shores.design\/","name":"Shores Design","description":"Graphics, Web, and Desktop Design Services","publisher":{"@id":"https:\/\/shores.design\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/shores.design\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/shores.design\/#organization","name":"Shores Design","url":"https:\/\/shores.design\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/shores.design\/#\/schema\/logo\/image\/","url":"https:\/\/shores.design\/wp-content\/uploads\/2023\/11\/LogoBackwardsWhite.png","contentUrl":"https:\/\/shores.design\/wp-content\/uploads\/2023\/11\/LogoBackwardsWhite.png","width":480,"height":480,"caption":"Shores Design"},"image":{"@id":"https:\/\/shores.design\/#\/schema\/logo\/image\/"}}]}},"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/shores.design\/index.php\/wp-json\/wp\/v2\/pages\/696"}],"collection":[{"href":"https:\/\/shores.design\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/shores.design\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/shores.design\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/shores.design\/index.php\/wp-json\/wp\/v2\/comments?post=696"}],"version-history":[{"count":4,"href":"https:\/\/shores.design\/index.php\/wp-json\/wp\/v2\/pages\/696\/revisions"}],"predecessor-version":[{"id":910,"href":"https:\/\/shores.design\/index.php\/wp-json\/wp\/v2\/pages\/696\/revisions\/910"}],"wp:attachment":[{"href":"https:\/\/shores.design\/index.php\/wp-json\/wp\/v2\/media?parent=696"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}