├── .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 |
2 | .button(
3 | :is = 'tag'
4 | :to = 'to'
5 | :style = 'styles'
6 | :class = 'classnames'
7 | @click = '$emit("click", $event)'
8 | )
9 | slot
10 |
11 |
12 |
63 |
64 |
114 |
--------------------------------------------------------------------------------
/components/_common/Menu.vue:
--------------------------------------------------------------------------------
1 |
2 | .menu
3 | .menu__activator
4 | slot(
5 | name = 'activator'
6 | :on = 'toggle'
7 | :isShown = 'isShown'
8 | )
9 | transition
10 | .menu__card(
11 | v-show = 'isShown'
12 | )
13 | slot
14 |
15 |
16 |
31 |
32 |
75 |
--------------------------------------------------------------------------------
/components/_template/Controls.vue:
--------------------------------------------------------------------------------
1 |
2 | .controls
3 | .buttons
4 | Button(
5 | width = '36px'
6 | height = '36px'
7 | radius = '50%'
8 | @click = '$store.commit("playPause")'
9 | )
10 | IconPause(
11 | v-if = 'isPlaying'
12 | )
13 | IconPlay(
14 | v-else
15 | )
16 | Button(
17 | width = '36px'
18 | height = '36px'
19 | radius = '50%'
20 | @click = 'resetControls'
21 | )
22 | IconRestore
23 | Button(
24 | width = '36px'
25 | height = '36px'
26 | radius = '50%'
27 | :active = 'isShownHelper'
28 | @click = 'toggleHelper'
29 | )
30 | IconHelpRhombusOutline
31 | .buttons
32 | Menu
33 | template(
34 | v-slot:activator = '{ on, isShown }'
35 | )
36 | Button(
37 | width = '36px'
38 | height = '36px'
39 | radius = '50%'
40 | :active = 'isShown'
41 | @click = 'on'
42 | )
43 | IconHelp
44 | MenuHelp
45 |
46 |
47 |
68 |
69 |
117 |
--------------------------------------------------------------------------------
/components/_template/Header.vue:
--------------------------------------------------------------------------------
1 |
2 | .header
3 | h1
4 | |study-threejs-lighting
5 | p
6 | |It's a study record of 3D graphic lighting
7 | br
8 | |with the shaders that I created by quoting from three.js.
9 | .buttons
10 | Button(
11 | role = 'transparent'
12 | tag = 'a'
13 | href = 'https://github.com/ykob/study-threejs-lighting'
14 | width = '32px'
15 | height = '32px'
16 | radius = '50%'
17 | target = '_blank'
18 | )
19 | IconGithub
20 | Button(
21 | role = 'transparent'
22 | tag = 'a'
23 | href = 'https://twitter.com/ykob0123'
24 | width = '32px'
25 | height = '32px'
26 | radius = '50%'
27 | target = '_blank'
28 | )
29 | IconTwitter
30 |
31 |
32 |
35 |
36 |
70 |
--------------------------------------------------------------------------------
/components/icon/Base.vue:
--------------------------------------------------------------------------------
1 |
2 | svg(
3 | xmlns="http://www.w3.org/2000/svg"
4 | :width = 'size'
5 | :height = 'size'
6 | viewBox = '0 0 24 24'
7 | :aria-labelledby = 'iconName'
8 | role = 'presentation'
9 | )
10 | title(
11 | :id = 'iconName'
12 | lang = 'en'
13 | )
14 | |{{ iconName }} icon
15 | g(
16 | :fill = 'fill'
17 | )
18 | slot
19 |
20 |
21 |
39 |
--------------------------------------------------------------------------------
/components/icon/Cube.vue:
--------------------------------------------------------------------------------
1 |
2 | IconBase(
3 | iconName = 'cube'
4 | :size = 'size'
5 | :fill = 'fill'
6 | )
7 | path(
8 | :d = 'd'
9 | )
10 |
11 |
12 |
33 |
--------------------------------------------------------------------------------
/components/icon/CubeOutline.vue:
--------------------------------------------------------------------------------
1 |
2 | IconBase(
3 | iconName = 'cube-outline'
4 | :size = 'size'
5 | :fill = 'fill'
6 | )
7 | path(
8 | :d = 'd'
9 | )
10 |
11 |
12 |
33 |
--------------------------------------------------------------------------------
/components/icon/Github.vue:
--------------------------------------------------------------------------------
1 |
2 | IconBase(
3 | iconName = 'github'
4 | :size = 'size'
5 | :fill = 'fill'
6 | )
7 | path(
8 | :d = 'd'
9 | )
10 |
11 |
12 |
33 |
--------------------------------------------------------------------------------
/components/icon/Help.vue:
--------------------------------------------------------------------------------
1 |
2 | IconBase(
3 | iconName = 'help'
4 | :size = 'size'
5 | :fill = 'fill'
6 | )
7 | path(
8 | :d = 'd'
9 | )
10 |
11 |
12 |
33 |
--------------------------------------------------------------------------------
/components/icon/HelpRhombusOutline .vue:
--------------------------------------------------------------------------------
1 |
2 | IconBase(
3 | iconName = 'help-rhombus-outline'
4 | :size = 'size'
5 | :fill = 'fill'
6 | )
7 | path(
8 | :d = 'd'
9 | )
10 |
11 |
12 |
33 |
--------------------------------------------------------------------------------
/components/icon/OpenInNew.vue:
--------------------------------------------------------------------------------
1 |
2 | IconBase(
3 | iconName = 'open-in-new'
4 | :size = 'size'
5 | :fill = 'fill'
6 | )
7 | path(
8 | :d = 'd'
9 | )
10 |
11 |
12 |
33 |
--------------------------------------------------------------------------------
/components/icon/Pause.vue:
--------------------------------------------------------------------------------
1 |
2 | IconBase(
3 | iconName = 'pause'
4 | :size = 'size'
5 | :fill = 'fill'
6 | )
7 | path(
8 | :d = 'd'
9 | )
10 |
11 |
12 |
33 |
--------------------------------------------------------------------------------
/components/icon/Play.vue:
--------------------------------------------------------------------------------
1 |
2 | IconBase(
3 | iconName = 'play'
4 | :size = 'size'
5 | :fill = 'fill'
6 | )
7 | path(
8 | :d = 'd'
9 | )
10 |
11 |
12 |
33 |
--------------------------------------------------------------------------------
/components/icon/Restore.vue:
--------------------------------------------------------------------------------
1 |
2 | IconBase(
3 | iconName = 'restore'
4 | :size = 'size'
5 | :fill = 'fill'
6 | )
7 | path(
8 | :d = 'd'
9 | )
10 |
11 |
12 |
33 |
--------------------------------------------------------------------------------
/components/icon/Twitter.vue:
--------------------------------------------------------------------------------
1 |
2 | IconBase(
3 | iconName = 'twitter'
4 | :size = 'size'
5 | :fill = 'fill'
6 | )
7 | path(
8 | :d = 'd'
9 | )
10 |
11 |
12 |
33 |
--------------------------------------------------------------------------------
/components/menu/Help.vue:
--------------------------------------------------------------------------------
1 |
2 | .menu-help
3 | .menu-help__heading
4 | |Assets
5 | ul
6 | li
7 | a(
8 | href = 'https://www.cgtrader.com/3d-model-collections/ocean-8k'
9 | target = '_blank'
10 | )
11 | |Water Surface Normal Map
12 | IconOpenInNew(
13 | :size = '16'
14 | )
15 | li
16 | a(
17 | href = 'https://www.cgtrader.com/3d-models/textures/natural/s-ea3e180f-bfed-4c62-aaa1-4045e48d8d59'
18 | target = '_blank'
19 | )
20 | |Object Normal Maps
21 | IconOpenInNew(
22 | :size = '16'
23 | )
24 | li
25 | a(
26 | href = 'https://www.cgtrader.com/3d-models/textures/miscellaneous/nebula-spherical-maps-and-skyboxes-8192x4096-px'
27 | target = '_blank'
28 | )
29 | |Nebula Spherical Map
30 | IconOpenInNew(
31 | :size = '16'
32 | )
33 |
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 |
2 | div
3 | Header
4 | .page
5 | nuxt
6 | Controls
7 |
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 |
2 | div
3 |
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 |
--------------------------------------------------------------------------------