├── .gitignore ├── README.md ├── dst └── img │ ├── app-icon.png │ ├── icon.ico │ ├── share.png │ └── texture.png ├── gulp ├── conf.js ├── plugins.js └── tasks │ ├── clean.js │ ├── copy-vendor-script-to-build.js │ ├── copy-vendor-script.js │ ├── imagemin.js │ ├── minify-css.js │ ├── pug.js │ ├── replace-html.js │ ├── sass.js │ ├── scripts.js │ ├── serve.js │ └── uglify.js ├── gulpfile.js ├── package.json └── src ├── .keep ├── css ├── foundation │ ├── _global.scss │ ├── _mixin-easing.scss │ ├── _mixin-utils.scss │ ├── _normalize.scss │ └── _variables.scss ├── main.scss └── object │ ├── component │ └── .keep │ ├── project │ ├── .keep │ └── _contents-summary.scss │ └── utility │ └── .keep ├── glsl ├── modules │ ├── rotate_matrix.glsl │ ├── rotate_matrix_x.glsl │ ├── rotate_matrix_y.glsl │ ├── rotate_matrix_z.glsl │ ├── scale_matrix.glsl │ └── translate_matrix.glsl ├── sphere_plane_object.fs └── sphere_plane_object.vs ├── html ├── index.pug └── modules │ └── _head.pug └── js ├── main.js ├── modules └── sphere_plane_object.js └── vendor └── dat.gui.min.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | ignore 4 | dst/css/**/* 5 | dst/js/**/* 6 | dst/**/*.json 7 | dst/**/*.html 8 | css/**/* 9 | js/**/* 10 | img/**/* 11 | index.html 12 | .sass-cache 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sphere-to-plane 2 | 3 |  4 | 5 | this is WebGL demo that is moving vertices from sphere geometry to plane geometry. 6 | 7 | https://ykob.github.io/sphere-to-plane/ 8 | -------------------------------------------------------------------------------- /dst/img/app-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ykob/sphere-to-plane/64353d7d1b91d85aa063eddfeca56f115e1a22a5/dst/img/app-icon.png -------------------------------------------------------------------------------- /dst/img/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ykob/sphere-to-plane/64353d7d1b91d85aa063eddfeca56f115e1a22a5/dst/img/icon.ico -------------------------------------------------------------------------------- /dst/img/share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ykob/sphere-to-plane/64353d7d1b91d85aa063eddfeca56f115e1a22a5/dst/img/share.png -------------------------------------------------------------------------------- /dst/img/texture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ykob/sphere-to-plane/64353d7d1b91d85aa063eddfeca56f115e1a22a5/dst/img/texture.png -------------------------------------------------------------------------------- /gulp/conf.js: -------------------------------------------------------------------------------- 1 | // 設定ファイル 2 | // 対象パスやオプションを指定 3 | 4 | const DIR = module.exports.DIR = { 5 | PATH: '', 6 | SRC: 'src', 7 | DEST: 'dst', 8 | BUILD: '' 9 | }; 10 | 11 | module.exports.serve = { 12 | notify: false, 13 | startPath: DIR.PATH, 14 | ghostMode: false, 15 | server: { 16 | baseDir: DIR.DEST, 17 | index: 'index.html', 18 | routes: { 19 | [DIR.PATH]: `${DIR.DEST}${DIR.PATH}/` 20 | } 21 | } 22 | }; 23 | 24 | module.exports.scripts = { 25 | common: '', 26 | entryFiles: [ 27 | `./${DIR.SRC}/js/main.js`, 28 | ], 29 | browserifyOpts: { 30 | transform: [ 31 | ['babelify', { 32 | babelrc: false, 33 | presets: ['es2015'] 34 | }], 35 | 'envify', 36 | 'glslify' 37 | ] 38 | }, 39 | dest: `${DIR.DEST}${DIR.PATH}/js` 40 | }; 41 | 42 | module.exports.pug = { 43 | src: [ 44 | `${DIR.SRC}/**/*.pug`, 45 | `!${DIR.SRC}/**/_**/*.pug`, 46 | `!${DIR.SRC}/**/_*.pug` 47 | ], 48 | dest: `${DIR.DEST}${DIR.PATH}`, 49 | opts: { 50 | pretty: true 51 | } 52 | }; 53 | 54 | module.exports.sass = { 55 | src: [ 56 | `${DIR.SRC}/**/*.{sass,scss}`, 57 | `!${DIR.SRC}/**/_**/*.{sass,scss}`, 58 | `!${DIR.SRC}/**/_*.{sass,scss}` 59 | ], 60 | dest: `${DIR.DEST}${DIR.PATH}/css`, 61 | browsers: [ 62 | 'last 2 versions', 63 | 'ie >= 9', 64 | 'Android >= 4', 65 | 'ios_saf >= 8', 66 | ] 67 | }; 68 | 69 | module.exports.replace_html = { 70 | src: [ 71 | `${DIR.DEST}${DIR.PATH}/**/*.html` 72 | ], 73 | dest: `${DIR.BUILD}${DIR.PATH}`, 74 | path: `${DIR.PATH}` 75 | }; 76 | 77 | module.exports.minify_css = { 78 | src: `${DIR.DEST}${DIR.PATH}/css/main.css`, 79 | dest: `.${DIR.BUILD}${DIR.PATH}/css` 80 | }; 81 | 82 | module.exports.uglify = { 83 | src: [ 84 | `./${DIR.DEST}${DIR.PATH}/js/main.js`, 85 | ], 86 | dest: `.${DIR.BUILD}${DIR.PATH}/js`, 87 | opts: { 88 | preserveComments: (node, comment) => /This header is generated by licensify/.test(comment.value) 89 | } 90 | }; 91 | 92 | module.exports.copy_vendor_script = { 93 | src: [ 94 | `${DIR.SRC}/js/vendor/*.js`, 95 | ], 96 | dest: `${DIR.DEST}${DIR.PATH}/js/vendor/` 97 | }; 98 | 99 | module.exports.copy_vendor_script_to_build = { 100 | src: [ 101 | `${DIR.DEST}${DIR.PATH}/js/vendor/*.js`, 102 | ], 103 | dest: `.${DIR.BUILD}${DIR.PATH}/js/vendor/` 104 | }; 105 | 106 | module.exports.imagemin = { 107 | src: [ 108 | `${DIR.DEST}${DIR.PATH}/**/*.{jpg,jpeg,png,gif}` 109 | ], 110 | dest: `.${DIR.BUILD}${DIR.PATH}/img` 111 | }; 112 | 113 | module.exports.clean = { 114 | path: [`${DIR.BUILD}${DIR.PATH}`] 115 | }; 116 | -------------------------------------------------------------------------------- /gulp/plugins.js: -------------------------------------------------------------------------------- 1 | module.exports = require('gulp-load-plugins')(); 2 | -------------------------------------------------------------------------------- /gulp/tasks/clean.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp'); 2 | const del = require('del'); 3 | 4 | const conf = require('../conf').clean; 5 | 6 | gulp.task('clean', cb => { 7 | del(conf.path).then(() => { 8 | cb(); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /gulp/tasks/copy-vendor-script-to-build.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp'); 2 | 3 | const conf = require('../conf').copy_vendor_script_to_build; 4 | 5 | gulp.task('copy-vendor-script-to-build', () => { 6 | return gulp.src(conf.src) 7 | .pipe(gulp.dest(conf.dest)); 8 | }); 9 | -------------------------------------------------------------------------------- /gulp/tasks/copy-vendor-script.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp'); 2 | 3 | const conf = require('../conf').copy_vendor_script; 4 | 5 | gulp.task('copy-vendor-script', () => { 6 | return gulp.src(conf.src) 7 | .pipe(gulp.dest(conf.dest)); 8 | }); 9 | -------------------------------------------------------------------------------- /gulp/tasks/imagemin.js: -------------------------------------------------------------------------------- 1 | // imagemin with pngquant 2 | const gulp = require('gulp'); 3 | const pngquant = require('imagemin-pngquant'); 4 | 5 | const $ = require('../plugins'); 6 | const conf = require('../conf').imagemin; 7 | 8 | gulp.task('imagemin', () => { 9 | return gulp.src(conf.src) 10 | .pipe($.imagemin({ 11 | progressive: true, 12 | svgoPlugins: [{removeViewBox: false}], 13 | use: [pngquant()] 14 | })) 15 | .pipe($.rename(path => { 16 | path.dirname = path.dirname.replace('img', '.'); 17 | })) 18 | .pipe(gulp.dest(conf.dest)); 19 | }); 20 | -------------------------------------------------------------------------------- /gulp/tasks/minify-css.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp'); 2 | 3 | const $ = require('../plugins'); 4 | const conf = require('../conf').minify_css; 5 | 6 | gulp.task('minify-css', () => { 7 | return gulp.src(conf.src) 8 | .pipe($.minifyCss()) 9 | .pipe($.rename({suffix: '.min'})) 10 | .pipe(gulp.dest(conf.dest)); 11 | }); 12 | -------------------------------------------------------------------------------- /gulp/tasks/pug.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp'); 2 | 3 | const $ = require('../plugins'); 4 | const conf = require('../conf').pug; 5 | 6 | gulp.task('pug', () => { 7 | return gulp.src(conf.src) 8 | .pipe($.plumber({ 9 | errorHandler: $.notify.onError('<%= error.message %>') 10 | })) 11 | .pipe($.pug(conf.opts)) 12 | .pipe($.rename(path => { 13 | path.dirname = path.dirname.replace('html', '.'); 14 | })) 15 | .pipe(gulp.dest(conf.dest)); 16 | }); 17 | -------------------------------------------------------------------------------- /gulp/tasks/replace-html.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp'); 2 | 3 | const $ = require('../plugins'); 4 | const conf = require('../conf').replace_html; 5 | 6 | gulp.task('replace-html', () => { 7 | return gulp.src(conf.src) 8 | .pipe($.replace(/(src="\.\/js\/)([a-z0-9]*)(\.js")/g, '$1$2.min$3')) 9 | .pipe($.replace(/(href="\.\/css\/)([a-z0-9]*)(\.css")/g, '$1$2.min$3')) 10 | .pipe(gulp.dest(conf.dest)); 11 | }); 12 | -------------------------------------------------------------------------------- /gulp/tasks/sass.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp'); 2 | 3 | const $ = require('../plugins'); 4 | const conf = require('../conf').sass; 5 | 6 | gulp.task('sass', () => { 7 | return gulp.src(conf.src) 8 | .pipe($.sass().on('error', $.sass.logError)) 9 | .pipe($.autoprefixer({ 10 | browsers: conf.browsers, 11 | cascade: false 12 | })) 13 | .pipe($.rename(path => { 14 | path.dirname = path.dirname.replace('css', '.'); 15 | })) 16 | .pipe(gulp.dest(conf.dest)); 17 | }); 18 | -------------------------------------------------------------------------------- /gulp/tasks/scripts.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp'); 2 | const browserify = require('browserify'); 3 | const watchify = require('watchify'); 4 | const licensify = require('licensify'); 5 | const source = require('vinyl-source-stream'); 6 | const eventStream = require('event-stream'); 7 | 8 | const $ = require('../plugins'); 9 | const conf = require('../conf').scripts; 10 | 11 | const bundler = (entry, isWatch) => { 12 | const bOpts = conf.browserifyOpts; 13 | var b; 14 | 15 | bOpts.entries = [conf.common, entry] 16 | 17 | if (isWatch) { 18 | // bOpts.debug = true 19 | bOpts.cache = {}; 20 | bOpts.packageCache = {}; 21 | bOpts.fullPath = true; 22 | b = watchify(browserify(bOpts)); 23 | } else { 24 | b = browserify(bOpts); 25 | } 26 | 27 | if (process.env.NODE_ENV === 'production') { 28 | b.plugin(licensify); 29 | } 30 | 31 | const bundle = () => { 32 | return b.bundle() 33 | .on('error', err => { 34 | console.log(`bundle error: ${err}`); 35 | }) 36 | .pipe(source(entry)) 37 | .pipe($.rename({ 38 | dirname: '', 39 | extname: '.js' 40 | })) 41 | .pipe(gulp.dest(conf.dest)); 42 | }; 43 | 44 | b 45 | .on('update', bundle) 46 | .on('log', message => { 47 | console.log(message); 48 | }); 49 | 50 | return bundle(); 51 | }; 52 | 53 | gulp.task('browserify', () => { 54 | const tasks = conf.entryFiles.map(entry => { 55 | return bundler(entry); 56 | }); 57 | return eventStream.merge.apply(null, tasks); 58 | }); 59 | 60 | gulp.task('watchify', () => { 61 | const tasks = conf.entryFiles.map(entry => { 62 | return bundler(entry, true); 63 | }); 64 | return eventStream.merge.apply(null, tasks); 65 | }); 66 | -------------------------------------------------------------------------------- /gulp/tasks/serve.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp'); 2 | const browserSync = require('browser-sync'); 3 | 4 | const conf = require('../conf').serve; 5 | 6 | gulp.task('serve', () => { 7 | browserSync(conf); 8 | }); 9 | -------------------------------------------------------------------------------- /gulp/tasks/uglify.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp'); 2 | 3 | const $ = require('../plugins'); 4 | const conf = require('../conf').uglify; 5 | 6 | gulp.task('uglify', () => { 7 | return gulp.src(conf.src) 8 | .pipe($.uglify(conf.opts)) 9 | .pipe($.rename({ 10 | suffix: '.min' 11 | })) 12 | .pipe(gulp.dest(conf.dest)); 13 | }); 14 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp'); 2 | const requireDir = require('require-dir'); 3 | const runSequence = require('run-sequence'); 4 | const browserSync = require('browser-sync'); 5 | const reload = browserSync.reload; 6 | 7 | const DIR = require('./gulp/conf').DIR; 8 | 9 | requireDir('./gulp/tasks'); 10 | 11 | gulp.task('predefault', cb => { 12 | runSequence( 13 | ['pug', 'sass', 'watchify', 'copy-vendor-script'], 14 | 'serve', 15 | cb 16 | ); 17 | }); 18 | 19 | gulp.task('default', ['predefault'], () => { 20 | gulp.watch( 21 | [`./${DIR.SRC}/**/*.pug`], 22 | ['pug', reload] 23 | ); 24 | 25 | gulp.watch( 26 | [`./${DIR.SRC}/**/*.{scss,sass}`], 27 | ['sass', reload] 28 | ); 29 | 30 | gulp.watch( 31 | [`./${DIR.DEST}/**/*.js`], 32 | reload 33 | ); 34 | }); 35 | 36 | gulp.task('build', cb => { 37 | runSequence( 38 | 'clean', 39 | ['pug', 'sass'], 40 | 'replace-html', 41 | ['minify-css', 'browserify', 'imagemin'], 42 | 'uglify', 43 | 'copy-vendor-script-to-build', 44 | cb 45 | ); 46 | }); 47 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sphere-to-plane", 3 | "description": "", 4 | "repository": { 5 | "type": "git", 6 | "url": "https://github.com/ykob/sphere-to-plane" 7 | }, 8 | "private": true, 9 | "scripts": { 10 | "start": "gulp", 11 | "build": "NODE_ENV=production gulp build" 12 | }, 13 | "engines": { 14 | "node": "4.2.x" 15 | }, 16 | "devDependencies": { 17 | "babel-core": "^6.10.4", 18 | "babel-preset-es2015": "^6.9.0", 19 | "babelify": "^7.3.0", 20 | "browser-sync": "^2.13.0", 21 | "browserify": "^12.0.2", 22 | "del": "^2.2.1", 23 | "envify": "^3.4.1", 24 | "gulp": "^3.9.1", 25 | "gulp-autoprefixer": "^3.1.0", 26 | "gulp-imagemin": "^2.4.0", 27 | "gulp-load-plugins": "^1.2.4", 28 | "gulp-minify-css": "^1.2.4", 29 | "gulp-notify": "^2.2.0", 30 | "gulp-plumber": "^1.1.0", 31 | "gulp-pug": "^3.0.3", 32 | "gulp-rename": "^1.2.2", 33 | "gulp-replace": "^0.5.4", 34 | "gulp-sass": "^2.3.2", 35 | "gulp-uglify": "^1.5.4", 36 | "imagemin-pngquant": "^4.2.2", 37 | "licensify": "^2.2.0", 38 | "require-dir": "^0.3.0", 39 | "run-sequence": "^1.2.1", 40 | "vinyl-source-stream": "^1.1.0", 41 | "watchify": "^3.7.0" 42 | }, 43 | "dependencies": { 44 | "glsl-easings": "^1.0.0", 45 | "glsl-inverse": "^1.0.0", 46 | "glsl-noise": "0.0.0", 47 | "glslify": "^5.1.0" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ykob/sphere-to-plane/64353d7d1b91d85aa063eddfeca56f115e1a22a5/src/.keep -------------------------------------------------------------------------------- /src/css/foundation/_global.scss: -------------------------------------------------------------------------------- 1 | html { 2 | height: 100%; 3 | } 4 | body { 5 | min-height: 100%; 6 | overflow: hidden; 7 | color: $color-text; 8 | font-family: "Noto Sans"; 9 | background: radial-gradient(ellipse at center, rgba(255,255,255,1) 50%, rgba(200,218,210,1) 100%); 10 | } 11 | a { 12 | color: $color-text; 13 | text-decoration: none; 14 | } 15 | ::selection { 16 | color: #fff; 17 | background: rgba(0, 0, 0, 0.5); 18 | } 19 | -------------------------------------------------------------------------------- /src/css/foundation/_mixin-easing.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Ceaser/developer/ceaser-easings.scss 3 | // https://github.com/matthewlein/Ceaser/blob/master/developer/ceaser-easings.scss 4 | // 5 | 6 | // Cubic 7 | $easeInCubic : cubic-bezier(0.550, 0.055, 0.675, 0.190); 8 | $easeOutCubic : cubic-bezier(0.215, 0.610, 0.355, 1.000); 9 | $easeInOutCubic : cubic-bezier(0.645, 0.045, 0.355, 1.000); 10 | 11 | // Circ 12 | $easeInCirc : cubic-bezier(0.600, 0.040, 0.980, 0.335); 13 | $easeOutCirc : cubic-bezier(0.075, 0.820, 0.165, 1.000); 14 | $easeInOutCirc : cubic-bezier(0.785, 0.135, 0.150, 0.860); 15 | 16 | // Expo 17 | $easeInExpo : cubic-bezier(0.950, 0.050, 0.795, 0.035); 18 | $easeOutExpo : cubic-bezier(0.190, 1.000, 0.220, 1.000); 19 | $easeInOutExpo : cubic-bezier(1.000, 0.000, 0.000, 1.000); 20 | 21 | // Quad 22 | $easeInQuad : cubic-bezier(0.550, 0.085, 0.680, 0.530); 23 | $easeOutQuad : cubic-bezier(0.250, 0.460, 0.450, 0.940); 24 | $easeInOutQuad : cubic-bezier(0.455, 0.030, 0.515, 0.955); 25 | 26 | // Quart 27 | $easeInQuart : cubic-bezier(0.895, 0.030, 0.685, 0.220); 28 | $easeOutQuart : cubic-bezier(0.165, 0.840, 0.440, 1.000); 29 | $easeInOutQuart : cubic-bezier(0.770, 0.000, 0.175, 1.000); 30 | 31 | // Quint 32 | $easeInQuint : cubic-bezier(0.755, 0.050, 0.855, 0.060); 33 | $easeOutQuint : cubic-bezier(0.230, 1.000, 0.320, 1.000); 34 | $easeInOutQuint : cubic-bezier(0.860, 0.000, 0.070, 1.000); 35 | 36 | // Sine 37 | $easeInSine : cubic-bezier(0.470, 0.000, 0.745, 0.715); 38 | $easeOutSine : cubic-bezier(0.390, 0.575, 0.565, 1.000); 39 | $easeInOutSine : cubic-bezier(0.445, 0.050, 0.550, 0.950); 40 | 41 | // Back 42 | $easeInBack : cubic-bezier(0.600, -0.280, 0.735, 0.045); 43 | $easeOutBack : cubic-bezier(0.175, 0.885, 0.320, 1.275); 44 | $easeInOutBack : cubic-bezier(0.680, -0.550, 0.265, 1.550); 45 | -------------------------------------------------------------------------------- /src/css/foundation/_mixin-utils.scss: -------------------------------------------------------------------------------- 1 | @mixin fontSize($size: 14) { 2 | font-size: $size + px; 3 | font-size: $size / 16 * 1rem; 4 | } 5 | @mixin clearfix { 6 | &:before, 7 | &:after { 8 | content: ""; 9 | display: table; 10 | } 11 | &:after { 12 | clear: both; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/css/foundation/_normalize.scss: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */ 2 | 3 | /** 4 | * 1. Set default font family to sans-serif. 5 | * 2. Prevent iOS text size adjust after orientation change, without disabling 6 | * user zoom. 7 | */ 8 | 9 | html { 10 | font-family: sans-serif; /* 1 */ 11 | -ms-text-size-adjust: 100%; /* 2 */ 12 | -webkit-text-size-adjust: 100%; /* 2 */ 13 | } 14 | 15 | /** 16 | * Remove default margin. 17 | */ 18 | 19 | body { 20 | margin: 0; 21 | } 22 | 23 | /* HTML5 display definitions 24 | ========================================================================== */ 25 | 26 | /** 27 | * Correct `block` display not defined for any HTML5 element in IE 8/9. 28 | * Correct `block` display not defined for `details` or `summary` in IE 10/11 29 | * and Firefox. 30 | * Correct `block` display not defined for `main` in IE 11. 31 | */ 32 | 33 | article, 34 | aside, 35 | details, 36 | figcaption, 37 | figure, 38 | footer, 39 | header, 40 | hgroup, 41 | main, 42 | menu, 43 | nav, 44 | section, 45 | summary { 46 | display: block; 47 | } 48 | 49 | /** 50 | * 1. Correct `inline-block` display not defined in IE 8/9. 51 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. 52 | */ 53 | 54 | audio, 55 | canvas, 56 | progress, 57 | video { 58 | display: inline-block; /* 1 */ 59 | vertical-align: baseline; /* 2 */ 60 | } 61 | 62 | /** 63 | * Prevent modern browsers from displaying `audio` without controls. 64 | * Remove excess height in iOS 5 devices. 65 | */ 66 | 67 | audio:not([controls]) { 68 | display: none; 69 | height: 0; 70 | } 71 | 72 | /** 73 | * Address `[hidden]` styling not present in IE 8/9/10. 74 | * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. 75 | */ 76 | 77 | [hidden], 78 | template { 79 | display: none; 80 | } 81 | 82 | /* Links 83 | ========================================================================== */ 84 | 85 | /** 86 | * Remove the gray background color from active links in IE 10. 87 | */ 88 | 89 | a { 90 | background-color: transparent; 91 | } 92 | 93 | /** 94 | * Improve readability when focused and also mouse hovered in all browsers. 95 | */ 96 | 97 | a:active, 98 | a:hover { 99 | outline: 0; 100 | } 101 | 102 | /* Text-level semantics 103 | ========================================================================== */ 104 | 105 | /** 106 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome. 107 | */ 108 | 109 | abbr[title] { 110 | border-bottom: 1px dotted; 111 | } 112 | 113 | /** 114 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. 115 | */ 116 | 117 | b, 118 | strong { 119 | font-weight: bold; 120 | } 121 | 122 | /** 123 | * Address styling not present in Safari and Chrome. 124 | */ 125 | 126 | dfn { 127 | font-style: italic; 128 | } 129 | 130 | /** 131 | * Address variable `h1` font-size and margin within `section` and `article` 132 | * contexts in Firefox 4+, Safari, and Chrome. 133 | */ 134 | 135 | h1 { 136 | font-size: 2em; 137 | margin: 0.67em 0; 138 | } 139 | 140 | /** 141 | * Address styling not present in IE 8/9. 142 | */ 143 | 144 | mark { 145 | background: #ff0; 146 | color: #000; 147 | } 148 | 149 | /** 150 | * Address inconsistent and variable font size in all browsers. 151 | */ 152 | 153 | small { 154 | font-size: 80%; 155 | } 156 | 157 | /** 158 | * Prevent `sub` and `sup` affecting `line-height` in all browsers. 159 | */ 160 | 161 | sub, 162 | sup { 163 | font-size: 75%; 164 | line-height: 0; 165 | position: relative; 166 | vertical-align: baseline; 167 | } 168 | 169 | sup { 170 | top: -0.5em; 171 | } 172 | 173 | sub { 174 | bottom: -0.25em; 175 | } 176 | 177 | /* Embedded content 178 | ========================================================================== */ 179 | 180 | /** 181 | * Remove border when inside `a` element in IE 8/9/10. 182 | */ 183 | 184 | img { 185 | border: 0; 186 | } 187 | 188 | /** 189 | * Correct overflow not hidden in IE 9/10/11. 190 | */ 191 | 192 | svg:not(:root) { 193 | overflow: hidden; 194 | } 195 | 196 | /* Grouping content 197 | ========================================================================== */ 198 | 199 | /** 200 | * Address margin not present in IE 8/9 and Safari. 201 | */ 202 | 203 | figure { 204 | margin: 1em 40px; 205 | } 206 | 207 | /** 208 | * Address differences between Firefox and other browsers. 209 | */ 210 | 211 | hr { 212 | -moz-box-sizing: content-box; 213 | box-sizing: content-box; 214 | height: 0; 215 | } 216 | 217 | /** 218 | * Contain overflow in all browsers. 219 | */ 220 | 221 | pre { 222 | overflow: auto; 223 | } 224 | 225 | /** 226 | * Address odd `em`-unit font size rendering in all browsers. 227 | */ 228 | 229 | code, 230 | kbd, 231 | pre, 232 | samp { 233 | font-family: monospace, monospace; 234 | font-size: 1em; 235 | } 236 | 237 | /* Forms 238 | ========================================================================== */ 239 | 240 | /** 241 | * Known limitation: by default, Chrome and Safari on OS X allow very limited 242 | * styling of `select`, unless a `border` property is set. 243 | */ 244 | 245 | /** 246 | * 1. Correct color not being inherited. 247 | * Known issue: affects color of disabled elements. 248 | * 2. Correct font properties not being inherited. 249 | * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. 250 | */ 251 | 252 | button, 253 | input, 254 | optgroup, 255 | select, 256 | textarea { 257 | color: inherit; /* 1 */ 258 | font: inherit; /* 2 */ 259 | margin: 0; /* 3 */ 260 | } 261 | 262 | /** 263 | * Address `overflow` set to `hidden` in IE 8/9/10/11. 264 | */ 265 | 266 | button { 267 | overflow: visible; 268 | } 269 | 270 | /** 271 | * Address inconsistent `text-transform` inheritance for `button` and `select`. 272 | * All other form control elements do not inherit `text-transform` values. 273 | * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. 274 | * Correct `select` style inheritance in Firefox. 275 | */ 276 | 277 | button, 278 | select { 279 | text-transform: none; 280 | } 281 | 282 | /** 283 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 284 | * and `video` controls. 285 | * 2. Correct inability to style clickable `input` types in iOS. 286 | * 3. Improve usability and consistency of cursor style between image-type 287 | * `input` and others. 288 | */ 289 | 290 | button, 291 | html input[type="button"], /* 1 */ 292 | input[type="reset"], 293 | input[type="submit"] { 294 | -webkit-appearance: button; /* 2 */ 295 | cursor: pointer; /* 3 */ 296 | } 297 | 298 | /** 299 | * Re-set default cursor for disabled elements. 300 | */ 301 | 302 | button[disabled], 303 | html input[disabled] { 304 | cursor: default; 305 | } 306 | 307 | /** 308 | * Remove inner padding and border in Firefox 4+. 309 | */ 310 | 311 | button::-moz-focus-inner, 312 | input::-moz-focus-inner { 313 | border: 0; 314 | padding: 0; 315 | } 316 | 317 | /** 318 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in 319 | * the UA stylesheet. 320 | */ 321 | 322 | input { 323 | line-height: normal; 324 | } 325 | 326 | /** 327 | * It's recommended that you don't attempt to style these elements. 328 | * Firefox's implementation doesn't respect box-sizing, padding, or width. 329 | * 330 | * 1. Address box sizing set to `content-box` in IE 8/9/10. 331 | * 2. Remove excess padding in IE 8/9/10. 332 | */ 333 | 334 | input[type="checkbox"], 335 | input[type="radio"] { 336 | box-sizing: border-box; /* 1 */ 337 | padding: 0; /* 2 */ 338 | } 339 | 340 | /** 341 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain 342 | * `font-size` values of the `input`, it causes the cursor style of the 343 | * decrement button to change from `default` to `text`. 344 | */ 345 | 346 | input[type="number"]::-webkit-inner-spin-button, 347 | input[type="number"]::-webkit-outer-spin-button { 348 | height: auto; 349 | } 350 | 351 | /** 352 | * 1. Address `appearance` set to `searchfield` in Safari and Chrome. 353 | * 2. Address `box-sizing` set to `border-box` in Safari and Chrome 354 | * (include `-moz` to future-proof). 355 | */ 356 | 357 | input[type="search"] { 358 | -webkit-appearance: textfield; /* 1 */ 359 | -moz-box-sizing: content-box; 360 | -webkit-box-sizing: content-box; /* 2 */ 361 | box-sizing: content-box; 362 | } 363 | 364 | /** 365 | * Remove inner padding and search cancel button in Safari and Chrome on OS X. 366 | * Safari (but not Chrome) clips the cancel button when the search input has 367 | * padding (and `textfield` appearance). 368 | */ 369 | 370 | input[type="search"]::-webkit-search-cancel-button, 371 | input[type="search"]::-webkit-search-decoration { 372 | -webkit-appearance: none; 373 | } 374 | 375 | /** 376 | * Define consistent border, margin, and padding. 377 | */ 378 | 379 | fieldset { 380 | border: 1px solid #c0c0c0; 381 | margin: 0 2px; 382 | padding: 0.35em 0.625em 0.75em; 383 | } 384 | 385 | /** 386 | * 1. Correct `color` not being inherited in IE 8/9/10/11. 387 | * 2. Remove padding so people aren't caught out if they zero out fieldsets. 388 | */ 389 | 390 | legend { 391 | border: 0; /* 1 */ 392 | padding: 0; /* 2 */ 393 | } 394 | 395 | /** 396 | * Remove default vertical scrollbar in IE 8/9/10/11. 397 | */ 398 | 399 | textarea { 400 | overflow: auto; 401 | } 402 | 403 | /** 404 | * Don't inherit the `font-weight` (applied by a rule above). 405 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. 406 | */ 407 | 408 | optgroup { 409 | font-weight: bold; 410 | } 411 | 412 | /* Tables 413 | ========================================================================== */ 414 | 415 | /** 416 | * Remove most spacing between table cells. 417 | */ 418 | 419 | table { 420 | border-collapse: collapse; 421 | border-spacing: 0; 422 | } 423 | 424 | td, 425 | th { 426 | padding: 0; 427 | } 428 | -------------------------------------------------------------------------------- /src/css/foundation/_variables.scss: -------------------------------------------------------------------------------- 1 | $color-text: #444; 2 | -------------------------------------------------------------------------------- /src/css/main.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | @import url("https://fonts.googleapis.com/css?family=Noto+Sans:400,700"); 4 | 5 | // ========================================================================== 6 | // Foundation 7 | // ========================================================================== 8 | @import "foundation/_variables"; 9 | 10 | // Mixins 11 | @import "foundation/_mixin-utils"; 12 | @import "foundation/_mixin-easing"; 13 | 14 | // Base 15 | @import "foundation/_normalize"; 16 | @import "foundation/_global"; 17 | 18 | // ========================================================================== 19 | // Layout 20 | // ========================================================================== 21 | 22 | // ========================================================================== 23 | // Object 24 | // ========================================================================== 25 | // ----------------------------------------------------------------- 26 | // Component 27 | // ----------------------------------------------------------------- 28 | // @import "object/component/_xxx"; 29 | 30 | // ----------------------------------------------------------------- 31 | // Project 32 | // ----------------------------------------------------------------- 33 | @import "object/project/_contents-summary"; 34 | 35 | // ----------------------------------------------------------------- 36 | // Utility 37 | // ----------------------------------------------------------------- 38 | -------------------------------------------------------------------------------- /src/css/object/component/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ykob/sphere-to-plane/64353d7d1b91d85aa063eddfeca56f115e1a22a5/src/css/object/component/.keep -------------------------------------------------------------------------------- /src/css/object/project/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ykob/sphere-to-plane/64353d7d1b91d85aa063eddfeca56f115e1a22a5/src/css/object/project/.keep -------------------------------------------------------------------------------- /src/css/object/project/_contents-summary.scss: -------------------------------------------------------------------------------- 1 | .p-contents-summary { 2 | position: absolute; 3 | top: 2%; left: 2%; 4 | z-index: 100; 5 | &__head { 6 | margin: 0; 7 | font-weight: 400; 8 | letter-spacing: 2px; 9 | } 10 | &__text { 11 | max-width: 360px; 12 | line-height: 1.75; 13 | margin: 1em 0; 14 | @include fontSize(13); 15 | letter-spacing: 1px; 16 | } 17 | &__link-source { 18 | margin: 0; 19 | @include fontSize(13); 20 | letter-spacing: 1px; 21 | a { 22 | position: relative; 23 | &:after { 24 | content: ''; 25 | display: block; 26 | position: absolute; 27 | z-index: -1; 28 | top: 0; right: 0; bottom: 0; left: 0; 29 | background-color: $color-text; 30 | } 31 | } 32 | } 33 | // 34 | // Init Interaction 35 | // 36 | &__link-source { 37 | a { 38 | transition-duration: 0.3s; 39 | transition-timing-function: $easeOutQuad; 40 | &:after { 41 | transform: scale(0, 1); 42 | transform-origin: left center; 43 | transition-duration: 0.3s; 44 | transition-timing-function: $easeOutQuad; 45 | } 46 | } 47 | } 48 | // 49 | // Running Interaction 50 | // 51 | &__link-source { 52 | a { 53 | &:hover { 54 | color: #fff; 55 | &:after { 56 | transform: scale(1, 1); 57 | } 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/css/object/utility/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ykob/sphere-to-plane/64353d7d1b91d85aa063eddfeca56f115e1a22a5/src/css/object/utility/.keep -------------------------------------------------------------------------------- /src/glsl/modules/rotate_matrix.glsl: -------------------------------------------------------------------------------- 1 | #pragma glslify: rotateMatrixX = require(./rotate_matrix_x); 2 | #pragma glslify: rotateMatrixY = require(./rotate_matrix_y); 3 | #pragma glslify: rotateMatrixZ = require(./rotate_matrix_z); 4 | 5 | mat4 rotateMatrix(float radian_x, float radian_y, float radian_z) { 6 | return rotateMatrixX(radian_x) * rotateMatrixY(radian_y) * rotateMatrixZ(radian_z); 7 | } 8 | #pragma glslify: export(rotateMatrix) 9 | -------------------------------------------------------------------------------- /src/glsl/modules/rotate_matrix_x.glsl: -------------------------------------------------------------------------------- 1 | mat4 rotateMatrixX(float radian) { 2 | return mat4( 3 | 1.0, 0.0, 0.0, 0.0, 4 | 0.0, cos(radian), -sin(radian), 0.0, 5 | 0.0, sin(radian), cos(radian), 0.0, 6 | 0.0, 0.0, 0.0, 1.0 7 | ); 8 | } 9 | #pragma glslify: export(rotateMatrixX) 10 | -------------------------------------------------------------------------------- /src/glsl/modules/rotate_matrix_y.glsl: -------------------------------------------------------------------------------- 1 | mat4 rotateMatrixY(float radian) { 2 | return mat4( 3 | cos(radian), 0.0, sin(radian), 0.0, 4 | 0.0, 1.0, 0.0, 0.0, 5 | -sin(radian), 0.0, cos(radian), 0.0, 6 | 0.0, 0.0, 0.0, 1.0 7 | ); 8 | } 9 | #pragma glslify: export(rotateMatrixY) 10 | -------------------------------------------------------------------------------- /src/glsl/modules/rotate_matrix_z.glsl: -------------------------------------------------------------------------------- 1 | mat4 rotateMatrixZ(float radian) { 2 | return mat4( 3 | cos(radian), -sin(radian), 0.0, 0.0, 4 | sin(radian), cos(radian), 0.0, 0.0, 5 | 0.0, 0.0, 1.0, 0.0, 6 | 0.0, 0.0, 0.0, 1.0 7 | ); 8 | } 9 | #pragma glslify: export(rotateMatrixZ) 10 | -------------------------------------------------------------------------------- /src/glsl/modules/scale_matrix.glsl: -------------------------------------------------------------------------------- 1 | mat4 scaleMatrix(vec3 scale) { 2 | return mat4( 3 | scale.x, 0.0, 0.0, 0.0, 4 | 0.0, scale.y, 0.0, 0.0, 5 | 0.0, 0.0, scale.z, 0.0, 6 | 0.0, 0.0, 0.0, 1.0 7 | ); 8 | } 9 | #pragma glslify: export(scaleMatrix) 10 | -------------------------------------------------------------------------------- /src/glsl/modules/translate_matrix.glsl: -------------------------------------------------------------------------------- 1 | mat4 translateMatrix(vec3 v) { 2 | return mat4( 3 | 1.0, 0.0, 0.0, 0.0, 4 | 0.0, 1.0, 0.0, 0.0, 5 | 0.0, 0.0, 1.0, 0.0, 6 | v.x, v.y, v.z, 1.0 7 | ); 8 | } 9 | #pragma glslify: export(translateMatrix) 10 | -------------------------------------------------------------------------------- /src/glsl/sphere_plane_object.fs: -------------------------------------------------------------------------------- 1 | uniform float radius; 2 | uniform sampler2D texture; 3 | uniform float valid_tex; 4 | 5 | varying vec4 vPosition; 6 | varying vec2 vUv; 7 | varying mat4 vInvertMatrix; 8 | 9 | void main(void) { 10 | vec3 normal = normalize(cross(dFdx(vPosition.xyz), dFdy(vPosition.xyz))); 11 | // vec3 normal = normalize(vPosition.xyz); 12 | vec3 inv_light = normalize(vInvertMatrix * vec4(vec3(0.7), 0.0)).xyz; 13 | float diff = (dot(normal, inv_light) + 1.0) / 2.0; 14 | vec3 light = vec3(0.2) * diff; 15 | vec4 color = vec4(0.6, 0.7, 0.68, 1.0); 16 | vec4 tex_color = texture2D(texture, vUv); 17 | gl_FragColor = (color + vec4(light, 1.0)) * (1.0 - valid_tex) + vec4(tex_color.rgb + light, tex_color.a) * valid_tex; 18 | } 19 | -------------------------------------------------------------------------------- /src/glsl/sphere_plane_object.vs: -------------------------------------------------------------------------------- 1 | attribute vec3 position2; 2 | 3 | uniform float time; 4 | uniform float ease_time; 5 | uniform float ease_time_max; 6 | uniform float radius; 7 | uniform float noise_a; 8 | uniform float noise_x; 9 | uniform float noise_y; 10 | uniform float noise_z; 11 | uniform float plane_noise_a; 12 | uniform float plane_noise_z; 13 | uniform float plane_noise_y; 14 | uniform float smoothstep_min; 15 | uniform float smoothstep_max; 16 | 17 | varying vec4 vPosition; 18 | varying vec2 vUv; 19 | varying mat4 vInvertMatrix; 20 | 21 | #pragma glslify: inverse = require(glsl-inverse); 22 | #pragma glslify: cnoise3 = require(glsl-noise/classic/3d); 23 | #pragma glslify: ease = require(glsl-easings/circular-in-out); 24 | #pragma glslify: rotateMatrix = require(./modules/rotate_matrix); 25 | #pragma glslify: scaleMatrix = require(./modules/scale_matrix); 26 | 27 | void main(void) { 28 | float step = ease(clamp(ease_time, 0.0, ease_time_max) / ease_time_max); 29 | vec3 plane_position = (rotateMatrix(0.0, radians(-90.0), 0.0) * vec4(position2, 1.0)).xyz; 30 | vec3 ease_position = position * (1.0 - step) + plane_position * step; 31 | float noise = smoothstep(smoothstep_min, smoothstep_max, cnoise3( 32 | vec3( 33 | ease_position.x * noise_x + time, 34 | ease_position.y * noise_y + time, 35 | ease_position.z * noise_z + time 36 | ) 37 | )); 38 | float noise2 = smoothstep(smoothstep_min, smoothstep_max, cnoise3( 39 | vec3( 40 | ease_position.x + time, 41 | ease_position.y * plane_noise_y + time, 42 | ease_position.z * plane_noise_z + time 43 | ) 44 | )); 45 | mat4 scale_matrix = scaleMatrix(vec3(radius)); 46 | vec4 scale_position = scale_matrix * vec4(ease_position, 1.0); 47 | vec4 noise_position = vec4(scale_position.xyz + vec3( 48 | position.x * noise * noise_a * (1.0 - step) + (plane_position.x + plane_noise_a * 2.0) * noise2 * step, 49 | position.y * noise * noise_a * (1.0 - step), 50 | position.z * noise * noise_a * (1.0 - step) 51 | ), 1.0); 52 | vPosition = noise_position; 53 | vUv = uv; 54 | vInvertMatrix = inverse(scale_matrix * modelMatrix); 55 | gl_Position = projectionMatrix * modelViewMatrix * noise_position; 56 | } 57 | -------------------------------------------------------------------------------- /src/html/index.pug: -------------------------------------------------------------------------------- 1 | - var meta_title = 'sphere to plane'; 2 | - var meta_keywords = 'WebGL, three.js'; 3 | - var meta_description = 'this is WebGL demo that is moving vertices from sphere geometry to plane geometry.'; 4 | - var meta_path = "/"; 5 | - var meta_ogp_img = "share.png" 6 | 7 | doctype html 8 | html(lang="ja") 9 | head 10 | include ./modules/_head.pug 11 | body 12 | .p-contents-summary 13 | h1.p-contents-summary__head 14 | |#{meta_title} 15 | p.p-contents-summary__text 16 | |#{meta_description} 17 | p.p-contents-summary__link-source 18 | a(href="https://github.com/ykob/sphere-to-plane") 19 | |view source. 20 | canvas(id="canvas-webgl", class="p-canvas-webgl") 21 | script(src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r78/three.min.js") 22 | script(src="https://code.jquery.com/jquery-3.0.0.slim.min.js") 23 | script(src="./js/vendor/dat.gui.min.js") 24 | script(src="./js/main.js") 25 | -------------------------------------------------------------------------------- /src/html/modules/_head.pug: -------------------------------------------------------------------------------- 1 | - var website_domain = "http://ykob.github.io/sphere-to-plane"; 2 | - var meta_ogp_description = meta_description; 3 | 4 | meta(charset="utf-8") 5 | meta(http-equiv="X-UA-Compatible", content="IE=edge") 6 | title #{meta_title} 7 | meta(name="viewport", content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1") 8 | meta(name="description", content = meta_description) 9 | meta(name="keywords", content = meta_keywords) 10 | meta(name="theme-color", content="#ffffff") 11 | link(rel="shortcut icon" href="./img/icon.ico") 12 | link(rel="apple-touch-icon" href="./img/app-icon.png") 13 | link(rel="stylesheet" href="./css/main.css") 14 | 15 | meta(property="og:title", content = meta_title) 16 | meta(property="og:site_name", content = meta_title) 17 | meta(property="og:type", content="website") 18 | meta(property="og:description", content = meta_ogp_description) 19 | meta(property="og:url", content = website_domain + meta_path) 20 | meta(property="og:image", content = website_domain + '/img/' + meta_ogp_img) 21 | 22 | meta(name="twitter:card", content="summary_large_image") 23 | meta(name="twitter:title", content = meta_title) 24 | meta(name="twitter:description", content = meta_ogp_description) 25 | meta(name="twitter:image", content = website_domain + '/img/' + meta_ogp_img) 26 | -------------------------------------------------------------------------------- /src/js/main.js: -------------------------------------------------------------------------------- 1 | import SpherePlaneObject from './modules/sphere_plane_object.js'; 2 | 3 | const canvas = document.getElementById('canvas-webgl'); 4 | const renderer = new THREE.WebGLRenderer({ 5 | antialias: true, 6 | canvas: canvas, 7 | alpha: true 8 | }); 9 | const scene = new THREE.Scene(); 10 | const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000); 11 | const clock = new THREE.Clock(); 12 | 13 | const sp_obj = new SpherePlaneObject(); 14 | 15 | const resizeWindow = () => { 16 | canvas.width = window.innerWidth; 17 | canvas.height = window.innerHeight; 18 | camera.aspect = window.innerWidth / window.innerHeight; 19 | camera.updateProjectionMatrix(); 20 | renderer.setSize(window.innerWidth, window.innerHeight); 21 | } 22 | const setEvent = () => { 23 | $(window).on('resize', () => { 24 | resizeWindow(); 25 | }); 26 | } 27 | const initDatGui = () => { 28 | const gui = new dat.GUI(); 29 | const controller = { 30 | radius: gui.add(sp_obj, 'radius', 0, 1000), 31 | noise_a: gui.add(sp_obj, 'noise_a', 0, 500), 32 | noise_x: gui.add(sp_obj, 'noise_x', -20, 20), 33 | noise_y: gui.add(sp_obj, 'noise_y', -20, 20), 34 | noise_z: gui.add(sp_obj, 'noise_z', -20, 20), 35 | plane_noise_a: gui.add(sp_obj, 'plane_noise_a', 0, 100), 36 | plane_noise_y: gui.add(sp_obj, 'plane_noise_y', -10, 10), 37 | plane_noise_z: gui.add(sp_obj, 'plane_noise_z', -10, 10), 38 | smoothstep_min: gui.add(sp_obj, 'smoothstep_min', -1, 1), 39 | smoothstep_max: gui.add(sp_obj, 'smoothstep_max', -1, 1), 40 | time: gui.add(sp_obj, 'time', 0, 10), 41 | plane: gui.add(sp_obj, 'plane'), 42 | texture: gui.add(sp_obj, 'texture'), 43 | } 44 | controller.radius.onChange((value) => { 45 | sp_obj.mesh.material.uniforms.radius.value = value; 46 | }); 47 | controller.noise_a.onChange((value) => { 48 | sp_obj.mesh.material.uniforms.noise_a.value = value; 49 | }); 50 | controller.noise_x.onChange((value) => { 51 | sp_obj.mesh.material.uniforms.noise_x.value = value; 52 | }); 53 | controller.noise_y.onChange((value) => { 54 | sp_obj.mesh.material.uniforms.noise_y.value = value; 55 | }); 56 | controller.noise_z.onChange((value) => { 57 | sp_obj.mesh.material.uniforms.noise_z.value = value; 58 | }); 59 | controller.plane_noise_a.onChange((value) => { 60 | sp_obj.mesh.material.uniforms.plane_noise_a.value = value; 61 | }); 62 | controller.plane_noise_y.onChange((value) => { 63 | sp_obj.mesh.material.uniforms.plane_noise_y.value = value; 64 | }); 65 | controller.plane_noise_z.onChange((value) => { 66 | sp_obj.mesh.material.uniforms.plane_noise_z.value = value; 67 | }); 68 | controller.smoothstep_min.onChange((value) => { 69 | sp_obj.mesh.material.uniforms.smoothstep_min.value = value; 70 | }); 71 | controller.smoothstep_max.onChange((value) => { 72 | sp_obj.mesh.material.uniforms.smoothstep_max.value = value; 73 | }); 74 | controller.texture.onChange((value) => { 75 | sp_obj.mesh.material.uniforms.valid_tex.value = (value) ? 1 : 0; 76 | }); 77 | } 78 | const render = () => { 79 | sp_obj.render(clock.getDelta()); 80 | renderer.render(scene, camera); 81 | } 82 | const renderLoop = () => { 83 | render(); 84 | requestAnimationFrame(renderLoop); 85 | } 86 | 87 | const init = () => { 88 | renderer.setSize(window.innerWidth, window.innerHeight); 89 | renderer.setClearColor(0xffffff, 0.0); 90 | camera.position.set(2000, 0, 0); 91 | camera.lookAt(new THREE.Vector3()); 92 | 93 | scene.add(sp_obj.mesh); 94 | 95 | setEvent(); 96 | initDatGui(); 97 | resizeWindow(); 98 | renderLoop(); 99 | } 100 | init(); 101 | -------------------------------------------------------------------------------- /src/js/modules/sphere_plane_object.js: -------------------------------------------------------------------------------- 1 | const glslify = require('glslify'); 2 | 3 | export default class SpherePlaneObject { 4 | constructor() { 5 | this.radius = 250; 6 | this.noise_a = 20; 7 | this.noise_x = 5; 8 | this.noise_y = 5; 9 | this.noise_z = 5; 10 | this.plane_noise_a = 30; 11 | this.plane_noise_z = 1; 12 | this.plane_noise_y = 3; 13 | this.time = 1; 14 | this.smoothstep_min = -1.0; 15 | this.smoothstep_max = 1.0; 16 | this.plane = false; 17 | this.texture = false; 18 | this.uniforms = null; 19 | this.mesh = this.createMesh(); 20 | } 21 | createMesh() { 22 | const plane_geometry = new THREE.PlaneBufferGeometry(4, 4, 64, 64); 23 | const geometry = new THREE.SphereBufferGeometry(1, 64, 64); 24 | geometry.addAttribute('position2', plane_geometry.attributes.position); 25 | geometry.setIndex(plane_geometry.index); 26 | this.uniforms = { 27 | time: { 28 | type: 'f', 29 | value: 0, 30 | }, 31 | ease_time: { 32 | type: 'f', 33 | value: 0, 34 | }, 35 | ease_time_max: { 36 | type: 'f', 37 | value: 1, 38 | }, 39 | radius: { 40 | type: 'f', 41 | value: this.radius, 42 | }, 43 | noise_a: { 44 | type: 'f', 45 | value: this.noise_a, 46 | }, 47 | noise_i: { 48 | type: 'f', 49 | value: this.noise_i, 50 | }, 51 | noise_x: { 52 | type: 'f', 53 | value: this.noise_x, 54 | }, 55 | noise_y: { 56 | type: 'f', 57 | value: this.noise_y, 58 | }, 59 | noise_z: { 60 | type: 'f', 61 | value: this.noise_z 62 | }, 63 | plane_noise_a: { 64 | type: 'f', 65 | value: this.plane_noise_a, 66 | }, 67 | plane_noise_z: { 68 | type: 'f', 69 | value: this.plane_noise_z 70 | }, 71 | plane_noise_y: { 72 | type: 'f', 73 | value: this.plane_noise_y 74 | }, 75 | smoothstep_min: { 76 | type: 'f', 77 | value: this.smoothstep_min 78 | }, 79 | smoothstep_max: { 80 | type: 'f', 81 | value: this.smoothstep_max 82 | }, 83 | texture: { 84 | type: 't', 85 | value: new THREE.TextureLoader().load('img/texture.png') 86 | }, 87 | valid_tex: { 88 | type: 'f', 89 | value: 0 90 | }, 91 | } 92 | return new THREE.Mesh( 93 | geometry, 94 | new THREE.ShaderMaterial({ 95 | uniforms: this.uniforms, 96 | vertexShader: glslify('../../glsl/sphere_plane_object.vs'), 97 | fragmentShader: glslify('../../glsl/sphere_plane_object.fs'), 98 | transparent: true, 99 | shading: THREE.FlatShading, 100 | side: THREE.DoubleSide, 101 | }) 102 | ); 103 | } 104 | render(time) { 105 | this.uniforms.time.value += time * this.time; 106 | if (this.plane) { 107 | if (this.uniforms.ease_time.value < this.uniforms.ease_time_max.value) { 108 | this.uniforms.ease_time.value += time; 109 | } else { 110 | this.uniforms.ease_time.value = this.uniforms.ease_time_max.value; 111 | } 112 | } else { 113 | if (this.uniforms.ease_time.value > 0) { 114 | this.uniforms.ease_time.value -= time; 115 | } else { 116 | this.uniforms.ease_time.value = 0; 117 | } 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/js/vendor/dat.gui.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * dat-gui JavaScript Controller Library 3 | * http://code.google.com/p/dat-gui 4 | * 5 | * Copyright 2011 Data Arts Team, Google Creative Lab 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | */ 13 | var dat=dat||{};dat.gui=dat.gui||{};dat.utils=dat.utils||{};dat.controllers=dat.controllers||{};dat.dom=dat.dom||{};dat.color=dat.color||{};dat.utils.css=function(){return{load:function(f,a){a=a||document;var d=a.createElement("link");d.type="text/css";d.rel="stylesheet";d.href=f;a.getElementsByTagName("head")[0].appendChild(d)},inject:function(f,a){a=a||document;var d=document.createElement("style");d.type="text/css";d.innerHTML=f;a.getElementsByTagName("head")[0].appendChild(d)}}}(); 14 | dat.utils.common=function(){var f=Array.prototype.forEach,a=Array.prototype.slice;return{BREAK:{},extend:function(d){this.each(a.call(arguments,1),function(a){for(var c in a)this.isUndefined(a[c])||(d[c]=a[c])},this);return d},defaults:function(d){this.each(a.call(arguments,1),function(a){for(var c in a)this.isUndefined(d[c])&&(d[c]=a[c])},this);return d},compose:function(){var d=a.call(arguments);return function(){for(var e=a.call(arguments),c=d.length-1;0<=c;c--)e=[d[c].apply(this,e)];return e[0]}}, 15 | each:function(a,e,c){if(a)if(f&&a.forEach&&a.forEach===f)a.forEach(e,c);else if(a.length===a.length+0)for(var b=0,p=a.length;b
this.__max&&(a=this.__max);void 0!==this.__step&&0!=a%this.__step&&(a=Math.round(a/this.__step)*this.__step);return e.superclass.prototype.setValue.call(this,a)},min:function(a){this.__min=a;return this},max:function(a){this.__max=a;return this},step:function(a){this.__impliedStep=this.__step=a;this.__precision=d(a);return this}});return e}(dat.controllers.Controller,dat.utils.common);
29 | dat.controllers.NumberControllerBox=function(f,a,d){var e=function(c,b,f){function q(){var a=parseFloat(n.__input.value);d.isNaN(a)||n.setValue(a)}function l(a){var b=u-a.clientY;n.setValue(n.getValue()+b*n.__impliedStep);u=a.clientY}function r(){a.unbind(window,"mousemove",l);a.unbind(window,"mouseup",r)}this.__truncationSuspended=!1;e.superclass.call(this,c,b,f);var n=this,u;this.__input=document.createElement("input");this.__input.setAttribute("type","text");a.bind(this.__input,"change",q);a.bind(this.__input,
30 | "blur",function(){q();n.__onFinishChange&&n.__onFinishChange.call(n,n.getValue())});a.bind(this.__input,"mousedown",function(b){a.bind(window,"mousemove",l);a.bind(window,"mouseup",r);u=b.clientY});a.bind(this.__input,"keydown",function(a){13===a.keyCode&&(n.__truncationSuspended=!0,this.blur(),n.__truncationSuspended=!1)});this.updateDisplay();this.domElement.appendChild(this.__input)};e.superclass=f;d.extend(e.prototype,f.prototype,{updateDisplay:function(){var a=this.__input,b;if(this.__truncationSuspended)b=
31 | this.getValue();else{b=this.getValue();var d=Math.pow(10,this.__precision);b=Math.round(b*d)/d}a.value=b;return e.superclass.prototype.updateDisplay.call(this)}});return e}(dat.controllers.NumberController,dat.dom.dom,dat.utils.common);
32 | dat.controllers.NumberControllerSlider=function(f,a,d,e,c){function b(a,b,c,e,d){return e+(a-b)/(c-b)*(d-e)}var p=function(c,e,d,f,u){function A(c){c.preventDefault();var e=a.getOffset(k.__background),d=a.getWidth(k.__background);k.setValue(b(c.clientX,e.left,e.left+d,k.__min,k.__max));return!1}function g(){a.unbind(window,"mousemove",A);a.unbind(window,"mouseup",g);k.__onFinishChange&&k.__onFinishChange.call(k,k.getValue())}p.superclass.call(this,c,e,{min:d,max:f,step:u});var k=this;this.__background=
33 | document.createElement("div");this.__foreground=document.createElement("div");a.bind(this.__background,"mousedown",function(b){a.bind(window,"mousemove",A);a.bind(window,"mouseup",g);A(b)});a.addClass(this.__background,"slider");a.addClass(this.__foreground,"slider-fg");this.updateDisplay();this.__background.appendChild(this.__foreground);this.domElement.appendChild(this.__background)};p.superclass=f;p.useDefaultStyles=function(){d.inject(c)};e.extend(p.prototype,f.prototype,{updateDisplay:function(){var a=
34 | (this.getValue()-this.__min)/(this.__max-this.__min);this.__foreground.style.width=100*a+"%";return p.superclass.prototype.updateDisplay.call(this)}});return p}(dat.controllers.NumberController,dat.dom.dom,dat.utils.css,dat.utils.common,"/**\n * dat-gui JavaScript Controller Library\n * http://code.google.com/p/dat-gui\n *\n * Copyright 2011 Data Arts Team, Google Creative Lab\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n */\n\n.slider {\n box-shadow: inset 0 2px 4px rgba(0,0,0,0.15);\n height: 1em;\n border-radius: 1em;\n background-color: #eee;\n padding: 0 0.5em;\n overflow: hidden;\n}\n\n.slider-fg {\n padding: 1px 0 2px 0;\n background-color: #aaa;\n height: 1em;\n margin-left: -0.5em;\n padding-right: 0.5em;\n border-radius: 1em 0 0 1em;\n}\n\n.slider-fg:after {\n display: inline-block;\n border-radius: 1em;\n background-color: #fff;\n border: 1px solid #aaa;\n content: '';\n float: right;\n margin-right: -1em;\n margin-top: -1px;\n height: 0.9em;\n width: 0.9em;\n}");
35 | dat.controllers.FunctionController=function(f,a,d){var e=function(c,b,d){e.superclass.call(this,c,b);var f=this;this.__button=document.createElement("div");this.__button.innerHTML=void 0===d?"Fire":d;a.bind(this.__button,"click",function(a){a.preventDefault();f.fire();return!1});a.addClass(this.__button,"button");this.domElement.appendChild(this.__button)};e.superclass=f;d.extend(e.prototype,f.prototype,{fire:function(){this.__onChange&&this.__onChange.call(this);this.getValue().call(this.object);
36 | this.__onFinishChange&&this.__onFinishChange.call(this,this.getValue())}});return e}(dat.controllers.Controller,dat.dom.dom,dat.utils.common);
37 | dat.controllers.BooleanController=function(f,a,d){var e=function(c,b){e.superclass.call(this,c,b);var d=this;this.__prev=this.getValue();this.__checkbox=document.createElement("input");this.__checkbox.setAttribute("type","checkbox");a.bind(this.__checkbox,"change",function(){d.setValue(!d.__prev)},!1);this.domElement.appendChild(this.__checkbox);this.updateDisplay()};e.superclass=f;d.extend(e.prototype,f.prototype,{setValue:function(a){a=e.superclass.prototype.setValue.call(this,a);this.__onFinishChange&&
38 | this.__onFinishChange.call(this,this.getValue());this.__prev=this.getValue();return a},updateDisplay:function(){!0===this.getValue()?(this.__checkbox.setAttribute("checked","checked"),this.__checkbox.checked=!0):this.__checkbox.checked=!1;return e.superclass.prototype.updateDisplay.call(this)}});return e}(dat.controllers.Controller,dat.dom.dom,dat.utils.common);
39 | dat.color.toString=function(f){return function(a){if(1==a.a||f.isUndefined(a.a)){for(a=a.hex.toString(16);6>a.length;)a="0"+a;return"#"+a}return"rgba("+Math.round(a.r)+","+Math.round(a.g)+","+Math.round(a.b)+","+a.a+")"}}(dat.utils.common);
40 | dat.color.interpret=function(f,a){var d,e,c=[{litmus:a.isString,conversions:{THREE_CHAR_HEX:{read:function(a){a=a.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i);return null===a?!1:{space:"HEX",hex:parseInt("0x"+a[1].toString()+a[1].toString()+a[2].toString()+a[2].toString()+a[3].toString()+a[3].toString())}},write:f},SIX_CHAR_HEX:{read:function(a){a=a.match(/^#([A-F0-9]{6})$/i);return null===a?!1:{space:"HEX",hex:parseInt("0x"+a[1].toString())}},write:f},CSS_RGB:{read:function(a){a=a.match(/^rgb\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/);
41 | return null===a?!1:{space:"RGB",r:parseFloat(a[1]),g:parseFloat(a[2]),b:parseFloat(a[3])}},write:f},CSS_RGBA:{read:function(a){a=a.match(/^rgba\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\,\s*(.+)\s*\)/);return null===a?!1:{space:"RGB",r:parseFloat(a[1]),g:parseFloat(a[2]),b:parseFloat(a[3]),a:parseFloat(a[4])}},write:f}}},{litmus:a.isNumber,conversions:{HEX:{read:function(a){return{space:"HEX",hex:a,conversionName:"HEX"}},write:function(a){return a.hex}}}},{litmus:a.isArray,conversions:{RGB_ARRAY:{read:function(a){return 3!=
42 | a.length?!1:{space:"RGB",r:a[0],g:a[1],b:a[2]}},write:function(a){return[a.r,a.g,a.b]}},RGBA_ARRAY:{read:function(a){return 4!=a.length?!1:{space:"RGB",r:a[0],g:a[1],b:a[2],a:a[3]}},write:function(a){return[a.r,a.g,a.b,a.a]}}}},{litmus:a.isObject,conversions:{RGBA_OBJ:{read:function(b){return a.isNumber(b.r)&&a.isNumber(b.g)&&a.isNumber(b.b)&&a.isNumber(b.a)?{space:"RGB",r:b.r,g:b.g,b:b.b,a:b.a}:!1},write:function(a){return{r:a.r,g:a.g,b:a.b,a:a.a}}},RGB_OBJ:{read:function(b){return a.isNumber(b.r)&&
43 | a.isNumber(b.g)&&a.isNumber(b.b)?{space:"RGB",r:b.r,g:b.g,b:b.b}:!1},write:function(a){return{r:a.r,g:a.g,b:a.b}}},HSVA_OBJ:{read:function(b){return a.isNumber(b.h)&&a.isNumber(b.s)&&a.isNumber(b.v)&&a.isNumber(b.a)?{space:"HSV",h:b.h,s:b.s,v:b.v,a:b.a}:!1},write:function(a){return{h:a.h,s:a.s,v:a.v,a:a.a}}},HSV_OBJ:{read:function(b){return a.isNumber(b.h)&&a.isNumber(b.s)&&a.isNumber(b.v)?{space:"HSV",h:b.h,s:b.s,v:b.v}:!1},write:function(a){return{h:a.h,s:a.s,v:a.v}}}}}];return function(){e=!1;
44 | var b=1GUI
\'s constructor:\n\n \n\n localStorage
on exit.\n\n localStorage
will\n override those passed to dat.GUI
\'s constructor. This makes it\n easier to work incrementally, but localStorage
is fragile,\n and your friends may not see the same values you do.\n \n