{"id":182,"date":"2024-01-09T08:05:19","date_gmt":"2024-01-09T08:05:19","guid":{"rendered":"https:\/\/shores.design\/?page_id=182"},"modified":"2024-02-13T02:49:34","modified_gmt":"2024-02-13T02:49:34","slug":"shader-mesh-demo","status":"publish","type":"page","link":"https:\/\/shores.design\/index.php\/shader-mesh-demo\/","title":{"rendered":"Shader-Mesh-Demo"},"content":{"rendered":"<div data-colibri-id=\"182-c1\" class=\"style-203 style-local-182-c1 position-relative\">\n  <!---->\n  <div data-colibri-component=\"section\" data-colibri-id=\"182-c2\" id=\"custom\" class=\"h-section h-section-global-spacing d-flex align-items-lg-center align-items-md-center align-items-center style-205 style-local-182-c2 position-relative\">\n    <!---->\n    <!---->\n    <div class=\"h-section-grid-container h-section-fluid-container\">\n      <!---->\n      <div data-colibri-id=\"182-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-206 style-local-182-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-207-outer style-local-182-c4-outer\">\n            <div data-colibri-id=\"182-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-207 style-local-182-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=\"182-c5\" class=\"style-208 style-local-182-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 Mesh Demo<\/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: 0px;\r\n        }\r\n        #canvasParent {\r\n            height: 100vh;\r\n            width: 100vw;\r\n            margin: 0px;\r\n        }\r\n    <\/style>\r\n<\/head>\r\n<body>\r\n    <div id=\"canvasParent\"><\/div>\r\n    <script type=\"importmap\">\r\n        {\r\n            \"imports\": {\r\n                \"three\": \"https:\/\/unpkg.com\/three@0.147.0\/build\/three.module.js\"\r\n            }\r\n        }\r\n    <\/script>\r\n    <script type=\"module\">\r\n        import * as THREE from 'three'\r\n        import { OrbitControls } from 'https:\/\/unpkg.com\/three@0.147.0\/examples\/jsm\/controls\/OrbitControls.js'\r\n        import { RoundedBoxGeometry } from 'https:\/\/unpkg.com\/three@0.147.0\/examples\/jsm\/geometries\/RoundedBoxGeometry.js'\r\n        import { TeapotGeometry } from 'https:\/\/unpkg.com\/three@0.147.0\/examples\/jsm\/geometries\/TeapotGeometry.js'\r\n        import Stats from 'https:\/\/unpkg.com\/three@0.147.0\/examples\/jsm\/libs\/stats.module.js'\r\n        import { GUI } from 'https:\/\/unpkg.com\/three@0.147.0\/examples\/jsm\/libs\/lil-gui.module.min.js'\r\n\r\n        \/\/ Shaders!\r\n        const vert = `\r\n            varying vec2 vUv;\r\n            varying vec3 vNormal;\r\n            varying vec3 vWorldPos;\r\n            varying vec3 vProjPos;\r\n\r\n            void main() {\r\n                \/\/ Standard vertex shader stuff, with some extra varyings\r\n                vNormal = normal;\r\n                vUv = uv;\r\n                vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\r\n                vWorldPos = vec3(mvPosition);\r\n                gl_Position = projectionMatrix * mvPosition;\r\n                vProjPos = vec3(gl_Position);\r\n            }\r\n        `\r\n\r\n        const fragDepth = `\r\n            uniform sampler2D uOutputRef;\r\n\r\n            \/\/ RGBA Unpacking\r\n            float unpackRGBAToDepth( in vec4 pack ) {\r\n                \/\/ https:\/\/stackoverflow.com\/questions\/48288154\/pack-depth-information-in-a-rgba-texture-using-mediump-precison\r\n                float depth = dot( pack, 1.0 \/ vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0) );\r\n                return depth * (256.0*256.0*256.0) \/ (256.0*256.0*256.0 - 1.0);\r\n            }\r\n\r\n            \/\/ RGBA Packing\r\n            vec4 packDepthToRGBA( in float depth ) {\r\n                \/\/ https:\/\/stackoverflow.com\/questions\/48288154\/pack-depth-information-in-a-rgba-texture-using-mediump-precison\r\n                depth *= (256.0*256.0*256.0 - 1.0) \/ (256.0*256.0*256.0);\r\n                vec4 encode = fract( depth * vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0) );\r\n                return vec4( encode.xyz - encode.yzw \/ 256.0, encode.w ) + 1.0\/512.0;\r\n            }\r\n\r\n            \/\/ Custom depth shader with a depth peel mask to know where to start the depth test per fragment\r\n            void main() {\r\n\r\n                \/\/ Find previous depth values\r\n                vec2 uv = gl_FragCoord.xy\/vec2(textureSize(uOutputRef, 0));\r\n                float prevDepth = unpackRGBAToDepth(texture2D( uOutputRef, uv));\r\n                float currentDepth;\r\n\r\n                \/\/ Test if it is behind first depth value (Peel away first depth)\r\n                if (gl_FragCoord.z < prevDepth) {\r\n                    discard;\r\n                    return;\r\n                } else {\r\n                    \/\/ New depth is the depth of the next fragment that passes\r\n                    currentDepth = gl_FragCoord.z;\r\n                }\r\n\r\n                \/\/ Output\r\n                gl_FragColor = packDepthToRGBA(currentDepth);\r\n\r\n            }\r\n        `\r\n\r\n        const fragMain = `\r\n            #define MAX_STEPS 10000\r\n            #define MAX_DIST 200.\r\n            #define MIN_DIST 0.01\r\n            #define NORM_EPS 0.01\r\n            #define PI 3.141592\r\n            #define TAU 6.283185\r\n\r\n            varying vec3 vNormal;\r\n            varying vec2 vUv;\r\n            varying vec3 vWorldPos;\r\n            varying vec3 vProjPos;\r\n            uniform sampler2D uFrontTexture; \/\/ depth texture of front face\r\n            uniform sampler2D uBackTexture; \/\/ depth texture of back face\r\n            uniform sampler2D uFrontTextureSecond; \/\/ depth texture of Second front face\r\n            uniform sampler2D uBackTextureSecond; \/\/ depth texture of Second back face\r\n            uniform sampler2D uFrontTextureThird; \/\/ depth texture of Third front face\r\n            uniform sampler2D uBackTextureThird; \/\/ depth texture of Third back face\r\n            uniform sampler2D uFrontTextureFourth; \/\/ depth texture of Fourth front face\r\n            uniform sampler2D uBackTextureFourth; \/\/ depth texture of Fourth back face\r\n            uniform vec3 uCameraPos; \/\/ camera position (can I use the built-in instead?)\r\n            uniform vec2 uCameraSize; \/\/ size of orthographic camera viewport\r\n            uniform float uCameraNear; \/\/ how close it captures (used for depth unpacking)\r\n            uniform float uCameraFar; \/\/ how far it captures\r\n            uniform float uCameraZoom; \/\/ zoom level\r\n            uniform float uStepSize; \/\/ how far one step goes in the fixed-step marcher\r\n            uniform float uCellSize; \/\/ size of one unit cell, not calibrated to any unit\r\n            uniform vec3 uColor; \/\/ color of geometry\r\n            uniform float uLightTheta; \/\/ theta angle of spherical light position\r\n            uniform float uLightPhi; \/\/ phi angle of spherical light position\r\n            uniform float uLightRadius; \/\/ distance of light from center\r\n            uniform vec3 uLightCol; \/\/ color of light\r\n            uniform int uGeoType; \/\/ type of geo infill (e.g. gyroid, octet, etc)\r\n            uniform float uFillFactor; \/\/ thickness of infill, not calibrated to any unit (roughly 0 is empty and 1 is full)\r\n            uniform bool uToggleDisplacement; \/\/ bool of whether to use noise surface textures or not\r\n            uniform float uAdjustDisp; \/\/ how big the surface textures should be\r\n            uniform int uDepthPeelVal; \/\/ how many steps of the depth peel should occur\r\n            uniform float uAmbiStrength;\r\n            uniform float uDiffStrength;\r\n            uniform float uSpecStrength;\r\n            uniform float uSpecPow;\r\n            uniform float uAOAmplitude;\r\n\r\n            \/\/ Declare Parameters\r\n            \/\/ float uAmbiStrength = 0.4; \/\/ Ambient light strength\r\n            \/\/ float uDiffStrength = 0.4; \/\/ Diffuse light strength\r\n            \/\/ float uSpecStrength = 0.2; \/\/ Specular light strength\r\n            \/\/ float uSpecPow = 4.0; \/\/ Specular light power (spread)\r\n            float noiseSize = 8.0; \/\/ How big the noise should be scaled\r\n            float noisePower = 0.01; \/\/ How much displacement in mm a value 1 noise reading should be\r\n            float noiseSize2 = 2.0; \/\/ How big the noise should be scaled\r\n            float noisePower2 = 0.5; \/\/ How much displacement in mm a value 1 noise reading should be\r\n\r\n\r\n            \/\/ GEOMETRIES\r\n\r\n            \/\/ Mesh SDF\r\n            float distMesh(vec3 point, vec4 frontDepths, vec4 backDepths) {\r\n                \/\/ todo, make an sdf for the mesh instead of a custom marcher\r\n                return 0.0;\r\n            }\r\n\r\n            \/\/ Gyroid SDF\r\n            float distGyroidBeam(vec3 point, float scale) {\r\n                point *= scale;\r\n                return (dot(sin(point), cos(point.zxy))) + (1.5-uFillFactor*3.0);\r\n            }\r\n\r\n            float distGyroidSurface(vec3 point, float scale) {\r\n                point *= scale;\r\n                return abs(dot(sin(point), cos(point.zxy))) - uFillFactor*1.5;\r\n            }\r\n\r\n            \/\/ Shwarz P SDF\r\n            float distSchwarzP(vec3 point, float scale) {\r\n                point *= scale;\r\n                return abs(dot(vec3(1.), cos(point))) - uFillFactor*1.5;\r\n            }\r\n\r\n            \/\/ 3D repetition from HG_SDF https:\/\/mercury.sexy\/hg_sdf\/\r\n            void pMod3(inout vec3 p, vec3 size) {\r\n                p = mod(p + size*0.5, size) - size*0.5;\r\n            }\r\n\r\n            \/\/ Octet SDF\r\n            float distBeam(vec3 point, vec3 normal, float radius) {\r\n                return length(point - dot(point, normal) * normal) - radius;\r\n            }\r\n\r\n            float distOctet(vec3 position, float scale) {\r\n                \/\/ Octect is made up of many beams, and is repeated in 3d domain\r\n                float spacing = 10.0\/scale;\r\n                float beamRadius = uFillFactor*2.0;\r\n                \r\n                vec3 positionShiftXZ = position + vec3(spacing\/2.0, 0.0, spacing\/2.0);\r\n                vec3 positionShiftXY = position + vec3(spacing\/2.0, spacing\/2.0, 0.0);\r\n                \r\n                pMod3( position, vec3(spacing));\r\n                position = abs(position);\r\n                if (position.y > position.x) { position.xy = position.yx; } \r\n                if (position.z > position.y) { position.yz = position.zy; } \r\n                \r\n                float beamPlanar = distBeam(position, normalize(vec3(1.0,1.0,0.0)), beamRadius); \r\n                \r\n                pMod3( positionShiftXZ, vec3(spacing));\r\n                positionShiftXZ = abs(positionShiftXZ);\r\n                if (positionShiftXZ.y > positionShiftXZ.x) { positionShiftXZ.xy = positionShiftXZ.yx; } \r\n                if (positionShiftXZ.z > positionShiftXZ.y) { positionShiftXZ.yz = positionShiftXZ.zy; } \r\n\r\n                float beamAngles = distBeam(positionShiftXZ, normalize(vec3(1.0,1.0,0.0)), beamRadius);\r\n                \r\n                pMod3( positionShiftXY, vec3(spacing));\r\n                positionShiftXY = abs(positionShiftXY);\r\n                float beamSection = distBeam(positionShiftXY, normalize(vec3(1.0,0.0,1.0)), beamRadius);\r\n                \r\n                return min(min(beamPlanar, beamAngles), beamSection);\r\n            }\r\n\r\n            \/\/ Select Geometry Type\r\n            float distFill(vec3 position, float scale) {\r\n                float dist;\r\n                switch(uGeoType) {\r\n                    case 0:\r\n                        dist = distGyroidBeam(position, scale);\r\n                        break;\r\n                    case 1:\r\n                        dist = distGyroidSurface(position, scale);\r\n                        break;\r\n                    case 2:\r\n                        dist = distSchwarzP(position, scale);\r\n                        break;\r\n                    case 3:\r\n                        dist = distOctet(position, scale);\r\n                        break;\r\n                }\r\n                return dist;\r\n            }\r\n\r\n            \/\/ 3D Simplex Noise\r\n            \/\/ From: https:\/\/www.shadertoy.com\/view\/XsX3zB\r\n\r\n            \/* discontinuous pseudorandom uniformly distributed in [-0.5, +0.5]^3 *\/\r\n            vec3 random3(vec3 c) {\r\n                \/\/ https:\/\/www.shadertoy.com\/view\/XsX3zB\r\n                float j = 4096.0*sin(dot(c,vec3(17.0, 59.4, 15.0)));\r\n                vec3 r;\r\n                r.z = fract(512.0*j);\r\n                j *= .125;\r\n                r.x = fract(512.0*j);\r\n                j *= .125;\r\n                r.y = fract(512.0*j);\r\n                return r-0.5;\r\n            }\r\n\r\n            \/* skew constants for 3d simplex functions *\/\r\n            const float F3 =  0.3333333;\r\n            const float G3 =  0.1666667;\r\n\r\n            \/* 3d simplex noise *\/\r\n            float simplex3d(vec3 p) {\r\n                \/\/ https:\/\/www.shadertoy.com\/view\/XsX3zB\r\n                \/* 1. find current tetrahedron T and it's four vertices *\/\r\n                \/* s, s+i1, s+i2, s+1.0 - absolute skewed (integer) coordinates of T vertices *\/\r\n                \/* x, x1, x2, x3 - unskewed coordinates of p relative to each of T vertices*\/\r\n                \r\n                \/* calculate s and x *\/\r\n                vec3 s = floor(p + dot(p, vec3(F3)));\r\n                vec3 x = p - s + dot(s, vec3(G3));\r\n                \r\n                \/* calculate i1 and i2 *\/\r\n                vec3 e = step(vec3(0.0), x - x.yzx);\r\n                vec3 i1 = e*(1.0 - e.zxy);\r\n                vec3 i2 = 1.0 - e.zxy*(1.0 - e);\r\n                    \r\n                \/* x1, x2, x3 *\/\r\n                vec3 x1 = x - i1 + G3;\r\n                vec3 x2 = x - i2 + 2.0*G3;\r\n                vec3 x3 = x - 1.0 + 3.0*G3;\r\n                \r\n                \/* 2. find four surflets and store them in d *\/\r\n                vec4 w, d;\r\n                \r\n                \/* calculate surflet weights *\/\r\n                w.x = dot(x, x);\r\n                w.y = dot(x1, x1);\r\n                w.z = dot(x2, x2);\r\n                w.w = dot(x3, x3);\r\n                \r\n                \/* w fades from 0.6 at the center of the surflet to 0.0 at the margin *\/\r\n                w = max(0.6 - w, 0.0);\r\n                \r\n                \/* calculate surflet components *\/\r\n                d.x = dot(random3(s), x);\r\n                d.y = dot(random3(s + i1), x1);\r\n                d.z = dot(random3(s + i2), x2);\r\n                d.w = dot(random3(s + 1.0), x3);\r\n                \r\n                \/* multiply d by w^4 *\/\r\n                w *= w;\r\n                w *= w;\r\n                d *= w;\r\n                \r\n                \/* 3. return the sum of the four surflets *\/\r\n                return dot(d, vec4(52.0));\r\n            }\r\n            \/\/ End of 3D Simplex Noise Segment\r\n\r\n            \/\/ Fixed Step Ray Marcher\r\n            float fixedStepMarcher(vec3 position, vec3 direction, vec4 frontDepths, vec4 backDepths, float scale) {\r\n                float near = frontDepths.x;\r\n                float far = backDepths.x;\r\n                float dist = near;\r\n                position += near * direction;\r\n                int peel = 0;\r\n                for (int iStep=0; iStep<MAX_STEPS; iStep++) {\r\n                    float distToGeo = distFill(position, scale);\r\n                    if (distToGeo > MIN_DIST && dist < MAX_DIST && dist < far) {\r\n                        position += uStepSize * direction;\r\n                        dist += uStepSize;\r\n                    } else if (dist >= far) {\r\n                        if (peel < (uDepthPeelVal - 1)) {\r\n                            \/\/ start next depth peel at the second front face deep\r\n                            peel++;\r\n                            float bigStep = (frontDepths[peel] - far);\r\n                            position += bigStep * direction;\r\n                            dist += bigStep;\r\n                            far = backDepths[peel];\r\n                        } else{\r\n                            return MAX_DIST;\r\n                        }\r\n                    } else {\r\n                        return dist;\r\n                    }\r\n                }\r\n                return 0.;\r\n            }\r\n\r\n            \/\/ Add Surface Noise for Bonus Texture\r\n            float noiseDisplacement(vec3 position) {\r\n                \/\/ Adds two frequencies of noise displacement to the surface\r\n                float displacement1 = (noisePower\/(1.5*uAdjustDisp)) * (1.0 - (2.0 * simplex3d(position * uAdjustDisp*noiseSize \/ uCellSize)));\r\n                float displacement2 = (noisePower2\/(1.5*uAdjustDisp)) * (1.0 - (2.0 * simplex3d(position * uAdjustDisp*noiseSize2 \/ uCellSize)));\r\n                float totalDisplacement = displacement1 + displacement2;\r\n                if (!uToggleDisplacement) {totalDisplacement = 0.0;}\r\n                return totalDisplacement;\r\n            }\r\n            \r\n            float distFillPlusNoiseDisp(vec3 position, float scale) {\r\n                return distFill(position, scale) + noiseDisplacement(position);\r\n            }\r\n\r\n            \/\/ Gyroid Beam Gradient (For Normal, faster than sampling the marcher for normals)\r\n            vec3 tpmsGradBeam(vec3 position, float scale) {\r\n                vec3 change;\r\n                change.x = (distFillPlusNoiseDisp( position + vec3(NORM_EPS, 0, 0), scale) - distFillPlusNoiseDisp( position - vec3(NORM_EPS, 0, 0), scale));\r\n                change.y = (distFillPlusNoiseDisp( position + vec3(0, NORM_EPS, 0), scale) - distFillPlusNoiseDisp( position - vec3(0, NORM_EPS, 0), scale)); \r\n                change.z = (distFillPlusNoiseDisp( position + vec3(0, 0, NORM_EPS), scale) - distFillPlusNoiseDisp( position - vec3(0, 0, NORM_EPS), scale)); \r\n                return normalize( change );\r\n            }\r\n\r\n            \/\/ Camera Fragment Position (Orthographic)\r\n            vec3 orthoFragPos(vec2 fragCoord, vec3 cameraDir, vec3 cameraPos) {\r\n\r\n                \/\/ Ortho Pixel Pos Adj\r\n                vec3 initialUp = vec3(0.0, 1.0, 0.0);\r\n                if (cameraDir.x == 0.0 && cameraDir.z == 0.0 && cameraDir.y != 0.0) {\r\n                    initialUp = vec3(0.0, 0.0, 1.0);\r\n                }\r\n                vec2 uv = gl_FragCoord.xy\/vec2(textureSize(uFrontTexture, 0));\r\n                vec2 offset = (uv * uCameraSize \/ uCameraZoom) - (uCameraSize \/ uCameraZoom * 0.5);\r\n                vec3 rightChange = normalize(cross(cameraDir, initialUp));\r\n                vec3 upChange = normalize(cross(rightChange, cameraDir));\r\n                vec3 worldOffset = offset.x * rightChange + offset.y * upChange;\r\n                return cameraPos + worldOffset;\r\n            }\r\n\r\n            \/\/ RGBA Unpacking\r\n            float unpackRGBAToDepth( in vec4 pack ) {\r\n                \/\/ https:\/\/stackoverflow.com\/questions\/48288154\/pack-depth-information-in-a-rgba-texture-using-mediump-precison\r\n                float depth = dot( pack, 1.0 \/ vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0) );\r\n                return depth * (256.0*256.0*256.0) \/ (256.0*256.0*256.0 - 1.0);\r\n            }\r\n\r\n            \/\/ MAIN\r\n            void main() {\r\n\r\n                \/\/ Determine Gyroid Geometry Scale\r\n                float scale = 2.0*PI\/uCellSize; \/\/ Geo scale\r\n\r\n                \/\/ Find Front and Back Depth from Textures (First Peel)\r\n                vec2 uv = gl_FragCoord.xy\/vec2(textureSize(uFrontTexture, 0));\r\n\r\n                \/\/ Depth Peels and Pack into Vec4\r\n                vec4 frontDepths = vec4(\r\n                    unpackRGBAToDepth(texture2D( uFrontTexture, uv)), \r\n                    unpackRGBAToDepth(texture2D( uFrontTextureSecond, uv)),\r\n                    unpackRGBAToDepth(texture2D( uFrontTextureThird, uv)),\r\n                    unpackRGBAToDepth(texture2D( uFrontTextureFourth, uv))\r\n                );\r\n                frontDepths = uCameraNear + (frontDepths) * uCameraFar;\r\n\r\n                vec4 backDepths = vec4(\r\n                    unpackRGBAToDepth(texture2D( uBackTexture, uv)), \r\n                    unpackRGBAToDepth(texture2D( uBackTextureSecond, uv)),\r\n                    unpackRGBAToDepth(texture2D( uBackTextureThird, uv)),\r\n                    unpackRGBAToDepth(texture2D( uBackTextureFourth, uv))\r\n                );\r\n                backDepths = uCameraNear + (backDepths) * uCameraFar;\r\n\r\n                \/\/ Restrict Depth Peel Steps (Debug Only)\r\n                for (int i=3; i>(uDepthPeelVal-1); i--) {\r\n                    frontDepths[i] = uCameraFar;\r\n                    backDepths[i] = uCameraFar;\r\n                }\r\n\r\n                \/\/ Find Camera Angle\r\n                vec3 cameraDir = normalize(-uCameraPos);\r\n                vec3 fragPos = orthoFragPos(gl_FragCoord.xy, cameraDir, uCameraPos);\r\n\r\n                \/\/ Background is Black\r\n                vec3 col = vec3(0.0);\r\n                gl_FragColor = vec4(vec3(col), 0.0);\r\n\r\n                \/\/ Ray March to Find Object Position (Fixed Step)\r\n                float objDist = fixedStepMarcher(fragPos.xyz, cameraDir, frontDepths, backDepths, scale);\r\n                vec3 objPos = fragPos + cameraDir * objDist;\r\n\r\n                \/\/ If Object Solve Lighting\r\n                if (objDist < MAX_DIST) {\r\n\r\n                    \/\/ Find Normal and Add Noise Displacement\r\n                    vec3 normal;\r\n                    if (objDist == frontDepths.x) {\r\n                        \/\/ Normal of Mesh Obj\r\n                        normal = vNormal;\r\n                    } else {\r\n                        \/\/ Normal of Gyroid\r\n                        normal = tpmsGradBeam(objPos, scale);\r\n\r\n                        \/\/ Add Noise Displacement\r\n                        objDist += noiseDisplacement(objPos); \r\n                    }\r\n\r\n\r\n                    \/\/ Adjust Light Position\r\n                    float lRadius = uLightRadius;\r\n                    float lPhi = uLightPhi;\r\n                    float lTheta = uLightTheta;\r\n                    vec3 lightPos = vec3(lRadius*sin(lPhi)*cos(lTheta), lRadius*cos(lPhi), lRadius*sin(lPhi)*sin(lTheta));\r\n                    \r\n                    \/\/ Dist From Light\r\n                    float lightDist = length(lightPos-objPos);\r\n                    float cheapAO = min(1.0, uAOAmplitude\/(lightDist)); \r\n\r\n                    \/\/ Ambient Lighting\r\n                    vec3 ambiLight = vec3(1.) * uAmbiStrength;\r\n                    \r\n                    \/\/ Diffuse Lighting\r\n                    vec3 diffDir = normalize(lightPos - objPos);\r\n                    vec3 diffLight = uLightCol * uDiffStrength * max(dot(normal, diffDir), 0.0);\r\n                    \r\n                    \/\/ Specular Lighting\r\n                    vec3 reflDir = reflect(-diffDir, normal);\r\n                    float specFact = pow(max(dot(-cameraDir, reflDir), 0.0), uSpecPow);\r\n                    vec3 specLight = uLightCol * uSpecStrength * specFact;\r\n                    \r\n                    \/\/ Phong Combined Lighting\r\n                    vec3 combLight = ambiLight + diffLight + specLight;\r\n\r\n                    \/\/ Base color\r\n                    vec3 baseColor = uColor*0.7 + 0.4*vec3(-objPos.xyz\/6. + 0.75);\r\n\r\n                    \/\/ Mix It All Up!\r\n                    col = combLight * baseColor * cheapAO;\r\n                    \r\n                    \/\/ Output Fragment\r\n                    gl_FragColor = vec4(vec3(col), 1.0);\r\n                }\r\n                \r\n            }\r\n        `\r\n        \/\/ End Shader Section\r\n\r\n        \/\/ JS Globals\r\n        let scene, frontScene, backScene\r\n        let depthMeshFront, depthMeshBack\r\n        let depthMatFront, depthMatBack, depthPeelMat\r\n        let renderTargetsBack = [] \r\n        let renderTargetsFront = []\r\n        let renderer, renderCanvas, camera, controls, stats\r\n        let shaderConfigs, shaderMaterial, meshConfigs, animationState\r\n        let bulbLight, bulbMat, floorMaterial\r\n\r\n        \/\/ Calc Light Position\r\n        const lightPosition = (phi, theta, radius) => {\r\n            return [\r\n                radius*Math.sin(phi)*Math.cos(theta), \r\n                radius*Math.cos(phi),\r\n                radius*Math.sin(phi)*Math.sin(theta)\r\n            ]\r\n        }\r\n\r\n        \/\/ Light Color Updates\r\n        const updateLightColor = (hueVal) => {\r\n            let color = new THREE.Color(\"hsl(\"+hueVal*255+\", 100%, 50%)\")\r\n            bulbMat.emissive = color\r\n            let rgb = color.toArray()\r\n            shaderMaterial.uniforms.uLightCol.value = rgb\r\n            floorMaterial.color = new THREE.Color(\"hsl(\"+hueVal*255+\", 15%, 20%)\")\r\n        }\r\n\r\n        \/\/ Setup\r\n        const init = () => {\r\n            const canvasParent = document.getElementById('canvasParent')\r\n            \r\n            \/\/ Consts\r\n            const dpmm = 25 \/\/ dots per mm\r\n            const cameraNear = 0 \/\/ mm\r\n            const cameraFar = 100 \/\/ mm\r\n            \r\n            \/\/ Window Params\r\n            let dpr = window.devicePixelRatio\r\n            let rect = canvasParent.getBoundingClientRect();\r\n            let width = Math.round(rect.width * dpr)\r\n            let height = Math.round(rect.height * dpr)\r\n            console.log(width, height)\r\n\r\n            renderer = new THREE.WebGLRenderer({ antialias: true })\r\n            renderer.setPixelRatio(dpr)\r\n            renderer.setSize(rect.width, rect.height)\r\n            renderer.autoClear = false\r\n            renderCanvas = canvasParent.appendChild(renderer.domElement)\r\n\r\n            \/\/ width = canvasParent.clientWidth\r\n            \/\/ height = canvasParent.clientHeight\r\n\r\n            \/\/ Scene, Renderer, Controls\r\n            scene = new THREE.Scene()\r\n            camera = new THREE.OrthographicCamera(-width\/(2*dpmm), width\/(2*dpmm), height\/(2*dpmm), -height\/(2*dpmm), cameraNear, cameraFar)\r\n            camera.position.set(25, 15, 20)\r\n            scene.add(camera)\r\n\r\n            controls = new OrbitControls(camera, renderer.domElement)\r\n            controls.mouseButtons.RIGHT = '' \/\/ disable pan\r\n            controls.minZoom = 0.6\r\n            controls.maxPolarAngle = Math.PI*(7\/16)\r\n\r\n\r\n            \/\/ Background Texture\r\n            scene.background = new THREE.Color( 0x000000 )\r\n            scene.fog = new THREE.Fog( 0x000000, 25, 75 )\r\n            floorMaterial = new THREE.MeshBasicMaterial()\r\n            floorMaterial.color = new THREE.Color(0x333333)\r\n            const floorMesh = new THREE.Mesh( new THREE.PlaneGeometry( 500000, 500000 ), floorMaterial )\r\n            floorMesh.rotation.x = - Math.PI \/ 2\r\n            floorMesh.position.y = -20\r\n            scene.add(floorMesh)\r\n\r\n\r\n            \/\/ Render Targets and Secondary Scenes for Depths\r\n            for (let i=0; i<4; i++) {\r\n                renderTargetsFront.push(\r\n                    new THREE.WebGLRenderTarget(width, height, {\r\n                        minFilter: THREE.LinearFilter,\r\n                        magFilter: THREE.LinearFilter,\r\n                    })\r\n                )\r\n                renderTargetsBack.push(\r\n                    new THREE.WebGLRenderTarget(width, height, {\r\n                        minFilter: THREE.LinearFilter,\r\n                        magFilter: THREE.LinearFilter,\r\n                    })\r\n                )\r\n            }\r\n            \r\n            frontScene = new THREE.Scene()\r\n            backScene = new THREE.Scene()\r\n\r\n            \/\/ Model\r\n            meshConfigs = {\r\n                'geometry': 'box',\r\n                'lightColor': [1.0, 1.0, 1.0],\r\n                'lightHue': 1.0,\r\n                'Animate!': animate \/\/ trigger function for GUI\r\n            }\r\n\r\n            const Torus = (radius, tube, radSegs, tubeSegs) => {\r\n                let newTorus = new THREE.TorusGeometry(radius, tube, radSegs, tubeSegs)\r\n                newTorus.rotateX(Math.PI\/2)\r\n                return newTorus\r\n            }\r\n\r\n            const geometries = {\r\n                box: new RoundedBoxGeometry(20, 20, 20, 10, 5),\r\n                flatBox: new RoundedBoxGeometry(2, 20, 20, 10, 5),\r\n                sphere: new THREE.SphereGeometry(10),\r\n                cone: new THREE.ConeGeometry(10, 20),\r\n                torus: Torus(10, 4, 16, 100),\r\n                torusKnot: new THREE.TorusKnotGeometry(10, 5),\r\n                teapot: new TeapotGeometry(10),\r\n            }\r\n            let geometry = geometries[meshConfigs.geometry]\r\n\r\n            \/\/ Depth Renders\r\n            \/\/ Front depth will track where the fragment hits the mesh (first time only)\r\n            depthMatFront = new THREE.MeshDepthMaterial()\r\n            depthMatFront.side = THREE.FrontSide\r\n            depthMatFront.depthPacking = THREE.RGBADepthPacking \r\n            depthMeshFront = new THREE.Mesh(geometry, depthMatFront)\r\n            frontScene.add(depthMeshFront)\r\n\r\n            \/\/ Back depth will track where the fragment exits the mesh (first time only)\r\n            depthMatBack = new THREE.MeshDepthMaterial()\r\n            depthMatBack.side = THREE.BackSide\r\n            depthMatBack.depthPacking = THREE.RGBADepthPacking\r\n            depthMeshBack = new THREE.Mesh(geometry, depthMatBack)\r\n            backScene.add(depthMeshBack)\r\n\r\n            \/\/ Subsequent depth peel material (2nd through 4th peel)\r\n            depthPeelMat = new THREE.ShaderMaterial({\r\n                uniforms: {\r\n                    'uOutputRef': {'value': renderTargetsBack[0].texture },\r\n                },\r\n                vertexShader: vert,\r\n                fragmentShader: fragDepth\r\n            })\r\n\r\n            \/\/ animation cycle settings\r\n            const cycleSizes = [4, 0.5, 4, 8]\r\n            animationState = {\r\n                'cycleIndex': 0,\r\n                'transitionProgress': 0,\r\n                'isTransitioning': false,\r\n                'currentSize': cycleSizes[0],\r\n                'cycleSizes': cycleSizes,\r\n                'cycleDuration': 240,\r\n                'transitionDuration': 60\r\n            }\r\n            \r\n            \/\/ Shader Material & Mesh\r\n            shaderConfigs = {\r\n                'stepSize': 0.02,\r\n                'cellSize': 4,\r\n                'lightTheta': Math.PI\/4,\r\n                'lightPhi': Math.PI\/3,\r\n                'lightRadius': 15,\r\n                'color': [0.8,0.8,0.8],\r\n                'geoType': 0,\r\n                'fillFactor': 0.25,\r\n                'toggleSurfaceNoise': true,\r\n                'surfaceNoiseSize': 1.0,\r\n                'depthPeelSteps': 4,\r\n                'ambientStrength': 0.4,\r\n                'diffuseStrength': 0.4,\r\n                'specularStrength': 0.4,\r\n                'specularPower': 2.0,\r\n                'AOAmplitude': 15\r\n            }\r\n            shaderMaterial = new THREE.ShaderMaterial({\r\n                uniforms: {\r\n                    'uFrontTexture': { 'value': renderTargetsFront[0].texture },\r\n                    'uBackTexture': { 'value': renderTargetsBack[0].texture },\r\n                    'uFrontTextureSecond': { 'value': renderTargetsFront[1].texture },\r\n                    'uBackTextureSecond': { 'value': renderTargetsBack[1].texture },\r\n                    'uFrontTextureThird': { 'value': renderTargetsFront[2].texture },\r\n                    'uBackTextureThird': { 'value': renderTargetsBack[2].texture },\r\n                    'uFrontTextureFourth': { 'value': renderTargetsFront[3].texture },\r\n                    'uBackTextureFourth': { 'value': renderTargetsBack[3].texture },\r\n                    'uCameraPos': { 'value': camera.position },\r\n                    'uCameraSize': { 'value': new THREE.Vector2(width\/dpmm, height\/dpmm)},\r\n                    'uCameraNear': { 'value': cameraNear },\r\n                    'uCameraFar': { 'value': cameraFar },\r\n                    'uCameraZoom': { 'value': camera.zoom },\r\n                    'uStepSize': { 'value': shaderConfigs.stepSize },\r\n                    'uCellSize': { 'value': shaderConfigs.cellSize },\r\n                    'uColor': { 'value': shaderConfigs.color },\r\n                    'uLightTheta': { 'value': shaderConfigs.lightTheta },\r\n                    'uLightPhi': { 'value': shaderConfigs.lightPhi },\r\n                    'uLightRadius': { 'value': shaderConfigs.lightRadius },\r\n                    'uLightCol': { 'value': meshConfigs.lightColor },\r\n                    'uGeoType': { 'value': shaderConfigs.geoType },\r\n                    'uFillFactor': { 'value': shaderConfigs.fillFactor },\r\n                    'uToggleDisplacement': { 'value': shaderConfigs.toggleSurfaceNoise },\r\n                    'uAdjustDisp': { 'value': shaderConfigs.surfaceNoiseSize },\r\n                    'uDepthPeelVal': { 'value': shaderConfigs.depthPeelSteps },\r\n                    'uAmbiStrength': { 'value': shaderConfigs.ambientStrength },\r\n                    'uDiffStrength': { 'value': shaderConfigs.diffuseStrength },\r\n                    'uSpecStrength': { 'value': shaderConfigs.specularStrength },\r\n                    'uSpecPow': { 'value': shaderConfigs.specularPower },\r\n                    'uAOAmplitude': { 'value': shaderConfigs.AOAmplitude }\r\n                },\r\n                vertexShader: vert,\r\n                fragmentShader: fragMain,\r\n                transparent: true\r\n            })\r\n            console.log(shaderMaterial.uniforms)\r\n            const mesh = new THREE.Mesh(geometry, shaderMaterial)\r\n            scene.add(mesh)\r\n\r\n            \/\/ Light Object \r\n            \/\/ from https:\/\/github.com\/mrdoob\/three.js\/blob\/master\/examples\/webgl_lights_physical.html)\r\n            const bulbGeometry = new THREE.SphereGeometry( 0.1, 16, 8 )\r\n            bulbLight = new THREE.PointLight( 0xffee88, 1, 100, 2 )\r\n\r\n            bulbMat = new THREE.MeshStandardMaterial( {\r\n                emissive: 0xffffff,\r\n                emissiveIntensity: 1,\r\n                color: 0x000000\r\n            } )\r\n            console.log(bulbMat)\r\n            bulbLight.add( new THREE.Mesh( bulbGeometry, bulbMat ) )\r\n            bulbLight.castShadow = true\r\n            \/\/ scene.add( bulbLight )\r\n\r\n            \/\/ Adjust Light Position\r\n            let lightPos = lightPosition(shaderConfigs.lightPhi, shaderConfigs.lightTheta, shaderConfigs.lightRadius)\r\n            bulbLight.position.set(lightPos[0], lightPos[1], lightPos[2])\r\n\r\n            \/\/ Controls Change Event Listener\r\n            controls.addEventListener('change', () => {\r\n                shaderMaterial.uniforms.uCameraPos.value = camera.position\r\n                shaderMaterial.uniforms.uCameraZoom.value = camera.zoom\r\n                updateRender()\r\n            })\r\n\r\n            \/\/ Window Resize Event Listener\r\n            window.addEventListener(\r\n                'resize',\r\n                () => {\r\n                    console.log('resize')\r\n\r\n                    \/\/ Get new width & height\r\n                    width = canvasParent.clientWidth\r\n                    height = canvasParent.clientHeight\r\n                    \r\n                    \/\/ Update Camera\r\n                    camera.left = -width\/(2*dpmm)\r\n                    camera.right = width\/(2*dpmm)\r\n                    camera.top = height\/(2*dpmm)\r\n                    camera.bottom = -height\/(2*dpmm)\r\n                    camera.updateProjectionMatrix()\r\n\r\n                    \/\/ Update Shader\r\n                    shaderMaterial.uniforms.uCameraSize.value = new THREE.Vector2(width\/dpmm, height\/dpmm)\r\n\r\n                    \/\/ Update Renderer and RenderTargets\r\n                    renderer.setSize(width, height)\r\n                    for (let i=0; i<4; i++) {\r\n                        renderTargetsFront[i].setSize(width, height)\r\n                        renderTargetsBack[i].setSize(width, height)\r\n                    }\r\n                    updateRender()\r\n                },\r\n                false\r\n            )\r\n\r\n            \/\/ FPS Stats\r\n            stats = Stats()\r\n            stats.dom.style.top = canvasParent.getBoundingClientRect().top+5 + 'px' \/\/ hacky way to get it to follow the div\r\n            canvasParent.appendChild(stats.dom)\r\n\r\n            \/\/ UI and Handlers\r\n            const gui = new GUI({container: canvasParent})\r\n            const guiElem = gui.domElement\r\n            guiElem.style.position = \"absolute\"\r\n            guiElem.style.top = '10px'\r\n            guiElem.style.right = \"10px\"\r\n\r\n            const geoFolder = gui.addFolder('__Geo Configs')\r\n            geoFolder.add(shaderConfigs, 'cellSize', 0.5, 10).onChange( value => { \r\n                shaderMaterial.uniforms.uCellSize.value = value \r\n                updateRender()\r\n            })\r\n            geoFolder.add(shaderConfigs, 'fillFactor', 0.1, 1).onChange( value => { \r\n                shaderMaterial.uniforms.uFillFactor.value = value \r\n                updateRender()\r\n            })\r\n            geoFolder.add(shaderConfigs, 'geoType', {'gyroidBeam': 0, 'gyroidSurface': 1, 'schwarzP': 2, 'octet': 3}).onChange( value => { \r\n                shaderMaterial.uniforms.uGeoType.value = value \r\n                updateRender()\r\n            })\r\n            geoFolder.add(meshConfigs, 'geometry', Object.keys(geometries)).onChange( value => {\r\n                mesh.geometry = geometries[value]\r\n                depthMeshBack.geometry = geometries[value]\r\n                depthMeshFront.geometry = geometries[value]\r\n                updateRender()\r\n            })\r\n            geoFolder.add(shaderConfigs, 'toggleSurfaceNoise').onChange( value => {\r\n                shaderMaterial.uniforms.uToggleDisplacement.value = value\r\n                updateRender()\r\n            })\r\n            geoFolder.add(shaderConfigs, 'surfaceNoiseSize', 0.1, 3.0).onChange( value => {\r\n                shaderMaterial.uniforms.uAdjustDisp.value = value\r\n                updateRender()\r\n            })\r\n\r\n            const sceneFolder = gui.addFolder('__Scene Configs')\r\n            \/\/ sceneFolder.add(meshConfigs, 'Animate!')\r\n            sceneFolder.add(meshConfigs, 'lightHue', 0.0, 1.0).onChange( value => {\r\n                updateLightColor(value)\r\n                updateRender()\r\n            })\r\n            sceneFolder.add(shaderConfigs, 'lightTheta', 0, Math.PI*2).onChange( value => {\r\n                shaderMaterial.uniforms.uLightTheta.value = value\r\n                lightPos = lightPosition(shaderConfigs.lightPhi, value, shaderConfigs.lightRadius),\r\n                bulbLight.position.set(lightPos[0], lightPos[1], lightPos[2])\r\n                updateRender()\r\n            })\r\n            sceneFolder.add(shaderConfigs, 'lightRadius', 0, 50, 1).onChange( value => {\r\n                shaderMaterial.uniforms.uLightRadius.value = value\r\n                lightPos = lightPosition(shaderConfigs.lightPhi, shaderConfigs.lightTheta, value)\r\n                bulbLight.position.set(lightPos[0], lightPos[1], lightPos[2])\r\n                updateRender()\r\n            })\r\n            sceneFolder.close()\r\n\r\n            const shaderFolder = gui.addFolder('__Shader Configs')\r\n            shaderFolder.add(shaderConfigs, 'stepSize', 0.001, 0.1).onChange( value => { \r\n                shaderMaterial.uniforms.uStepSize.value = value \r\n                updateRender()\r\n            })\r\n            shaderFolder.add(shaderConfigs, 'depthPeelSteps', 1, 4, 1).onChange( value => {\r\n                shaderMaterial.uniforms.uDepthPeelVal.value = value\r\n                updateRender()\r\n            })\r\n            shaderFolder.close()\r\n            \r\n            const matFolder = gui.addFolder('__Material Configs')\r\n            matFolder.addColor({color:shaderConfigs.color}, 'color').onChange( value => {\r\n                shaderMaterial.uniforms.uColor.value = value\r\n                updateRender()\r\n            })\r\n            matFolder.add(shaderConfigs, 'ambientStrength', 0.0, 1.0, 0.1).onChange( value => {\r\n                shaderMaterial.uniforms.uAmbiStrength.value = value\r\n                updateRender()\r\n            })\r\n            matFolder.add(shaderConfigs, 'diffuseStrength', 0.0, 1.0, 0.1).onChange( value => {\r\n                shaderMaterial.uniforms.uDiffStrength.value = value\r\n                updateRender()\r\n            })\r\n            matFolder.add(shaderConfigs, 'specularStrength', 0.0, 1.0, 0.1).onChange( value => {\r\n                shaderMaterial.uniforms.uSpecStrength.value = value\r\n                updateRender()\r\n            })\r\n            matFolder.add(shaderConfigs, 'specularPower', 0.0, 10.0, 0.5).onChange( value => {\r\n                shaderMaterial.uniforms.uSpecPow.value = value\r\n                updateRender()\r\n            })\r\n            matFolder.add(shaderConfigs, 'AOAmplitude', 0, 50, 1).onChange( value => {\r\n                shaderMaterial.uniforms.uAOAmplitude.value = value\r\n                updateRender()\r\n            })\r\n            matFolder.close()\r\n\r\n        }\r\n\r\n        \/\/ Render wrapper\r\n        function updateRender() {\r\n            render()\r\n            render() \/\/ second render helps with stuttering due to multiple render pass, unsure why\r\n            stats.update()\r\n        }\r\n\r\n        \/\/ Render one frame\r\n        function render() {\r\n            \r\n            \/\/ Render FRONT face depth peel target\r\n            depthMeshFront.material = depthMatFront\r\n            renderer.setRenderTarget(renderTargetsFront[0])\r\n            renderer.clear()\r\n            renderer.render(frontScene, camera)\r\n\r\n            \/\/ Render BACK face depth peel target\r\n            depthMeshBack.material = depthMatBack\r\n            renderer.setRenderTarget(renderTargetsBack[0])\r\n            renderer.clear()\r\n            renderer.render(backScene, camera)\r\n\r\n\r\n            \/\/ For subsequent depth peels, alternate front and back\r\n            depthMeshFront.material = depthPeelMat\r\n            depthMeshBack.material = depthPeelMat\r\n            let gl = renderer.getContext() \/\/ get webGL context\r\n            gl.enable(gl.CULL_FACE)\r\n\r\n            for (let iPass=1; iPass<4; iPass++) {\r\n                \r\n                \/\/ Front pass\r\n                depthPeelMat.uniforms.uOutputRef.value = renderTargetsBack[iPass-1].texture\r\n                gl.cullFace(gl.BACK)\r\n                renderer.setRenderTarget(renderTargetsFront[iPass])\r\n                renderer.clear()\r\n                renderer.render(frontScene, camera)\r\n                \r\n                \/\/ Back pass\r\n                depthPeelMat.uniforms.uOutputRef.value = renderTargetsFront[iPass].texture\r\n                gl.cullFace(gl.FRONT)\r\n                renderer.setRenderTarget(renderTargetsBack[iPass])\r\n                renderer.clear()\r\n                renderer.render(backScene, camera)\r\n            }\r\n\r\n            \/\/ render scene\r\n            gl.cullFace(gl.BACK)\r\n            renderer.setRenderTarget(null)\r\n            renderer.clear()\r\n            renderer.render(scene, camera)\r\n        }\r\n\r\n        const updateCellSize = () => {\r\n            const { cycleSizes, cycleDuration, transitionDuration, cycleIndex, transitionProgress, isTransitioning, currentSize } = animationState\r\n            if (isTransitioning) {\r\n                \/\/ Interpolate between current and next size\r\n                let nextSize = cycleSizes[(cycleIndex + 1) % cycleSizes.length]\r\n                let t = transitionProgress \/ transitionDuration\r\n                shaderConfigs.cellSize = currentSize * (1 - t) + nextSize * t\r\n                animationState.transitionProgress++\r\n\r\n                if (transitionProgress >= transitionDuration) {\r\n                    \/\/ Finish transition\r\n                    shaderConfigs.cellSize = nextSize\r\n                    animationState.currentSize = nextSize\r\n                    animationState.cycleIndex = (cycleIndex + 1) % cycleSizes.length\r\n                    animationState.isTransitioning = false\r\n                }\r\n            } else {\r\n                \/\/ Wait for full cycle before transitioning\r\n                if (--animationState.transitionProgress <= -cycleDuration) {\r\n                    animationState.transitionProgress = 0\r\n                    animationState.isTransitioning = true\r\n                }\r\n            }\r\n            console.log(shaderConfigs.cellSize)\r\n\r\n            shaderMaterial.uniforms.uCellSize.value = shaderConfigs.cellSize\r\n\r\n        }\r\n\r\n        \/\/ animation\r\n        const animate = () => {\r\n            requestAnimationFrame(animate)\r\n\r\n            \/\/ controls\r\n            controls.autoRotate = true\r\n            controls.autoRotateSpeed = -1\r\n            controls.update()\r\n\r\n            updateCellSize()\r\n            \r\n            \/\/ animate light\r\n            \/\/ shaderConfigs.lightTheta += 0.01\r\n            \/\/ if (shaderConfigs.lightTheta > Math.PI*2) { shaderConfigs.lightTheta -= Math.PI*2 }\r\n            \/\/ shaderMaterial.uniforms.uLightTheta.value = shaderConfigs.lightTheta\r\n            \/\/ let lightPos = lightPosition(shaderConfigs.lightPhi, shaderConfigs.lightTheta, shaderConfigs.lightRadius)\r\n            \/\/ bulbLight.position.set(lightPos[0], lightPos[1], lightPos[2])\r\n\r\n            updateRender()\r\n        }\r\n\r\n        \/\/ Start!\r\n        init()\r\n        animate()\r\n\r\n\r\n    <\/script>\r\n<\/body><\/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-182","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>Shader-Mesh-Demo - 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\/shader-mesh-demo\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Shader-Mesh-Demo - Shores Design\" \/>\n<meta property=\"og:url\" content=\"https:\/\/shores.design\/index.php\/shader-mesh-demo\/\" \/>\n<meta property=\"og:site_name\" content=\"Shores Design\" \/>\n<meta property=\"article:modified_time\" content=\"2024-02-13T02:49:34+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\/shader-mesh-demo\/\",\"url\":\"https:\/\/shores.design\/index.php\/shader-mesh-demo\/\",\"name\":\"Shader-Mesh-Demo - Shores Design\",\"isPartOf\":{\"@id\":\"https:\/\/shores.design\/#website\"},\"datePublished\":\"2024-01-09T08:05:19+00:00\",\"dateModified\":\"2024-02-13T02:49:34+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/shores.design\/index.php\/shader-mesh-demo\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/shores.design\/index.php\/shader-mesh-demo\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/shores.design\/index.php\/shader-mesh-demo\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/shores.design\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Shader-Mesh-Demo\"}]},{\"@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":"Shader-Mesh-Demo - 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\/shader-mesh-demo\/","og_locale":"en_US","og_type":"article","og_title":"Shader-Mesh-Demo - Shores Design","og_url":"https:\/\/shores.design\/index.php\/shader-mesh-demo\/","og_site_name":"Shores Design","article_modified_time":"2024-02-13T02:49:34+00:00","twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/shores.design\/index.php\/shader-mesh-demo\/","url":"https:\/\/shores.design\/index.php\/shader-mesh-demo\/","name":"Shader-Mesh-Demo - Shores Design","isPartOf":{"@id":"https:\/\/shores.design\/#website"},"datePublished":"2024-01-09T08:05:19+00:00","dateModified":"2024-02-13T02:49:34+00:00","breadcrumb":{"@id":"https:\/\/shores.design\/index.php\/shader-mesh-demo\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/shores.design\/index.php\/shader-mesh-demo\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/shores.design\/index.php\/shader-mesh-demo\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/shores.design\/"},{"@type":"ListItem","position":2,"name":"Shader-Mesh-Demo"}]},{"@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\/182"}],"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=182"}],"version-history":[{"count":11,"href":"https:\/\/shores.design\/index.php\/wp-json\/wp\/v2\/pages\/182\/revisions"}],"predecessor-version":[{"id":931,"href":"https:\/\/shores.design\/index.php\/wp-json\/wp\/v2\/pages\/182\/revisions\/931"}],"wp:attachment":[{"href":"https:\/\/shores.design\/index.php\/wp-json\/wp\/v2\/media?parent=182"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}