├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── README.md ├── assets ├── README.md ├── css │ ├── functions.scss │ ├── global.scss │ ├── mixins.scss │ └── variables.scss └── img │ ├── 004_nebula_red.jpg │ ├── Alunar_Cliff_basecolor.png │ ├── Alunar_Cliff_normal.jpg │ ├── Alunar_Ground_basecolor.jpg │ ├── Alunar_Ground_normal.jpg │ └── Ocean-4-Normal.jpg ├── components ├── README.md ├── _common │ ├── Button.vue │ └── Menu.vue ├── _template │ ├── Controls.vue │ └── Header.vue ├── icon │ ├── Base.vue │ ├── Cube.vue │ ├── CubeOutline.vue │ ├── Github.vue │ ├── Help.vue │ ├── HelpRhombusOutline .vue │ ├── OpenInNew.vue │ ├── Pause.vue │ ├── Play.vue │ ├── Restore.vue │ └── Twitter.vue └── menu │ └── Help.vue ├── jsconfig.json ├── layouts ├── README.md └── default.vue ├── middleware └── README.md ├── nuxt.config.js ├── package.json ├── pages ├── README.md └── index.vue ├── plugins ├── README.md └── webgl.js ├── static ├── README.md └── favicon.ico ├── store ├── README.md └── index.js ├── webgl ├── AmbientLight.js ├── Background.js ├── Camera.js ├── DirectionalLight.js ├── Ground.js ├── InstanceMeshPhong.js ├── MeshLambert.js ├── MeshPhong.js ├── PointLight.js ├── Water.js ├── glsl │ ├── Background.fs │ ├── Background.vs │ ├── InstanceMeshPhong.vs │ ├── MeshLambert.fs │ ├── MeshLambert.vs │ ├── MeshPhong.fs │ ├── MeshPhong.vs │ ├── Water.fs │ ├── Water.vs │ ├── _MeshPhong.fs │ └── _MeshPhong.vs └── index.js └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | browser: true, 5 | node: true, 6 | }, 7 | parserOptions: { 8 | parser: 'babel-eslint', 9 | }, 10 | extends: [ 11 | '@nuxtjs', 12 | 'plugin:prettier/recommended', 13 | 'plugin:nuxt/recommended', 14 | ], 15 | plugins: [], 16 | // add your custom rules here 17 | rules: {}, 18 | } 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Node template 3 | # Logs 4 | /logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | *.pid.lock 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # nyc test coverage 23 | .nyc_output 24 | 25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 26 | .grunt 27 | 28 | # Bower dependency directory (https://bower.io/) 29 | bower_components 30 | 31 | # node-waf configuration 32 | .lock-wscript 33 | 34 | # Compiled binary addons (https://nodejs.org/api/addons.html) 35 | build/Release 36 | 37 | # Dependency directories 38 | node_modules/ 39 | jspm_packages/ 40 | 41 | # TypeScript v1 declaration files 42 | typings/ 43 | 44 | # Optional npm cache directory 45 | .npm 46 | 47 | # Optional eslint cache 48 | .eslintcache 49 | 50 | # Optional REPL history 51 | .node_repl_history 52 | 53 | # Output of 'npm pack' 54 | *.tgz 55 | 56 | # Yarn Integrity file 57 | .yarn-integrity 58 | 59 | # dotenv environment variables file 60 | .env 61 | 62 | # parcel-bundler cache (https://parceljs.org/) 63 | .cache 64 | 65 | # next.js build output 66 | .next 67 | 68 | # nuxt.js build output 69 | .nuxt 70 | 71 | # Nuxt generate 72 | dist 73 | 74 | # vuepress build output 75 | .vuepress/dist 76 | 77 | # Serverless directories 78 | .serverless 79 | 80 | # IDE / Editor 81 | .idea 82 | 83 | # Service worker 84 | sw.* 85 | 86 | # macOS 87 | .DS_Store 88 | 89 | # Vim swap files 90 | *.swp 91 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true 4 | } 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # study-threejs-lighting 2 | It's a study record of 3D graphic lighting with the shaders that I created by quoting from three.js. 3 | https://ykob.github.io/study-threejs-lighting/ 4 | 5 | ## Build Setup 6 | 7 | ```bash 8 | # install dependencies 9 | $ yarn install 10 | 11 | # serve with hot reload at localhost:8080 12 | $ yarn dev 13 | 14 | # build for production and launch server 15 | $ yarn build 16 | $ yarn start 17 | 18 | # generate static project 19 | $ yarn generate 20 | 21 | # deploy to GitHub Pages 22 | $ yarn deploy 23 | ``` 24 | 25 | ## Reference sources 26 | 27 | - [three.js shaders](https://github.com/mrdoob/three.js/tree/master/src/renderers/shaders) 28 | - [THREE.AmbientLight](https://threejs.org/docs/?q=Light#api/en/lights/AmbientLight) 29 | - [THREE.DirectionalLight](https://threejs.org/docs/?q=Light#api/en/lights/DirectionalLight) 30 | - [THREE.HemisphereLight](https://threejs.org/docs/?q=Light#api/en/lights/HemisphereLight) 31 | - [THREE.PointLight](https://threejs.org/docs/?q=Light#api/en/lights/PointLight) 32 | - [THREE.SpotLight](https://threejs.org/docs/?q=Light#api/en/lights/SpotLight) 33 | 34 | ## Assets 35 | 36 | - [Water Surface Normal Map](https://www.cgtrader.com/3d-model-collections/ocean-8k) 37 | - [Object Normal Maps](https://www.cgtrader.com/3d-models/textures/natural/s-ea3e180f-bfed-4c62-aaa1-4045e48d8d59) 38 | - [Nebula Spherical Map](https://www.cgtrader.com/3d-models/textures/miscellaneous/nebula-spherical-maps-and-skyboxes-8192x4096-px) 39 | -------------------------------------------------------------------------------- /assets/README.md: -------------------------------------------------------------------------------- 1 | # ASSETS 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your un-compiled assets such as LESS, SASS, or JavaScript. 6 | 7 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#webpacked). 8 | -------------------------------------------------------------------------------- /assets/css/functions.scss: -------------------------------------------------------------------------------- 1 | @function z($name) { 2 | @return index($z-map, $name); 3 | } -------------------------------------------------------------------------------- /assets/css/global.scss: -------------------------------------------------------------------------------- 1 | html { 2 | height: 100%; 3 | } 4 | body { 5 | min-height: 100%; 6 | line-height: 1; 7 | color: #fff; 8 | } 9 | h1, 10 | h2, 11 | h3, 12 | h4, 13 | h5, 14 | h6 { 15 | line-height: 0.65; 16 | font-weight: 400; 17 | } 18 | #canvas-webgl { 19 | position: absolute; 20 | top: 0; 21 | left: 0; 22 | z-index: z(canvas); 23 | } 24 | -------------------------------------------------------------------------------- /assets/css/mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin fontSizeMobile($size: 14) { 2 | font-size: $size / 375 * 100vw; 3 | } 4 | @mixin l-mobile { 5 | @media all and (max-width: $break-point - 1px) { 6 | @content; 7 | } 8 | } 9 | @mixin l-pc { 10 | @media all and (min-width: $break-point) { 11 | @content; 12 | } 13 | } -------------------------------------------------------------------------------- /assets/css/variables.scss: -------------------------------------------------------------------------------- 1 | $z-map: ( 2 | canvas, 3 | page, 4 | header, 5 | controls, 6 | ); 7 | 8 | $break-point: 768px; 9 | -------------------------------------------------------------------------------- /assets/img/004_nebula_red.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ykob/study-threejs-lighting/5d597978a857a9cfbfe27a673cf6efa89b180bcd/assets/img/004_nebula_red.jpg -------------------------------------------------------------------------------- /assets/img/Alunar_Cliff_basecolor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ykob/study-threejs-lighting/5d597978a857a9cfbfe27a673cf6efa89b180bcd/assets/img/Alunar_Cliff_basecolor.png -------------------------------------------------------------------------------- /assets/img/Alunar_Cliff_normal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ykob/study-threejs-lighting/5d597978a857a9cfbfe27a673cf6efa89b180bcd/assets/img/Alunar_Cliff_normal.jpg -------------------------------------------------------------------------------- /assets/img/Alunar_Ground_basecolor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ykob/study-threejs-lighting/5d597978a857a9cfbfe27a673cf6efa89b180bcd/assets/img/Alunar_Ground_basecolor.jpg -------------------------------------------------------------------------------- /assets/img/Alunar_Ground_normal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ykob/study-threejs-lighting/5d597978a857a9cfbfe27a673cf6efa89b180bcd/assets/img/Alunar_Ground_normal.jpg -------------------------------------------------------------------------------- /assets/img/Ocean-4-Normal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ykob/study-threejs-lighting/5d597978a857a9cfbfe27a673cf6efa89b180bcd/assets/img/Ocean-4-Normal.jpg -------------------------------------------------------------------------------- /components/README.md: -------------------------------------------------------------------------------- 1 | # COMPONENTS 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | The components directory contains your Vue.js Components. 6 | 7 | _Nuxt.js doesn't supercharge these components._ 8 | -------------------------------------------------------------------------------- /components/_common/Button.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 63 | 64 | 114 | -------------------------------------------------------------------------------- /components/_common/Menu.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 31 | 32 | 75 | -------------------------------------------------------------------------------- /components/_template/Controls.vue: -------------------------------------------------------------------------------- 1 | 46 | 47 | 68 | 69 | 117 | -------------------------------------------------------------------------------- /components/_template/Header.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 35 | 36 | 70 | -------------------------------------------------------------------------------- /components/icon/Base.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 39 | -------------------------------------------------------------------------------- /components/icon/Cube.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 33 | -------------------------------------------------------------------------------- /components/icon/CubeOutline.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 33 | -------------------------------------------------------------------------------- /components/icon/Github.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 33 | -------------------------------------------------------------------------------- /components/icon/Help.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 33 | -------------------------------------------------------------------------------- /components/icon/HelpRhombusOutline .vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 33 | -------------------------------------------------------------------------------- /components/icon/OpenInNew.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 33 | -------------------------------------------------------------------------------- /components/icon/Pause.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 33 | -------------------------------------------------------------------------------- /components/icon/Play.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 33 | -------------------------------------------------------------------------------- /components/icon/Restore.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 33 | -------------------------------------------------------------------------------- /components/icon/Twitter.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 33 | -------------------------------------------------------------------------------- /components/menu/Help.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 38 | 39 | 75 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "~/*": ["./*"], 6 | "@/*": ["./*"], 7 | "~~/*": ["./*"], 8 | "@@/*": ["./*"] 9 | } 10 | }, 11 | "exclude": ["node_modules", ".nuxt", "dist"] 12 | } 13 | -------------------------------------------------------------------------------- /layouts/README.md: -------------------------------------------------------------------------------- 1 | # LAYOUTS 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your Application Layouts. 6 | 7 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/views#layouts). 8 | -------------------------------------------------------------------------------- /layouts/default.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 29 | 30 | 36 | -------------------------------------------------------------------------------- /middleware/README.md: -------------------------------------------------------------------------------- 1 | # MIDDLEWARE 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your application middleware. 6 | Middleware let you define custom functions that can be run before rendering either a page or a group of pages. 7 | 8 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/routing#middleware). 9 | -------------------------------------------------------------------------------- /nuxt.config.js: -------------------------------------------------------------------------------- 1 | import sass from 'sass' 2 | 3 | export default { 4 | server: { 5 | port: 8080, // デフォルト: 3000, 6 | host: '0.0.0.0', // デフォルト: localhost 7 | }, 8 | 9 | // Disable server-side rendering: https://go.nuxtjs.dev/ssr-mode 10 | ssr: false, 11 | 12 | // Target: https://go.nuxtjs.dev/config-target 13 | target: 'static', 14 | router: { 15 | base: '/study-threejs-lighting/' 16 | }, 17 | 18 | // Global page headers: https://go.nuxtjs.dev/config-head 19 | head: { 20 | title: 'study-threejs-lighting', 21 | htmlAttrs: { 22 | lang: 'en', 23 | }, 24 | meta: [ 25 | { charset: 'utf-8' }, 26 | { name: 'viewport', content: 'width=device-width, initial-scale=1, user-scalable=no' }, 27 | { hid: 'description', name: 'description', content: 'It\'s a study record of 3D graphic lighting with the shaders that I created by quoting from three.js.' }, 28 | ], 29 | link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }], 30 | }, 31 | 32 | // Global CSS: https://go.nuxtjs.dev/config-css 33 | css: [ 34 | 'normalize.css', 35 | '@/assets/css/global.scss', 36 | ], 37 | 38 | // Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins 39 | plugins: ['@/plugins/webgl'], 40 | 41 | // Auto import components: https://go.nuxtjs.dev/config-components 42 | components: [ 43 | { 44 | path: '@/components', 45 | pathPrefix: false, 46 | }, 47 | { 48 | path: '@/components/icon/', 49 | prefix: 'Icon', 50 | }, 51 | { 52 | path: '@/components/menu/', 53 | prefix: 'Menu', 54 | }, 55 | ], 56 | 57 | // Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules 58 | buildModules: [ 59 | // https://go.nuxtjs.dev/eslint 60 | '@nuxtjs/eslint-module', 61 | ], 62 | 63 | // Modules: https://go.nuxtjs.dev/config-modules 64 | modules: [ 65 | '@nuxtjs/style-resources', 66 | ], 67 | 68 | // Build Configuration: https://go.nuxtjs.dev/config-build 69 | build: { 70 | loaders: { 71 | scss: { 72 | implementation: sass, 73 | }, 74 | }, 75 | extend(config) { 76 | config.module.rules.push({ 77 | test: /\.(glsl|fs|vs)$/, 78 | exclude: /(node_modules)/, 79 | use: [ 80 | 'glslify-import-loader', 81 | 'raw-loader', 82 | 'glslify-loader', 83 | ], 84 | }) 85 | }, 86 | }, 87 | 88 | styleResources: { 89 | scss: [ 90 | '@/assets/css/variables.scss', 91 | '@/assets/css/functions.scss', 92 | '@/assets/css/mixins.scss', 93 | ], 94 | }, 95 | } 96 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "study-threejs-lighting", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "nuxt", 7 | "build": "nuxt build", 8 | "start": "nuxt start", 9 | "generate": "nuxt generate", 10 | "deploy": "push-dir --dir=dist --branch=gh-pages --cleanup", 11 | "lint:js": "eslint --ext \".js,.vue\" --ignore-path .gitignore .", 12 | "lint": "yarn lint:js" 13 | }, 14 | "dependencies": { 15 | "core-js": "^3.9.1", 16 | "normalize.css": "^8.0.1", 17 | "nuxt": "^2.15.3", 18 | "three": "^0.132.2" 19 | }, 20 | "devDependencies": { 21 | "@mdi/js": "^5.9.55", 22 | "@nuxtjs/eslint-config": "^6.0.0", 23 | "@nuxtjs/eslint-module": "^3.0.2", 24 | "@nuxtjs/style-resources": "^1.0.0", 25 | "babel-eslint": "^10.1.0", 26 | "eslint": "^7.22.0", 27 | "eslint-config-prettier": "^8.1.0", 28 | "eslint-plugin-nuxt": "^2.0.0", 29 | "eslint-plugin-prettier": "^3.3.1", 30 | "eslint-plugin-vue": "^7.7.0", 31 | "glsl-util": "git://github.com/ykob/glsl-util.git", 32 | "glslify-import-loader": "^0.1.2", 33 | "glslify-loader": "^2.0.0", 34 | "prettier": "^2.2.1", 35 | "pug": "^3.0.2", 36 | "pug-plain-loader": "^1.1.0", 37 | "push-dir": "^0.4.1", 38 | "raw-loader": "^4.0.2", 39 | "sass": "^1.32.12", 40 | "sass-loader": "10.1.1" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /pages/README.md: -------------------------------------------------------------------------------- 1 | # PAGES 2 | 3 | This directory contains your Application Views and Routes. 4 | The framework reads all the `*.vue` files inside this directory and creates the router of your application. 5 | 6 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/routing). 7 | -------------------------------------------------------------------------------- /pages/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /plugins/README.md: -------------------------------------------------------------------------------- 1 | # PLUGINS 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains Javascript plugins that you want to run before mounting the root Vue.js application. 6 | 7 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/plugins). 8 | -------------------------------------------------------------------------------- /plugins/webgl.js: -------------------------------------------------------------------------------- 1 | import WebGLContent from '@/webgl' 2 | 3 | export default ({}, inject) => { 4 | inject('webgl', new WebGLContent()) 5 | } 6 | -------------------------------------------------------------------------------- /static/README.md: -------------------------------------------------------------------------------- 1 | # STATIC 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your static files. 6 | Each file inside this directory is mapped to `/`. 7 | Thus you'd want to delete this README.md before deploying to production. 8 | 9 | Example: `/static/robots.txt` is mapped as `/robots.txt`. 10 | 11 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#static). 12 | -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ykob/study-threejs-lighting/5d597978a857a9cfbfe27a673cf6efa89b180bcd/static/favicon.ico -------------------------------------------------------------------------------- /store/README.md: -------------------------------------------------------------------------------- 1 | # STORE 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your Vuex Store files. 6 | Vuex Store option is implemented in the Nuxt.js framework. 7 | 8 | Creating a file in this directory automatically activates the option in the framework. 9 | 10 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/vuex-store). 11 | -------------------------------------------------------------------------------- /store/index.js: -------------------------------------------------------------------------------- 1 | export const state = () => ({ 2 | isPlaying: true, 3 | }) 4 | 5 | export const mutations = { 6 | playPause(state) { 7 | state.isPlaying = !state.isPlaying 8 | this.$webgl.playPause(state.isPlaying) 9 | }, 10 | } 11 | -------------------------------------------------------------------------------- /webgl/AmbientLight.js: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three' 2 | 3 | export default class AmbientLight extends THREE.AmbientLight { 4 | constructor(color = 0xffffff, intensity = 0.1) { 5 | super(color, intensity) 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /webgl/Background.js: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three' 2 | 3 | import vs from './glsl/Background.vs' 4 | import fs from './glsl/Background.fs' 5 | 6 | export default class Background extends THREE.Mesh { 7 | constructor() { 8 | // Define Geometry 9 | const geometry = new THREE.SphereGeometry(500, 32, 32) 10 | 11 | // Define Material 12 | const material = new THREE.RawShaderMaterial({ 13 | uniforms: { 14 | map: { 15 | value: null, 16 | }, 17 | }, 18 | vertexShader: vs, 19 | fragmentShader: fs, 20 | side: THREE.BackSide, 21 | }) 22 | 23 | // Create Object3D 24 | super(geometry, material) 25 | this.name = 'Background' 26 | this.rotation.y = (Math.PI / 180) * -180 27 | } 28 | 29 | start(map) { 30 | const { uniforms } = this.material 31 | 32 | uniforms.map.value = map 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /webgl/Camera.js: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three' 2 | 3 | export default class Camera extends THREE.PerspectiveCamera { 4 | constructor(fov, aspect, near, far) { 5 | super(fov, aspect, near, far) 6 | 7 | this.far = 1000 8 | this.setFocalLength(50) 9 | this.position.set(0, 0, 180) 10 | } 11 | 12 | resize(resolution) { 13 | this.aspect = resolution.x / resolution.y 14 | this.updateProjectionMatrix() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /webgl/DirectionalLight.js: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three' 2 | 3 | export default class DirectionalLight extends THREE.DirectionalLight { 4 | constructor(color = 0xff0000, intensity = 0.5) { 5 | super(color, intensity) 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /webgl/Ground.js: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three' 2 | 3 | import vs from './glsl/MeshPhong.vs' 4 | import fs from './glsl/MeshPhong.fs' 5 | 6 | export default class Ground extends THREE.Mesh { 7 | constructor() { 8 | // Define Geometry 9 | const geometry = new THREE.PlaneGeometry(1000, 1000) 10 | 11 | // Define Material 12 | const material = new THREE.RawShaderMaterial({ 13 | uniforms: THREE.UniformsUtils.merge([ 14 | THREE.UniformsLib.common, 15 | THREE.UniformsLib.normalmap, 16 | THREE.UniformsLib.lights, 17 | THREE.UniformsLib.fog, 18 | { 19 | time: { 20 | value: 0, 21 | }, 22 | shininess: { 23 | value: 30, 24 | }, 25 | }, 26 | ]), 27 | vertexShader: vs, 28 | fragmentShader: fs, 29 | lights: true, 30 | fog: true, 31 | }) 32 | material.uniforms.uvTransform.value.scale(10, 10) 33 | 34 | // Create Object3D 35 | super(geometry, material) 36 | this.name = 'Ground' 37 | this.position.y = -40 38 | this.rotation.x = (Math.PI / 180) * -90 39 | } 40 | 41 | start(map, normalMap) { 42 | const { uniforms } = this.material 43 | 44 | uniforms.map.value = map 45 | uniforms.normalMap.value = normalMap 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /webgl/InstanceMeshPhong.js: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three' 2 | 3 | import vs from './glsl/InstanceMeshPhong.vs' 4 | import fs from './glsl/MeshPhong.fs' 5 | 6 | const COUNT = 5 7 | 8 | export default class InstanceMeshPhong extends THREE.InstancedMesh { 9 | constructor() { 10 | // Define Geometry 11 | const geometry = new THREE.IcosahedronGeometry(20, 1) 12 | 13 | const material = new THREE.RawShaderMaterial({ 14 | uniforms: THREE.UniformsUtils.merge([ 15 | THREE.UniformsLib.common, 16 | THREE.UniformsLib.normalmap, 17 | THREE.UniformsLib.lights, 18 | THREE.UniformsLib.fog, 19 | { 20 | time: { 21 | value: 0, 22 | }, 23 | shininess: { 24 | value: 100, 25 | }, 26 | }, 27 | ]), 28 | vertexShader: vs, 29 | fragmentShader: fs, 30 | lights: true, 31 | fog: true, 32 | }) 33 | material.uniforms.uvTransform.value.scale(2, 1) 34 | 35 | // Create Object3D 36 | super(geometry, material, COUNT) 37 | this.name = 'InstanceMeshPhong' 38 | 39 | const dummy = new THREE.Object3D() 40 | for (let i = 0; i < COUNT; i++) { 41 | const alpha = i / COUNT 42 | dummy.position.set( 43 | Math.cos(alpha * ((Math.PI / 180) * 360)) * 60, 44 | -35, 45 | Math.sin(alpha * ((Math.PI / 180) * 360)) * 60 46 | ) 47 | dummy.updateMatrix() 48 | this.setMatrixAt(i, dummy.matrix) 49 | } 50 | this.instanceMatrix.needsUpdate = true 51 | } 52 | 53 | start(map, normalMap) { 54 | const { uniforms } = this.material 55 | 56 | uniforms.map.value = map 57 | uniforms.normalMap.value = normalMap 58 | } 59 | 60 | update() { 61 | this.rotation.y += 0.01 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /webgl/MeshLambert.js: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three' 2 | 3 | import vs from './glsl/MeshLambert.vs' 4 | import fs from './glsl/MeshLambert.fs' 5 | 6 | export default class MeshLambert extends THREE.Mesh { 7 | constructor() { 8 | // Define Geometry 9 | const geometry = new THREE.TorusGeometry(16, 6, 16, 100) 10 | 11 | // Define Material 12 | const material = new THREE.RawShaderMaterial({ 13 | uniforms: THREE.UniformsUtils.merge([ 14 | THREE.UniformsLib.lights, 15 | { 16 | time: { 17 | value: 0, 18 | }, 19 | normalMap: { 20 | value: null, 21 | }, 22 | }, 23 | ]), 24 | vertexShader: vs, 25 | fragmentShader: fs, 26 | lights: true, 27 | }) 28 | 29 | // Create Object3D 30 | super(geometry, material) 31 | this.name = 'MeshLambert' 32 | } 33 | 34 | start(normalMap) { 35 | const { uniforms } = this.material 36 | 37 | uniforms.normalMap.value = normalMap 38 | } 39 | 40 | update() { 41 | this.rotation.y += 0.01 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /webgl/MeshPhong.js: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three' 2 | 3 | import vs from './glsl/MeshPhong.vs' 4 | import fs from './glsl/MeshPhong.fs' 5 | 6 | export default class MeshPhong extends THREE.Mesh { 7 | constructor() { 8 | // Define Geometry 9 | const geometry = new THREE.TorusGeometry(16, 6, 16, 100) 10 | 11 | const material = new THREE.RawShaderMaterial({ 12 | uniforms: THREE.UniformsUtils.merge([ 13 | THREE.UniformsLib.common, 14 | THREE.UniformsLib.normalmap, 15 | THREE.UniformsLib.lights, 16 | THREE.UniformsLib.fog, 17 | { 18 | time: { 19 | value: 0, 20 | }, 21 | shininess: { 22 | value: 100, 23 | }, 24 | }, 25 | ]), 26 | vertexShader: vs, 27 | fragmentShader: fs, 28 | lights: true, 29 | fog: true, 30 | }) 31 | material.uniforms.uvTransform.value.scale(3, 1) 32 | 33 | // Create Object3D 34 | super(geometry, material) 35 | this.name = 'MeshPhong' 36 | this.position.y = 5 37 | } 38 | 39 | start(map, normalMap) { 40 | const { uniforms } = this.material 41 | 42 | uniforms.map.value = map 43 | uniforms.normalMap.value = normalMap 44 | } 45 | 46 | update() { 47 | this.rotation.y += 0.01 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /webgl/PointLight.js: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three' 2 | 3 | export default class PointLight extends THREE.PointLight { 4 | constructor(color = 0xff0000, intensity = 0.5, distance = 100, decay = 1) { 5 | super(color, intensity, distance, decay) 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /webgl/Water.js: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three' 2 | import { Reflector } from 'three/examples/jsm/objects/Reflector.js' 3 | import { Refractor } from 'three/examples/jsm/objects/Refractor.js' 4 | 5 | import vs from './glsl/Water.vs' 6 | import fs from './glsl/Water.fs' 7 | 8 | export default class Water extends THREE.Mesh { 9 | constructor() { 10 | // Define Geometry 11 | const geometry = new THREE.PlaneGeometry(1000, 1000) 12 | geometry.computeTangents() 13 | 14 | const material = new THREE.RawShaderMaterial({ 15 | uniforms: THREE.UniformsUtils.merge([ 16 | THREE.UniformsLib.common, 17 | THREE.UniformsLib.normalmap, 18 | THREE.UniformsLib.lights, 19 | THREE.UniformsLib.fog, 20 | { 21 | time: { 22 | value: 0, 23 | }, 24 | shininess: { 25 | value: 120, 26 | }, 27 | reflectivity: { 28 | value: 0.05, 29 | }, 30 | textureMatrix: { 31 | value: new THREE.Matrix4(), 32 | }, 33 | tReflectionMap: { 34 | value: null, 35 | }, 36 | tRefractionMap: { 37 | value: null, 38 | }, 39 | resolution: { 40 | value: new THREE.Vector2(), 41 | }, 42 | tDepth1: { 43 | value: null, 44 | }, 45 | tDepth2: { 46 | value: null, 47 | }, 48 | cameraNear: { 49 | value: 0.1, 50 | }, 51 | cameraFar: { 52 | value: 1000, 53 | }, 54 | }, 55 | ]), 56 | vertexShader: vs, 57 | fragmentShader: fs, 58 | lights: true, 59 | fog: true, 60 | }) 61 | material.uniforms.uvTransform.value.scale(5, 5) 62 | material.uniforms.diffuse.value.set(0x440044) 63 | 64 | // Create Object3D 65 | super(geometry, material) 66 | this.name = 'MeshRipple' 67 | this.position.y = -25 68 | this.rotation.x = (Math.PI / 180) * -90 69 | 70 | const textureWidth = 1024 71 | const textureHeight = 1024 72 | const clipBias = 0 73 | const encoding = THREE.LinearEncoding 74 | 75 | // Define Reflector and Refractor 76 | this.reflector = new Reflector(geometry, { 77 | textureWidth, 78 | textureHeight, 79 | clipBias, 80 | encoding, 81 | }) 82 | this.refractor = new Refractor(geometry, { 83 | textureWidth, 84 | textureHeight, 85 | clipBias, 86 | encoding, 87 | }) 88 | this.reflector.matrixAutoUpdate = false 89 | this.refractor.matrixAutoUpdate = false 90 | material.uniforms.tReflectionMap.value = this.reflector.getRenderTarget().texture 91 | material.uniforms.tRefractionMap.value = this.refractor.getRenderTarget().texture 92 | } 93 | 94 | start(normalMap, tDepth1, tDepth2) { 95 | const { uniforms } = this.material 96 | 97 | uniforms.normalMap.value = normalMap 98 | uniforms.tDepth1.value = tDepth1 99 | uniforms.tDepth2.value = tDepth2 100 | } 101 | 102 | onBeforeRender(renderer, scene, camera) { 103 | const { uniforms } = this.material 104 | 105 | // prettier-ignore 106 | uniforms.textureMatrix.value.set( 107 | 0.5, 0.0, 0.0, 0.5, 108 | 0.0, 0.5, 0.0, 0.5, 109 | 0.0, 0.0, 0.5, 0.5, 110 | 0.0, 0.0, 0.0, 1.0, 111 | ) 112 | uniforms.textureMatrix.value.multiply(camera.projectionMatrix) 113 | uniforms.textureMatrix.value.multiply(camera.matrixWorldInverse) 114 | uniforms.textureMatrix.value.multiply(this.matrixWorld) 115 | this.visible = false 116 | this.reflector.matrixWorld.copy(this.matrixWorld) 117 | this.refractor.matrixWorld.copy(this.matrixWorld) 118 | this.reflector.onBeforeRender(renderer, scene, camera) 119 | this.refractor.onBeforeRender(renderer, scene, camera) 120 | this.visible = true 121 | } 122 | 123 | update(time) { 124 | const { uniforms } = this.material 125 | 126 | uniforms.time.value += time 127 | } 128 | 129 | resize(resolution) { 130 | const { uniforms } = this.material 131 | 132 | uniforms.resolution.value.copy(resolution) 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /webgl/glsl/Background.fs: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform sampler2D map; 4 | 5 | varying vec2 vUv; 6 | 7 | void main() { 8 | vec4 texelColor = texture2D(map, vUv); 9 | float gradual = smoothstep(0.48, 0.52, vUv.y); 10 | 11 | gl_FragColor = vec4(texelColor.rgb * gradual, 1.0); 12 | } 13 | -------------------------------------------------------------------------------- /webgl/glsl/Background.vs: -------------------------------------------------------------------------------- 1 | attribute vec3 position; 2 | attribute vec2 uv; 3 | 4 | uniform mat4 projectionMatrix; 5 | uniform mat4 viewMatrix; 6 | uniform mat4 modelMatrix; 7 | 8 | varying vec2 vUv; 9 | 10 | void main(void) { 11 | vec3 transformed = position; 12 | vec4 mvPosition = viewMatrix * modelMatrix * vec4(transformed, 1.0); 13 | 14 | vUv = uv + vec2(0.45, 0.0); 15 | 16 | gl_Position = projectionMatrix * mvPosition; 17 | } 18 | -------------------------------------------------------------------------------- /webgl/glsl/InstanceMeshPhong.vs: -------------------------------------------------------------------------------- 1 | attribute vec3 position; 2 | attribute vec3 normal; 3 | attribute vec2 uv; 4 | attribute vec4 tangent; 5 | 6 | uniform mat4 modelMatrix; 7 | uniform mat4 viewMatrix; 8 | uniform mat4 projectionMatrix; 9 | uniform mat3 normalMatrix; 10 | uniform mat3 uvTransform; 11 | 12 | varying vec3 vViewPosition; 13 | varying vec2 vUv; 14 | varying vec3 vNormal; 15 | 16 | // Instancing 17 | attribute mat4 instanceMatrix; 18 | 19 | // Fog 20 | varying float fogDepth; 21 | 22 | void main(void) { 23 | vec3 transformedNormal = normal; 24 | transformedNormal = normalMatrix * transformedNormal; 25 | 26 | vec3 transformed = position; 27 | vec4 mvPosition = viewMatrix * modelMatrix * instanceMatrix * vec4(transformed, 1.0); 28 | 29 | vViewPosition = -mvPosition.xyz; 30 | vUv = (uvTransform * vec3(uv, 1.0)).xy; 31 | vNormal = normalize(transformedNormal); 32 | 33 | // Fog 34 | fogDepth = -mvPosition.z; 35 | 36 | gl_Position = projectionMatrix * mvPosition; 37 | } 38 | -------------------------------------------------------------------------------- /webgl/glsl/MeshLambert.fs: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | // https://github.com/mrdoob/three.js/blob/master/src/renderers/shaders/ShaderLib/meshbasic_frag.glsl.js 4 | uniform vec3 diffuse; 5 | uniform vec3 emissive; 6 | uniform float opacity; 7 | 8 | varying vec3 vLightFront; 9 | varying vec3 vIndirectFront; 10 | 11 | #ifdef DOUBLE_SIDED 12 | varying vec3 vLightBack; 13 | varying vec3 vIndirectBack; 14 | #endif 15 | 16 | // #include 17 | uniform vec3 ambientLightColor; 18 | 19 | struct ReflectedLight { 20 | vec3 directDiffuse; 21 | vec3 directSpecular; 22 | vec3 indirectDiffuse; 23 | vec3 indirectSpecular; 24 | }; 25 | 26 | void main() { 27 | ReflectedLight reflectedLight = ReflectedLight(vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0)); 28 | 29 | #ifdef DOUBLE_SIDED 30 | reflectedLight.indirectDiffuse += (gl_FrontFacing) ? vIndirectFront : vIndirectBack; 31 | #else 32 | reflectedLight.indirectDiffuse += vIndirectFront; 33 | #endif 34 | 35 | #ifdef DOUBLE_SIDED 36 | reflectedLight.directDiffuse = (gl_FrontFacing) ? vLightFront : vLightBack; 37 | #else 38 | reflectedLight.directDiffuse = vLightFront; 39 | #endif 40 | 41 | vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse; 42 | 43 | gl_FragColor = vec4(outgoingLight, 1.0); 44 | } 45 | -------------------------------------------------------------------------------- /webgl/glsl/MeshLambert.vs: -------------------------------------------------------------------------------- 1 | attribute vec3 position; 2 | attribute vec3 normal; 3 | attribute vec2 uv; 4 | 5 | uniform mat4 modelMatrix; 6 | uniform mat4 modelViewMatrix; 7 | uniform mat4 viewMatrix; 8 | uniform mat4 projectionMatrix; 9 | uniform mat3 normalMatrix; 10 | uniform vec3 cameraPosition; 11 | uniform bool isOrthographic; 12 | 13 | // https://github.com/mrdoob/three.js/blob/master/src/renderers/shaders/ShaderLib/meshbasic_vert.glsl.js 14 | #define LAMBERT 15 | 16 | varying vec3 vLightFront; 17 | varying vec3 vIndirectFront; 18 | 19 | #ifdef DOUBLE_SIDED 20 | varying vec3 vLightBack; 21 | varying vec3 vIndirectBack; 22 | #endif 23 | 24 | // #include 25 | #define PI 3.141592653589793 26 | 27 | #ifndef saturate 28 | #define saturate(a) clamp(a, 0.0, 1.0) 29 | #endif 30 | 31 | struct IncidentLight { 32 | vec3 color; 33 | vec3 direction; 34 | bool visible; 35 | }; 36 | 37 | struct GeometricContext { 38 | vec3 position; 39 | vec3 normal; 40 | vec3 viewDir; 41 | #ifdef CLEARCOAT 42 | vec3 clearcoatNormal; 43 | #endif 44 | }; 45 | 46 | // #include 47 | uniform vec3 ambientLightColor; 48 | 49 | vec3 getAmbientLightIrradiance(const in vec3 ambientLightColor) { 50 | vec3 irradiance = ambientLightColor; 51 | return irradiance *= PI; 52 | } 53 | 54 | #if NUM_DIR_LIGHTS > 0 55 | struct DirectionalLight { 56 | vec3 direction; 57 | vec3 color; 58 | }; 59 | 60 | uniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ]; 61 | 62 | void getDirectionalDirectLightIrradiance( 63 | const in DirectionalLight directionalLight, 64 | const in GeometricContext geometry, 65 | out IncidentLight directLight 66 | ) { 67 | directLight.color = directionalLight.color; 68 | directLight.direction = directionalLight.direction; 69 | directLight.visible = true; 70 | } 71 | #endif 72 | 73 | void main(void) { 74 | // #include 75 | vec3 objectNormal = vec3(normal); 76 | 77 | // #include 78 | vec3 transformedNormal = objectNormal; 79 | transformedNormal = normalMatrix * transformedNormal; 80 | 81 | // #include 82 | vec3 transformed = vec3(position); 83 | 84 | // #include 85 | vec4 mvPosition = vec4(transformed, 1.0); 86 | mvPosition = modelViewMatrix * mvPosition; 87 | gl_Position = projectionMatrix * mvPosition; 88 | 89 | // #include 90 | vec3 diffuse = vec3( 1.0 ); 91 | 92 | GeometricContext geometry; 93 | geometry.position = mvPosition.xyz; 94 | geometry.normal = normalize(transformedNormal); 95 | geometry.viewDir = (isOrthographic) 96 | ? vec3(0, 0, 1) 97 | : normalize(-mvPosition.xyz); 98 | 99 | GeometricContext backGeometry; 100 | backGeometry.position = geometry.position; 101 | backGeometry.normal = -geometry.normal; 102 | backGeometry.viewDir = geometry.viewDir; 103 | 104 | vLightFront = vec3(0.0); 105 | vIndirectFront = vec3(0.0); 106 | #ifdef DOUBLE_SIDED 107 | vLightBack = vec3(0.0); 108 | vIndirectBack = vec3(0.0); 109 | #endif 110 | 111 | IncidentLight directLight; 112 | float dotNL; 113 | vec3 directLightColor_Diffuse; 114 | 115 | vIndirectFront += getAmbientLightIrradiance(ambientLightColor); 116 | 117 | #if NUM_DIR_LIGHTS > 0 118 | #pragma unroll_loop_start 119 | for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) { 120 | getDirectionalDirectLightIrradiance(directionalLights[ i ], geometry, directLight); 121 | dotNL = dot(geometry.normal, directLight.direction); 122 | directLightColor_Diffuse = PI * directLight.color; 123 | vLightFront += saturate(dotNL) * directLightColor_Diffuse; 124 | #ifdef DOUBLE_SIDED 125 | vLightBack += saturate(-dotNL) * directLightColor_Diffuse; 126 | #endif 127 | } 128 | #pragma unroll_loop_end 129 | #endif 130 | } 131 | -------------------------------------------------------------------------------- /webgl/glsl/MeshPhong.fs: -------------------------------------------------------------------------------- 1 | #extension GL_OES_standard_derivatives : enable 2 | 3 | precision highp float; 4 | 5 | uniform mat4 viewMatrix; 6 | 7 | uniform float shininess; 8 | 9 | uniform vec3 diffuse; 10 | uniform float opacity; 11 | uniform sampler2D map; 12 | uniform sampler2D normalMap; 13 | uniform vec2 normalScale; 14 | 15 | varying vec3 vViewPosition; 16 | varying vec2 vUv; 17 | varying vec3 vNormal; 18 | 19 | // Common 20 | #define RECIPROCAL_PI 0.3183098861837907 21 | 22 | struct GeometricContext { 23 | vec3 position; 24 | vec3 normal; 25 | vec3 viewDir; 26 | }; 27 | struct IncidentLight { 28 | vec3 color; 29 | vec3 direction; 30 | bool visible; 31 | }; 32 | 33 | // Ambient Light 34 | uniform vec3 ambientLightColor; 35 | 36 | // Directional Lights 37 | #if NUM_DIR_LIGHTS > 0 38 | struct DirectionalLight { 39 | vec3 direction; 40 | vec3 color; 41 | }; 42 | uniform DirectionalLight directionalLights[NUM_DIR_LIGHTS]; 43 | #endif 44 | 45 | // Point Lights 46 | #if NUM_POINT_LIGHTS > 0 47 | struct PointLight { 48 | vec3 position; 49 | vec3 color; 50 | float distance; 51 | float decay; 52 | }; 53 | uniform PointLight pointLights[NUM_POINT_LIGHTS]; 54 | 55 | void getPointDirectLightIrradiance( 56 | const in PointLight pointLight, 57 | const in GeometricContext geometry, 58 | out IncidentLight directLight 59 | ) { 60 | vec3 lVector = pointLight.position - geometry.position; 61 | directLight.direction = normalize(lVector); 62 | float lightDistance = length(lVector); 63 | directLight.color = pointLight.color; 64 | directLight.color *= pow(clamp(-lightDistance / pointLight.distance + 1.0, 0.0, 1.0), pointLight.decay); 65 | } 66 | #endif 67 | 68 | // Diffuse 69 | vec3 calcDiffuse( 70 | const in GeometricContext geometry, 71 | const in IncidentLight directLight 72 | ) { 73 | float dotNL = dot(geometry.normal, directLight.direction); 74 | return directLight.color * clamp(dotNL, 0.0, 1.0); 75 | } 76 | 77 | // Specular 78 | vec3 F_Schlick(const in vec3 specularColor, const in float dotLH) { 79 | float fresnel = exp2((-5.55473 * dotLH - 6.98316) * dotLH); 80 | return (1.0 - specularColor) * fresnel + specularColor; 81 | } 82 | float D_BlinnPhong(const in float shininess, const in float dotNH) { 83 | return RECIPROCAL_PI * (shininess * 0.5 + 1.0) * pow(dotNH, shininess); 84 | } 85 | vec3 calcSpecular( 86 | const in GeometricContext geometry, 87 | const in IncidentLight directLight 88 | ) { 89 | vec3 halfDir = normalize(directLight.direction + geometry.viewDir); 90 | float dotNH = clamp(dot(geometry.normal, halfDir), 0.0, 1.0); 91 | float dotLH = clamp(dot(directLight.direction, halfDir), 0.0, 1.0); 92 | vec3 F = F_Schlick(vec3(1.0), dotLH); 93 | float G = 0.25; 94 | float D = D_BlinnPhong(shininess, dotNH); 95 | return (F * (G * D)); 96 | } 97 | 98 | // Perturb Normal 99 | // https://github.com/glslify/glsl-perturb-normal 100 | mat3 cotangent(vec3 N, vec3 p, vec2 uv) { 101 | // get edge vectors of the pixel triangle 102 | vec3 dp1 = dFdx(p); 103 | vec3 dp2 = dFdy(p); 104 | vec2 duv1 = dFdx(uv); 105 | vec2 duv2 = dFdy(uv); 106 | 107 | // solve the linear system 108 | vec3 dp2perp = cross(dp2, N); 109 | vec3 dp1perp = cross(N, dp1); 110 | vec3 T = dp2perp * duv1.x + dp1perp * duv2.x; 111 | vec3 B = dp2perp * duv1.y + dp1perp * duv2.y; 112 | 113 | // construct a scale-invariant frame 114 | float invmax = 1.0 / sqrt(max(dot(T,T), dot(B,B))); 115 | return mat3(normalize(T * invmax), normalize(B * invmax), N); 116 | } 117 | vec3 perturb(vec3 map, vec3 N, vec3 V, vec2 texcoord) { 118 | mat3 TBN = cotangent(N, -V, texcoord); 119 | return normalize(TBN * map); 120 | } 121 | 122 | // Fog 123 | uniform vec3 fogColor; 124 | uniform float fogNear; 125 | uniform float fogFar; 126 | varying float fogDepth; 127 | 128 | void main() { 129 | vec4 diffuseColor = vec4(diffuse, opacity); 130 | 131 | // Map Fragment 132 | vec4 texelColor = texture2D(map, vUv); 133 | diffuseColor *= texelColor; 134 | 135 | // Normal with Tangent Space 136 | vec3 normal = normalize(vNormal); 137 | vec3 mapN = texture2D(normalMap, vUv).xyz * 2.0 - 1.0; 138 | mapN.xy *= normalScale; 139 | normal = perturb(mapN, normal, normalize(vViewPosition), vUv); 140 | 141 | // Define geometry 142 | GeometricContext geometry; 143 | geometry.position = -vViewPosition; 144 | geometry.normal = normal; 145 | geometry.viewDir = normalize(vViewPosition); 146 | 147 | vec3 diffuse; 148 | vec3 specular; 149 | vec3 irradiance; 150 | IncidentLight directLight; 151 | 152 | // Directional Light 153 | #if NUM_DIR_LIGHTS > 0 154 | #pragma unroll_loop_start 155 | for (int i = 0; i < NUM_DIR_LIGHTS; i++) { 156 | directLight.direction = directionalLights[i].direction; 157 | directLight.color = directionalLights[i].color; 158 | 159 | // diffuse 160 | irradiance = calcDiffuse(geometry, directLight); 161 | diffuse += irradiance * diffuseColor.rgb; 162 | 163 | // specular 164 | specular += irradiance * calcSpecular(geometry, directLight); 165 | } 166 | #pragma unroll_loop_end 167 | #endif 168 | 169 | // Point Light 170 | #if NUM_POINT_LIGHTS > 0 171 | #pragma unroll_loop_start 172 | for (int i = 0; i < NUM_POINT_LIGHTS; i++) { 173 | getPointDirectLightIrradiance(pointLights[i], geometry, directLight); 174 | 175 | // diffuse 176 | irradiance = calcDiffuse(geometry, directLight); 177 | diffuse += irradiance * diffuseColor.rgb; 178 | 179 | // specular 180 | specular += irradiance * calcSpecular(geometry, directLight); 181 | } 182 | #pragma unroll_loop_end 183 | #endif 184 | 185 | vec3 light = diffuse + specular + ambientLightColor * diffuseColor.rgb; 186 | 187 | gl_FragColor = vec4(light, diffuseColor.a); 188 | 189 | // Fog 190 | float fogFactor = smoothstep(fogNear, fogFar, fogDepth); 191 | 192 | gl_FragColor.rgb = mix(gl_FragColor.rgb, fogColor, fogFactor); 193 | } 194 | -------------------------------------------------------------------------------- /webgl/glsl/MeshPhong.vs: -------------------------------------------------------------------------------- 1 | attribute vec3 position; 2 | attribute vec3 normal; 3 | attribute vec2 uv; 4 | 5 | uniform mat4 modelMatrix; 6 | uniform mat4 viewMatrix; 7 | uniform mat4 projectionMatrix; 8 | uniform mat3 normalMatrix; 9 | uniform mat3 uvTransform; 10 | 11 | varying vec3 vViewPosition; 12 | varying vec2 vUv; 13 | varying vec3 vNormal; 14 | 15 | // Fog 16 | varying float fogDepth; 17 | 18 | void main(void) { 19 | vec3 transformedNormal = normal; 20 | transformedNormal = normalMatrix * transformedNormal; 21 | 22 | vec3 transformed = position; 23 | vec4 mvPosition = viewMatrix * modelMatrix * vec4(transformed, 1.0); 24 | 25 | vViewPosition = -mvPosition.xyz; 26 | vUv = (uvTransform * vec3(uv, 1.0)).xy; 27 | vNormal = normalize(transformedNormal); 28 | 29 | // Fog 30 | fogDepth = -mvPosition.z; 31 | 32 | gl_Position = projectionMatrix * mvPosition; 33 | } 34 | -------------------------------------------------------------------------------- /webgl/glsl/Water.fs: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform mat4 viewMatrix; 4 | 5 | uniform float time; 6 | uniform float shininess; 7 | uniform float reflectivity; 8 | uniform mat4 textureMatrix; 9 | uniform sampler2D tReflectionMap; 10 | uniform sampler2D tRefractionMap; 11 | uniform vec2 resolution; 12 | uniform sampler2D tDepth1; 13 | uniform sampler2D tDepth2; 14 | uniform float cameraNear; 15 | uniform float cameraFar; 16 | 17 | uniform vec3 diffuse; 18 | uniform float opacity; 19 | uniform sampler2D normalMap; 20 | uniform vec2 normalScale; 21 | 22 | varying vec3 vViewPosition; 23 | varying vec3 vToEye; 24 | varying vec2 vUv; 25 | varying vec4 vCoord; 26 | varying vec3 vNormal; 27 | varying vec3 vTangent; 28 | varying vec3 vBitangent; 29 | 30 | // Common 31 | #define RECIPROCAL_PI 0.3183098861837907 32 | 33 | struct GeometricContext { 34 | vec3 position; 35 | vec3 normal; 36 | vec3 viewDir; 37 | }; 38 | struct IncidentLight { 39 | vec3 color; 40 | vec3 direction; 41 | bool visible; 42 | }; 43 | 44 | // Directional Lights 45 | #if NUM_DIR_LIGHTS > 0 46 | struct DirectionalLight { 47 | vec3 direction; 48 | vec3 color; 49 | }; 50 | uniform DirectionalLight directionalLights[NUM_DIR_LIGHTS]; 51 | #endif 52 | 53 | // Point Lights 54 | #if NUM_POINT_LIGHTS > 0 55 | struct PointLight { 56 | vec3 position; 57 | vec3 color; 58 | float distance; 59 | float decay; 60 | }; 61 | uniform PointLight pointLights[NUM_POINT_LIGHTS]; 62 | 63 | void getPointDirectLightIrradiance( 64 | const in PointLight pointLight, 65 | const in GeometricContext geometry, 66 | out IncidentLight directLight 67 | ) { 68 | vec3 lVector = pointLight.position - geometry.position; 69 | directLight.direction = normalize(lVector); 70 | float lightDistance = length(lVector); 71 | directLight.color = pointLight.color; 72 | directLight.color *= pow(clamp(-lightDistance / pointLight.distance + 1.0, 0.0, 1.0), pointLight.decay); 73 | } 74 | #endif 75 | 76 | // Diffuse 77 | vec3 calcDiffuse( 78 | const in GeometricContext geometry, 79 | const in IncidentLight directLight 80 | ) { 81 | float dotNL = dot(geometry.normal, directLight.direction); 82 | return directLight.color * clamp(dotNL, 0.0, 1.0); 83 | } 84 | 85 | // Specular 86 | vec3 F_Schlick(const in vec3 specularColor, const in float dotLH) { 87 | float fresnel = exp2((-5.55473 * dotLH - 6.98316) * dotLH); 88 | return (1.0 - specularColor) * fresnel + specularColor; 89 | } 90 | float D_BlinnPhong(const in float shininess, const in float dotNH) { 91 | return RECIPROCAL_PI * (shininess * 0.5 + 1.0) * pow(dotNH, shininess); 92 | } 93 | vec3 calcSpecular( 94 | const in GeometricContext geometry, 95 | const in IncidentLight directLight 96 | ) { 97 | vec3 halfDir = normalize(directLight.direction + geometry.viewDir); 98 | float dotNH = clamp(dot(geometry.normal, halfDir), 0.0, 1.0); 99 | float dotLH = clamp(dot(directLight.direction, halfDir), 0.0, 1.0); 100 | vec3 F = F_Schlick(vec3(1.0), dotLH); 101 | float G = 0.25; 102 | float D = D_BlinnPhong(shininess, dotNH); 103 | return (F * (G * D)); 104 | } 105 | 106 | // Blending Normal Map 107 | vec3 blendNormalRNM(vec3 n1, vec3 n2) { 108 | n1 += vec3(0.0, 0.0, 1.0); 109 | n2 *= vec3(-1.0, -1.0, 1.0); 110 | return n1 * dot(n1, n2) / n1.z - n2; 111 | } 112 | 113 | // Fog 114 | uniform vec3 fogColor; 115 | uniform float fogNear; 116 | uniform float fogFar; 117 | varying float fogDepth; 118 | 119 | // Depth 120 | float viewZToOrthographicDepth(const in float viewZ, const in float near, const in float far) { 121 | return (viewZ + near) / (near - far); 122 | } 123 | float perspectiveDepthToViewZ(const in float invClipZ, const in float near, const in float far) { 124 | return (near * far) / ((far - near) * invClipZ - far); 125 | } 126 | float readDepth(sampler2D depthSampler, vec2 coord) { 127 | float fragCoordZ = texture2D(depthSampler, coord).x; 128 | float viewZ = perspectiveDepthToViewZ(fragCoordZ, cameraNear, cameraFar); 129 | return viewZToOrthographicDepth(viewZ, cameraNear, cameraFar); 130 | } 131 | 132 | void main() { 133 | vec4 diffuseColor = vec4(diffuse, opacity); 134 | 135 | // Normal Map 136 | vec4 mapN1 = texture2D(normalMap, vUv + time * vec2(0.01, -0.01)); 137 | vec4 mapN2 = texture2D(normalMap, vUv - time * vec2(0.01, -0.01)); 138 | vec3 mapN = blendNormalRNM(mapN1.xyz * 2.0 - 1.0, mapN2.xyz * 2.0 - 1.0); 139 | mapN.xy *= normalScale; 140 | 141 | // Normal with Tangent Space 142 | vec3 normal = normalize(vNormal); 143 | vec3 tangent = normalize(vTangent); 144 | vec3 bitangent = normalize(vBitangent); 145 | mat3 vTBN = mat3(tangent, bitangent, normal); 146 | normal = normalize(vTBN * mapN); 147 | 148 | // Define geometry 149 | GeometricContext geometry; 150 | geometry.position = -vViewPosition; 151 | geometry.normal = normal; 152 | geometry.viewDir = normalize(vViewPosition); 153 | 154 | vec3 diffuse; 155 | vec3 specular; 156 | vec3 irradiance; 157 | IncidentLight directLight; 158 | 159 | // Directional Light 160 | #if NUM_DIR_LIGHTS > 0 161 | #pragma unroll_loop_start 162 | for (int i = 0; i < NUM_DIR_LIGHTS; i++) { 163 | directLight.direction = directionalLights[i].direction; 164 | directLight.color = directionalLights[i].color; 165 | 166 | // diffuse 167 | irradiance = calcDiffuse(geometry, directLight); 168 | diffuse += irradiance * diffuseColor.rgb; 169 | } 170 | #pragma unroll_loop_end 171 | #endif 172 | 173 | // Point Light 174 | #if NUM_POINT_LIGHTS > 0 175 | #pragma unroll_loop_start 176 | for (int i = 0; i < NUM_POINT_LIGHTS; i++) { 177 | getPointDirectLightIrradiance(pointLights[i], geometry, directLight); 178 | 179 | // diffuse 180 | irradiance = calcDiffuse(geometry, directLight); 181 | diffuse += irradiance * diffuseColor.rgb; 182 | 183 | // specular 184 | specular += irradiance * calcSpecular(geometry, directLight); 185 | } 186 | #pragma unroll_loop_end 187 | #endif 188 | 189 | vec3 light = diffuse + specular; 190 | 191 | // Normal for reflect and refract. 192 | vec4 mapNR = mix(mapN1, mapN2, 0.1); 193 | vec3 normalR = normalize(vec3(mapNR.r * 2.0 - 1.0, mapNR.b, mapNR.g * 2.0 - 1.0)); 194 | 195 | // calculate the fresnel term to blend reflection and refraction maps 196 | float theta = max(dot(normalize(vToEye), normalR), 0.0); 197 | float reflectance = reflectivity + (1.0 - reflectivity) * pow((1.0 - theta), 5.0); 198 | vec3 coord = vCoord.xyz / vCoord.w; 199 | vec2 uv = coord.xy + coord.z * normalR.xz * 0.15; 200 | vec4 reflectColor = texture2D(tReflectionMap, vec2(1.0 - uv.x, uv.y)); 201 | vec4 refractColor = texture2D(tRefractionMap, uv) * 0.2; 202 | 203 | // Depth for water's edge 204 | float depth1 = readDepth(tDepth1, gl_FragCoord.xy / resolution + mapN.xy * 0.06); 205 | float depth2 = readDepth(tDepth2, gl_FragCoord.xy / resolution + mapN.xy * 0.06); 206 | float waterEdge = (1.0 - smoothstep(0.0015, 0.003, abs(depth1 - depth2))) * 0.15; 207 | 208 | gl_FragColor = vec4(light, 1.0) + mix(refractColor, reflectColor, reflectance) + waterEdge; 209 | 210 | // Fog 211 | float fogFactor = smoothstep(fogNear, fogFar, fogDepth); 212 | 213 | gl_FragColor.rgb = mix(gl_FragColor.rgb, fogColor, fogFactor); 214 | } 215 | -------------------------------------------------------------------------------- /webgl/glsl/Water.vs: -------------------------------------------------------------------------------- 1 | attribute vec3 position; 2 | attribute vec3 normal; 3 | attribute vec2 uv; 4 | attribute vec4 tangent; 5 | 6 | uniform mat4 textureMatrix; 7 | 8 | uniform mat4 modelMatrix; 9 | uniform mat4 viewMatrix; 10 | uniform mat4 projectionMatrix; 11 | uniform mat3 normalMatrix; 12 | uniform vec3 cameraPosition; 13 | 14 | uniform mat3 uvTransform; 15 | 16 | varying vec3 vViewPosition; 17 | varying vec3 vToEye; 18 | varying vec2 vUv; 19 | varying vec4 vCoord; 20 | varying vec3 vNormal; 21 | varying vec3 vTangent; 22 | varying vec3 vBitangent; 23 | 24 | // Fog 25 | varying float fogDepth; 26 | 27 | void main(void) { 28 | vec3 transformedNormal = normal; 29 | transformedNormal = normalMatrix * transformedNormal; 30 | 31 | vec3 transformed = position; 32 | vec4 mvPosition = viewMatrix * modelMatrix * vec4(transformed, 1.0); 33 | 34 | vec3 transformedTangent = (viewMatrix * modelMatrix * vec4(tangent.xyz, 0.0)).xyz; 35 | 36 | vViewPosition = -mvPosition.xyz; 37 | vToEye = cameraPosition - (modelMatrix * vec4(transformed, 1.0)).xyz; 38 | vUv = (uvTransform * vec3(uv, 1.0)).xy; 39 | vCoord = textureMatrix * vec4(position, 1.0); 40 | vNormal = normalize(transformedNormal); 41 | vTangent = normalize(transformedTangent); 42 | vBitangent = normalize(cross(vNormal, vTangent) * tangent.w); 43 | 44 | // Fog 45 | fogDepth = -mvPosition.z; 46 | 47 | gl_Position = projectionMatrix * mvPosition; 48 | } 49 | -------------------------------------------------------------------------------- /webgl/glsl/_MeshPhong.fs: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform bool isOrthographic; 4 | 5 | // https://github.com/mrdoob/three.js/blob/master/src/renderers/shaders/ShaderLib/meshphong_frag.glsl.js 6 | #define PHONG 7 | 8 | uniform vec3 diffuse; 9 | uniform vec3 emissive; 10 | uniform vec3 specular; 11 | uniform float shininess; 12 | uniform float opacity; 13 | 14 | // #include 15 | #define PI 3.141592653589793 16 | #define RECIPROCAL_PI 0.3183098861837907 17 | 18 | #ifndef saturate 19 | #define saturate(a) clamp(a, 0.0, 1.0) 20 | #endif 21 | 22 | struct GeometricContext { 23 | vec3 position; 24 | vec3 normal; 25 | vec3 viewDir; 26 | #ifdef CLEARCOAT 27 | vec3 clearcoatNormal; 28 | #endif 29 | }; 30 | 31 | struct IncidentLight { 32 | vec3 color; 33 | vec3 direction; 34 | bool visible; 35 | }; 36 | 37 | // #include 38 | vec3 F_Schlick(const in vec3 specularColor, const in float dotLH) { 39 | float fresnel = exp2((-5.55473 * dotLH - 6.98316) * dotLH); 40 | return (1.0 - specularColor) * fresnel + specularColor; 41 | } 42 | 43 | vec3 BRDF_Diffuse_Lambert(const in vec3 diffuseColor) { 44 | return RECIPROCAL_PI * diffuseColor; 45 | } 46 | 47 | float G_BlinnPhong_Implicit() { 48 | return 0.25; 49 | } 50 | 51 | float D_BlinnPhong(const in float shininess, const in float dotNH) { 52 | return RECIPROCAL_PI * (shininess * 0.5 + 1.0) * pow(dotNH, shininess); 53 | } 54 | 55 | vec3 BRDF_Specular_BlinnPhong( 56 | const in IncidentLight incidentLight, 57 | const in GeometricContext geometry, 58 | const in vec3 specularColor, 59 | const in float shininess 60 | ) { 61 | vec3 halfDir = normalize(incidentLight.direction + geometry.viewDir); 62 | float dotNH = saturate(dot(geometry.normal, halfDir)); 63 | float dotLH = saturate(dot(incidentLight.direction, halfDir)); 64 | vec3 F = F_Schlick(specularColor, dotLH); 65 | float G = G_BlinnPhong_Implicit(); 66 | float D = D_BlinnPhong(shininess, dotNH); 67 | return F * (G * D); 68 | } 69 | 70 | // #include 71 | uniform vec3 ambientLightColor; 72 | 73 | struct ReflectedLight { 74 | vec3 directDiffuse; 75 | vec3 directSpecular; 76 | vec3 indirectDiffuse; 77 | vec3 indirectSpecular; 78 | }; 79 | 80 | vec3 getAmbientLightIrradiance(const in vec3 ambientLightColor) { 81 | vec3 irradiance = ambientLightColor; 82 | return irradiance *= PI; 83 | } 84 | 85 | #if NUM_DIR_LIGHTS > 0 86 | struct DirectionalLight { 87 | vec3 direction; 88 | vec3 color; 89 | }; 90 | 91 | uniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ]; 92 | 93 | void getDirectionalDirectLightIrradiance( 94 | const in DirectionalLight directionalLight, 95 | const in GeometricContext geometry, 96 | out IncidentLight directLight 97 | ) { 98 | directLight.color = directionalLight.color; 99 | directLight.direction = directionalLight.direction; 100 | directLight.visible = true; 101 | } 102 | #endif 103 | 104 | // #include 105 | varying vec3 vViewPosition; 106 | 107 | #ifndef FLAT_SHADED 108 | varying vec3 vNormal; 109 | #endif 110 | 111 | struct BlinnPhongMaterial { 112 | vec3 diffuseColor; 113 | vec3 specularColor; 114 | float specularShininess; 115 | float specularStrength; 116 | }; 117 | 118 | void RE_Direct_BlinnPhong( 119 | const in IncidentLight directLight, 120 | const in GeometricContext geometry, 121 | const in BlinnPhongMaterial material, 122 | inout ReflectedLight reflectedLight 123 | ) { 124 | float dotNL = saturate(dot(geometry.normal, directLight.direction)); 125 | vec3 irradiance = dotNL * directLight.color; 126 | 127 | #ifndef PHYSICALLY_CORRECT_LIGHTS 128 | irradiance *= PI; 129 | #endif 130 | reflectedLight.directDiffuse += 131 | irradiance * 132 | BRDF_Diffuse_Lambert(material.diffuseColor); 133 | reflectedLight.directSpecular += 134 | irradiance * 135 | BRDF_Specular_BlinnPhong( 136 | directLight, 137 | geometry, 138 | material.specularColor, 139 | material.specularShininess 140 | ) * 141 | material.specularStrength; 142 | } 143 | 144 | void RE_IndirectDiffuse_BlinnPhong( 145 | const in vec3 irradiance, 146 | const in GeometricContext geometry, 147 | const in BlinnPhongMaterial material, 148 | inout ReflectedLight reflectedLight 149 | ) { 150 | reflectedLight.indirectDiffuse += 151 | irradiance * BRDF_Diffuse_Lambert(material.diffuseColor); 152 | } 153 | 154 | #define RE_Direct RE_Direct_BlinnPhong 155 | #define RE_IndirectDiffuse RE_IndirectDiffuse_BlinnPhong 156 | 157 | void main() { 158 | // meshphong_vert.glsl.js 159 | vec4 diffuseColor = vec4(diffuse, opacity); 160 | ReflectedLight reflectedLight = ReflectedLight(vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0)); 161 | vec3 totalEmissiveRadiance = emissive; 162 | 163 | // #include 164 | float specularStrength; 165 | 166 | #ifdef USE_SPECULARMAP 167 | vec4 texelSpecular = texture2D(specularMap, vUv ; 168 | specularStrength = texelSpecular.r; 169 | #else 170 | specularStrength = 1.0; 171 | #endif 172 | 173 | // #include 174 | float faceDirection = gl_FrontFacing ? 1.0 : - 1.0; 175 | 176 | #ifdef FLAT_SHADED 177 | // Workaround for Adreno GPUs not able to do dFdx(vViewPosition) 178 | vec3 fdx = vec3(dFdx(vViewPosition.x), dFdx(vViewPosition.y), dFdx(vViewPosition.z)); 179 | vec3 fdy = vec3(dFdy(vViewPosition.x), dFdy(vViewPosition.y), dFdy(vViewPosition.z)); 180 | vec3 normal = normalize(cross(fdx, fdy)); 181 | #else 182 | vec3 normal = normalize(vNormal); 183 | #ifdef DOUBLE_SIDED 184 | normal = normal * faceDirection; 185 | #endif 186 | #ifdef USE_TANGENT 187 | vec3 tangent = normalize(vTangent); 188 | vec3 bitangent = normalize(vBitangent); 189 | #ifdef DOUBLE_SIDED 190 | tangent = tangent * faceDirection; 191 | bitangent = bitangent * faceDirection; 192 | #endif 193 | #endif 194 | #endif 195 | 196 | // non perturbed normal for clearcoat among others 197 | vec3 geometryNormal = normal; 198 | 199 | // accumulation 200 | // #include 201 | BlinnPhongMaterial material; 202 | material.diffuseColor = diffuseColor.rgb; 203 | material.specularColor = specular; 204 | material.specularShininess = shininess; 205 | material.specularStrength = specularStrength; 206 | 207 | // #include 208 | GeometricContext geometry; 209 | geometry.position = - vViewPosition; 210 | geometry.normal = normal; 211 | geometry.viewDir = (isOrthographic) 212 | ? vec3(0, 0, 1) 213 | : normalize(vViewPosition); 214 | 215 | IncidentLight directLight; 216 | 217 | #if (NUM_DIR_LIGHTS > 0) && defined(RE_Direct) 218 | DirectionalLight directionalLight; 219 | #if defined(USE_SHADOWMAP) && NUM_DIR_LIGHT_SHADOWS > 0 220 | DirectionalLightShadow directionalLightShadow; 221 | #endif 222 | #pragma unroll_loop_start 223 | 224 | for (int i = 0; i < NUM_DIR_LIGHTS; i ++) { 225 | directionalLight = directionalLights[ i ]; 226 | getDirectionalDirectLightIrradiance(directionalLight, geometry, directLight); 227 | RE_Direct(directLight, geometry, material, reflectedLight); 228 | } 229 | #pragma unroll_loop_end 230 | 231 | #if defined(RE_IndirectSpecular) 232 | vec3 radiance = vec3(0.0); 233 | vec3 clearcoatRadiance = vec3(0.0); 234 | #endif 235 | #endif 236 | 237 | #if defined(RE_IndirectDiffuse) 238 | vec3 iblIrradiance = vec3(0.0); 239 | vec3 irradiance = getAmbientLightIrradiance(ambientLightColor); 240 | 241 | #if (NUM_HEMI_LIGHTS > 0) 242 | #pragma unroll_loop_start 243 | for (int i = 0; i < NUM_HEMI_LIGHTS; i ++) { 244 | irradiance += getHemisphereLightIrradiance(hemisphereLights[i], geometry); 245 | } 246 | #pragma unroll_loop_end 247 | #endif 248 | #endif 249 | 250 | // #include 251 | #if defined(RE_IndirectDiffuse) 252 | RE_IndirectDiffuse(irradiance, geometry, material, reflectedLight); 253 | #endif 254 | 255 | #if defined(RE_IndirectSpecular) 256 | RE_IndirectSpecular(radiance, iblIrradiance, clearcoatRadiance, geometry, material, reflectedLight); 257 | #endif 258 | 259 | // meshphong_vert.glsl.js 260 | vec3 outgoingLight = 261 | reflectedLight.directDiffuse + 262 | reflectedLight.indirectDiffuse + 263 | reflectedLight.directSpecular + 264 | reflectedLight.indirectSpecular + 265 | totalEmissiveRadiance; 266 | 267 | gl_FragColor = vec4(outgoingLight, 1.0); 268 | // gl_FragColor = vec4(outgoingLight, diffuseColor.a); 269 | } 270 | -------------------------------------------------------------------------------- /webgl/glsl/_MeshPhong.vs: -------------------------------------------------------------------------------- 1 | attribute vec3 position; 2 | attribute vec3 normal; 3 | attribute vec2 uv; 4 | 5 | uniform mat4 modelMatrix; 6 | uniform mat4 modelViewMatrix; 7 | uniform mat4 viewMatrix; 8 | uniform mat4 projectionMatrix; 9 | uniform mat3 normalMatrix; 10 | uniform vec3 cameraPosition; 11 | uniform bool isOrthographic; 12 | 13 | // https://github.com/mrdoob/three.js/blob/master/src/renderers/shaders/ShaderLib/meshphong_vert.glsl.js 14 | 15 | #define PHONG 16 | 17 | varying vec3 vViewPosition; 18 | 19 | #ifndef FLAT_SHADED 20 | varying vec3 vNormal; 21 | #endif 22 | 23 | void main(void) { 24 | // #include 25 | vec3 objectNormal = vec3(normal); 26 | 27 | // #include 28 | vec3 transformedNormal = objectNormal; 29 | transformedNormal = normalMatrix * transformedNormal; 30 | 31 | // meshphong_vert.glsl.js 32 | vNormal = normalize(transformedNormal); 33 | 34 | // #include 35 | vec3 transformed = vec3(position); 36 | 37 | // #include 38 | vec4 mvPosition = vec4(transformed, 1.0); 39 | mvPosition = modelViewMatrix * mvPosition; 40 | gl_Position = projectionMatrix * mvPosition; 41 | 42 | // meshphong_vert.glsl.js 43 | vViewPosition = - mvPosition.xyz; 44 | } 45 | -------------------------------------------------------------------------------- /webgl/index.js: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three' 2 | import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' 3 | 4 | import Camera from './Camera' 5 | import MeshLambert from './MeshLambert' 6 | import MeshPhong from './MeshPhong' 7 | import Water from './Water' 8 | import AmbientLight from './AmbientLight' 9 | import DirectionalLight from './DirectionalLight' 10 | import PointLight from './PointLight' 11 | import InstanceMeshPhong from './InstanceMeshPhong' 12 | import Ground from './Ground' 13 | import Background from './Background' 14 | 15 | const canvas = document.createElement('canvas') 16 | canvas.setAttribute('id', 'canvas-webgl') 17 | 18 | export default class WebGLContent { 19 | constructor() { 20 | // basics three.js instances 21 | this.renderer = new THREE.WebGL1Renderer({ 22 | canvas, 23 | alpha: true, 24 | antialias: true, 25 | }) 26 | this.resolution = new THREE.Vector2() 27 | this.clock = new THREE.Clock(false) 28 | this.scene = new THREE.Scene() 29 | this.camera = new Camera() 30 | this.texLoader = new THREE.TextureLoader() 31 | this.controls = new OrbitControls(this.camera, canvas) 32 | 33 | // meshes and lights 34 | this.meshLambert = new MeshLambert() 35 | this.meshPhong = new MeshPhong() 36 | this.water = new Water() 37 | this.ambLight = new AmbientLight() 38 | this.dirLight1 = new DirectionalLight(0xff0000, 0.1) 39 | this.dirLight1.position.set(-20, 20, 20) 40 | this.dirLight2 = new DirectionalLight(0x0000ff, 0.1) 41 | this.dirLight2.position.set(20, 20, 20) 42 | this.pointLight1 = new PointLight(0xff3333, 0.4, 160) 43 | this.pointLight1.position.set(-50, 20, 0) 44 | this.pointLight2 = new PointLight(0x3333ff, 0.4, 160) 45 | this.pointLight2.position.set(50, 20, 0) 46 | this.instanceMeshPhong = new InstanceMeshPhong() 47 | this.ground = new Ground() 48 | this.background = new Background() 49 | this.dirLightHelper1 = new THREE.DirectionalLightHelper(this.dirLight1, 5) 50 | this.dirLightHelper2 = new THREE.DirectionalLightHelper(this.dirLight2, 5) 51 | this.pointLightHelper1 = new THREE.PointLightHelper(this.pointLight1, 5) 52 | this.pointLightHelper2 = new THREE.PointLightHelper(this.pointLight2, 5) 53 | 54 | // render targets 55 | this.target1 = new THREE.WebGLRenderTarget() 56 | this.target2 = new THREE.WebGLRenderTarget() 57 | this.target1.depthBuffer = this.target2.depthBuffer = true 58 | this.target1.depthTexture = new THREE.DepthTexture() 59 | this.target2.depthTexture = new THREE.DepthTexture() 60 | this.target1.depthTexture.format = this.target2.depthTexture.format = 61 | THREE.DepthFormat 62 | this.target1.depthTexture.type = this.target2.depthTexture.type = 63 | THREE.UnsignedIntType 64 | 65 | // Other than three.js 66 | this.isPlaying = true 67 | 68 | // initialize 69 | this.renderer.setClearColor(0x000000, 1.0) 70 | this.renderer.shadowMap.enabled = true 71 | this.renderer.shadowMap.type = THREE.PCFSoftShadowMap 72 | this.scene.fog = new THREE.Fog(0x000000, 100, 500) 73 | this.controls.dampingFactor = 0.1 74 | this.controls.enableDamping = true 75 | this.controls.target.set(0, 0, 0) 76 | this.controls.saveState() 77 | 78 | document.body.appendChild(canvas) 79 | } 80 | 81 | async start() { 82 | const imgs = [ 83 | require('@/assets/img/Alunar_Cliff_basecolor.png'), 84 | require('@/assets/img/Alunar_Ground_basecolor.jpg'), 85 | require('@/assets/img/Alunar_Cliff_normal.jpg'), 86 | require('@/assets/img/Alunar_Ground_normal.jpg'), 87 | require('@/assets/img/Ocean-4-Normal.jpg'), 88 | require('@/assets/img/004_nebula_red.jpg'), 89 | ] 90 | let map1 91 | let map2 92 | let normalMap1 93 | let normalMap2 94 | let normalMap3 95 | let bgMap 96 | 97 | await Promise.all([ 98 | ...imgs.map((o) => { 99 | return this.texLoader.loadAsync(o) 100 | }), 101 | ]).then((response) => { 102 | map1 = response[0] 103 | map1.wrapT = map1.wrapS = THREE.RepeatWrapping 104 | map2 = response[1] 105 | map2.wrapT = map2.wrapS = THREE.RepeatWrapping 106 | normalMap1 = response[2] 107 | normalMap1.wrapT = normalMap1.wrapS = THREE.RepeatWrapping 108 | normalMap2 = response[3] 109 | normalMap2.wrapT = normalMap2.wrapS = THREE.RepeatWrapping 110 | normalMap3 = response[4] 111 | normalMap3.wrapT = normalMap3.wrapS = THREE.RepeatWrapping 112 | bgMap = response[5] 113 | bgMap.wrapT = bgMap.wrapS = THREE.RepeatWrapping 114 | }) 115 | this.meshLambert.start(normalMap1) 116 | this.meshPhong.start(map1, normalMap1) 117 | this.water.start( 118 | normalMap3, 119 | this.target1.depthTexture, 120 | this.target2.depthTexture 121 | ) 122 | this.instanceMeshPhong.start(map1, normalMap1) 123 | this.ground.start(map2, normalMap2) 124 | this.background.start(bgMap) 125 | 126 | this.scene.add(this.meshLambert) 127 | this.scene.add(this.meshPhong) 128 | this.scene.add(this.water) 129 | this.scene.add(this.ambLight) 130 | this.scene.add(this.dirLight1) 131 | this.scene.add(this.dirLight2) 132 | this.scene.add(this.pointLight1) 133 | this.scene.add(this.pointLight2) 134 | this.scene.add(this.instanceMeshPhong) 135 | this.scene.add(this.ground) 136 | this.scene.add(this.background) 137 | this.scene.add(this.dirLightHelper1) 138 | this.scene.add(this.dirLightHelper2) 139 | this.scene.add(this.pointLightHelper1) 140 | this.scene.add(this.pointLightHelper2) 141 | 142 | this.meshLambert.visible = false 143 | this.meshPhong.visible = true 144 | this.water.visible = true 145 | this.dirLightHelper1.visible = false 146 | this.dirLightHelper2.visible = false 147 | this.pointLightHelper1.visible = false 148 | this.pointLightHelper2.visible = false 149 | 150 | this.clock.start() 151 | } 152 | 153 | update() { 154 | const time = this.clock.running === true ? this.clock.getDelta() : 0 155 | 156 | if (this.isPlaying) { 157 | this.meshLambert.update() 158 | this.meshPhong.update() 159 | this.water.update(time, this.renderer, this.scene, this.camera) 160 | } 161 | this.water.visible = false 162 | this.renderer.setRenderTarget(this.target1) 163 | this.renderer.render(this.scene, this.camera) 164 | this.meshPhong.visible = false 165 | this.instanceMeshPhong.visible = false 166 | this.water.visible = true 167 | this.water.material.uniforms.tDepth2.value = null 168 | this.renderer.setRenderTarget(this.target2) 169 | this.renderer.render(this.scene, this.camera) 170 | this.meshPhong.visible = true 171 | this.instanceMeshPhong.visible = true 172 | this.water.material.uniforms.tDepth2.value = this.target2.depthTexture 173 | this.renderer.setRenderTarget(null) 174 | this.renderer.render(this.scene, this.camera) 175 | this.controls.update() 176 | } 177 | 178 | resize() { 179 | this.resolution.set(window.innerWidth, window.innerHeight) 180 | this.camera.resize(this.resolution) 181 | this.water.resize(this.resolution) 182 | this.target1.setSize(this.resolution.x, this.resolution.y) 183 | this.target2.setSize(this.resolution.x, this.resolution.y) 184 | this.renderer.setSize(this.resolution.x, this.resolution.y) 185 | } 186 | 187 | playPause(bool) { 188 | this.isPlaying = bool 189 | } 190 | 191 | resetControls() { 192 | this.controls.reset() 193 | } 194 | 195 | toggleHelper() { 196 | this.dirLightHelper1.visible = !this.dirLightHelper1.visible 197 | this.dirLightHelper2.visible = !this.dirLightHelper2.visible 198 | this.pointLightHelper1.visible = !this.pointLightHelper1.visible 199 | this.pointLightHelper2.visible = !this.pointLightHelper2.visible 200 | } 201 | } 202 | --------------------------------------------------------------------------------