Browse Source

sky and water domes using shaders

Bachir Soussi Chiadmi 3 years ago
parent
commit
654fd08863

+ 6 - 0
assets/glsl/BgVertex.glsl

@@ -0,0 +1,6 @@
+varying vec3 vWorldPosition;
+void main() {
+  vec4 worldPosition = modelMatrix * vec4( position, 1.0 );
+  vWorldPosition = worldPosition.xyz;
+  gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
+}

+ 22 - 0
assets/glsl/SkyFragment.glsl

@@ -0,0 +1,22 @@
+// https://gamedevelopment.tutsplus.com/tutorials/a-beginners-guide-to-coding-graphics-shaders--cms-23313
+uniform vec3 topColor;
+uniform vec3 horizontColor;
+uniform float offset;
+uniform float exponent;
+varying vec3 vWorldPosition;
+void main() {
+  float h = normalize( vWorldPosition + offset ).y;
+  gl_FragColor = vec4(
+    mix(
+      horizontColor,
+      topColor,
+      max(
+        pow(
+          max( h , 0.0),
+          exponent
+        ),
+        0.0
+      )
+    ), 1.0
+  );
+}

+ 26 - 0
assets/glsl/WaterFragment.glsl

@@ -0,0 +1,26 @@
+// https://gamedevelopment.tutsplus.com/tutorials/a-beginners-guide-to-coding-graphics-shaders--cms-23313
+uniform vec3 waterColor;
+uniform vec3 bottomColor;
+uniform float wateroffset;
+uniform float waterexponent;
+varying vec3 vWorldPosition;
+
+void main() {
+  float h = normalize( vWorldPosition * -1.0 + wateroffset ).y;
+  gl_FragColor = vec4(
+    // mix(x, y, a) performs a linear interpolation between x and y using a to weight between them.
+    // The return value is computed as x×(1−a)+y×a.
+    mix(
+      waterColor,
+      bottomColor,
+      max(
+        pow(
+          max( h , 0.0),
+          waterexponent
+        ),
+        0.0
+      )
+    ),
+    1.0
+  );
+}

+ 6 - 1
build/webpack.config.base.js

@@ -4,12 +4,13 @@ const HtmlWebpackPlugin = require('html-webpack-plugin')
 const CopyWebpackPlugin = require('copy-webpack-plugin')
 const HtmlWebpackHarddiskPlugin = require('html-webpack-harddisk-plugin');
 const { VueLoaderPlugin } = require('vue-loader')
+// const { GlslLoaderPlugin } = require('webpack-glsl-loader')
 
 const utils = require('./utils')
 
 module.exports = {
   resolve: {
-    extensions: ['.js', '.vue', '.json'],
+    extensions: ['.js', '.vue', '.json', '.glsl'],
     alias: {
       'assets': utils.resolve('assets'),
       'pages': utils.resolve('src/pages'),
@@ -28,6 +29,9 @@ module.exports = {
       }, {
         test: /\.vue$/,
         use: 'vue-loader'
+      }, {
+        test: /\.glsl$/,
+        loader: 'webpack-glsl-loader'
       }, {
         test: /\.js$/,
         use: {
@@ -73,6 +77,7 @@ module.exports = {
     }),
     new HtmlWebpackHarddiskPlugin(),
     new VueLoaderPlugin(),
+    // new GlslLoaderPlugin(),
     new CopyWebpackPlugin([{
       from: utils.resolve('static/img'),
       to: utils.resolve('dist/static/img'),

+ 22 - 0
package-lock.json

@@ -7618,6 +7618,12 @@
         "readable-stream": "^2.0.0"
       }
     },
+    "fs": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.2.tgz",
+      "integrity": "sha1-4fJE7zkzwbKmS9R5kTYGDQ9ZFPg=",
+      "dev": true
+    },
     "fs-write-stream-atomic": {
       "version": "1.0.10",
       "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz",
@@ -11552,6 +11558,12 @@
       "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
       "dev": true
     },
+    "path": {
+      "version": "0.11.14",
+      "resolved": "https://registry.npmjs.org/path/-/path-0.11.14.tgz",
+      "integrity": "sha1-y8dWk1XLPIOv60rOQ+z/lSMeWn0=",
+      "dev": true
+    },
     "path-browserify": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz",
@@ -15161,6 +15173,16 @@
         }
       }
     },
+    "webpack-glsl-loader": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/webpack-glsl-loader/-/webpack-glsl-loader-1.0.1.tgz",
+      "integrity": "sha1-cqDjAZK9V5R9YNbVBckVvmgNCsw=",
+      "dev": true,
+      "requires": {
+        "fs": "0.0.2",
+        "path": "^0.11.14"
+      }
+    },
     "webpack-log": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz",

+ 1 - 0
package.json

@@ -70,6 +70,7 @@
     "webpack": "^4.43.0",
     "webpack-cli": "^3.3.12",
     "webpack-dev-server": "^3.11.0",
+    "webpack-glsl-loader": "^1.0.1",
     "webpack-merge": "^4.2.2"
   }
 }

+ 65 - 37
src/App.vue

@@ -14,6 +14,8 @@
         <renderer :obj="myRenderer" :size="size">
           <scene :obj="myScene" @update:obj="handleScene">
 
+            <!-- <SkyBox :size="{x:500,y:500,z:500}" :position="{x:0,y:0,z:0}" :color="0x992222" /> -->
+
             <!-- <orbit-controls ref="cam_controls" :position="init_cam_pos" :rotation="{ x: 0, y: 0, z: 0 }">
               <camera />
             </orbit-controls> -->
@@ -30,7 +32,7 @@
               <cube :size="{x:1,y:1,z:30}" :position="{x:0,y:0,z:15}" :color="0x17d100" />
             </template>
 
-            <plan :size="{w:5000,h:5000}" :position="{x:0,y:0,z:0}" :color="0x1a1a1a" :rotation="{x:90,y:0,z:0}" />
+            <ground :size="{w:5000,h:5000}" :position="{x:0,y:0,z:0}" :color="0x000011" :rotation="{x:90,y:0,z:0}" />
 
             <template v-if="projects.length">
               <project
@@ -56,12 +58,16 @@ import mixins from 'components/mixins'
 import * as THREE from 'three'
 import TWEEN from '@tweenjs/tween.js'
 
-import Plan from './components/objects/Plan'
+import BgVertex from 'assets/glsl/BgVertex'
+import SkyFragment from 'assets/glsl/SkyFragment'
+import WaterFragment from 'assets/glsl/WaterFragment'
+
+import Ground from './components/objects/Ground'
 import Cube from './components/objects/Cube'
 import Project from './components/objects/Project'
 
 // const TWEEN = require('@tweenjs/tween.js')
-const _debug = true
+const _debug = false
 
 export default {
   metaInfo: {
@@ -73,7 +79,7 @@ export default {
   components: {
     Cube,
     Project,
-    Plan
+    Ground
   },
   mixins: [mixins],
   data () {
@@ -85,11 +91,41 @@ export default {
     // scene obj is well overwrited but background color not visible
     let scene = new THREE.Scene()
     scene.background = new THREE.Color(0x1a1a1a)
-    scene.fog = new THREE.Fog(scene.background, 50, 400)
+    // scene.fog = new THREE.Fog(new THREE.Color(0xffffff), 50, 200)
     // console.log('myScene', scene)
 
-    // let cameraHelper = new THREE.CameraHelper()
-    // scene.add(cameraHelper)
+    // SKYDOME
+    // https://github.com/mrdoob/three.js/blob/master/examples/webgl_lights_hemisphere.html
+    // https://gamedevelopment.tutsplus.com/tutorials/a-beginners-guide-to-coding-graphics-shaders--cms-23313
+    var uniforms = {
+      'topColor': { value: new THREE.Color(0x0077ff) },
+      'horizontColor': { value: new THREE.Color(0xffffff) },
+      'waterColor': { value: new THREE.Color(0x0000aa) },
+      'bottomColor': { value: new THREE.Color(0x000000) },
+      'offset': { value: 33 },
+      'wateroffset': { value: 33 },
+      'exponent': { value: 0.6 },
+      'waterexponent': { value: 0.6 }
+    }
+    // SphereBufferGeometry(radius : Float, widthSegments : Integer, heightSegments : Integer, phiStart : Float, phiLength : Float, thetaStart : Float, thetaLength : Float)
+    var bgGeo = new THREE.SphereBufferGeometry(900, 32, 15, 0, 2 * Math.PI, 0, 0.5 * Math.PI)
+    var skyMat = new THREE.ShaderMaterial({
+      uniforms: uniforms,
+      vertexShader: BgVertex,
+      fragmentShader: SkyFragment,
+      side: THREE.BackSide
+    })
+    var sky = new THREE.Mesh(bgGeo, skyMat)
+    scene.add(sky)
+    var waterMat = new THREE.ShaderMaterial({
+      uniforms: uniforms,
+      vertexShader: BgVertex,
+      fragmentShader: WaterFragment,
+      side: THREE.BackSide
+    })
+    var ground = new THREE.Mesh(bgGeo, waterMat)
+    ground.rotateZ(this.deg2rad(180))
+    scene.add(ground)
 
     return {
       debug: _debug,
@@ -112,7 +148,7 @@ export default {
         cam_target: new THREE.Vector3(0, 0, 0)
       },
       // cam_controls: null,
-      init_cam_pos: { x: 0, y: 10, z: 150 },
+      init_cam_pos: { x: 0, y: 10, z: 100 },
       raycaster: new THREE.Raycaster(),
       interactive_objects: [],
       light_opts: {
@@ -195,47 +231,39 @@ export default {
       // CONTROLS
       this.controls.user_interact = false
 
-      // INTERACT
+      // INTERACTIONS
       // TODO: check if draging
       // update the picking ray with the camera and mouse position
       this.raycaster.setFromCamera(this.mouse, this.camera)
       // calculate objects intersecting the picking ray
       var intersects = this.raycaster.intersectObjects(this.interactive_objects)
-
       // console.log('intersects', intersects)
-      // console.log('camera', this.camera)
-      // console.log('TWEEN', TWEEN)
-      let object, vnode, topos
-      let cam = this.camera
-      // let camControls = this.cam_controls
-      let camPos = { ...this.camera.position }
-      // console.log('camPos', camPos)
+
+      let object, vnode//, toPos
+      // let cam = this.camera
+      // let camPos = { ...this.camera.position }
       if (intersects.length) {
         for (var i = 0; i < intersects.length; i++) {
-          // intersects[i].object.material.color.set(0xff0000)
           object = intersects[i].object
           vnode = object.userData.vnode
           vnode.isOpened = true
-          // this.cam_controls.target = object.position
-
-          new TWEEN.Tween(this.controls.cam_target)
-            .to(object.position, 400)
-            .start()
 
-          // cam.position.set({ x: camPos.x, y: camPos.y, z: camPos.z })
-          // camControls.update()
-          topos = { ...object.position }
-          topos.z += 20
-          topos.y = 5
-          new TWEEN.Tween(camPos)
-            .easing(TWEEN.Easing.Quadratic.InOut)
-            .to(topos, 3000)
-            .onUpdate(function () {
-              // console.log('tween update', this._object)
-              cam.position.set(this._object.x, this._object.y, this._object.z)
-              // camControls.update()
-            })
-            .start()
+          // new TWEEN.Tween(this.controls.cam_target)
+          //   .to(object.position, 400)
+          //   .start()
+          //
+          // toPos = { ...object.position }
+          // toPos.z += 20
+          // toPos.y = 5
+          // new TWEEN.Tween(camPos)
+          //   .easing(TWEEN.Easing.Quadratic.InOut)
+          //   .to(toPos, 3000)
+          //   .onUpdate(function () {
+          //     // console.log('tween update', this._object)
+          //     cam.position.set(this._object.x, this._object.y, this._object.z)
+          //     // camControls.update()
+          //   })
+          //   .start()
 
           // console.log('tween', tween)
           break

+ 2 - 2
src/components/objects/Plan.vue → src/components/objects/Ground.vue

@@ -1,6 +1,6 @@
 <template>
   <mesh
-    name="Plane"
+    name="Ground"
     :position="position"
     :rotation="{
       x:deg2rad(rotation.x),
@@ -19,7 +19,7 @@ import mixins from 'components/mixins'
 import * as THREE from 'three'
 
 export default {
-  name: 'Plan',
+  name: 'Ground',
   mixins: [mixins],
   props: {
     size: Object,