├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .postcssrc.js ├── LICENSE ├── README.md ├── Screenshot └── a.jpg ├── build ├── build.js ├── check-versions.js ├── logo.png ├── utils.js ├── vue-loader.conf.js ├── webpack.base.conf.js ├── webpack.dev.conf.js └── webpack.prod.conf.js ├── config ├── dev.env.js ├── index.js ├── prod.env.js └── test.env.js ├── index.html ├── package-lock.json ├── package.json ├── src ├── Produce.vue ├── assets │ ├── attributes-tabs.css │ ├── core │ │ ├── icons.css │ │ └── icons │ │ │ ├── eye.gif │ │ │ ├── geometry.gif │ │ │ ├── image.gif │ │ │ ├── light.gif │ │ │ ├── material.gif │ │ │ ├── mesh.gif │ │ │ ├── model.gif │ │ │ ├── node.gif │ │ │ └── scene.gif │ ├── fonts │ │ └── fontawesome-webfont.woff2 │ ├── logo.png │ ├── materialDefs │ │ ├── GizmoDef │ │ └── HelperUnlitDef │ ├── materialdefs │ │ └── HelperMaterialDef │ ├── shadernodes │ │ ├── controls.css │ │ ├── index.sass │ │ └── shadernodes.css │ ├── textures │ │ └── lightbulb32.png │ └── tools.css ├── components │ ├── Attributes.vue │ ├── HelloWorld.vue │ ├── LeadingPrinciples.vue │ ├── Port.vue │ ├── ShaderNode.vue │ ├── ShadingEdit.vue │ ├── Viewer.vue │ ├── attributes │ │ ├── AttrItem.vue │ │ ├── material │ │ │ └── MaterialProperty.vue │ │ ├── object │ │ │ ├── OBJ_Geometry.vue │ │ │ ├── OBJ_Light.vue │ │ │ ├── OBJ_Node.vue │ │ │ └── OBJ_None.vue │ │ └── renderer │ │ │ └── RendererProperty.vue │ ├── common │ │ ├── BoolComponent.vue │ │ ├── BoolGroupComponent.vue │ │ ├── ColorComponent.vue │ │ ├── CombinationComponent.vue │ │ ├── ImgComponent.vue │ │ ├── NumberComponent.vue │ │ ├── SelectComponent.vue │ │ ├── TransformComponent.vue │ │ ├── VectorColorComponent.vue │ │ └── VectorComponent.vue │ ├── shadernodes │ │ ├── common │ │ │ ├── Color.vue │ │ │ └── TextInput.vue │ │ └── math │ │ │ └── Number.vue │ └── ui │ │ ├── ContextMenu.vue │ │ └── Tree.vue ├── editor │ ├── Arrow.js │ ├── EditorContext.js │ ├── GlobalConfig.js │ ├── attributes │ │ └── object │ │ │ └── ObjNode.js │ ├── command │ │ ├── BaseCommand.js │ │ ├── CommandFactory.js │ │ └── CommandManager.js │ ├── common │ │ ├── LightFactory.js │ │ ├── Material.js │ │ ├── PostFilterFactory.js │ │ └── ShapeFactory.js │ ├── leadingPrinciples │ │ └── LeadingPrinciples.js │ ├── shadernodes │ │ ├── MaterialDefFactory.js │ │ ├── ShaderNode.js │ │ ├── ShaderNodes.js │ │ ├── Sockets.js │ │ ├── common │ │ │ ├── Commons.js │ │ │ ├── IfElseBranchComponent.js │ │ │ └── TransformVector3Component.js │ │ ├── input │ │ │ ├── BoolInputStructureComponent.js │ │ │ ├── FloatInputStructureComponent.js │ │ │ ├── InputAttributeComponent.js │ │ │ ├── InputMatrixComponent.js │ │ │ ├── InputStructureComponent.js │ │ │ ├── Inputs.js │ │ │ ├── IntInputStructureComponent.js │ │ │ ├── Vec2InputStructureComponent.js │ │ │ ├── Vec3InputStructureComponent.js │ │ │ └── Vec4InputStructureComponent.js │ │ ├── math │ │ │ ├── AddComponent.js │ │ │ ├── ConstructVec2Component.js │ │ │ ├── ConstructVec3Component.js │ │ │ ├── ConstructVec4Component.js │ │ │ ├── DivideComponent.js │ │ │ ├── MathComponent.js │ │ │ ├── Maths.js │ │ │ ├── MultiplyComponent.js │ │ │ ├── NumberComponent.js │ │ │ ├── NumberControl.js │ │ │ ├── SubtractComponent.js │ │ │ └── Vec2Splitter.js │ │ ├── output │ │ │ ├── BoolOutputStructureComponent.js │ │ │ ├── FloatOutputStructureComponent.js │ │ │ ├── FragmentShaderOutComponent.js │ │ │ ├── IntOutputStructureComponent.js │ │ │ ├── OutputStructureComponent.js │ │ │ ├── Outputs.js │ │ │ ├── Vec2OutputStructureComponent.js │ │ │ ├── Vec3OutputStructureComponent.js │ │ │ ├── Vec4OutputStructureComponent.js │ │ │ └── VertexShaderOutComponent.js │ │ ├── param │ │ │ ├── BoolParamComponent.js │ │ │ ├── FloatParamComponent.js │ │ │ ├── IntParamComponent.js │ │ │ ├── ParamComponent.js │ │ │ ├── Params.js │ │ │ ├── TextControl.js │ │ │ ├── Texture2DParamComponent.js │ │ │ ├── TextureCubeParamComponent.js │ │ │ ├── Vec2ParamComponent.js │ │ │ ├── Vec3ParamComponent.js │ │ │ └── Vec4ParamComponent.js │ │ └── texture │ │ │ ├── ColorControl.js │ │ │ ├── SamplerTexture2DComponent.js │ │ │ └── Textures.js │ ├── utils │ │ ├── ColorMath.js │ │ ├── ObjControl.js │ │ └── Utils.js │ └── viewer │ │ └── Viewer.js ├── main.js └── router │ ├── index.js │ └── produce.js ├── static ├── .gitkeep ├── MaterialDefinitionSource.html └── heighlight │ ├── default.min.css │ ├── glsl.min.js │ └── highlight.min.js ├── test.html ├── test.txt └── test ├── e2e ├── custom-assertions │ └── elementCount.js ├── nightwatch.conf.js ├── runner.js └── specs │ └── test.js └── unit ├── .eslintrc ├── jest.conf.js ├── setup.js └── specs └── HelloWorld.spec.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false, 5 | "targets": { 6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] 7 | } 8 | }], 9 | "stage-2" 10 | ], 11 | "plugins": ["transform-vue-jsx", "transform-runtime"], 12 | "env": { 13 | "test": { 14 | "presets": ["env", "stage-2"], 15 | "plugins": ["transform-vue-jsx", "transform-es2015-modules-commonjs", "dynamic-import-node"] 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /config/ 3 | /dist/ 4 | /*.js 5 | /test/unit/coverage/ 6 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | // https://eslint.org/docs/user-guide/configuring 2 | 3 | module.exports = { 4 | root: true, 5 | parserOptions: { 6 | parser: 'babel-eslint' 7 | }, 8 | env: { 9 | browser: true, 10 | }, 11 | extends: [ 12 | // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention 13 | // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules. 14 | 'plugin:vue/essential', 15 | // https://github.com/standard/standard/blob/master/docs/RULES-en.md 16 | 'standard' 17 | ], 18 | // required to lint *.vue files 19 | plugins: [ 20 | 'vue' 21 | ], 22 | // add your custom rules here 23 | rules: { 24 | // allow async-await 25 | 'generator-star-spacing': 'off', 26 | // allow debugger during development 27 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | /dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | /test/unit/coverage/ 8 | /test/e2e/reports/ 9 | selenium-debug.log 10 | 11 | # Editor directories and files 12 | .idea 13 | .vscode 14 | *.suo 15 | *.ntvs* 16 | *.njsproj 17 | *.sln 18 | -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | "postcss-import": {}, 6 | "postcss-url": {}, 7 | // to edit target browsers: use "browserslist" field in package.json 8 | "autoprefixer": {} 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # produce 2 | 3 | > Lightweight 3D editor on the web,It uses [Try3d.Js](https://github.com/JohnLKkk/try3d.git) I wrote as renderer. 4 | 5 | ![image](https://github.com/JohnLKkk/Produce/blob/main/Screenshot/a.jpg) 6 | ## Build Setup 7 | 8 | ``` bash 9 | clone project 10 | # serve with hot reload at localhost:8080 11 | npm run dev 12 | ``` 13 | 14 | For questions, please contact me:
15 | email:18402012144@163.com
16 | wechat:18402012144 17 | -------------------------------------------------------------------------------- /Screenshot/a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnLKkk/Produce/c1faed67e6365bb5e35724fe549f9d869a6c5140/Screenshot/a.jpg -------------------------------------------------------------------------------- /build/build.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | require('./check-versions')() 3 | 4 | process.env.NODE_ENV = 'production' 5 | 6 | const ora = require('ora') 7 | const rm = require('rimraf') 8 | const path = require('path') 9 | const chalk = require('chalk') 10 | const webpack = require('webpack') 11 | const config = require('../config') 12 | const webpackConfig = require('./webpack.prod.conf') 13 | 14 | const spinner = ora('building for production...') 15 | spinner.start() 16 | 17 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { 18 | if (err) throw err 19 | webpack(webpackConfig, (err, stats) => { 20 | spinner.stop() 21 | if (err) throw err 22 | process.stdout.write(stats.toString({ 23 | colors: true, 24 | modules: false, 25 | children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build. 26 | chunks: false, 27 | chunkModules: false 28 | }) + '\n\n') 29 | 30 | if (stats.hasErrors()) { 31 | console.log(chalk.red(' Build failed with errors.\n')) 32 | process.exit(1) 33 | } 34 | 35 | console.log(chalk.cyan(' Build complete.\n')) 36 | console.log(chalk.yellow( 37 | ' Tip: built files are meant to be served over an HTTP server.\n' + 38 | ' Opening index.html over file:// won\'t work.\n' 39 | )) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /build/check-versions.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const chalk = require('chalk') 3 | const semver = require('semver') 4 | const packageConfig = require('../package.json') 5 | const shell = require('shelljs') 6 | 7 | function exec (cmd) { 8 | return require('child_process').execSync(cmd).toString().trim() 9 | } 10 | 11 | const versionRequirements = [ 12 | { 13 | name: 'node', 14 | currentVersion: semver.clean(process.version), 15 | versionRequirement: packageConfig.engines.node 16 | } 17 | ] 18 | 19 | if (shell.which('npm')) { 20 | versionRequirements.push({ 21 | name: 'npm', 22 | currentVersion: exec('npm --version'), 23 | versionRequirement: packageConfig.engines.npm 24 | }) 25 | } 26 | 27 | module.exports = function () { 28 | const warnings = [] 29 | 30 | for (let i = 0; i < versionRequirements.length; i++) { 31 | const mod = versionRequirements[i] 32 | 33 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 34 | warnings.push(mod.name + ': ' + 35 | chalk.red(mod.currentVersion) + ' should be ' + 36 | chalk.green(mod.versionRequirement) 37 | ) 38 | } 39 | } 40 | 41 | if (warnings.length) { 42 | console.log('') 43 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 44 | console.log() 45 | 46 | for (let i = 0; i < warnings.length; i++) { 47 | const warning = warnings[i] 48 | console.log(' ' + warning) 49 | } 50 | 51 | console.log() 52 | process.exit(1) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /build/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnLKkk/Produce/c1faed67e6365bb5e35724fe549f9d869a6c5140/build/logo.png -------------------------------------------------------------------------------- /build/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const config = require('../config') 4 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 5 | const packageConfig = require('../package.json') 6 | 7 | exports.assetsPath = function (_path) { 8 | const assetsSubDirectory = process.env.NODE_ENV === 'production' 9 | ? config.build.assetsSubDirectory 10 | : config.dev.assetsSubDirectory 11 | 12 | return path.posix.join(assetsSubDirectory, _path) 13 | } 14 | 15 | exports.cssLoaders = function (options) { 16 | options = options || {} 17 | 18 | const cssLoader = { 19 | loader: 'css-loader', 20 | options: { 21 | sourceMap: options.sourceMap 22 | } 23 | } 24 | 25 | const postcssLoader = { 26 | loader: 'postcss-loader', 27 | options: { 28 | sourceMap: options.sourceMap 29 | } 30 | } 31 | 32 | // generate loader string to be used with extract text plugin 33 | function generateLoaders (loader, loaderOptions) { 34 | const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader] 35 | 36 | if (loader) { 37 | loaders.push({ 38 | loader: loader + '-loader', 39 | options: Object.assign({}, loaderOptions, { 40 | sourceMap: options.sourceMap 41 | }) 42 | }) 43 | } 44 | 45 | // Extract CSS when that option is specified 46 | // (which is the case during production build) 47 | if (options.extract) { 48 | return ExtractTextPlugin.extract({ 49 | use: loaders, 50 | fallback: 'vue-style-loader' 51 | }) 52 | } else { 53 | return ['vue-style-loader'].concat(loaders) 54 | } 55 | } 56 | 57 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html 58 | return { 59 | css: generateLoaders(), 60 | postcss: generateLoaders(), 61 | less: generateLoaders('less'), 62 | sass: generateLoaders('sass', { indentedSyntax: true }), 63 | scss: generateLoaders('sass'), 64 | stylus: generateLoaders('stylus'), 65 | styl: generateLoaders('stylus') 66 | } 67 | } 68 | 69 | // Generate loaders for standalone style files (outside of .vue) 70 | exports.styleLoaders = function (options) { 71 | const output = [] 72 | const loaders = exports.cssLoaders(options) 73 | 74 | for (const extension in loaders) { 75 | const loader = loaders[extension] 76 | output.push({ 77 | test: new RegExp('\\.' + extension + '$'), 78 | use: loader 79 | }) 80 | } 81 | 82 | return output 83 | } 84 | 85 | exports.createNotifierCallback = () => { 86 | const notifier = require('node-notifier') 87 | 88 | return (severity, errors) => { 89 | if (severity !== 'error') return 90 | 91 | const error = errors[0] 92 | const filename = error.file && error.file.split('!').pop() 93 | 94 | notifier.notify({ 95 | title: packageConfig.name, 96 | message: severity + ': ' + error.name, 97 | subtitle: filename || '', 98 | icon: path.join(__dirname, 'logo.png') 99 | }) 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const config = require('../config') 4 | const isProduction = process.env.NODE_ENV === 'production' 5 | const sourceMapEnabled = isProduction 6 | ? config.build.productionSourceMap 7 | : config.dev.cssSourceMap 8 | 9 | module.exports = { 10 | loaders: utils.cssLoaders({ 11 | sourceMap: sourceMapEnabled, 12 | extract: isProduction 13 | }), 14 | cssSourceMap: sourceMapEnabled, 15 | cacheBusting: config.dev.cacheBusting, 16 | transformToRequire: { 17 | video: ['src', 'poster'], 18 | source: 'src', 19 | img: 'src', 20 | image: 'xlink:href' 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const config = require('../config') 5 | const vueLoaderConfig = require('./vue-loader.conf') 6 | 7 | function resolve (dir) { 8 | return path.join(__dirname, '..', dir) 9 | } 10 | 11 | const createLintingRule = () => ({ 12 | test: /\.(js|vue)$/, 13 | loader: 'eslint-loader', 14 | enforce: 'pre', 15 | include: [resolve('src'), resolve('test')], 16 | options: { 17 | formatter: require('eslint-friendly-formatter'), 18 | emitWarning: !config.dev.showEslintErrorsInOverlay 19 | } 20 | }) 21 | 22 | module.exports = { 23 | context: path.resolve(__dirname, '../'), 24 | entry: { 25 | app: './src/main.js' 26 | }, 27 | output: { 28 | path: config.build.assetsRoot, 29 | filename: '[name].js', 30 | publicPath: process.env.NODE_ENV === 'production' 31 | ? config.build.assetsPublicPath 32 | : config.dev.assetsPublicPath 33 | }, 34 | resolve: { 35 | extensions: ['.js', '.vue', '.json'], 36 | alias: { 37 | 'vue$': 'vue/dist/vue.esm.js', 38 | '@': resolve('src'), 39 | } 40 | }, 41 | module: { 42 | rules: [ 43 | // ...(config.dev.useEslint ? [createLintingRule()] : []), 44 | { 45 | test: /\.vue$/, 46 | loader: 'vue-loader', 47 | options: vueLoaderConfig 48 | }, 49 | { 50 | test: /\.js$/, 51 | loader: 'babel-loader', 52 | include: [resolve('src'), resolve('test'), resolve('node_modules/try3d/src'), resolve('node_modules/webpack-dev-server/client')] 53 | }, 54 | { 55 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 56 | loader: 'url-loader', 57 | options: { 58 | limit: 10000, 59 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 60 | } 61 | }, 62 | { 63 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 64 | loader: 'url-loader', 65 | options: { 66 | limit: 10000, 67 | name: utils.assetsPath('media/[name].[hash:7].[ext]') 68 | } 69 | }, 70 | { 71 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 72 | loader: 'url-loader', 73 | options: { 74 | limit: 10000, 75 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 76 | } 77 | } 78 | ] 79 | }, 80 | node: { 81 | // prevent webpack from injecting useless setImmediate polyfill because Vue 82 | // source contains it (although only uses it if it's native). 83 | setImmediate: false, 84 | // prevent webpack from injecting mocks to Node native modules 85 | // that does not make sense for the client 86 | dgram: 'empty', 87 | fs: 'empty', 88 | net: 'empty', 89 | tls: 'empty', 90 | child_process: 'empty' 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const webpack = require('webpack') 4 | const config = require('../config') 5 | const merge = require('webpack-merge') 6 | const path = require('path') 7 | const baseWebpackConfig = require('./webpack.base.conf') 8 | const CopyWebpackPlugin = require('copy-webpack-plugin') 9 | const HtmlWebpackPlugin = require('html-webpack-plugin') 10 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 11 | const portfinder = require('portfinder') 12 | 13 | const HOST = process.env.HOST 14 | const PORT = process.env.PORT && Number(process.env.PORT) 15 | 16 | const devWebpackConfig = merge(baseWebpackConfig, { 17 | module: { 18 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true }) 19 | }, 20 | // cheap-module-eval-source-map is faster for development 21 | devtool: config.dev.devtool, 22 | 23 | // these devServer options should be customized in /config/index.js 24 | devServer: { 25 | clientLogLevel: 'warning', 26 | historyApiFallback: { 27 | rewrites: [ 28 | { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') }, 29 | ], 30 | }, 31 | hot: true, 32 | contentBase: false, // since we use CopyWebpackPlugin. 33 | compress: true, 34 | host: HOST || config.dev.host, 35 | port: PORT || config.dev.port, 36 | open: config.dev.autoOpenBrowser, 37 | overlay: config.dev.errorOverlay 38 | ? { warnings: false, errors: true } 39 | : false, 40 | publicPath: config.dev.assetsPublicPath, 41 | proxy: config.dev.proxyTable, 42 | quiet: true, // necessary for FriendlyErrorsPlugin 43 | watchOptions: { 44 | poll: config.dev.poll, 45 | } 46 | }, 47 | plugins: [ 48 | new webpack.DefinePlugin({ 49 | 'process.env': require('../config/dev.env') 50 | }), 51 | new webpack.HotModuleReplacementPlugin(), 52 | new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update. 53 | new webpack.NoEmitOnErrorsPlugin(), 54 | // https://github.com/ampedandwired/html-webpack-plugin 55 | new HtmlWebpackPlugin({ 56 | filename: 'index.html', 57 | template: 'index.html', 58 | inject: true 59 | }), 60 | // copy custom static assets 61 | new CopyWebpackPlugin([ 62 | { 63 | from: path.resolve(__dirname, '../static'), 64 | to: config.dev.assetsSubDirectory, 65 | ignore: ['.*'] 66 | } 67 | ]) 68 | ] 69 | }) 70 | 71 | module.exports = new Promise((resolve, reject) => { 72 | portfinder.basePort = process.env.PORT || config.dev.port 73 | portfinder.getPort((err, port) => { 74 | if (err) { 75 | reject(err) 76 | } else { 77 | // publish the new Port, necessary for e2e tests 78 | process.env.PORT = port 79 | // add port to devServer config 80 | devWebpackConfig.devServer.port = port 81 | 82 | // Add FriendlyErrorsPlugin 83 | devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({ 84 | compilationSuccessInfo: { 85 | messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`], 86 | }, 87 | onErrors: config.dev.notifyOnErrors 88 | ? utils.createNotifierCallback() 89 | : undefined 90 | })) 91 | 92 | resolve(devWebpackConfig) 93 | } 94 | }) 95 | }) 96 | -------------------------------------------------------------------------------- /build/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const webpack = require('webpack') 5 | const config = require('../config') 6 | const merge = require('webpack-merge') 7 | const baseWebpackConfig = require('./webpack.base.conf') 8 | const CopyWebpackPlugin = require('copy-webpack-plugin') 9 | const HtmlWebpackPlugin = require('html-webpack-plugin') 10 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 11 | const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') 12 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin') 13 | 14 | const env = process.env.NODE_ENV === 'testing' 15 | ? require('../config/test.env') 16 | : require('../config/prod.env') 17 | 18 | const webpackConfig = merge(baseWebpackConfig, { 19 | module: { 20 | rules: utils.styleLoaders({ 21 | sourceMap: config.build.productionSourceMap, 22 | extract: true, 23 | usePostCSS: true 24 | }) 25 | }, 26 | devtool: config.build.productionSourceMap ? config.build.devtool : false, 27 | output: { 28 | path: config.build.assetsRoot, 29 | filename: utils.assetsPath('js/[name].[chunkhash].js'), 30 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 31 | }, 32 | plugins: [ 33 | // http://vuejs.github.io/vue-loader/en/workflow/production.html 34 | new webpack.DefinePlugin({ 35 | 'process.env': env 36 | }), 37 | new UglifyJsPlugin({ 38 | uglifyOptions: { 39 | compress: { 40 | warnings: false 41 | } 42 | }, 43 | sourceMap: config.build.productionSourceMap, 44 | parallel: true 45 | }), 46 | // extract css into its own file 47 | new ExtractTextPlugin({ 48 | filename: utils.assetsPath('css/[name].[contenthash].css'), 49 | // Setting the following option to `false` will not extract CSS from codesplit chunks. 50 | // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack. 51 | // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`, 52 | // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110 53 | allChunks: true, 54 | }), 55 | // Compress extracted CSS. We are using this plugin so that possible 56 | // duplicated CSS from different components can be deduped. 57 | new OptimizeCSSPlugin({ 58 | cssProcessorOptions: config.build.productionSourceMap 59 | ? { safe: true, map: { inline: false } } 60 | : { safe: true } 61 | }), 62 | // generate dist index.html with correct asset hash for caching. 63 | // you can customize output by editing /index.html 64 | // see https://github.com/ampedandwired/html-webpack-plugin 65 | new HtmlWebpackPlugin({ 66 | filename: process.env.NODE_ENV === 'testing' 67 | ? 'index.html' 68 | : config.build.index, 69 | template: 'index.html', 70 | inject: true, 71 | minify: { 72 | removeComments: true, 73 | collapseWhitespace: true, 74 | removeAttributeQuotes: true 75 | // more options: 76 | // https://github.com/kangax/html-minifier#options-quick-reference 77 | }, 78 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 79 | chunksSortMode: 'dependency' 80 | }), 81 | // keep module.id stable when vendor modules does not change 82 | new webpack.HashedModuleIdsPlugin(), 83 | // enable scope hoisting 84 | new webpack.optimize.ModuleConcatenationPlugin(), 85 | // split vendor js into its own file 86 | new webpack.optimize.CommonsChunkPlugin({ 87 | name: 'vendor', 88 | minChunks (module) { 89 | // any required modules inside node_modules are extracted to vendor 90 | return ( 91 | module.resource && 92 | /\.js$/.test(module.resource) && 93 | module.resource.indexOf( 94 | path.join(__dirname, '../node_modules') 95 | ) === 0 96 | ) 97 | } 98 | }), 99 | // extract webpack runtime and module manifest to its own file in order to 100 | // prevent vendor hash from being updated whenever app bundle is updated 101 | new webpack.optimize.CommonsChunkPlugin({ 102 | name: 'manifest', 103 | minChunks: Infinity 104 | }), 105 | // This instance extracts shared chunks from code splitted chunks and bundles them 106 | // in a separate chunk, similar to the vendor chunk 107 | // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk 108 | new webpack.optimize.CommonsChunkPlugin({ 109 | name: 'app', 110 | async: 'vendor-async', 111 | children: true, 112 | minChunks: 3 113 | }), 114 | 115 | // copy custom static assets 116 | new CopyWebpackPlugin([ 117 | { 118 | from: path.resolve(__dirname, '../static'), 119 | to: config.build.assetsSubDirectory, 120 | ignore: ['.*'] 121 | } 122 | ]) 123 | ] 124 | }) 125 | 126 | if (config.build.productionGzip) { 127 | const CompressionWebpackPlugin = require('compression-webpack-plugin') 128 | 129 | webpackConfig.plugins.push( 130 | new CompressionWebpackPlugin({ 131 | asset: '[path].gz[query]', 132 | algorithm: 'gzip', 133 | test: new RegExp( 134 | '\\.(' + 135 | config.build.productionGzipExtensions.join('|') + 136 | ')$' 137 | ), 138 | threshold: 10240, 139 | minRatio: 0.8 140 | }) 141 | ) 142 | } 143 | 144 | if (config.build.bundleAnalyzerReport) { 145 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin 146 | webpackConfig.plugins.push(new BundleAnalyzerPlugin()) 147 | } 148 | 149 | module.exports = webpackConfig 150 | -------------------------------------------------------------------------------- /config/dev.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const prodEnv = require('./prod.env') 4 | 5 | module.exports = merge(prodEnv, { 6 | NODE_ENV: '"development"' 7 | }) 8 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // Template version: 1.3.1 3 | // see http://vuejs-templates.github.io/webpack for documentation. 4 | 5 | const path = require('path') 6 | 7 | module.exports = { 8 | dev: { 9 | 10 | // Paths 11 | assetsSubDirectory: 'static', 12 | assetsPublicPath: '/', 13 | proxyTable: {}, 14 | 15 | // Various Dev Server settings 16 | host: 'localhost', // can be overwritten by process.env.HOST 17 | port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined 18 | autoOpenBrowser: false, 19 | errorOverlay: true, 20 | notifyOnErrors: true, 21 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- 22 | 23 | // Use Eslint Loader? 24 | // If true, your code will be linted during bundling and 25 | // linting errors and warnings will be shown in the console. 26 | useEslint: true, 27 | // If true, eslint errors and warnings will also be shown in the error overlay 28 | // in the browser. 29 | showEslintErrorsInOverlay: false, 30 | 31 | /** 32 | * Source Maps 33 | */ 34 | 35 | // https://webpack.js.org/configuration/devtool/#development 36 | devtool: 'cheap-module-eval-source-map', 37 | 38 | // If you have problems debugging vue-files in devtools, 39 | // set this to false - it *may* help 40 | // https://vue-loader.vuejs.org/en/options.html#cachebusting 41 | cacheBusting: true, 42 | 43 | cssSourceMap: true 44 | }, 45 | 46 | build: { 47 | // Template for index.html 48 | index: path.resolve(__dirname, '../dist/index.html'), 49 | 50 | // Paths 51 | assetsRoot: path.resolve(__dirname, '../dist'), 52 | assetsSubDirectory: 'static', 53 | assetsPublicPath: '/', 54 | 55 | /** 56 | * Source Maps 57 | */ 58 | 59 | productionSourceMap: true, 60 | // https://webpack.js.org/configuration/devtool/#production 61 | devtool: '#source-map', 62 | 63 | // Gzip off by default as many popular static hosts such as 64 | // Surge or Netlify already gzip all static assets for you. 65 | // Before setting to `true`, make sure to: 66 | // npm install --save-dev compression-webpack-plugin 67 | productionGzip: false, 68 | productionGzipExtensions: ['js', 'css'], 69 | 70 | // Run the build command with an extra argument to 71 | // View the bundle analyzer report after build finishes: 72 | // `npm run build --report` 73 | // Set to `true` or `false` to always turn it on or off 74 | bundleAnalyzerReport: process.env.npm_config_report 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /config/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | NODE_ENV: '"production"' 4 | } 5 | -------------------------------------------------------------------------------- /config/test.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const devEnv = require('./dev.env') 4 | 5 | module.exports = merge(devEnv, { 6 | NODE_ENV: '"testing"' 7 | }) 8 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | produce 7 | 8 | 9 |
10 | 11 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "produce", 3 | "version": "1.0.0", 4 | "description": "Effects editor on the web ", 5 | "author": "JhonKkk <1724624287@qq.com>", 6 | "private": true, 7 | "scripts": { 8 | "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", 9 | "start": "npm run dev", 10 | "unit": "jest --config test/unit/jest.conf.js --coverage", 11 | "e2e": "node test/e2e/runner.js", 12 | "test": "npm run unit && npm run e2e", 13 | "lint": "eslint --ext .js,.vue src test/unit test/e2e/specs", 14 | "build": "node build/build.js" 15 | }, 16 | "dependencies": { 17 | "@babel/polyfill": "^7.12.1", 18 | "@hscmap/vue-menu": "^2.10.1", 19 | "element": "^0.1.4", 20 | "element-resize-detector": "^1.2.4", 21 | "rete": "^1.2.2", 22 | "rete-area-plugin": "^0.2.1", 23 | "rete-connection-plugin": "^0.2.2", 24 | "rete-context-menu-plugin": "^0.5.2", 25 | "rete-history-plugin": "^0.2.2", 26 | "rete-task-plugin": "^0.2.2", 27 | "rete-vue-render-plugin": "^0.2.2", 28 | "splitpanes": "^2.3.8", 29 | "vcolorpicker": "^1.1.0", 30 | "vue": "^2.5.2", 31 | "vue-contextmenu": "^1.5.11", 32 | "vue-dialog-drag": "^0.1.29", 33 | "vue-drag-resize": "^1.5.4", 34 | "vue-jstree": "^2.1.6", 35 | "vue-nav-tabs": "^0.5.7", 36 | "vue-router": "^3.0.1" 37 | }, 38 | "devDependencies": { 39 | "autoprefixer": "^7.1.2", 40 | "babel-core": "^6.22.1", 41 | "babel-eslint": "^8.2.1", 42 | "babel-helper-vue-jsx-merge-props": "^2.0.3", 43 | "babel-jest": "^21.0.2", 44 | "babel-loader": "^7.1.1", 45 | "babel-plugin-dynamic-import-node": "^1.2.0", 46 | "babel-plugin-syntax-jsx": "^6.18.0", 47 | "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0", 48 | "babel-plugin-transform-runtime": "^6.22.0", 49 | "babel-plugin-transform-vue-jsx": "^3.5.0", 50 | "babel-preset-env": "^1.3.2", 51 | "babel-preset-stage-2": "^6.22.0", 52 | "babel-register": "^6.22.0", 53 | "chalk": "^2.0.1", 54 | "chromedriver": "^2.27.2", 55 | "copy-webpack-plugin": "^4.0.1", 56 | "cross-spawn": "^5.0.1", 57 | "css-loader": "^0.28.0", 58 | "eslint": "^4.15.0", 59 | "eslint-config-standard": "^10.2.1", 60 | "eslint-friendly-formatter": "^3.0.0", 61 | "eslint-loader": "^1.7.1", 62 | "eslint-plugin-import": "^2.7.0", 63 | "eslint-plugin-node": "^5.2.0", 64 | "eslint-plugin-promise": "^3.4.0", 65 | "eslint-plugin-standard": "^3.0.1", 66 | "eslint-plugin-vue": "^4.0.0", 67 | "extract-text-webpack-plugin": "^3.0.0", 68 | "file-loader": "^1.1.4", 69 | "friendly-errors-webpack-plugin": "^1.6.1", 70 | "html-webpack-plugin": "^2.30.1", 71 | "jest": "^22.0.4", 72 | "jest-serializer-vue": "^0.3.0", 73 | "nightwatch": "^0.9.12", 74 | "node-notifier": "^5.1.2", 75 | "optimize-css-assets-webpack-plugin": "^3.2.0", 76 | "ora": "^1.2.0", 77 | "portfinder": "^1.0.13", 78 | "postcss-import": "^11.0.0", 79 | "postcss-loader": "^2.0.8", 80 | "postcss-url": "^7.2.1", 81 | "rimraf": "^2.6.0", 82 | "selenium-server": "^3.0.1", 83 | "semver": "^5.3.0", 84 | "shelljs": "^0.7.6", 85 | "try3d": "^0.4.3", 86 | "uglifyjs-webpack-plugin": "^1.1.1", 87 | "url-loader": "^0.5.8", 88 | "vue-jest": "^1.0.2", 89 | "vue-loader": "^13.3.0", 90 | "vue-style-loader": "^3.0.1", 91 | "vue-template-compiler": "^2.5.2", 92 | "webpack": "^3.6.0", 93 | "webpack-bundle-analyzer": "^2.9.0", 94 | "webpack-dev-server": "^2.9.1", 95 | "webpack-merge": "^4.1.0" 96 | }, 97 | "engines": { 98 | "node": ">= 6.0.0", 99 | "npm": ">= 3.0.0" 100 | }, 101 | "browserslist": [ 102 | "> 1%", 103 | "last 2 versions", 104 | "not ie <= 8" 105 | ] 106 | } 107 | -------------------------------------------------------------------------------- /src/Produce.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 42 | 43 | 54 | -------------------------------------------------------------------------------- /src/assets/attributes-tabs.css: -------------------------------------------------------------------------------- 1 | .vue-tabs.stacked { 2 | display: flex; } 3 | 4 | .vue-tabs .tabs__link { 5 | text-decoration: none; 6 | color: gray; } 7 | 8 | .vue-tabs .nav { 9 | margin-bottom: 0; 10 | margin-top: 0; 11 | padding-left: 0; 12 | list-style: none; } 13 | .vue-tabs .nav:before, .vue-tabs .nav:after { 14 | content: " "; 15 | display: table; } 16 | .vue-tabs .nav:after { 17 | clear: both; } 18 | .vue-tabs .nav > li { 19 | position: relative; 20 | display: block; } 21 | .vue-tabs .nav > li > a { 22 | position: relative; 23 | display: block; 24 | margin: 5px 0px 5px 5px; 25 | padding: 5px; } 26 | .vue-tabs .nav > li > a:hover, .vue-tabs .nav > li > a:focus { 27 | text-decoration: none; 28 | background-color: #282828; } 29 | .vue-tabs .nav > li span.title { 30 | display: flex; 31 | justify-content: center; } 32 | .vue-tabs .nav > li.disabled > a { 33 | color: #777777; } 34 | .vue-tabs .nav > li.disabled > a:hover, .vue-tabs .nav > li.disabled > a:focus { 35 | color: #777777; 36 | text-decoration: none; 37 | cursor: not-allowed; 38 | background-color: transparent; 39 | border-color: transparent; } 40 | .vue-tabs .nav .nav-divider { 41 | height: 1px; 42 | margin: 9px 0; 43 | overflow: hidden; 44 | background-color: #e5e5e5; } 45 | .vue-tabs .nav > li > a > img { 46 | max-width: none; } 47 | 48 | .vue-tabs .nav-tabs { 49 | border-bottom: 1px solid #ddd; } 50 | .vue-tabs .nav-tabs > li { 51 | float: left; 52 | margin-bottom: -1px; } 53 | .vue-tabs .nav-tabs > li > a { 54 | margin-right: 2px; 55 | line-height: 1.42857; 56 | border: 1px solid transparent; 57 | border-radius: 4px 4px 0 0; } 58 | .vue-tabs .nav-tabs > li > a:hover { 59 | border-color: #eeeeee #eeeeee #ddd; } 60 | .vue-tabs .nav-tabs > li.active > a, .vue-tabs .nav-tabs > li.active > a:hover, .vue-tabs .nav-tabs > li.active > a:focus { 61 | color: #555555; 62 | background-color: #fff; 63 | border: 1px solid #ddd; 64 | border-bottom-color: transparent; 65 | cursor: default; } 66 | 67 | .vue-tabs .nav-pills > li { 68 | float: left; } 69 | .vue-tabs .nav-pills > li > a { 70 | border-radius: 4px 0px 0px 4px; } 71 | .vue-tabs .nav-pills > li + li { 72 | margin-left: 2px; } 73 | .vue-tabs .nav-pills > li.active > a, .vue-tabs .nav-pills > li.active > a:hover, .vue-tabs .nav-pills > li.active > a:focus { 74 | color: #fff; 75 | background-color: #337ab7; } 76 | 77 | .vue-tabs .nav-stacked > li { 78 | float: none; } 79 | .vue-tabs .nav-stacked > li + li { 80 | margin-top: 2px; 81 | margin-left: 0; } 82 | 83 | .vue-tabs .nav-justified, .vue-tabs .nav-tabs.nav-justified { 84 | width: 100%; } 85 | .vue-tabs .nav-justified > li, .vue-tabs .nav-tabs.nav-justified > li { 86 | float: none; } 87 | .vue-tabs .nav-justified > li > a, .vue-tabs .nav-tabs.nav-justified > li > a { 88 | text-align: center; 89 | margin-bottom: 5px; } 90 | .vue-tabs .nav-justified > .dropdown .dropdown-menu { 91 | top: auto; 92 | left: auto; } 93 | @media (min-width: 768px) { 94 | .vue-tabs .nav-justified > li, .vue-tabs .nav-tabs.nav-justified > li { 95 | display: table-cell; 96 | width: 1%; } 97 | .vue-tabs .nav-justified > li > a, .vue-tabs .nav-tabs.nav-justified > li > a { 98 | margin-bottom: 0; } } 99 | 100 | .vue-tabs .nav-tabs-justified, .vue-tabs .nav-tabs.nav-justified { 101 | border-bottom: 0; } 102 | .vue-tabs .nav-tabs-justified > li > a, .vue-tabs .nav-tabs.nav-justified > li > a { 103 | margin-right: 0; 104 | border-radius: 4px; } 105 | .vue-tabs .nav-tabs-justified > .active > a, .vue-tabs .nav-tabs.nav-justified > .active > a, 106 | .vue-tabs .nav-tabs-justified > .active > a:hover, .vue-tabs .nav-tabs.nav-justified > .active > a:hover, 107 | .vue-tabs .nav-tabs-justified > .active > a:focus, .vue-tabs .nav-tabs.nav-justified > .active > a:focus { 108 | border: 1px solid #ddd; } 109 | @media (min-width: 768px) { 110 | .vue-tabs .nav-tabs-justified > li > a, .vue-tabs .nav-tabs.nav-justified > li > a { 111 | border-bottom: 1px solid #ddd; 112 | border-radius: 4px 4px 0 0; } 113 | .vue-tabs .nav-tabs-justified > .active > a, .vue-tabs .nav-tabs.nav-justified > .active > a, 114 | .vue-tabs .nav-tabs-justified > .active > a:hover, .vue-tabs .nav-tabs.nav-justified > .active > a:hover, 115 | .vue-tabs .nav-tabs-justified > .active > a:focus, .vue-tabs .nav-tabs.nav-justified > .active > a:focus { 116 | border-bottom-color: #fff; } } 117 | 118 | .vue-tabs .tab-content > .tab-pane { 119 | display: none; } 120 | 121 | .vue-tabs .tab-content > .active { 122 | display: block; } 123 | 124 | .vue-tabs section[aria-hidden="true"] { 125 | display: none; } 126 | .right-text-tabs{ 127 | min-width: 100%; 128 | min-height: 100%; 129 | } 130 | -------------------------------------------------------------------------------- /src/assets/core/icons/eye.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnLKkk/Produce/c1faed67e6365bb5e35724fe549f9d869a6c5140/src/assets/core/icons/eye.gif -------------------------------------------------------------------------------- /src/assets/core/icons/geometry.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnLKkk/Produce/c1faed67e6365bb5e35724fe549f9d869a6c5140/src/assets/core/icons/geometry.gif -------------------------------------------------------------------------------- /src/assets/core/icons/image.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnLKkk/Produce/c1faed67e6365bb5e35724fe549f9d869a6c5140/src/assets/core/icons/image.gif -------------------------------------------------------------------------------- /src/assets/core/icons/light.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnLKkk/Produce/c1faed67e6365bb5e35724fe549f9d869a6c5140/src/assets/core/icons/light.gif -------------------------------------------------------------------------------- /src/assets/core/icons/material.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnLKkk/Produce/c1faed67e6365bb5e35724fe549f9d869a6c5140/src/assets/core/icons/material.gif -------------------------------------------------------------------------------- /src/assets/core/icons/mesh.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnLKkk/Produce/c1faed67e6365bb5e35724fe549f9d869a6c5140/src/assets/core/icons/mesh.gif -------------------------------------------------------------------------------- /src/assets/core/icons/model.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnLKkk/Produce/c1faed67e6365bb5e35724fe549f9d869a6c5140/src/assets/core/icons/model.gif -------------------------------------------------------------------------------- /src/assets/core/icons/node.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnLKkk/Produce/c1faed67e6365bb5e35724fe549f9d869a6c5140/src/assets/core/icons/node.gif -------------------------------------------------------------------------------- /src/assets/core/icons/scene.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnLKkk/Produce/c1faed67e6365bb5e35724fe549f9d869a6c5140/src/assets/core/icons/scene.gif -------------------------------------------------------------------------------- /src/assets/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnLKkk/Produce/c1faed67e6365bb5e35724fe549f9d869a6c5140/src/assets/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnLKkk/Produce/c1faed67e6365bb5e35724fe549f9d869a6c5140/src/assets/logo.png -------------------------------------------------------------------------------- /src/assets/materialDefs/GizmoDef: -------------------------------------------------------------------------------- 1 | // 用于3D视图编辑器中的ObjControl操作 2 | Def GizmoDef{ 3 | Params{ 4 | vec4 color; 5 | vec4 highlightColor; 6 | sampler2D colorMap; 7 | float alphaDiscard; 8 | } 9 | SubTechnology NormPass{ 10 | Vars{ 11 | vec4 wordPosition; 12 | vec2 uv0; 13 | } 14 | Vs_Shader{ 15 | void main(){ 16 | Context.OutPosition = Context.ProjectMatrix * Context.ViewMatrix * Context.ModelMatrix * vec4(Context.InPosition, 1.0f); 17 | uv0 = Context.InUv0; 18 | } 19 | } 20 | Fs_Shader{ 21 | void main(){ 22 | Context.OutColor = vec4(1.0f); 23 | // 使用自定义颜色输出 24 | #ifdef Params.color 25 | Context.OutColor *= Params.color; 26 | #endif 27 | #ifdef Params.colorMap 28 | Context.OutColor *= texture(Params.colorMap, uv0); 29 | #endif 30 | #ifdef Params.alphaDiscard 31 | if(Context.OutColor.a < Params.alphaDiscard){ 32 | discard; 33 | } 34 | #endif 35 | // 高亮 36 | #ifdef Params.highlightColor 37 | Context.OutColor = mix(Context.OutColor, Params.highlightColor, 0.85f); 38 | #endif 39 | } 40 | } 41 | } 42 | Technology{ 43 | Sub_Pass{ 44 | Pass NormPass{ 45 | DepthTest Off; 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/assets/materialDefs/HelperUnlitDef: -------------------------------------------------------------------------------- 1 | // 颜色材质,提供指定颜色或颜色纹理并渲染 2 | Def HelperUnlitDef{ 3 | Params{ 4 | vec4 color; 5 | sampler2D colorMap; 6 | float alphaDiscard; 7 | } 8 | SubTechnology ColorPass{ 9 | Vars{ 10 | vec4 wordPosition; 11 | vec2 uv0; 12 | } 13 | Vs_Shader{ 14 | void main(){ 15 | //Context.OutPosition = Context.ProjectViewModelMatrix * vec4(Context.InPosition, 1.0f); 16 | Context.OutPosition = Context.ProjectMatrix * Context.ViewMatrix * Context.ModelMatrix * vec4(Context.InPosition, 1.0f); 17 | wordPosition = Context.OutPosition; 18 | uv0 = Context.InUv0; 19 | } 20 | } 21 | Fs_Shader{ 22 | void main(){ 23 | Context.OutColor = vec4(1.0f); 24 | // 使用自定义颜色输出 25 | #ifdef Params.color 26 | Context.OutColor *= Params.color; 27 | #endif 28 | 29 | // 使用纹理 30 | #ifdef Params.colorMap 31 | Context.OutColor *= texture(Params.colorMap, uv0); 32 | #endif 33 | 34 | #ifdef Params.alphaDiscard 35 | if(Context.OutColor.a < Params.alphaDiscard){ 36 | discard; 37 | } 38 | #endif 39 | } 40 | } 41 | } 42 | Technology{ 43 | Sub_Pass{ 44 | Pass ColorPass{ 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/assets/materialdefs/HelperMaterialDef: -------------------------------------------------------------------------------- 1 | // 用于编辑器辅助工具材质定义 2 | Def HelperMaterialDef{ 3 | Params{ 4 | vec4 color; 5 | sampler2D colorMap; 6 | float alphaDiscard; 7 | } 8 | SubTechnology ScalePass{ 9 | Vars{ 10 | vec4 wordPosition; 11 | } 12 | Vs_Shader{ 13 | void main(){ 14 | //Context.OutPosition = Context.ProjectViewModelMatrix * vec4(Context.InPosition, 1.0f); 15 | mat4 scaleMat4 = mat4( 16 | 0.2f, 0.0f, 0.0f, 0.0f, 17 | 0.0f, 0.2f, 0.0f, 0.0f, 18 | 0.0f, 0.0f, 0.2f, 0.0f, 19 | 0.0f, 0.0f, 0.0f, 1.0f 20 | ); 21 | Context.OutPosition = Context.ProjectMatrix * Context.ViewMatrix * Context.ModelMatrix * vec4(Context.InPosition, 1.0f); 22 | wordPosition = Context.OutPosition; 23 | } 24 | } 25 | Fs_Shader{ 26 | void main(){ 27 | // 使用自定义颜色输出 28 | #ifdef Params.color 29 | Context.OutColor = Params.color; 30 | #else 31 | // 使用纹理 32 | #ifdef Params.colorMap 33 | Context.OutColor = texture(Params.colorMap, Context.InUv0); 34 | #ifdef Params.alphaDiscard 35 | if(Context.OutColor.a < Params.alphaDiscard){ 36 | discard; 37 | } 38 | #endif 39 | #else 40 | Context.OutColor = vec4(1.0f, 1.0f, 0.0f, 1.0f); 41 | #endif 42 | #endif 43 | vec4 wPosition = wordPosition; 44 | } 45 | } 46 | } 47 | SubTechnology ColorPass{ 48 | Vars{ 49 | vec4 wordPosition; 50 | vec2 uv0; 51 | } 52 | Vs_Shader{ 53 | void main(){ 54 | //Context.OutPosition = Context.ProjectViewModelMatrix * vec4(Context.InPosition, 1.0f); 55 | Context.OutPosition = Context.ProjectMatrix * Context.ViewMatrix * Context.ModelMatrix * vec4(Context.InPosition, 1.0f); 56 | wordPosition = Context.OutPosition; 57 | uv0 = Context.InUv0; 58 | } 59 | } 60 | Fs_Shader{ 61 | void main(){ 62 | // 使用自定义颜色输出 63 | #ifdef Params.color 64 | Context.OutColor = Params.color; 65 | #else 66 | // 使用纹理 67 | #ifdef Params.colorMap 68 | Context.OutColor = texture(Params.colorMap, uv0); 69 | #ifdef Params.alphaDiscard 70 | if(Context.OutColor.a < Params.alphaDiscard){ 71 | discard; 72 | } 73 | #endif 74 | #else 75 | Context.OutColor = vec4(1.0f, 1.0f, 1.0f, 1.0f); 76 | #endif 77 | #endif 78 | } 79 | } 80 | } 81 | Technology{ 82 | Sub_Pass{ 83 | Pass ColorPass{ 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/assets/shadernodes/controls.css: -------------------------------------------------------------------------------- 1 | .control_component_input{ 2 | border: 0px; 3 | color: white; 4 | max-width: 150px; 5 | border-radius: 2px; 6 | outline-style: none; 7 | background: #959595; 8 | margin-left: 4px; 9 | margin-right: 4px; 10 | } 11 | .control_component_input:hover{ 12 | background: #383838; 13 | } 14 | .textcontrol_component_input{ 15 | border: 0px; 16 | color: white; 17 | max-width: 150px; 18 | border-radius: 2px; 19 | outline-style: none; 20 | background: #959595; 21 | margin-left: 4px; 22 | margin-right: 4px; 23 | } 24 | .textcontrol_component_input:hover{ 25 | background: #383838; 26 | } 27 | -------------------------------------------------------------------------------- /src/assets/shadernodes/index.sass: -------------------------------------------------------------------------------- 1 | .connection 2 | overflow: visible !important 3 | width: 1px 4 | height: 10px 5 | .main-path 6 | fill: none 7 | stroke-width: 5px 8 | stroke: steelblue 9 | -------------------------------------------------------------------------------- /src/assets/shadernodes/shadernodes.css: -------------------------------------------------------------------------------- 1 | /*连接端口,这里设置height:10px防止样式冲突带来的插槽线条偏移*/ 2 | .connection{ 3 | overflow: visible !important; 4 | width: 1px; 5 | height: 12px; 6 | } 7 | /*连接线条样式*/ 8 | .connection .main-path{ 9 | fill: none; 10 | stroke-width: 2px; 11 | stroke: rgba(255, 255, 255, 100); 12 | } 13 | /*shader node默认样式*/ 14 | .node { 15 | background: #3e3e3e !important; 16 | border: 0px solid #333 !important; 17 | border-radius: 5px !important; 18 | box-shadow: 0 0 15px #000; 19 | } 20 | /*进入shader node样式*/ 21 | .node:hover { 22 | background: rgba(120, 120, 120, 0.8) !important; 23 | } 24 | /*选中shader node样式*/ 25 | .node.selected { 26 | background: rgb(120, 120, 120) !important; 27 | border: 2px solid white !important; 28 | } 29 | 30 | /*title部分*/ 31 | .node .title { 32 | color: #ffffff !important; 33 | } 34 | .node .input-title, 35 | .node .output-title { 36 | margin: 0px 15px !important; 37 | } 38 | 39 | /*socket大小和默认颜色*/ 40 | .socket { 41 | width: 15px !important; 42 | height: 15px !important; 43 | margin-left: -7px !important; 44 | background: #96b38a !important; 45 | } 46 | .socket.output { 47 | margin-right: -7px !important; 48 | } 49 | 50 | 51 | /*内置节点title颜色*/ 52 | .number .title{ 53 | border-radius: 5px 5px 0px 0px !important; 54 | background-color: #2c98b0; 55 | } 56 | 57 | .constructvec2 .title, 58 | .constructvec3 .title, 59 | .constructvec4 .title, 60 | .add .title, 61 | .divide .title, 62 | .multiply .title, 63 | .subtract .title{ 64 | border-radius: 5px 5px 0px 0px !important; 65 | background-color: #ee0343; 66 | } 67 | 68 | .floatparam .title, 69 | .boolparam .title, 70 | .vec2param .title, 71 | .vec3param .title, 72 | .vec4param .title, 73 | .texture2dparam .title, 74 | .texturecubeparam .title, 75 | .intparam .title{ 76 | border-radius: 5px 5px 0px 0px !important; 77 | background-color: #2e6bb4; 78 | } 79 | 80 | .floatinputstructure .title, 81 | .boolinputstructure .title, 82 | .vec2inputstructure .title, 83 | .vec3inputstructure .title, 84 | .vec4inputstructure .title, 85 | .intinputstructure .title{ 86 | border-radius: 5px 5px 0px 0px !important; 87 | background-color: #3ba398; 88 | } 89 | .inputattribute .title, 90 | .inputmatrix .title{ 91 | border-radius: 5px 5px 0px 0px !important; 92 | background-color: rgba(255, 255, 255, 0.39); 93 | } 94 | 95 | .floatoutputstructure .title, 96 | .booloutputstructure .title, 97 | .vec2outputstructure .title, 98 | .vec3outputstructure .title, 99 | .vec4outputstructure .title, 100 | .intoutputstructure .title{ 101 | border-radius: 5px 5px 0px 0px !important; 102 | background-color: #3ba398; 103 | } 104 | 105 | .samplertexture2d .title{ 106 | border-radius: 5px 5px 0px 0px !important; 107 | background-color: #8064c9; 108 | } 109 | 110 | .ifelsebranch .title, 111 | .transformvector3 .title{ 112 | border-radius: 5px 5px 0px 0px !important; 113 | background-color: #71b453; 114 | } 115 | 116 | .vertexshaderout .title{ 117 | border-radius: 5px 5px 0px 0px !important; 118 | background-color: #d3ae02; 119 | } 120 | 121 | .fragmentshaderout .title{ 122 | border-radius: 5px 5px 0px 0px !important; 123 | background-color: #b43329; 124 | } 125 | 126 | /*上下文菜单*/ 127 | .context-menu .item { 128 | background-color: #333333dd !important; 129 | border: 0px solid white !important; 130 | padding: 5px 10px !important; 131 | min-width: 150px; 132 | font-family: sans-serif !important; 133 | } 134 | .context-menu .item:hover { 135 | min-width: 150px; 136 | background-color: #2b5088 !important; 137 | } 138 | -------------------------------------------------------------------------------- /src/assets/textures/lightbulb32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnLKkk/Produce/c1faed67e6365bb5e35724fe549f9d869a6c5140/src/assets/textures/lightbulb32.png -------------------------------------------------------------------------------- /src/assets/tools.css: -------------------------------------------------------------------------------- 1 | .topdeftoolbg { 2 | background: rgba(66, 66, 66, 0.53); 3 | width: 100%; 4 | height: 20px; 5 | } 6 | .topdeftoolbg2 { 7 | border-radius: 10px 10px 0 0; 8 | background: rgba(66, 66, 66, 0.53); 9 | width: 100%; 10 | height: 20px; 11 | } 12 | .transparent_div { 13 | background-color: transparent; 14 | width: 100%; 15 | min-height: 100%; 16 | } 17 | /*滚动条样式*/ 18 | .transparent_div::-webkit-scrollbar {/*滚动条整体样式*/ 19 | width: 4px; /*高宽分别对应横竖滚动条的尺寸*/ 20 | height: 4px; 21 | } 22 | .transparent_div::-webkit-scrollbar-thumb {/*滚动条里面小方块*/ 23 | border-radius: 5px; 24 | -webkit-box-shadow: inset 0 0 5px rgba(0,0,0,0.2); 25 | background: rgba(0,0,0,0.2); 26 | } 27 | .transparent_div::-webkit-scrollbar-track {/*滚动条里面轨道*/ 28 | -webkit-box-shadow: inset 0 0 5px rgba(0,0,0,0.2); 29 | border-radius: 0; 30 | background: rgba(0,0,0,0.1); 31 | } 32 | .transparent_div { 33 | border-radius: 10px 10px 0 0; 34 | background: rgba(66, 66, 66, 0.53); 35 | width: 100%; 36 | height: 20px; 37 | } 38 | .btmtoolbg { 39 | border-radius: 10px 10px 0 0; 40 | background: rgba(66, 66, 66, 0.53); 41 | width: 100%; 42 | height: 20px; 43 | } 44 | 45 | .attr_item_top { 46 | font-size: 12px; 47 | text-align: left; 48 | line-height: 20px; 49 | color: #cbcbcb; 50 | border-radius: 5px 5px 0 0; 51 | padding-top: 4px; 52 | padding-bottom: 4px; 53 | margin-top: 2px; 54 | background: rgba(97, 97, 97, 0.53); 55 | /* -50px 是为了属性面板左侧tabs图标大小以及tabContent内部padding*/ 56 | width: calc(100% - 50px); 57 | height: 20px; 58 | 59 | /* 文字不被选中*/ 60 | -webkit-user-select:none; 61 | -moz-user-select:none; 62 | -ms-user-select:none; 63 | user-select:none; 64 | } 65 | 66 | .attr_item_content { 67 | width: calc(100% - 50px); 68 | border-radius: 0 0 5px 5px; 69 | padding-bottom: 15px; 70 | background: rgba(97, 97, 97, 0.53); 71 | } 72 | 73 | .attr_item { 74 | font-size: 12px; 75 | text-align: left; 76 | line-height: 20px; 77 | color: #cbcbcb; 78 | border-radius: 5px; 79 | padding-top: 4px; 80 | padding-bottom: 4px; 81 | margin-top: 2px; 82 | background: rgba(97, 97, 97, 0.53); 83 | /* -50px 是为了属性面板左侧tabs图标大小以及tabContent内部padding*/ 84 | width: calc(100% - 50px); 85 | height: 20px; 86 | 87 | /* 文字不被选中*/ 88 | -webkit-user-select:none; 89 | -moz-user-select:none; 90 | -ms-user-select:none; 91 | user-select:none; 92 | 93 | /* shadow*/ 94 | box-shadow:0 0 2px #222222; 95 | } 96 | 97 | .attr_item_btm { 98 | border-radius: 0 0 10px 10px; 99 | background: white; 100 | /* -30px 是为了属性面板左侧tabs图标大小*/ 101 | width: calc(100% - 30px); 102 | height: 20px; 103 | } 104 | 105 | .component_input{ 106 | border: 0px; 107 | border-radius: 2px; 108 | outline-style: none; 109 | background: #777777; 110 | color: #cbcbcb; 111 | margin-left: 4px; 112 | margin-right: 4px; 113 | } 114 | .component_input:hover{ 115 | background: #383838; 116 | } 117 | 118 | .component_input_small{ 119 | border: 0px; 120 | border-radius: 2px; 121 | outline-style: none; 122 | background: #777777; 123 | color: #cbcbcb; 124 | max-width: 70px; 125 | margin-left: 4px; 126 | margin-right: 4px; 127 | } 128 | .component_input_small:hover{ 129 | background: #383838; 130 | } 131 | 132 | .component_select{ 133 | border: 0px; 134 | border-radius: 2px; 135 | outline-style: none; 136 | background: #383838; 137 | min-width: 100px; 138 | margin-left: 4px; 139 | margin-right: 4px; 140 | color: #cbcbcb;font-size: 12px; 141 | } 142 | 143 | .component_select:hover{ 144 | background: #777777; 145 | } 146 | 147 | .input[type='checkbox']:checked + label:before{ 148 | background: #4cd764; 149 | } 150 | 151 | .icon_right { 152 | width: 0; 153 | height: 0; 154 | display: block; 155 | float: left; 156 | transform: rotate(-90deg); 157 | border: 5px solid transparent; 158 | border-color: gray transparent transparent transparent; 159 | margin: 5px; 160 | } 161 | 162 | .icon_btm { 163 | width: 0; 164 | height: 0; 165 | display: block; 166 | float: left; 167 | border: 5px solid transparent; 168 | border-color: gray transparent transparent transparent; 169 | margin: 7px 5px 5px 5px; 170 | } 171 | 172 | /*context menu*/ 173 | .vue-contextmenu-listWrapper { 174 | margin: 0; 175 | background: #fff; 176 | z-index: 3000; 177 | position: absolute; 178 | list-style-type: none; 179 | padding: 5px 0; 180 | border-radius: 4px; 181 | font-size: 12px; 182 | font-weight: 400; 183 | min-width: 150px; 184 | color: #c2c2c2; 185 | box-shadow: 4px 4px 5px 0 rgba(0, 0, 0, 0.84); 186 | background-color: #0c0c0c; 187 | } 188 | 189 | .vue-contextmenu-listWrapper .context-menu-list { 190 | margin: 0; 191 | cursor: pointer; 192 | } 193 | 194 | .vue-contextmenu-listWrapper .context-menu-list:hover { 195 | background: #777777; 196 | } 197 | -------------------------------------------------------------------------------- /src/components/Attributes.vue: -------------------------------------------------------------------------------- 1 | 41 | 42 | 132 | 133 | 166 | -------------------------------------------------------------------------------- /src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 85 | 86 | 96 | 97 | 98 | 114 | -------------------------------------------------------------------------------- /src/components/Port.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 58 | 59 | 103 | -------------------------------------------------------------------------------- /src/components/ShaderNode.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 28 | 29 | 65 | -------------------------------------------------------------------------------- /src/components/attributes/AttrItem.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 60 | 61 | 72 | -------------------------------------------------------------------------------- /src/components/attributes/object/OBJ_Geometry.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 192 | 193 | 203 | -------------------------------------------------------------------------------- /src/components/attributes/object/OBJ_Node.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 148 | 149 | 159 | -------------------------------------------------------------------------------- /src/components/attributes/object/OBJ_None.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 15 | 18 | -------------------------------------------------------------------------------- /src/components/common/BoolComponent.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 53 | 54 | 57 | -------------------------------------------------------------------------------- /src/components/common/BoolGroupComponent.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 19 | 20 | 23 | -------------------------------------------------------------------------------- /src/components/common/ColorComponent.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 45 | 46 | 49 | -------------------------------------------------------------------------------- /src/components/common/CombinationComponent.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 43 | 44 | 58 | -------------------------------------------------------------------------------- /src/components/common/ImgComponent.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 143 | 144 | 147 | -------------------------------------------------------------------------------- /src/components/common/NumberComponent.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 68 | 69 | 72 | -------------------------------------------------------------------------------- /src/components/common/SelectComponent.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 51 | 52 | 55 | -------------------------------------------------------------------------------- /src/components/common/TransformComponent.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 24 | 25 | 36 | -------------------------------------------------------------------------------- /src/components/common/VectorColorComponent.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 100 | 101 | 104 | -------------------------------------------------------------------------------- /src/components/common/VectorComponent.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 58 | 59 | 62 | -------------------------------------------------------------------------------- /src/components/shadernodes/common/Color.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 30 | 31 | 34 | -------------------------------------------------------------------------------- /src/components/shadernodes/common/TextInput.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 31 | 32 | 35 | -------------------------------------------------------------------------------- /src/components/shadernodes/math/Number.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 31 | 32 | 35 | -------------------------------------------------------------------------------- /src/components/ui/ContextMenu.vue: -------------------------------------------------------------------------------- 1 | 27 | 107 | 175 | -------------------------------------------------------------------------------- /src/components/ui/Tree.vue: -------------------------------------------------------------------------------- 1 | 20 | 31 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /src/editor/Arrow.js: -------------------------------------------------------------------------------- 1 | import Try3d from 'try3d/src/Try3d' 2 | import Mesh from 'try3d/src/Core/WebGL/Mesh' 3 | 4 | export default class Arrow extends Try3d.Geometry{ 5 | getType(){ 6 | return 'Geometry'; 7 | } 8 | static positions = [ 9 | 0, 0, 0, 10 | 0, 0, 1, // tip 11 | 0.05, 0, 0.9, // tip right 12 | -0.05, 0, 0.9, // tip left 13 | 0, 0.05, 0.9, // tip top 14 | 0, -0.05, 0.9, // tip bottom 15 | ]; 16 | 17 | /** 18 | * 创建一个Arrow。
19 | * @param {Component}[owner] 20 | * @param {String}[cfg.id] 21 | * @param {Vector3}[cfg.extent] 22 | */ 23 | constructor (owner, cfg) { 24 | super(owner, cfg); 25 | this._m_TempQuat = new Try3d.Quaternion(); 26 | this._m_TempVec = new Try3d.Vector3(); 27 | 28 | let len = cfg.extent.length(); 29 | let up = Try3d.Vector3.S_UNIT_AXIS_Y; 30 | let dot = cfg.extent.dot(up); 31 | // 说明几乎朝向平行 32 | if(dot >= 0.9){ 33 | up = Try3d.Vector3.S_UNIT_AXIS_NEGATIVE_Z; 34 | } 35 | else if(dot <= -0.9){ 36 | up = Try3d.Vector3.S_UNIT_AXIS_Z; 37 | } 38 | this.lookAt(this._m_TempQuat, cfg.extent, up); 39 | let mesh = new Try3d.Mesh(); 40 | const positions = []; 41 | const indices = [0, 1, 42 | 1, 2, 43 | 1, 3, 44 | 1, 4, 45 | 1, 5]; 46 | for(let i = 0;i < Arrow.positions.length;i+=3){ 47 | this._m_TempVec.setToInXYZ(Arrow.positions[i], Arrow.positions[i + 1], Arrow.positions[i + 2]); 48 | this._m_TempVec.multLength(len); 49 | this._m_TempQuat.multVec3(this._m_TempVec, this._m_TempVec); 50 | positions.push(this._m_TempVec._m_X); 51 | positions.push(this._m_TempVec._m_Y); 52 | positions.push(this._m_TempVec._m_Z); 53 | } 54 | mesh.setData(Try3d.Mesh.S_POSITIONS, positions); 55 | mesh.setData(Try3d.Mesh.S_INDICES, indices); 56 | mesh.setPrimitive(Try3d.Mesh.S_PRIMITIVE_LINES); 57 | this.setMesh(mesh); 58 | this.updateBound(); 59 | } 60 | lookAt(q, direction, up){ 61 | let vect3 = new Try3d.Vector3(); 62 | vect3.setTo(direction).normal(); 63 | let vect1 = new Try3d.Vector3(); 64 | vect1.setTo(up); 65 | vect1.cross(direction); 66 | vect1.normal(); 67 | let vect2 = new Try3d.Vector3(); 68 | vect2.setTo(direction); 69 | vect2.cross(vect1); 70 | vect2.normal(); 71 | q.fromAxis(vect1, vect2, vect3); 72 | } 73 | 74 | }; 75 | -------------------------------------------------------------------------------- /src/editor/EditorContext.js: -------------------------------------------------------------------------------- 1 | import Events from 'try3d/src/Core/Util/Events' 2 | import ObjControl from './utils/ObjControl' 3 | import MaterialDefFactory from './shadernodes/MaterialDefFactory' 4 | 5 | export class EditorContext { 6 | static S_MAIN_CONTROL = 'S_MAIN_CONTROL'; 7 | // 场景根节点 8 | static S_ROOT_NODE = '_root_Node'; 9 | // 世界根节点 10 | static S_WORLD_ROOT_NODE = '_world_root_node'; 11 | // 默认辅助几何,不会出现在大纲编辑器列表中 12 | static S_HELPER_NODE = '_helper_node'; 13 | static S_HELPER_GRID = '_helper_grid'; 14 | static S_HELPER_X_AXIS = '_helper_x_axis'; 15 | static S_HELPER_Y_AXIS = '_helper_y_axis'; 16 | static S_HELPER_Z_AXIS = '_helper_z_axis'; 17 | static S_PICKABLE = 'S_PICKABLE'; 18 | 19 | // 一些全局配置信息 20 | static S_LIGHT_BULB_SIZE = 0.3; 21 | 22 | // EVENTS 23 | static S_EVENT_SCENE_LOAD_END = "S_EVENT_SCENE_LOAD_END"; 24 | 25 | // 唯一实例 26 | static _s_Instance = null; 27 | 28 | /** 29 | * 返回唯一实例。
30 | * @returns {null} 31 | */ 32 | static getInstance(){ 33 | if(!EditorContext._s_Instance){ 34 | EditorContext._s_Instance = new EditorContext(); 35 | } 36 | return EditorContext._s_Instance; 37 | } 38 | 39 | /** 40 | * 返回指定scene,默认返回第0个scene。
41 | * @param {Number}[index] 42 | */ 43 | static getScene(index){ 44 | // 这里暂时只返回第0个。 45 | if(EditorContext._s_Instance.getRenderer()){ 46 | return EditorContext._s_Instance.getRenderer()._scene; 47 | } 48 | return null; 49 | } 50 | 51 | constructor () { 52 | // 所有工作区 53 | this.m_Workspaces = {}; 54 | 55 | // 渲染器 56 | this.m_Renderer = null; 57 | 58 | this._m_Events = new Events(); 59 | } 60 | 61 | /** 62 | * 注册事件。
63 | * @param {String}[type 事件类型] 64 | * @param {Function}[callback 回调函数] 65 | */ 66 | registerEvent(type, callback){ 67 | this._m_Events.register(type, callback); 68 | } 69 | 70 | /** 71 | * 卸载指定事件的指定监听器。
72 | * @param {String}[type 事件类型] 73 | * @param {Function}[callback 回调函数] 74 | */ 75 | unregisterEvent(type, callback){ 76 | this._m_Events.unregister(type, callback); 77 | } 78 | 79 | /** 80 | * 分发事件。
81 | * @param {String}[type 事件类型] 82 | * @param {Object}[data 数据] 83 | */ 84 | notifyEvent(type, data){ 85 | this._m_Events.trigger(type, data); 86 | } 87 | 88 | setRenderer(renderer){ 89 | this.m_Renderer = renderer; 90 | } 91 | 92 | /** 93 | * 初始化编辑器。
94 | */ 95 | initEditor(){ 96 | let objControl = new ObjControl(EditorContext.getScene(0), {id:'OBJ_CONTROL'}); 97 | MaterialDefFactory.initMaterialDefs(); 98 | } 99 | 100 | getRenderer(){return this.m_Renderer;} 101 | } 102 | -------------------------------------------------------------------------------- /src/editor/GlobalConfig.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 全局配置。
3 | * @author JohnKkk 4 | * @date 2022年6月4日15点43分 5 | */ 6 | export default class GlobalConfig{ 7 | // 默认阴影贴图分辨率 8 | static S_DEFAULT_SHADOW_MAP_SIZE = 1024; 9 | } 10 | -------------------------------------------------------------------------------- /src/editor/attributes/object/ObjNode.js: -------------------------------------------------------------------------------- 1 | export default class ObjNode { 2 | constructor (obj) { 3 | this._m_Obj = obj; 4 | } 5 | 6 | } 7 | -------------------------------------------------------------------------------- /src/editor/command/BaseCommand.js: -------------------------------------------------------------------------------- 1 | /** 2 | * BaseCommand。
3 | * @author JohnKkk 4 | * @date 2022年5月11日19点11分 5 | */ 6 | export default class BaseCommand { 7 | /** 8 | * BaseCommand。
9 | * @param {Function}[data.redo] 10 | * @param {Function}[data.undo] 11 | * @param {Object}[data.redoData] 12 | * @param {Object}[data.undoData] 13 | */ 14 | constructor (data) { 15 | this._mData = {}; 16 | this._mData.redo = data.redo; 17 | this._mData.undo = data.undo; 18 | this._mData.redoData = data.redoData; 19 | this._mData.undoData = data.undoData; 20 | } 21 | 22 | redo(){ 23 | if(this._mData.redo){ 24 | this._mData.redo(this._mData.redoData); 25 | } 26 | } 27 | 28 | undo(){ 29 | if(this._mData.undo){ 30 | this._mData.undo(this._mData.undoData); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/editor/command/CommandFactory.js: -------------------------------------------------------------------------------- 1 | import CommandManager from './CommandManager' 2 | import BaseCommand from './BaseCommand' 3 | import Utils from '../utils/Utils' 4 | 5 | /** 6 | * Factory。
7 | * 用于快速创建命令。
8 | * @author JohnKkk 9 | * @date 2022年7月8日13点06分 10 | */ 11 | export default class CommandFactory { 12 | static _s_IsCommand = true; 13 | static setIsCommand(isCommand){ 14 | CommandFactory._s_IsCommand = isCommand; 15 | } 16 | static isCommand(){ 17 | return CommandFactory._s_IsCommand; 18 | } 19 | static createFastCommand(oldValue, undo, newValue, redo, noExc){ 20 | let command = new BaseCommand({ 21 | redo: redo, 22 | undo: undo, 23 | redoData: newValue, 24 | undoData: oldValue 25 | }); 26 | if(!noExc) 27 | CommandManager.getInstance().executeCommand(command); 28 | return command; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/editor/command/CommandManager.js: -------------------------------------------------------------------------------- 1 | /** 2 | * CommandManager。
3 | * @author JohnKkk 4 | * @date 2022年5月11日16点57分 5 | */ 6 | export default class CommandManager { 7 | // 最多缓存100条命令 8 | static S_MAX_COMMANDS = 100; 9 | static _s_Instance = null; 10 | 11 | constructor () { 12 | this._m_Undos = []; 13 | this._m_Redos = []; 14 | } 15 | 16 | static getInstance(){ 17 | if(!CommandManager._s_Instance){ 18 | CommandManager._s_Instance = new CommandManager(); 19 | } 20 | return CommandManager._s_Instance; 21 | } 22 | 23 | _addToUndos(command){ 24 | if((this._m_Undos.length + 1) > CommandManager.S_MAX_COMMANDS){ 25 | this._m_Undos.shift(); 26 | } 27 | this._m_Undos.push(command); 28 | } 29 | 30 | _addToRedos(command){ 31 | if((this._m_Redos.length + 1) > CommandManager.S_MAX_COMMANDS){ 32 | this._m_Redos.shift(); 33 | } 34 | this._m_Redos.push(command); 35 | } 36 | 37 | /** 38 | * 执行命令。
39 | * @param {Object}[command] 40 | */ 41 | executeCommand(command){ 42 | if(command){ 43 | command.redo(); 44 | this._addToUndos(command); 45 | // 一旦开始执行命令,意味着开始一个新命令集,所以清除旧的Redos列表 46 | if(this._m_Redos.length) 47 | this._m_Redos = []; 48 | } 49 | } 50 | 51 | /** 52 | * 撤销最后一个命令。
53 | */ 54 | undoLastCommand(){ 55 | if(this._m_Undos.length){ 56 | let lastCommand = this._m_Undos.pop(); 57 | lastCommand.undo(); 58 | this._addToRedos(lastCommand); 59 | } 60 | } 61 | 62 | /** 63 | * 重做最后一个命令。
64 | */ 65 | redoLastCommand(){ 66 | if(this._m_Redos.length){ 67 | let lastCommand = this._m_Redos.pop(); 68 | lastCommand.redo(); 69 | this._addToUndos(lastCommand); 70 | } 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/editor/common/PostFilterFactory.js: -------------------------------------------------------------------------------- 1 | import Try3d from 'try3d/src/Try3d' 2 | 3 | export default class PostFilterFactory { 4 | static _s_PostFilterList; 5 | static postFilterListRefresh(postFilterList){ 6 | PostFilterFactory._s_PostFilterList = postFilterList; 7 | } 8 | static getPostFilterList(){ 9 | return PostFilterFactory._s_PostFilterList; 10 | } 11 | /** 12 | * DofFilter.
13 | * @param scene 14 | * @param camera 15 | */ 16 | static createDofFilter(scene, camera){ 17 | let dofFilter = camera.addFilterFromMaterial(new Try3d.Material(scene, {id:'dofFilter', materialDef:Try3d.MaterialDef.parse(Try3d.Internal.S_DOF_FILTER_DEF_DATA)})); 18 | let mat = dofFilter.getMaterial(); 19 | let focusDistance = 50; 20 | let focusRange = 10; 21 | let hScale = 1.0; 22 | let vScale = 1.0; 23 | mat.setParam('focusDistance', new Try3d.FloatVars().valueOf(focusDistance)); 24 | mat.setParam('focusRange', new Try3d.FloatVars().valueOf(focusRange)); 25 | mat.setParam('hScale', new Try3d.FloatVars().valueOf(hScale)); 26 | mat.setParam('vScale', new Try3d.FloatVars().valueOf(vScale)); 27 | return dofFilter; 28 | } 29 | 30 | /** 31 | * FogFilter.
32 | * @param scene 33 | * @param camera 34 | * @returns {Filter} 35 | */ 36 | static createFogFilter(scene, camera){ 37 | let fogFilter = camera.addFilterFromMaterial(new Try3d.Material(scene, {id:'fogFilter', materialDef:Try3d.MaterialDef.parse(Try3d.Internal.S_FOG_FILTER_DEF_DATA)})); 38 | let mat = fogFilter.getMaterial(); 39 | fogFilter.getMaterial().selectTechnology('Default'); 40 | fogFilter.getMaterial().setParam('vNear', new Try3d.FloatVars().valueOf(camera.getNear())); 41 | fogFilter.getMaterial().setParam('vFar', new Try3d.FloatVars().valueOf(camera.getFar())); 42 | fogFilter.getMaterial().setParam('fogNear', new Try3d.FloatVars().valueOf(150)); 43 | fogFilter.getMaterial().setParam('fogFar', new Try3d.FloatVars().valueOf(250)); 44 | return fogFilter; 45 | } 46 | static createBloomFilter(scene, camera){ 47 | let bloomFilter = camera.addFilterFromMaterial(new Try3d.Material(scene, {id:'bloomFilter', materialDef:Try3d.MaterialDef.parse(Try3d.Internal.S_BLOOM_FILTER_DEF_DATA)})); 48 | let mat = bloomFilter.getMaterial(); 49 | mat.setParam('extractThreshold', new Try3d.FloatVars().valueOf(0.2)); 50 | mat.setParam('bloomIntensity', new Try3d.FloatVars().valueOf(0.25)); 51 | return bloomFilter; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/editor/common/ShapeFactory.js: -------------------------------------------------------------------------------- 1 | import {EditorContext} from '../EditorContext' 2 | import Material from './Material' 3 | import Try3d from 'try3d/src/Try3d' 4 | import Utils from '../utils/Utils' 5 | import Arrow from '../Arrow' 6 | 7 | export default class ShapeFactory { 8 | constructor (props) { 9 | } 10 | static createArrow(options){ 11 | let scene = options.scene || EditorContext.getScene(0); 12 | let arrow = new Arrow(scene, {id:options.id || 'arrow_' + Utils.nextId(), extent:options.extent}); 13 | let mat = null; 14 | if(options.matStrId){ 15 | switch (options.matStrId) { 16 | case 'x': 17 | mat = Material.getRedColorMatIns(scene, false); 18 | break; 19 | case 'y': 20 | mat = Material.getGreenColorMatIns(scene, false); 21 | break; 22 | case 'z': 23 | mat = Material.getBlueColorMatIns(scene, false); 24 | break; 25 | case 'light': 26 | default: 27 | mat = Material.getGizmoDefIns(scene, false); 28 | break; 29 | } 30 | } 31 | arrow.setMaterial(mat); 32 | return arrow; 33 | } 34 | static createRound(options){ 35 | let radiusMesh = Try3d.MeshFactor.createRoundMesh(3, options.dashed); 36 | let radius = new Try3d.Geometry(options.scene, {id:'radius_' + Utils.nextId()}); 37 | radius.receiveShadow(false); 38 | radius.castShadow(false); 39 | radius.setMesh(radiusMesh); 40 | radius.setMaterial(new Try3d.Material(options.scene, {id:'radiusMat_' + Utils.nextId(), materialDef:Material.S_COLOR_MAT})); 41 | radius.updateBound(); 42 | radius.setLocalRotationFromEuler(Try3d.MoreMath.toRadians(90), 0, 0); 43 | return radius; 44 | } 45 | 46 | /** 47 | * 创建Box。
48 | * @param options 49 | * @returns {Box} 50 | */ 51 | static createBox(options){ 52 | let scene = EditorContext.getScene(0); 53 | let box1Mat = Material.getWhiteBasicLightingMatIns(scene, true); 54 | let box = new Try3d.Box(scene, {id:'box_' + Utils.nextId(), xHalf:0.2, yHalf:0.2, zHalf:0.2}); 55 | box.setMaterial(box1Mat); 56 | return box; 57 | } 58 | 59 | /** 60 | * 创建Cylinder。
61 | * @param options 62 | * @returns {Cylinder} 63 | */ 64 | static createCylinder(options){ 65 | let scene = EditorContext.getScene(0); 66 | // 定义一个Cylinder 67 | let cylinder = new Try3d.Cylinder(scene, {id:'cylinder_' + Utils.nextId(), radiusTop:0.0, radiusBottom:0.3, height:1}); 68 | // 创建cylinderMat 69 | let cylinderMat = Material.getWhiteBasicLightingMatIns(scene, true); 70 | cylinder.setMaterial(cylinderMat); 71 | return cylinder; 72 | } 73 | 74 | /** 75 | * 创建Sphere。
76 | * @param options 77 | * @returns {Sphere} 78 | */ 79 | static createSphere(options){ 80 | // 定义一个Sphere 81 | let scene = EditorContext.getScene(0); 82 | let sphere = new Try3d.Sphere(scene, {id:'sphere_' + Utils.nextId(), radius:0.2}); 83 | // 创建sphereMat 84 | let sphereMat = Material.getWhiteBasicLightingMatIns(scene, true); 85 | sphere.setMaterial(sphereMat); 86 | return sphere; 87 | } 88 | 89 | /** 90 | * 创建Teapot。
91 | * @param options 92 | * @returns {Teapot} 93 | */ 94 | static createTeapot(options){ 95 | let scene = EditorContext.getScene(0); 96 | // 定义一个Teapot 97 | let teapot = new Try3d.Teapot(scene, {id:'teapot_' + Utils.nextId()}); 98 | let teapotMat = Material.getWhiteBasicLightingMatIns(scene, true); 99 | teapot.setMaterial(teapotMat); 100 | return teapot; 101 | } 102 | 103 | /** 104 | * 创建Torus。
105 | * @param options 106 | * @returns {Torus} 107 | */ 108 | static createTorus(options){ 109 | let scene = EditorContext.getScene(0); 110 | // 定义一个Torus 111 | let torus = new Try3d.Torus(scene, {id:'torus', tube:0.05, radius:0.2, segmentsR:64, segmentsT:64}); 112 | // 创建torusMat 113 | let torusMat = Material.getWhiteBasicLightingMatIns(scene, true); 114 | torus.setMaterial(torusMat); 115 | return torus; 116 | } 117 | 118 | /** 119 | * 创建Plane。
120 | * @param options 121 | * @returns {GroupPlane} 122 | */ 123 | static createPlane(options){ 124 | let scene = EditorContext.getScene(0); 125 | // 定义一个GroupPlane 126 | let groupPlane = new Try3d.GroupPlane(scene, {id:'groupPlane_' + Utils.nextId(), xSize:4, zSize:4, xSegments:2, zSegments:2}); 127 | // 创建groupPlaneMat 128 | let groupPlaneMat = Material.getWhiteBasicLightingMatIns(scene, true); 129 | groupPlane.setMaterial(groupPlaneMat); 130 | return groupPlane; 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /src/editor/leadingPrinciples/LeadingPrinciples.js: -------------------------------------------------------------------------------- 1 | import {EditorContext} from '../EditorContext' 2 | import Try3d from 'try3d/src/Try3d' 3 | import Utils from '../utils/Utils' 4 | import Material from '../common/Material' 5 | import ShapeFactory from '../common/ShapeFactory' 6 | 7 | /** 8 | * 大纲编辑器。
9 | * @author JohnKkk 10 | * @date 2022年5月5日16点48分 11 | */ 12 | export default class LeadingPrinciples { 13 | // EVENTs 14 | static S_LEADINGPRINCIPLES_EVENT_SELECTED = 'S_LEADINGPRINCIPLES_EVENT_SELECTED'; 15 | 16 | // type 17 | static SG_NODE = 'sg_node'; 18 | static SG_GEOMETRY = 'sg_geometry'; 19 | static SG_LIGHT = 'sg_light'; 20 | constructor () { 21 | } 22 | 23 | /** 24 | * 获取scene数据。
25 | * @param {Array}[parent] 26 | * @param {Node}[node] 27 | * @private 28 | */ 29 | _getSceneData(parent, node){ 30 | if(node){ 31 | // 创建一个新节点 32 | let newNode = { 33 | "id": node.getId(), 34 | "text": node.getName(), 35 | "value": node, 36 | "icon": this._getTypeIcon(node.getType()), // 后续根据node.getType()区分图标 37 | "opened": true, 38 | "selected": false, 39 | "disabled": false, 40 | "loading": false, 41 | "dragDisabled": !this._canDrag(node.getType()), 42 | "dropDisabled": !this._canDrop(node.getType()), 43 | "children": [ 44 | ] 45 | }; 46 | if(parent){ 47 | parent.push(newNode); 48 | } 49 | 50 | if(!(node instanceof Try3d.Light)){ 51 | // 查找所有子节点 52 | node.getChildren().forEach(c=>{ 53 | // 跳过这个节点 54 | if(c.getName() != EditorContext.S_HELPER_NODE){ 55 | this._getSceneData(newNode.children, c); 56 | } 57 | }); 58 | } 59 | } 60 | } 61 | 62 | _canDrag(type){ 63 | return true; 64 | } 65 | 66 | _canDrop(type){ 67 | if(type == 'Node')return true; 68 | return false; 69 | } 70 | 71 | getType(type){ 72 | return this._getTypeIcon(type); 73 | } 74 | 75 | _getTypeIcon(type){ 76 | switch (type) { 77 | case 'Node': 78 | return 'sg_node'; 79 | case 'Geometry': 80 | case 'Box': 81 | case 'Sphere': 82 | case 'Plane': 83 | case 'SkyBox': 84 | return 'sg_geometry'; 85 | case 'Light': 86 | case 'DirectionalLight': 87 | case 'PointLight': 88 | case 'SpotLight': 89 | return 'sg_light'; 90 | default: 91 | return ''; 92 | } 93 | } 94 | 95 | /** 96 | * 返回当前场景数据,以便在大纲编辑器中展示。
97 | * @returns {[]} 98 | */ 99 | getData(){ 100 | // 将scene解析为大纲面板渲染列表 101 | let data = []; 102 | let editorContext = EditorContext.getInstance(); 103 | if(editorContext.getRenderer() && editorContext.getRenderer()._scene){ 104 | // 开始转换 105 | // 这里暂时只读取一个scene,后续可以增加为多个scene 106 | let scene = editorContext.getRenderer()._scene.getSceneNode(0).getChildrenAtName(EditorContext.S_ROOT_NODE); 107 | this._getSceneData(data, scene); 108 | } 109 | return data; 110 | } 111 | 112 | newNode(options){ 113 | // 创建一个node 114 | let scene = EditorContext.getScene(0); 115 | if(scene){ 116 | let newNode = new Try3d.Node(scene, {id:'node_' + Utils.nextId()}); 117 | return newNode; 118 | } 119 | return null; 120 | } 121 | 122 | newBox(options){ 123 | return ShapeFactory.createBox(options); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/editor/shadernodes/ShaderNodes.js: -------------------------------------------------------------------------------- 1 | import Maths from './math/Maths' 2 | import Textures from './texture/Textures' 3 | import Outputs from './output/Outputs' 4 | import Params from './param/Params' 5 | import Inputs from './input/Inputs' 6 | import Sockets from './Sockets' 7 | import Commons from './common/Commons' 8 | 9 | export default class ShaderNodes { 10 | static _s_Filters = [ 11 | Params, 12 | Inputs, 13 | Outputs, 14 | Maths, 15 | Commons, 16 | Textures, 17 | ]; 18 | 19 | static _s_VarTypes = { 20 | 'bool':0, 21 | 'int':1, 22 | 'float':2, 23 | 'vec2':3, 24 | 'vec3':4, 25 | 'vec4':5 26 | }; 27 | 28 | static filter(component){ 29 | for(let f in ShaderNodes._s_Filters){ 30 | if(ShaderNodes._s_Filters[f].filter(component)){ 31 | return ShaderNodes._s_Filters[f].getGroup(); 32 | } 33 | } 34 | return null; 35 | } 36 | 37 | /** 38 | * 注册所有系统节点。
39 | * @param {Object}[editor] 40 | * @param {Object}[engine] 41 | */ 42 | static registerShaderNodes(editor, engine){ 43 | Sockets.init(); 44 | let node = null; 45 | for(let group in ShaderNodes._s_Filters){ 46 | for(let shaderNode in ShaderNodes._s_Filters[group]._s_Filters){ 47 | node = ShaderNodes._s_Filters[group]._s_Filters[shaderNode]; 48 | node = new node(); 49 | editor.register(node); 50 | engine.register(node); 51 | } 52 | } 53 | } 54 | 55 | /** 56 | * 提升类型转换,将转换为varType1和varType2中其中的一个类型。
57 | * @param {String}[varType1] 58 | * @param {String}[varType2] 59 | * @return {String} 60 | */ 61 | static upgradeCast(varType1, varType2){ 62 | return (ShaderNodes._s_VarTypes[varType1] > ShaderNodes._s_VarTypes[varType2]) ? varType1 : varType2; 63 | } 64 | static cast(varType1, varType2){ 65 | 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/editor/shadernodes/Sockets.js: -------------------------------------------------------------------------------- 1 | import Rete from "rete"; 2 | 3 | /** 4 | * Sockets类提供了当前系统内置shaderNode可以连接的插槽类型。
5 | * @author JohnKkk 6 | * @date 2022年7月9日10点21分 7 | */ 8 | export default class Sockets{ 9 | static s_NoContinueSocket = new Rete.Socket('s_NoContinueSocket'); 10 | static s_OperationSocket = new Rete.Socket('s_OperationSocket'); 11 | static s_NumSocket = new Rete.Socket('s_NumSocket'); 12 | static s_BoolSocket = new Rete.Socket('s_BoolSocket'); 13 | static s_UniversalSocket = new Rete.Socket('s_UniversalSocket'); 14 | static s_NumArraySocket = new Rete.Socket('s_NumArraySocket'); 15 | static s_Texture2DSocket = new Rete.Socket('s_Texture2DSocket'); 16 | static s_TextureCubeSocket = new Rete.Socket('s_TextureCubeSocket'); 17 | static s_Vector2Socket = new Rete.Socket('s_Vector2Socket'); 18 | static s_Vector3Socket = new Rete.Socket('s_Vector3Socket'); 19 | static s_Vector4Socket = new Rete.Socket('s_Vector4Socket'); 20 | static s_Matrix4Socket = new Rete.Socket('s_Matrix4Socket'); 21 | static s_Matrix3Socket = new Rete.Socket('s_Matrix3Socket'); 22 | 23 | // Param 24 | static s_PNumSocket = new Rete.Socket('s_PNumSocket'); 25 | static s_PBoolSocket = new Rete.Socket('s_PBoolSocket'); 26 | static s_PTexture2DSocket = new Rete.Socket('s_PTexture2DSocket'); 27 | static s_PTextureCubeSocket = new Rete.Socket('s_PTextureCubeSocket'); 28 | static s_PVector2Socket = new Rete.Socket('s_PVector2Socket'); 29 | static s_PVector3Socket = new Rete.Socket('s_PVector3Socket'); 30 | static s_PVector4Socket = new Rete.Socket('s_PVector4Socket'); 31 | static s_PMatrix4Socket = new Rete.Socket('s_PMatrix4Socket'); 32 | static s_PMatrix3Socket = new Rete.Socket('s_PMatrix3Socket'); 33 | 34 | 35 | static s_Attribute = new Rete.Socket('s_Attribute'); 36 | static init(){ 37 | // 运行socket的连接 38 | Sockets.s_NumSocket.combineWith(Sockets.s_OperationSocket); 39 | Sockets.s_NumArraySocket.combineWith(Sockets.s_OperationSocket); 40 | Sockets.s_BoolSocket.combineWith(Sockets.s_OperationSocket); 41 | Sockets.s_Vector2Socket.combineWith(Sockets.s_OperationSocket); 42 | Sockets.s_Vector3Socket.combineWith(Sockets.s_OperationSocket); 43 | Sockets.s_Vector4Socket.combineWith(Sockets.s_OperationSocket); 44 | Sockets.s_Texture2DSocket.combineWith(Sockets.s_OperationSocket); 45 | Sockets.s_TextureCubeSocket.combineWith(Sockets.s_OperationSocket); 46 | 47 | Sockets.s_OperationSocket.combineWith(Sockets.s_NumSocket); 48 | Sockets.s_OperationSocket.combineWith(Sockets.s_NumArraySocket); 49 | Sockets.s_OperationSocket.combineWith(Sockets.s_BoolSocket); 50 | Sockets.s_OperationSocket.combineWith(Sockets.s_Vector2Socket); 51 | Sockets.s_OperationSocket.combineWith(Sockets.s_Vector3Socket); 52 | Sockets.s_OperationSocket.combineWith(Sockets.s_Vector4Socket); 53 | Sockets.s_OperationSocket.combineWith(Sockets.s_Texture2DSocket); 54 | Sockets.s_OperationSocket.combineWith(Sockets.s_TextureCubeSocket); 55 | 56 | Sockets.s_PNumSocket.combineWith(Sockets.s_OperationSocket); 57 | Sockets.s_PBoolSocket.combineWith(Sockets.s_OperationSocket); 58 | Sockets.s_PVector2Socket.combineWith(Sockets.s_OperationSocket); 59 | Sockets.s_PVector3Socket.combineWith(Sockets.s_OperationSocket); 60 | Sockets.s_PVector4Socket.combineWith(Sockets.s_OperationSocket); 61 | Sockets.s_PMatrix3Socket.combineWith(Sockets.s_OperationSocket); 62 | Sockets.s_PMatrix4Socket.combineWith(Sockets.s_OperationSocket); 63 | 64 | Sockets.s_OperationSocket.combineWith(Sockets.s_PNumSocket); 65 | Sockets.s_OperationSocket.combineWith(Sockets.s_PBoolSocket); 66 | Sockets.s_OperationSocket.combineWith(Sockets.s_PVector2Socket); 67 | Sockets.s_OperationSocket.combineWith(Sockets.s_PVector3Socket); 68 | Sockets.s_OperationSocket.combineWith(Sockets.s_PVector4Socket); 69 | Sockets.s_OperationSocket.combineWith(Sockets.s_PMatrix3Socket); 70 | Sockets.s_OperationSocket.combineWith(Sockets.s_PMatrix4Socket); 71 | 72 | Sockets.s_PBoolSocket.combineWith(Sockets.s_BoolSocket); 73 | Sockets.s_PNumSocket.combineWith(Sockets.s_NumSocket); 74 | Sockets.s_PVector2Socket.combineWith(Sockets.s_Vector2Socket); 75 | Sockets.s_PVector3Socket.combineWith(Sockets.s_Vector3Socket); 76 | Sockets.s_PVector4Socket.combineWith(Sockets.s_Vector4Socket); 77 | Sockets.s_PMatrix3Socket.combineWith(Sockets.s_Matrix3Socket); 78 | Sockets.s_PMatrix4Socket.combineWith(Sockets.s_Matrix4Socket); 79 | Sockets.s_PTexture2DSocket.combineWith(Sockets.s_Texture2DSocket); 80 | Sockets.s_PTextureCubeSocket.combineWith(Sockets.s_TextureCubeSocket); 81 | Sockets.s_PNumSocket.combineWith(Sockets.s_BoolSocket); 82 | Sockets.s_PVector2Socket.combineWith(Sockets.s_BoolSocket); 83 | Sockets.s_PVector3Socket.combineWith(Sockets.s_BoolSocket); 84 | Sockets.s_PVector4Socket.combineWith(Sockets.s_BoolSocket); 85 | Sockets.s_PMatrix3Socket.combineWith(Sockets.s_BoolSocket); 86 | Sockets.s_PMatrix4Socket.combineWith(Sockets.s_BoolSocket); 87 | Sockets.s_PTexture2DSocket.combineWith(Sockets.s_BoolSocket); 88 | Sockets.s_PTextureCubeSocket.combineWith(Sockets.s_BoolSocket); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/editor/shadernodes/common/Commons.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Commons表示可用的一组常用的节点,包括顶点变换,法线转换,视察计算等。
3 | * @author JohnKkk 4 | * @date 2022年7月20日21点16分 5 | */ 6 | import IfElseBranchComponent from './IfElseBranchComponent' 7 | import TransformVector3Component from './TransformVector3Component' 8 | 9 | export default class Commons { 10 | static _s_Filters = [ 11 | IfElseBranchComponent, 12 | TransformVector3Component, 13 | ]; 14 | static getGroup(){ 15 | return 'common'; 16 | } 17 | static filter(component){ 18 | let r = false; 19 | let targetComponentName = component.name + 'Component'; 20 | for(let c in Commons._s_Filters){ 21 | if(Commons._s_Filters[c].name == targetComponentName){ 22 | r = true; 23 | break; 24 | } 25 | } 26 | return r; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/editor/shadernodes/common/TransformVector3Component.js: -------------------------------------------------------------------------------- 1 | import Rete from "rete"; 2 | import Sockets from "../Sockets"; 3 | import ShaderNode from '../ShaderNode' 4 | export default class TransformVector3Component extends ShaderNode { 5 | constructor() { 6 | super('TransformVector3'); 7 | } 8 | 9 | _builder(node) { 10 | let vec4Out = new Rete.Output('vec4Out', 'Vec4Out', Sockets.s_Vector4Socket); 11 | 12 | let inMatrix4x4 = new Rete.Input('inMatrix4x4', 'InMatrix4x4', Sockets.s_Matrix4Socket); 13 | let inVec3 = new Rete.Input('inVec3', 'InVec3', Sockets.s_Vector3Socket); 14 | 15 | node.addOutput(vec4Out); 16 | node.addInput(inVec3); 17 | node.addInput(inMatrix4x4); 18 | 19 | // inputMap 20 | node.data._m_Props._m_InputsMap['inVec3'] = {type:'vec3', varname:this.getVarName(node, 'inVec3')}; 21 | node.data._m_Props._m_InputsMap['inMatrix4x4'] = {type:'mat4', varname:this.getVarName(node, 'inMatrix4x4')}; 22 | // outputMap 23 | node.data._m_Props._m_OutputsMap['vec4Out'] = {type:'vec4', varname:this.getVarName(node, 'vec4Out'), defaultValue:null}; 24 | return node; 25 | } 26 | _getNodeCodeString (node) { 27 | return ' vec4Out = inMatrix4x4 * vec4( inVec3 , 1.0f) ;\n'; 28 | } 29 | 30 | _worker(node, inputs, outputs) { 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/editor/shadernodes/input/BoolInputStructureComponent.js: -------------------------------------------------------------------------------- 1 | import Sockets from '../Sockets' 2 | import InputStructureComponent from './InputStructureComponent' 3 | 4 | export default class BoolInputStructureComponent extends InputStructureComponent{ 5 | constructor () { 6 | super('BoolInputStructure'); 7 | 8 | } 9 | 10 | _outputSocket () { 11 | return Sockets.s_BoolSocket; 12 | } 13 | 14 | _paramType () { 15 | return 'bool'; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/editor/shadernodes/input/FloatInputStructureComponent.js: -------------------------------------------------------------------------------- 1 | import Sockets from '../Sockets' 2 | import InputStructureComponent from './InputStructureComponent' 3 | 4 | export default class FloatInputStructureComponent extends InputStructureComponent{ 5 | constructor () { 6 | super('FloatInputStructure'); 7 | 8 | } 9 | 10 | _outputSocket () { 11 | return Sockets.s_NumSocket; 12 | } 13 | 14 | _paramType () { 15 | return 'float'; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/editor/shadernodes/input/InputAttributeComponent.js: -------------------------------------------------------------------------------- 1 | import ShaderNode from '../ShaderNode' 2 | import Sockets from '../Sockets' 3 | import Rete from 'rete' 4 | import TextControl from '../param/TextControl' 5 | import Try3d from 'try3d/src/Try3d' 6 | 7 | /** 8 | * InputAttributeComponent,所有可用的顶点输入属性。
9 | * @author JohnKkk 10 | * @date 2022年7月19日19点46分 11 | */ 12 | export default class InputAttributeComponent extends ShaderNode{ 13 | constructor () { 14 | super('InputAttribute'); 15 | } 16 | _getNodeCodeString (node) { 17 | return ''; 18 | } 19 | 20 | _getNodeCode(node){ 21 | return ''; 22 | } 23 | 24 | /** 25 | * 返回输出Socket。
26 | * @return {null} 27 | * @private 28 | */ 29 | _outputSocket(){ 30 | return null; 31 | } 32 | 33 | /** 34 | * 返回参数类型。
35 | * @return {string} 36 | * @private 37 | */ 38 | _paramType(){ 39 | return ''; 40 | } 41 | 42 | _builder(node) { 43 | let inPosition = new Rete.Output('inPosition', 'InPosition(vec3)', Sockets.s_Vector3Socket); 44 | let inNormal = new Rete.Output('inNormal', 'InNormal(vec3)', Sockets.s_Vector3Socket); 45 | let inTangent = new Rete.Output('inTangent', 'InTangent(vec3)', Sockets.s_Vector3Socket); 46 | let inUv0 = new Rete.Output('inUv0', 'InUv0(vec2)', Sockets.s_Vector2Socket); 47 | let inJoint0 = new Rete.Output('inJoint0', 'InJoint0(int)', Sockets.s_Vector4Socket); 48 | let inWeight0 = new Rete.Output('inWeight0', 'InWeight0(vec4)', Sockets.s_Vector4Socket); 49 | 50 | node.addOutput(inPosition); 51 | node.addOutput(inNormal); 52 | node.addOutput(inTangent); 53 | node.addOutput(inUv0); 54 | node.addOutput(inJoint0); 55 | node.addOutput(inWeight0); 56 | 57 | // outputMap 58 | node.data._m_Props._m_OutputsMap['inPosition'] = {type:Try3d.ShaderSource.Context_Data['Context.InPosition'].type, varname:'Context.InPosition', defaultValue:null}; 59 | node.data._m_Props._m_OutputsMap['inNormal'] = {type:Try3d.ShaderSource.Context_Data['Context.InNormal'].type, varname:'Context.InNormal', defaultValue:null}; 60 | node.data._m_Props._m_OutputsMap['inTangent'] = {type:Try3d.ShaderSource.Context_Data['Context.InTangent'].type, varname:'Context.InTangent', defaultValue:null}; 61 | node.data._m_Props._m_OutputsMap['inUv0'] = {type:Try3d.ShaderSource.Context_Data['Context.InUv0'].type, varname:'Context.InUv0', defaultValue:null}; 62 | node.data._m_Props._m_OutputsMap['inJoint0'] = {type:Try3d.ShaderSource.Context_Data['Context.InJoint0'].type, varname:'Context.InJoint0', defaultValue:null}; 63 | node.data._m_Props._m_OutputsMap['inWeight0'] = {type:Try3d.ShaderSource.Context_Data['Context.InWeight0'].type, varname:'Context.InWeight0', defaultValue:null}; 64 | return node; 65 | } 66 | 67 | _updateBinding(node){ 68 | } 69 | 70 | _updateShaderNodeCode(node){ 71 | let props = node.data._m_Props; 72 | props._m_ShaderNodeCode = props._m_ShaderNodeCodeSource = ''; 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/editor/shadernodes/input/InputMatrixComponent.js: -------------------------------------------------------------------------------- 1 | import ShaderNode from '../ShaderNode' 2 | import Sockets from '../Sockets' 3 | import Rete from 'rete' 4 | import TextControl from '../param/TextControl' 5 | import Try3d from 'try3d/src/Try3d' 6 | 7 | /** 8 | * InputMatrixComponent,所有可用的上下文输入矩阵。
9 | * @author JohnKkk 10 | * @date 2022年7月29日11点27分 11 | */ 12 | export default class InputMatrixComponent extends ShaderNode{ 13 | constructor () { 14 | super('InputMatrix'); 15 | } 16 | _getNodeCodeString (node) { 17 | return ''; 18 | } 19 | 20 | _getNodeCode(node){ 21 | return ''; 22 | } 23 | 24 | /** 25 | * 返回输出Socket。
26 | * @return {null} 27 | * @private 28 | */ 29 | _outputSocket(){ 30 | return null; 31 | } 32 | 33 | /** 34 | * 返回参数类型。
35 | * @return {string} 36 | * @private 37 | */ 38 | _paramType(){ 39 | return ''; 40 | } 41 | 42 | _builder(node) { 43 | let inModelMatrix4x4 = new Rete.Output('inModelMatrix4x4', 'InModelMatrix4x4', Sockets.s_Matrix4Socket); 44 | let inViewMatrix4x4 = new Rete.Output('inViewMatrix4x4', 'InViewMatrix4x4', Sockets.s_Matrix4Socket); 45 | let inProjectMatrix4x4 = new Rete.Output('inProjectMatrix4x4', 'InProjectMatrix4x4', Sockets.s_Matrix4Socket); 46 | let inMVPMatrix4x4 = new Rete.Output('inMVPMatrix4x4', 'InMVPMatrix4x4', Sockets.s_Matrix4Socket); 47 | let inVPMatrix4x4 = new Rete.Output('inVPMatrix4x4', 'InProjViewMatrix4x4', Sockets.s_Matrix4Socket); 48 | 49 | node.addOutput(inModelMatrix4x4); 50 | node.addOutput(inViewMatrix4x4); 51 | node.addOutput(inProjectMatrix4x4); 52 | node.addOutput(inMVPMatrix4x4); 53 | node.addOutput(inVPMatrix4x4); 54 | 55 | // outputMap 56 | node.data._m_Props._m_OutputsMap['inModelMatrix4x4'] = {type:Try3d.ShaderSource.Context_Data['Context.ModelMatrix'].type, varname:'Context.ModelMatrix', defaultValue:null}; 57 | node.data._m_Props._m_OutputsMap['inViewMatrix4x4'] = {type:Try3d.ShaderSource.Context_Data['Context.ViewMatrix'].type, varname:'Context.ViewMatrix', defaultValue:null}; 58 | node.data._m_Props._m_OutputsMap['inProjectMatrix4x4'] = {type:Try3d.ShaderSource.Context_Data['Context.ProjectMatrix'].type, varname:'Context.ProjectMatrix', defaultValue:null}; 59 | node.data._m_Props._m_OutputsMap['inMVPMatrix4x4'] = {type:Try3d.ShaderSource.Context_Data['Context.ProjectViewModelMatrix'].type, varname:'Context.ProjectViewModelMatrix', defaultValue:null}; 60 | node.data._m_Props._m_OutputsMap['inVPMatrix4x4'] = {type:Try3d.ShaderSource.Context_Data['Context.ProjectViewMatrix'].type, varname:'Context.ProjectViewMatrix', defaultValue:null}; 61 | return node; 62 | } 63 | 64 | _updateBinding(node){ 65 | } 66 | 67 | _updateShaderNodeCode(node){ 68 | let props = node.data._m_Props; 69 | props._m_ShaderNodeCode = props._m_ShaderNodeCodeSource = ''; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/editor/shadernodes/input/InputStructureComponent.js: -------------------------------------------------------------------------------- 1 | import ShaderNode from '../ShaderNode' 2 | import Sockets from '../Sockets' 3 | import Rete from 'rete' 4 | import TextControl from '../param/TextControl' 5 | 6 | /** 7 | * InputStructureComponent,是所有输入结构类型节点的父类。
8 | * @author JohnKkk 9 | * @date 2022年7月19日18点31分 10 | */ 11 | export default class InputStructureComponent extends ShaderNode{ 12 | _getNodeCodeString (node) { 13 | return ''; 14 | } 15 | static getParam(node){ 16 | let props = node.data._m_Props; 17 | return {type:props._m_OutputsMap['valueOut'].type, name:props._m_OutputsMap['valueOut'].varname}; 18 | } 19 | 20 | _getNodeCode(node){ 21 | return ''; 22 | } 23 | 24 | /** 25 | * 返回输出Socket。
26 | * @return {null} 27 | * @private 28 | */ 29 | _outputSocket(){ 30 | return null; 31 | } 32 | 33 | /** 34 | * 返回参数类型。
35 | * @return {string} 36 | * @private 37 | */ 38 | _paramType(){ 39 | return ''; 40 | } 41 | 42 | _builder(node) { 43 | let out = new Rete.Output('valueOut', 'Value', this._outputSocket()); 44 | let inVarName = new Rete.Input('inVarName', 'VarName', Sockets.s_NoContinueSocket); 45 | 46 | inVarName.addControl(new TextControl(this.editor, "inVarName")); 47 | node.addInput(inVarName); 48 | node.addOutput(out); 49 | 50 | // outputMap 51 | node.data._m_Props._m_OutputsMap['valueOut'] = {type:this._paramType(), varname:this.getVarName(node, 'valueOut'), defaultValue:null}; 52 | return node; 53 | } 54 | 55 | _updateBinding(node){ 56 | let nodeProps = node.data._m_Props; 57 | let varname = node.data.inVarName; 58 | if(varname == undefined || varname.trim() == ''){ 59 | varname = this.getVarName(node, 'valueOut'); 60 | } 61 | nodeProps._m_OutputsMap['valueOut'].varname = varname; 62 | } 63 | 64 | _updateShaderNodeCode(node){ 65 | let props = node.data._m_Props; 66 | props._m_ShaderNodeCode = props._m_ShaderNodeCodeSource = ''; 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/editor/shadernodes/input/Inputs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Inputs表示可用的一组输入相关的节点,主要是上下文输入变量,顶点属性。
3 | * 输入节点用于构建最终ShaderCode的上下文变量和顶点属性。
4 | * @author JohnKkk 5 | * @date 2022年7月19日17点33分 6 | */ 7 | import BoolInputStructureComponent from './BoolInputStructureComponent' 8 | import IntInputStructureComponent from './IntInputStructureComponent' 9 | import FloatInputStructureComponent from './FloatInputStructureComponent' 10 | import Vec2InputStructureComponent from './Vec2InputStructureComponent' 11 | import Vec3InputStructureComponent from './Vec3InputStructureComponent' 12 | import Vec4InputStructureComponent from './Vec4InputStructureComponent' 13 | import InputAttributeComponent from './InputAttributeComponent' 14 | import InputMatrixComponent from './InputMatrixComponent' 15 | 16 | export default class Inputs { 17 | static _s_InputStructureFilters = [ 18 | BoolInputStructureComponent, 19 | IntInputStructureComponent, 20 | FloatInputStructureComponent, 21 | Vec2InputStructureComponent, 22 | Vec3InputStructureComponent, 23 | Vec4InputStructureComponent 24 | ]; 25 | static _s_InputContexts = [ 26 | InputAttributeComponent 27 | ]; 28 | static _s_Filters = [ 29 | InputAttributeComponent, 30 | InputMatrixComponent, 31 | BoolInputStructureComponent, 32 | IntInputStructureComponent, 33 | FloatInputStructureComponent, 34 | Vec2InputStructureComponent, 35 | Vec3InputStructureComponent, 36 | Vec4InputStructureComponent 37 | ]; 38 | static getGroup(){ 39 | return 'input'; 40 | } 41 | static filterInputContext(component){ 42 | let r = false; 43 | let targetComponentName = component.name + 'Component'; 44 | for(let c in Inputs._s_InputContexts){ 45 | if(Inputs._s_InputContexts[c].name == targetComponentName){ 46 | r = true; 47 | break; 48 | } 49 | } 50 | return r; 51 | } 52 | static filterInputStructure(component){ 53 | let r = false; 54 | let targetComponentName = component.name + 'Component'; 55 | for(let c in Inputs._s_InputStructureFilters){ 56 | if(Inputs._s_Filters[c].name == targetComponentName){ 57 | r = true; 58 | break; 59 | } 60 | } 61 | return r; 62 | } 63 | static filter(component){ 64 | let r = false; 65 | let targetComponentName = component.name + 'Component'; 66 | for(let c in Inputs._s_Filters){ 67 | if(Inputs._s_Filters[c].name == targetComponentName){ 68 | r = true; 69 | break; 70 | } 71 | } 72 | return r; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/editor/shadernodes/input/IntInputStructureComponent.js: -------------------------------------------------------------------------------- 1 | import Sockets from '../Sockets' 2 | import InputStructureComponent from './InputStructureComponent' 3 | 4 | export default class IntInputStructureComponent extends InputStructureComponent{ 5 | constructor () { 6 | super('IntInputStructure'); 7 | 8 | } 9 | 10 | _outputSocket () { 11 | return Sockets.s_NumSocket; 12 | } 13 | 14 | _paramType () { 15 | return 'int'; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/editor/shadernodes/input/Vec2InputStructureComponent.js: -------------------------------------------------------------------------------- 1 | import Sockets from '../Sockets' 2 | import InputStructureComponent from './InputStructureComponent' 3 | 4 | export default class Vec2InputStructureComponent extends InputStructureComponent{ 5 | constructor () { 6 | super('Vec2InputStructure'); 7 | 8 | } 9 | 10 | _outputSocket () { 11 | return Sockets.s_Vector2Socket; 12 | } 13 | 14 | _paramType () { 15 | return 'vec2'; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/editor/shadernodes/input/Vec3InputStructureComponent.js: -------------------------------------------------------------------------------- 1 | import Sockets from '../Sockets' 2 | import InputStructureComponent from './InputStructureComponent' 3 | 4 | export default class Vec3InputStructureComponent extends InputStructureComponent{ 5 | constructor () { 6 | super('Vec3InputStructure'); 7 | 8 | } 9 | 10 | _outputSocket () { 11 | return Sockets.s_Vector3Socket; 12 | } 13 | 14 | _paramType () { 15 | return 'vec3'; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/editor/shadernodes/input/Vec4InputStructureComponent.js: -------------------------------------------------------------------------------- 1 | import Sockets from '../Sockets' 2 | import InputStructureComponent from './InputStructureComponent' 3 | 4 | export default class Vec4InputStructureComponent extends InputStructureComponent{ 5 | constructor () { 6 | super('Vec4InputStructure'); 7 | 8 | } 9 | 10 | _outputSocket () { 11 | return Sockets.s_Vector4Socket; 12 | } 13 | 14 | _paramType () { 15 | return 'vec4'; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/editor/shadernodes/math/AddComponent.js: -------------------------------------------------------------------------------- 1 | import MathComponent from "./MathComponent"; 2 | 3 | export default class AddComponent extends MathComponent { 4 | constructor() { 5 | super("Add"); 6 | } 7 | doOperation(v1, v2) { 8 | return v1 + v2; 9 | } 10 | 11 | /** 12 | * 返回节点代码。
13 | * @return {string} 14 | * @private 15 | */ 16 | _getNodeCodeString (node) { 17 | return ' numOut = inNum1 + inNum2 ;\n'; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/editor/shadernodes/math/ConstructVec2Component.js: -------------------------------------------------------------------------------- 1 | import ShaderNode from '../ShaderNode' 2 | import Rete from 'rete' 3 | import Sockets from '../Sockets' 4 | import NumberControl from './NumberControl' 5 | 6 | export default class ConstructVec2Component extends ShaderNode{ 7 | constructor () { 8 | super('ConstructVec2'); 9 | } 10 | 11 | _builder(node) { 12 | let inp1 = new Rete.Input("inX", "X", Sockets.s_NumSocket); 13 | let inp2 = new Rete.Input("inY", "Y", Sockets.s_NumSocket); 14 | let out = new Rete.Output("ResultOut", "Result", Sockets.s_Vector2Socket); 15 | 16 | inp1.addControl(new NumberControl(this.editor, "inX")); 17 | inp2.addControl(new NumberControl(this.editor, "inY")); 18 | 19 | let nodeProps = node.data._m_Props; 20 | // inputMap 21 | nodeProps._m_InputsMap['inX'] = {type:'float', varname:this.getVarName(node, 'inX'), defaultValue:'0.0f'}; 22 | nodeProps._m_InputsMap['inY'] = {type:'float', varname:this.getVarName(node, 'inY'), defaultValue:'0.0f'}; 23 | 24 | // outputMap 25 | nodeProps._m_OutputsMap['ResultOut'] = {type:'vec2', varname:this.getVarName(node, 'Result'), defaultValue:'vec2( ' + this.getVarName(node, 'inX') + ' , ' + this.getVarName(node, 'inY') + ' )'}; 26 | 27 | return node 28 | .addInput(inp1) 29 | .addInput(inp2) 30 | .addOutput(out); 31 | } 32 | 33 | _worker(node, inputs, outputs) { 34 | let nodeProps = node.data._m_Props; 35 | let x = inputs["inX"].length ? inputs["inX"][0] : node.data.inX; 36 | let y = inputs["inY"].length ? inputs["inY"][0] : node.data.inY; 37 | if(x != undefined) 38 | nodeProps._m_InputsMap['inX'].defaultValue = 'float(' + x + ')'; 39 | if(y != undefined) 40 | nodeProps._m_InputsMap['inY'].defaultValue = 'float(' + y + ')'; 41 | 42 | outputs["ResultOut"] = 'vec2(' + x + ',' + y + ')'; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/editor/shadernodes/math/ConstructVec3Component.js: -------------------------------------------------------------------------------- 1 | import ShaderNode from '../ShaderNode' 2 | import Rete from 'rete' 3 | import Sockets from '../Sockets' 4 | import NumberControl from './NumberControl' 5 | 6 | export default class ConstructVec3Component extends ShaderNode{ 7 | constructor () { 8 | super('ConstructVec3'); 9 | } 10 | 11 | _builder(node) { 12 | let inp1 = new Rete.Input("inX", "X", Sockets.s_NumSocket); 13 | let inp2 = new Rete.Input("inY", "Y", Sockets.s_NumSocket); 14 | let inp3 = new Rete.Input("inZ", "Z", Sockets.s_NumSocket); 15 | let out = new Rete.Output("ResultOut", "Result", Sockets.s_Vector3Socket); 16 | 17 | inp1.addControl(new NumberControl(this.editor, "inX")); 18 | inp2.addControl(new NumberControl(this.editor, "inY")); 19 | inp3.addControl(new NumberControl(this.editor, "inZ")); 20 | 21 | let nodeProps = node.data._m_Props; 22 | // inputMap 23 | nodeProps._m_InputsMap['inX'] = {type:'float', varname:this.getVarName(node, 'inX'), defaultValue:'0.0f'}; 24 | nodeProps._m_InputsMap['inY'] = {type:'float', varname:this.getVarName(node, 'inY'), defaultValue:'0.0f'}; 25 | nodeProps._m_InputsMap['inZ'] = {type:'float', varname:this.getVarName(node, 'inZ'), defaultValue:'0.0f'}; 26 | 27 | // outputMap 28 | nodeProps._m_OutputsMap['ResultOut'] = {type:'vec3', varname:this.getVarName(node, 'Result'), defaultValue:'vec3( ' + this.getVarName(node, 'inX') + ' , ' + this.getVarName(node, 'inY') + ' , ' + this.getVarName(node, 'inZ') + ' )'}; 29 | 30 | return node 31 | .addInput(inp1) 32 | .addInput(inp2) 33 | .addInput(inp3) 34 | .addOutput(out); 35 | } 36 | 37 | _worker(node, inputs, outputs) { 38 | let nodeProps = node.data._m_Props; 39 | let x = inputs["inX"].length ? inputs["inX"][0] : node.data.inX; 40 | let y = inputs["inY"].length ? inputs["inY"][0] : node.data.inY; 41 | let z = inputs["inZ"].length ? inputs["inZ"][0] : node.data.inZ; 42 | if(x != undefined) 43 | nodeProps._m_InputsMap['inX'].defaultValue = 'float(' + x + ')'; 44 | if(y != undefined) 45 | nodeProps._m_InputsMap['inY'].defaultValue = 'float(' + y + ')'; 46 | if(z != undefined) 47 | nodeProps._m_InputsMap['inZ'].defaultValue = 'float(' + z + ')'; 48 | 49 | outputs["ResultOut"] = 'vec3( ' + x + ' , ' + y + ' , ' + z + ' )'; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/editor/shadernodes/math/ConstructVec4Component.js: -------------------------------------------------------------------------------- 1 | import ShaderNode from '../ShaderNode' 2 | import Rete from 'rete' 3 | import Sockets from '../Sockets' 4 | import NumberControl from './NumberControl' 5 | 6 | export default class ConstructVec4Component extends ShaderNode{ 7 | constructor () { 8 | super('ConstructVec4'); 9 | } 10 | 11 | _builder(node) { 12 | let inp1 = new Rete.Input("inX", "X", Sockets.s_NumSocket); 13 | let inp2 = new Rete.Input("inY", "Y", Sockets.s_NumSocket); 14 | let inp3 = new Rete.Input("inZ", "Z", Sockets.s_NumSocket); 15 | let inp4 = new Rete.Input("inW", "W", Sockets.s_NumSocket); 16 | let out = new Rete.Output("ResultOut", "Result", Sockets.s_Vector4Socket); 17 | 18 | inp1.addControl(new NumberControl(this.editor, "inX")); 19 | inp2.addControl(new NumberControl(this.editor, "inY")); 20 | inp3.addControl(new NumberControl(this.editor, "inZ")); 21 | inp4.addControl(new NumberControl(this.editor, "inW")); 22 | 23 | let nodeProps = node.data._m_Props; 24 | // inputMap 25 | nodeProps._m_InputsMap['inX'] = {type:'float', varname:this.getVarName(node, 'inX'), defaultValue:'0.0f'}; 26 | nodeProps._m_InputsMap['inY'] = {type:'float', varname:this.getVarName(node, 'inY'), defaultValue:'0.0f'}; 27 | nodeProps._m_InputsMap['inZ'] = {type:'float', varname:this.getVarName(node, 'inZ'), defaultValue:'0.0f'}; 28 | nodeProps._m_InputsMap['inW'] = {type:'float', varname:this.getVarName(node, 'inW'), defaultValue:'0.0f'}; 29 | 30 | // outputMap 31 | nodeProps._m_OutputsMap['ResultOut'] = {type:'vec4', varname:this.getVarName(node, 'Result'), defaultValue:'vec4( ' + this.getVarName(node, 'inX') + ' , ' + this.getVarName(node, 'inY') + ' , ' + this.getVarName(node, 'inZ') + ' , ' + this.getVarName(node, 'inW') + ' )'}; 32 | 33 | return node 34 | .addInput(inp1) 35 | .addInput(inp2) 36 | .addInput(inp3) 37 | .addInput(inp4) 38 | .addOutput(out); 39 | } 40 | 41 | _worker(node, inputs, outputs) { 42 | let nodeProps = node.data._m_Props; 43 | let x = inputs["inX"].length ? inputs["inX"][0] : node.data.inX; 44 | let y = inputs["inY"].length ? inputs["inY"][0] : node.data.inY; 45 | let z = inputs["inZ"].length ? inputs["inZ"][0] : node.data.inZ; 46 | let w = inputs["inW"].length ? inputs["inW"][0] : node.data.inW; 47 | if(x != undefined) 48 | nodeProps._m_InputsMap['inX'].defaultValue = 'float(' + x + ')'; 49 | if(y != undefined) 50 | nodeProps._m_InputsMap['inY'].defaultValue = 'float(' + y + ')'; 51 | if(z != undefined) 52 | nodeProps._m_InputsMap['inZ'].defaultValue = 'float(' + z + ')'; 53 | if(w != undefined) 54 | nodeProps._m_InputsMap['inW'].defaultValue = 'float(' + w + ')'; 55 | 56 | outputs["ResultOut"] = 'vec3( ' + x + ' , ' + y + ' , ' + z + ' , ' + w + ' )'; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/editor/shadernodes/math/DivideComponent.js: -------------------------------------------------------------------------------- 1 | import MathComponent from "./MathComponent"; 2 | 3 | export default class DivideComponent extends MathComponent { 4 | constructor() { 5 | super("Divide"); 6 | } 7 | doOperation(v1, v2) { 8 | return v2 != 0 ? v1 / v2 : 0; 9 | } 10 | _getNodeCodeString (node) { 11 | return ' numOut = inNum1 / inNum2 ;\n'; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/editor/shadernodes/math/MathComponent.js: -------------------------------------------------------------------------------- 1 | import Rete from "rete"; 2 | import NumberControl from "./NumberControl"; 3 | import Sockets from "../Sockets"; 4 | import ShaderNode from '../ShaderNode' 5 | 6 | export default class MathComponent extends ShaderNode { 7 | static _s_VarTypes = { 8 | 'bool':0, 9 | 'int':1, 10 | 'float':2, 11 | 'vec2':3, 12 | 'vec3':4, 13 | 'vec4':5 14 | }; 15 | 16 | /** 17 | * 提升类型转换,将转换为varType1和varType2中其中的一个类型。
18 | * @param {String}[varType1] 19 | * @param {String}[varType2] 20 | * @return {String} 21 | */ 22 | static upgradeCast(varType1, varType2){ 23 | return (MathComponent._s_VarTypes[varType1] > MathComponent._s_VarTypes[varType2]) ? varType1 : varType2; 24 | } 25 | 26 | static cast(varType1, varType2){ 27 | 28 | } 29 | 30 | doOperation(v1, v2) { 31 | return 0; 32 | } 33 | 34 | _builder(node) { 35 | let inp1 = new Rete.Input("inNum1", "Value 1", Sockets.s_OperationSocket); 36 | let inp2 = new Rete.Input("inNum2", "Value 2", Sockets.s_OperationSocket); 37 | let out = new Rete.Output("numOut", "Result", Sockets.s_OperationSocket); 38 | 39 | inp1.addControl(new NumberControl(this.editor, "inNum1")); 40 | inp2.addControl(new NumberControl(this.editor, "inNum2")); 41 | 42 | let nodeProps = node.data._m_Props; 43 | // inputMap 44 | nodeProps._m_InputsMap['inNum1'] = {type:'float', varname:this.getVarName(node, 'inNum1'), defaultValue:null}; 45 | nodeProps._m_InputsMap['inNum2'] = {type:'float', varname:this.getVarName(node, 'inNum2'), defaultValue:null}; 46 | 47 | // outputMap 48 | nodeProps._m_OutputsMap['numOut'] = {type:'float', varname:this.getVarName(node, 'numOut'), defaultValue:null}; 49 | 50 | return node 51 | .addInput(inp1) 52 | .addInput(inp2) 53 | .addControl(new NumberControl(this.editor, "preview", true)) 54 | .addOutput(out); 55 | } 56 | isNumber(value) { 57 | return typeof value === 'number' && isFinite(value); 58 | } 59 | 60 | isNumberObject(n) { 61 | return (Object.prototype.toString.apply(n) === '[object Number]'); 62 | } 63 | 64 | isCustomNumber(n){ 65 | return this.isNumber(n) || this.isNumberObject(n); 66 | } 67 | 68 | _worker(node, inputs, outputs) { 69 | // if(node.inputs.num1.connections.length){ 70 | // let num1Node = this.editor.nodes.find(n=>n.id == node.inputs.num1.connections[0].node); 71 | // console.log('num1Node:',num1Node); 72 | // } 73 | let n1 = inputs["inNum1"].length ? inputs["inNum1"][0] : node.data.inNum1; 74 | let nodeProps = node.data._m_Props; 75 | if(this.isCustomNumber(n1)){ 76 | nodeProps._m_InputsMap['inNum1'].defaultValue = n1; 77 | } 78 | else{ 79 | nodeProps._m_InputsMap['inNum1'].defaultValue = null; 80 | } 81 | let n2 = inputs["inNum2"].length ? inputs["inNum2"][0] : node.data.inNum2; 82 | if(this.isCustomNumber(n2)){ 83 | nodeProps._m_InputsMap['inNum2'].defaultValue = n2; 84 | } 85 | else{ 86 | nodeProps._m_InputsMap['inNum2'].defaultValue = null; 87 | } 88 | let sum = this.doOperation(n1, n2); 89 | 90 | this.editor.nodes 91 | .find(n => n.id == node.id) 92 | .controls.get("preview") 93 | .setValue(sum); 94 | outputs["numOut"] = sum; 95 | } 96 | 97 | _updateBinding(node){ 98 | let nodeProps = node.data._m_Props; 99 | // 转换类型 100 | let numContinue = super._getContinueNode(node, 'inNum1', 0); 101 | if(numContinue){ 102 | let cont = node.inputs['inNum1'].connections[0].output; 103 | if(cont){ 104 | nodeProps._m_InputsMap['inNum1'].type = numContinue.data._m_Props._m_OutputsMap[cont].type; 105 | } 106 | } 107 | else{ 108 | nodeProps._m_InputsMap['inNum1'].type = 'float'; 109 | } 110 | numContinue = super._getContinueNode(node, 'inNum2', 0); 111 | if(numContinue){ 112 | let cont = node.inputs['inNum2'].connections[0].output; 113 | if(cont){ 114 | nodeProps._m_InputsMap['inNum2'].type = numContinue.data._m_Props._m_OutputsMap[cont].type; 115 | } 116 | } 117 | else{ 118 | nodeProps._m_InputsMap['inNum2'].type = 'float'; 119 | } 120 | let type1 = nodeProps._m_InputsMap['inNum1'].type; 121 | let type2 = nodeProps._m_InputsMap['inNum2'].type; 122 | let castType = MathComponent.upgradeCast(type1, type2); 123 | if(type1 == castType){ 124 | // todo:类型转换,确保运算正确 125 | } 126 | nodeProps._m_OutputsMap['numOut'].type = castType; 127 | this._updateOutputsBinding(node); 128 | super._updateBinding(node); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/editor/shadernodes/math/Maths.js: -------------------------------------------------------------------------------- 1 | import MathComponent from './MathComponent' 2 | import AddComponent from './AddComponent' 3 | import DivideComponent from './DivideComponent' 4 | import MultiplyComponent from './MultiplyComponent' 5 | import SubtractComponent from './SubtractComponent' 6 | import NumberComponent from './NumberComponent' 7 | import ConstructVec2Component from './ConstructVec2Component' 8 | import ConstructVec3Component from './ConstructVec3Component' 9 | import ConstructVec4Component from './ConstructVec4Component' 10 | 11 | /** 12 | * 表示Maths可用节点。
13 | * @author JohnKkk 14 | * @date 2022年7月12日12点43分 15 | */ 16 | export default class Maths { 17 | static _s_Filters = [ 18 | ConstructVec2Component, 19 | ConstructVec3Component, 20 | ConstructVec4Component, 21 | AddComponent, 22 | DivideComponent, 23 | MultiplyComponent, 24 | SubtractComponent, 25 | NumberComponent 26 | ]; 27 | static getGroup(){ 28 | return 'math'; 29 | } 30 | static filter(component){ 31 | let r = false; 32 | let targetComponentName = component.name + 'Component'; 33 | for(let c in Maths._s_Filters){ 34 | if(Maths._s_Filters[c].name == targetComponentName){ 35 | r = true; 36 | break; 37 | } 38 | } 39 | return r; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/editor/shadernodes/math/MultiplyComponent.js: -------------------------------------------------------------------------------- 1 | import MathComponent from "./MathComponent"; 2 | 3 | export default class MultiplyComponent extends MathComponent { 4 | constructor() { 5 | super("Multiply"); 6 | } 7 | doOperation(v1, v2) { 8 | return v1 * v2; 9 | } 10 | _getNodeCodeString (node) { 11 | return ' numOut = inNum1 * inNum2 ;\n'; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/editor/shadernodes/math/NumberComponent.js: -------------------------------------------------------------------------------- 1 | import Rete from "rete"; 2 | import Sockets from "../Sockets"; 3 | import NumberControl from "./NumberControl"; 4 | import ShaderNode from '../ShaderNode' 5 | export default class NumberComponent extends ShaderNode { 6 | constructor() { 7 | super('Number'); 8 | } 9 | 10 | _builder(node) { 11 | let out = new Rete.Output('numOut', 'Result', Sockets.s_NumSocket); 12 | 13 | node.addControl(new NumberControl(this.editor, "numOut")); 14 | node.addOutput(out); 15 | 16 | // outputMap 17 | node.data._m_Props._m_OutputsMap['numOut'] = {type:'float', varname:this.getVarName(node, 'numOut'), defaultValue:'0.0f'}; 18 | return node; 19 | } 20 | _getNodeCodeString (node) { 21 | let r = node.data.numOut != undefined ? 'float(' + node.data.numOut + ')' : '0.0f'; 22 | return ' numOut = ' + r + ' ;\n'; 23 | } 24 | 25 | _worker(node, inputs, outputs) { 26 | outputs['numOut'] = node.data.numOut; 27 | node.data._m_Props._m_RebuildCode = true; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/editor/shadernodes/math/NumberControl.js: -------------------------------------------------------------------------------- 1 | import Rete from "rete"; 2 | import Number from '../../../components/shadernodes/math/Number' 3 | 4 | export default class NumberControl extends Rete.Control { 5 | 6 | constructor(emitter, key, readonly) { 7 | super(key); 8 | this.component = Number; 9 | this.props = { emitter, key, readonly }; 10 | } 11 | 12 | setValue(val) { 13 | this.vueContext.value = val; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/editor/shadernodes/math/SubtractComponent.js: -------------------------------------------------------------------------------- 1 | import MathComponent from "./MathComponent"; 2 | 3 | export default class SubtractComponent extends MathComponent { 4 | constructor() { 5 | super("Subtract"); 6 | } 7 | doOperation(v1, v2) { 8 | return v1 - v2; 9 | } 10 | _getNodeCodeString (node) { 11 | return ' numOut = inNum1 - inNum2 ;\n'; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/editor/shadernodes/math/Vec2Splitter.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnLKkk/Produce/c1faed67e6365bb5e35724fe549f9d869a6c5140/src/editor/shadernodes/math/Vec2Splitter.js -------------------------------------------------------------------------------- /src/editor/shadernodes/output/BoolOutputStructureComponent.js: -------------------------------------------------------------------------------- 1 | import Sockets from '../Sockets' 2 | import OutputStructureComponent from './OutputStructureComponent' 3 | 4 | export default class BoolOutputStructureComponent extends OutputStructureComponent{ 5 | constructor () { 6 | super('BoolOutputStructure'); 7 | 8 | } 9 | 10 | _outputSocket () { 11 | return Sockets.s_Attribute; 12 | } 13 | 14 | _inputSocket () { 15 | return Sockets.s_BoolSocket; 16 | } 17 | 18 | _paramType () { 19 | return 'bool'; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/editor/shadernodes/output/FloatOutputStructureComponent.js: -------------------------------------------------------------------------------- 1 | import Sockets from '../Sockets' 2 | import OutputStructureComponent from './OutputStructureComponent' 3 | 4 | export default class FloatOutputStructureComponent extends OutputStructureComponent{ 5 | constructor () { 6 | super('FloatOutputStructure'); 7 | 8 | } 9 | 10 | _outputSocket () { 11 | return Sockets.s_Attribute; 12 | } 13 | 14 | _inputSocket () { 15 | return Sockets.s_NumSocket; 16 | } 17 | 18 | _paramType () { 19 | return 'float'; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/editor/shadernodes/output/FragmentShaderOutComponent.js: -------------------------------------------------------------------------------- 1 | import ShaderNode from '../ShaderNode' 2 | import Sockets from '../Sockets' 3 | import Rete from 'rete' 4 | import MaterialDefFactory from '../MaterialDefFactory' 5 | 6 | export default class FragmentShaderOutComponent extends ShaderNode{ 7 | constructor () { 8 | super('FragmentShaderOut'); 9 | 10 | } 11 | 12 | _builder (node) { 13 | let inColor = new Rete.Input('inColor', 'Color', Sockets.s_Vector4Socket); 14 | let nodeProps = node.data._m_Props; 15 | // inputMap 16 | nodeProps._m_InputsMap['inColor'] = {type:'vec4', varname:this.getVarName(node, 'inColor'), defaultValue:'vec4(1.0f)'}; 17 | nodeProps._m_IsOutput = true; 18 | 19 | return node 20 | .addInput(inColor); 21 | } 22 | 23 | _output (node) { 24 | super._output(node); 25 | MaterialDefFactory.setFsShader(node.data._m_Props._m_ShaderNodeCode); 26 | console.log('matDef:\n' + MaterialDefFactory.toMaterialDefString()); 27 | } 28 | 29 | _getNodeCodeString (node) { 30 | return ' Context.OutColor = inColor ;\n'; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/editor/shadernodes/output/IntOutputStructureComponent.js: -------------------------------------------------------------------------------- 1 | import Sockets from '../Sockets' 2 | import OutputStructureComponent from './OutputStructureComponent' 3 | 4 | export default class IntOutputStructureComponent extends OutputStructureComponent{ 5 | constructor () { 6 | super('IntOutputStructure'); 7 | 8 | } 9 | 10 | _outputSocket () { 11 | return Sockets.s_Attribute; 12 | } 13 | 14 | _inputSocket () { 15 | return Sockets.s_NumSocket; 16 | } 17 | 18 | _paramType () { 19 | return 'int'; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/editor/shadernodes/output/OutputStructureComponent.js: -------------------------------------------------------------------------------- 1 | import ShaderNode from '../ShaderNode' 2 | import Sockets from '../Sockets' 3 | import Rete from 'rete' 4 | import TextControl from '../param/TextControl' 5 | 6 | /** 7 | * OutputStructureComponent,是所有输出结构类型节点的父类。
8 | * @author JohnKkk 9 | * @date 2022年7月19日20点08分 10 | */ 11 | export default class OutputStructureComponent extends ShaderNode{ 12 | _getNodeCodeString (node) { 13 | return ''; 14 | } 15 | static getParam(node){ 16 | let props = node.data._m_Props; 17 | return {type:props._m_InputsMap['varOut'].type, name:props._m_InputsMap['varOut'].varname}; 18 | } 19 | 20 | _getNodeCode(node){ 21 | return ''; 22 | } 23 | 24 | /** 25 | * 返回输出Socket。
26 | * @return {null} 27 | * @private 28 | */ 29 | _outputSocket(){ 30 | return null; 31 | } 32 | 33 | /** 34 | * 返回输入Socket。
35 | * @return {null} 36 | * @private 37 | */ 38 | _inputSocket(){ 39 | return null; 40 | } 41 | 42 | /** 43 | * 返回参数类型。
44 | * @return {string} 45 | * @private 46 | */ 47 | _paramType(){ 48 | return ''; 49 | } 50 | 51 | _builder(node) { 52 | let out = new Rete.Output('varOut', 'VarOut', this._outputSocket()); 53 | let inVar = new Rete.Input('inVar', 'InVar', this._inputSocket()); 54 | let inVarName = new Rete.Input('inVarName', 'VarName', Sockets.s_NoContinueSocket); 55 | 56 | inVarName.addControl(new TextControl(this.editor, "inVarName")); 57 | node.addInput(inVarName); 58 | node.addInput(inVar); 59 | node.addOutput(out); 60 | 61 | // inputMap 62 | node.data._m_Props._m_InputsMap['inVar'] = {type:'', vartype:this._paramType(), varname:this.getVarName(node, 'inVar'), defaultValue:null}; 63 | return node; 64 | } 65 | 66 | _updateBinding(node){ 67 | let nodeProps = node.data._m_Props; 68 | let varname = node.data.inVarName; 69 | if(varname == undefined || varname.trim() == ''){ 70 | varname = this.getVarName(node, 'inVar'); 71 | } 72 | nodeProps._m_InputsMap['inVar'].varname = varname; 73 | super._updateBinding(node); 74 | } 75 | 76 | _updateShaderNodeCode(node){ 77 | super._updateShaderNodeCode(node); 78 | // let props = node.data._m_Props; 79 | // props._m_ShaderNodeCode = props._m_ShaderNodeCodeSource = ''; 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/editor/shadernodes/output/Outputs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Outputs表示可用的一组输出相关的节点,包括传递结构。
3 | * 输出节点用于构建最终ShaderCode的作用。
4 | * @author JohnKkk 5 | * @date 2022年7月15日16点39分 6 | */ 7 | import FragmentShaderOutComponent from './FragmentShaderOutComponent' 8 | import VertexShaderOutComponent from './VertexShaderOutComponent' 9 | import BoolOutputStructureComponent from './BoolOutputStructureComponent' 10 | import IntOutputStructureComponent from './IntOutputStructureComponent' 11 | import FloatOutputStructureComponent from './FloatOutputStructureComponent' 12 | import Vec2OutputStructureComponent from './Vec2OutputStructureComponent' 13 | import Vec3OutputStructureComponent from './Vec3OutputStructureComponent' 14 | import Vec4OutputStructureComponent from './Vec4OutputStructureComponent' 15 | 16 | export default class Outputs { 17 | static _s_OutputStructureFilters = [ 18 | BoolOutputStructureComponent, 19 | IntOutputStructureComponent, 20 | FloatOutputStructureComponent, 21 | Vec2OutputStructureComponent, 22 | Vec3OutputStructureComponent, 23 | Vec4OutputStructureComponent, 24 | ]; 25 | static _s_Filters = [ 26 | BoolOutputStructureComponent, 27 | IntOutputStructureComponent, 28 | FloatOutputStructureComponent, 29 | Vec2OutputStructureComponent, 30 | Vec3OutputStructureComponent, 31 | Vec4OutputStructureComponent, 32 | VertexShaderOutComponent, 33 | FragmentShaderOutComponent 34 | ]; 35 | static getGroup(){ 36 | return 'output'; 37 | } 38 | static filterOutputStructure(component){ 39 | let r = false; 40 | let targetComponentName = component.name + 'Component'; 41 | for(let c in Outputs._s_OutputStructureFilters){ 42 | if(Outputs._s_OutputStructureFilters[c].name == targetComponentName){ 43 | r = true; 44 | break; 45 | } 46 | } 47 | return r; 48 | } 49 | static filter(component){ 50 | let r = false; 51 | let targetComponentName = component.name + 'Component'; 52 | for(let c in Outputs._s_Filters){ 53 | if(Outputs._s_Filters[c].name == targetComponentName){ 54 | r = true; 55 | break; 56 | } 57 | } 58 | return r; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/editor/shadernodes/output/Vec2OutputStructureComponent.js: -------------------------------------------------------------------------------- 1 | import Sockets from '../Sockets' 2 | import OutputStructureComponent from './OutputStructureComponent' 3 | 4 | export default class Vec2OutputStructureComponent extends OutputStructureComponent{ 5 | constructor () { 6 | super('Vec2OutputStructure'); 7 | 8 | } 9 | 10 | _outputSocket () { 11 | return Sockets.s_Attribute; 12 | } 13 | 14 | _inputSocket () { 15 | return Sockets.s_Vector2Socket; 16 | } 17 | 18 | _paramType () { 19 | return 'vec2'; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/editor/shadernodes/output/Vec3OutputStructureComponent.js: -------------------------------------------------------------------------------- 1 | import Sockets from '../Sockets' 2 | import OutputStructureComponent from './OutputStructureComponent' 3 | 4 | export default class Vec3OutputStructureComponent extends OutputStructureComponent{ 5 | constructor () { 6 | super('Vec3OutputStructure'); 7 | 8 | } 9 | 10 | _outputSocket () { 11 | return Sockets.s_Attribute; 12 | } 13 | 14 | _inputSocket () { 15 | return Sockets.s_Vector3Socket; 16 | } 17 | 18 | _paramType () { 19 | return 'vec3'; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/editor/shadernodes/output/Vec4OutputStructureComponent.js: -------------------------------------------------------------------------------- 1 | import Sockets from '../Sockets' 2 | import OutputStructureComponent from './OutputStructureComponent' 3 | 4 | export default class Vec4OutputStructureComponent extends OutputStructureComponent{ 5 | constructor () { 6 | super('Vec4OutputStructure'); 7 | 8 | } 9 | 10 | _outputSocket () { 11 | return Sockets.s_Attribute; 12 | } 13 | 14 | _inputSocket () { 15 | return Sockets.s_Vector4Socket; 16 | } 17 | 18 | _paramType () { 19 | return 'vec4'; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/editor/shadernodes/output/VertexShaderOutComponent.js: -------------------------------------------------------------------------------- 1 | import ShaderNode from '../ShaderNode' 2 | import Sockets from '../Sockets' 3 | import Rete from 'rete' 4 | import MaterialDefFactory from '../MaterialDefFactory' 5 | 6 | export default class VertexShaderOutComponent extends ShaderNode{ 7 | constructor () { 8 | super('VertexShaderOut'); 9 | 10 | } 11 | 12 | _builder (node) { 13 | let inPosition = new Rete.Input('inPosition', 'Position', Sockets.s_Vector4Socket); 14 | let inAttributes = new Rete.Input('inAttributes', 'Attributes', Sockets.s_Attribute, true); 15 | let nodeProps = node.data._m_Props; 16 | // inputMap 17 | nodeProps._m_InputsMap['inPosition'] = {type:'vec4', varname:this.getVarName(node, 'inPosition'), defaultValue:'vec4(1.0f)'}; 18 | nodeProps._m_IsOutput = true; 19 | 20 | return node 21 | .addInput(inPosition) 22 | .addInput(inAttributes); 23 | } 24 | 25 | _output (node) { 26 | super._output(node); 27 | MaterialDefFactory.setVsShader(node.data._m_Props._m_ShaderNodeCode); 28 | console.log('matDef:\n' + MaterialDefFactory.toMaterialDefString()); 29 | } 30 | 31 | _getNodeCodeString (node) { 32 | return ' Context.OutPosition = inPosition ;\n'; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/editor/shadernodes/param/BoolParamComponent.js: -------------------------------------------------------------------------------- 1 | import ParamComponent from './ParamComponent' 2 | import Sockets from '../Sockets' 3 | 4 | export default class BoolParamComponent extends ParamComponent{ 5 | constructor () { 6 | super('BoolParam'); 7 | 8 | } 9 | 10 | _outputSocket () { 11 | return Sockets.s_PBoolSocket; 12 | } 13 | 14 | _paramType () { 15 | return 'bool'; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/editor/shadernodes/param/FloatParamComponent.js: -------------------------------------------------------------------------------- 1 | import ParamComponent from './ParamComponent' 2 | import Sockets from '../Sockets' 3 | 4 | export default class FloatParamComponent extends ParamComponent{ 5 | constructor () { 6 | super('FloatParam'); 7 | 8 | } 9 | 10 | _outputSocket () { 11 | return Sockets.s_PNumSocket; 12 | } 13 | 14 | _paramType () { 15 | return 'float'; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/editor/shadernodes/param/IntParamComponent.js: -------------------------------------------------------------------------------- 1 | import ParamComponent from './ParamComponent' 2 | import Sockets from '../Sockets' 3 | 4 | export default class IntParamComponent extends ParamComponent{ 5 | constructor () { 6 | super('IntParam'); 7 | 8 | } 9 | 10 | _outputSocket () { 11 | return Sockets.s_PNumSocket; 12 | } 13 | 14 | _paramType () { 15 | return 'int'; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/editor/shadernodes/param/ParamComponent.js: -------------------------------------------------------------------------------- 1 | import ShaderNode from '../ShaderNode' 2 | import Sockets from '../Sockets' 3 | import Rete from 'rete' 4 | import TextControl from './TextControl' 5 | 6 | /** 7 | * ParamComponent,是所有参数类型节点的父类。
8 | * @author JohnKkk 9 | * @date 2022年7月19日09点57分 10 | */ 11 | export default class ParamComponent extends ShaderNode{ 12 | _getNodeCodeString (node) { 13 | return ''; 14 | } 15 | static getParam(node){ 16 | let props = node.data._m_Props; 17 | return {type:props._m_OutputsMap['paramOut'].type, name:props._m_OutputsMap['paramOut'].varname}; 18 | } 19 | 20 | _getNodeCode(node){ 21 | return ''; 22 | } 23 | 24 | /** 25 | * 返回输出Socket。
26 | * @return {null} 27 | * @private 28 | */ 29 | _outputSocket(){ 30 | return null; 31 | } 32 | 33 | /** 34 | * 返回参数类型。
35 | * @return {string} 36 | * @private 37 | */ 38 | _paramType(){ 39 | return ''; 40 | } 41 | 42 | _builder(node) { 43 | let out = new Rete.Output('paramOut', 'Value', this._outputSocket()); 44 | let paramName = new Rete.Input('inParamName', 'ParamName', Sockets.s_NoContinueSocket); 45 | 46 | paramName.addControl(new TextControl(this.editor, "inParamName")); 47 | node.addInput(paramName); 48 | node.addOutput(out); 49 | 50 | // outputMap 51 | node.data._m_Props._m_OutputsMap['paramOut'] = {type:this._paramType(), varname:'Params.' + this.getVarName(node, 'paramOut'), defaultValue:null}; 52 | return node; 53 | } 54 | 55 | _updateBinding(node){ 56 | let nodeProps = node.data._m_Props; 57 | let varname = node.data.inParamName; 58 | if(varname == undefined || varname.trim() == ''){ 59 | varname = this.getVarName(node, 'paramOut'); 60 | } 61 | nodeProps._m_OutputsMap['paramOut'].varname = 'Params.' + varname; 62 | } 63 | 64 | _updateShaderNodeCode(node){ 65 | let props = node.data._m_Props; 66 | props._m_ShaderNodeCode = props._m_ShaderNodeCodeSource = ''; 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/editor/shadernodes/param/Params.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Params表示可用的输入参数。
3 | * @author JohnKkk 4 | * @date 2022年7月12日14点08分 5 | */ 6 | import Rete from 'rete'; 7 | import FloatParamComponent from './FloatParamComponent' 8 | import IntParamComponent from './IntParamComponent' 9 | import BoolParamComponent from './BoolParamComponent' 10 | import Vec2ParamComponent from './Vec2ParamComponent' 11 | import Vec3ParamComponent from './Vec3ParamComponent' 12 | import Vec4ParamComponent from './Vec4ParamComponent' 13 | import Texture2DParamComponent from './Texture2DParamComponent' 14 | import TextureCubeParamComponent from './TextureCubeParamComponent' 15 | 16 | export default class Params extends Rete.Component{ 17 | static _s_Filters = [ 18 | FloatParamComponent, 19 | IntParamComponent, 20 | BoolParamComponent, 21 | Vec2ParamComponent, 22 | Vec3ParamComponent, 23 | Vec4ParamComponent, 24 | Texture2DParamComponent, 25 | TextureCubeParamComponent, 26 | ]; 27 | static getGroup(){ 28 | return 'param'; 29 | } 30 | static filter(component){ 31 | let r = false; 32 | let targetComponentName = component.name + 'Component'; 33 | for(let c in Params._s_Filters){ 34 | if(Params._s_Filters[c].name == targetComponentName){ 35 | r = true; 36 | break; 37 | } 38 | } 39 | return r; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/editor/shadernodes/param/TextControl.js: -------------------------------------------------------------------------------- 1 | import Rete from "rete"; 2 | import TextInput from '../../../components/shadernodes/common/TextInput' 3 | 4 | export default class TextControl extends Rete.Control { 5 | 6 | constructor(emitter, key, readonly) { 7 | super(key); 8 | this.component = TextInput; 9 | this.props = { emitter, key, readonly }; 10 | } 11 | 12 | setValue(val) { 13 | this.vueContext.value = val; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/editor/shadernodes/param/Texture2DParamComponent.js: -------------------------------------------------------------------------------- 1 | import ParamComponent from './ParamComponent' 2 | import Sockets from '../Sockets' 3 | 4 | export default class Texture2DParamComponent extends ParamComponent{ 5 | constructor () { 6 | super('Texture2DParam'); 7 | 8 | } 9 | 10 | _outputSocket () { 11 | return Sockets.s_PTexture2DSocket; 12 | } 13 | 14 | _paramType () { 15 | return 'sampler2D'; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/editor/shadernodes/param/TextureCubeParamComponent.js: -------------------------------------------------------------------------------- 1 | import ParamComponent from './ParamComponent' 2 | import Sockets from '../Sockets' 3 | 4 | export default class TextureCubeParamComponent extends ParamComponent{ 5 | constructor () { 6 | super('TextureCubeParam'); 7 | 8 | } 9 | 10 | _outputSocket () { 11 | return Sockets.s_PTextureCubeSocket; 12 | } 13 | 14 | _paramType () { 15 | return 'samplerCube'; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/editor/shadernodes/param/Vec2ParamComponent.js: -------------------------------------------------------------------------------- 1 | import ParamComponent from './ParamComponent' 2 | import Sockets from '../Sockets' 3 | 4 | export default class Vec2ParamComponent extends ParamComponent{ 5 | constructor () { 6 | super('Vec2Param'); 7 | 8 | } 9 | 10 | _outputSocket () { 11 | return Sockets.s_PVector2Socket; 12 | } 13 | 14 | _paramType () { 15 | return 'vec2'; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/editor/shadernodes/param/Vec3ParamComponent.js: -------------------------------------------------------------------------------- 1 | import ParamComponent from './ParamComponent' 2 | import Sockets from '../Sockets' 3 | 4 | export default class Vec3ParamComponent extends ParamComponent{ 5 | constructor () { 6 | super('Vec3Param'); 7 | 8 | } 9 | 10 | _outputSocket () { 11 | return Sockets.s_PVector3Socket; 12 | } 13 | 14 | _paramType () { 15 | return 'vec3'; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/editor/shadernodes/param/Vec4ParamComponent.js: -------------------------------------------------------------------------------- 1 | import ParamComponent from './ParamComponent' 2 | import Sockets from '../Sockets' 3 | 4 | export default class Vec4ParamComponent extends ParamComponent{ 5 | constructor () { 6 | super('Vec4Param'); 7 | 8 | } 9 | 10 | _outputSocket () { 11 | return Sockets.s_PVector4Socket; 12 | } 13 | 14 | _paramType () { 15 | return 'vec4'; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/editor/shadernodes/texture/ColorControl.js: -------------------------------------------------------------------------------- 1 | import Rete from 'rete' 2 | import Color from '../../../components/shadernodes/common/Color' 3 | 4 | export default class ColorControl extends Rete.Control { 5 | 6 | constructor(emitter, key, readonly) { 7 | super(key); 8 | this.component = Color; 9 | this.props = { emitter, key, readonly }; 10 | } 11 | 12 | setValue(val) { 13 | this.vueContext.value = val; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/editor/shadernodes/texture/SamplerTexture2DComponent.js: -------------------------------------------------------------------------------- 1 | import Rete from 'rete'; 2 | import Sockets from '../Sockets'; 3 | import ShaderNode from '../ShaderNode' 4 | 5 | export default class SamplerTexture2DComponent extends ShaderNode{ 6 | constructor () { 7 | super('SamplerTexture2D'); 8 | } 9 | _builder (node) { 10 | let inTexture2D = new Rete.Input('inTexture2D', 'Texture', Sockets.s_Texture2DSocket); 11 | let inTexCoords = new Rete.Input('inTexCoords', 'TexCoords', Sockets.s_Vector2Socket); 12 | let rgbaOut = new Rete.Output('rgbaOut', "RGBA", Sockets.s_Vector4Socket); 13 | let rOut = new Rete.Output('rOut', "R", Sockets.s_NumSocket); 14 | let gOut = new Rete.Output('gOut', "G", Sockets.s_NumSocket); 15 | let bOut = new Rete.Output('bOut', "B", Sockets.s_NumSocket); 16 | let aOut = new Rete.Output('aOut', "A", Sockets.s_NumSocket); 17 | 18 | let nodeProps = node.data._m_Props; 19 | // inputMap 20 | nodeProps._m_InputsMap['inTexture2D'] = {type:'sampler2D', varname:this.getVarName(node, 'inTexture2D'), defaultValue:null}; 21 | nodeProps._m_InputsMap['inTexCoords'] = {type:'vec2', varname:this.getVarName(node, 'inTexCoords'), defaultValue:null}; 22 | 23 | // outputMap 24 | nodeProps._m_OutputsMap['rgbaOut'] = {type:'vec4', varname:this.getVarName(node, 'rgbaOut'), defaultValue:'vec4(1.0f)'}; 25 | nodeProps._m_OutputsMap['rOut'] = {type:'float', varname:this.getVarName(node, 'rOut'), defaultValue:this.getVarName(node, 'rgbaOut') + '.r'}; 26 | nodeProps._m_OutputsMap['gOut'] = {type:'float', varname:this.getVarName(node, 'gOut'), defaultValue:this.getVarName(node, 'rgbaOut') + '.g'}; 27 | nodeProps._m_OutputsMap['bOut'] = {type:'float', varname:this.getVarName(node, 'bOut'), defaultValue:this.getVarName(node, 'rgbaOut') + '.b'}; 28 | nodeProps._m_OutputsMap['aOut'] = {type:'float', varname:this.getVarName(node, 'aOut'), defaultValue:this.getVarName(node, 'rgbaOut') + '.a'}; 29 | 30 | return node 31 | .addInput(inTexture2D) 32 | .addInput(inTexCoords) 33 | .addOutput(rgbaOut) 34 | .addOutput(rOut) 35 | .addOutput(gOut) 36 | .addOutput(bOut) 37 | .addOutput(aOut); 38 | } 39 | _updateBinding(node){ 40 | let nodeProps = node.data._m_Props; 41 | let varname = null; 42 | let inTexture2DContinue = super._getContinueNode(node, 'inTexture2D', 0); 43 | if(inTexture2DContinue) { 44 | let cont = node.inputs['inTexture2D'].connections[0].output; 45 | if(cont){ 46 | varname = inTexture2DContinue.data._m_Props._m_OutputsMap[cont].varname; 47 | } 48 | } 49 | if(varname == undefined || varname.trim() == ''){ 50 | varname = this.getVarName(node, 'inTexture2D'); 51 | nodeProps._m_InputsMap['inTexture2D'].skip = false; 52 | } 53 | else{ 54 | nodeProps._m_InputsMap['inTexture2D'].skip = true; 55 | } 56 | nodeProps._m_RebuildCode = true; 57 | nodeProps._m_InputsMap['inTexture2D'].varname = varname; 58 | super._updateBinding(node); 59 | nodeProps._m_InputsBinding['inTexture2D'] = null; 60 | } 61 | _getNodeCodeString (node) { 62 | return ' rgbaOut = texture( inTexture2D , inTexCoords ) ;\n'; 63 | } 64 | 65 | _worker (node, inputs, outputs, ...args) { 66 | // 正常输出用于节点展示 67 | outputs['rgba'] = node.data.rgba; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/editor/shadernodes/texture/Textures.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Textures表示可用的一组Texture计算相关的节点。
3 | * @author JohnKkk 4 | * @date 2022年7月12日14点54分 5 | */ 6 | import SamplerTexture2DComponent from './SamplerTexture2DComponent' 7 | 8 | export default class Textures { 9 | static _s_Filters = [ 10 | SamplerTexture2DComponent 11 | ]; 12 | static getGroup(){ 13 | return 'texture'; 14 | } 15 | static filter(component){ 16 | let r = false; 17 | let targetComponentName = component.name + 'Component'; 18 | for(let c in Textures._s_Filters){ 19 | if(Textures._s_Filters[c].name == targetComponentName){ 20 | r = true; 21 | break; 22 | } 23 | } 24 | return r; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/editor/utils/ColorMath.js: -------------------------------------------------------------------------------- 1 | let tmpComponent; 2 | 3 | const ColorMath = { 4 | hsv_to_rgb: function(h, s, v) { 5 | const hi = Math.floor(h / 60) % 6; 6 | 7 | const f = h / 60 - Math.floor(h / 60); 8 | const p = v * (1.0 - s); 9 | const q = v * (1.0 - (f * s)); 10 | const t = v * (1.0 - ((1.0 - f) * s)); 11 | 12 | const c = [ 13 | [v, t, p], 14 | [q, v, p], 15 | [p, v, t], 16 | [p, q, v], 17 | [t, p, v], 18 | [v, p, q] 19 | ][hi]; 20 | 21 | return { 22 | r: c[0] * 255, 23 | g: c[1] * 255, 24 | b: c[2] * 255 25 | }; 26 | }, 27 | 28 | rgb_to_hsv: function(r, g, b) { 29 | const min = Math.min(r, g, b); 30 | const max = Math.max(r, g, b); 31 | const delta = max - min; 32 | let h; 33 | let s; 34 | 35 | if (max !== 0) { 36 | s = delta / max; 37 | } else { 38 | return { 39 | h: NaN, 40 | s: 0, 41 | v: 0 42 | }; 43 | } 44 | 45 | if (r === max) { 46 | h = (g - b) / delta; 47 | } else if (g === max) { 48 | h = 2 + (b - r) / delta; 49 | } else { 50 | h = 4 + (r - g) / delta; 51 | } 52 | h /= 6; 53 | if (h < 0) { 54 | h += 1; 55 | } 56 | 57 | return { 58 | h: h * 360, 59 | s: s, 60 | v: max / 255 61 | }; 62 | }, 63 | 64 | rgb_to_hex: function(r, g, b) { 65 | let hex_r = (r * 255).toFixed(0).toString(16); 66 | let hex_g = (g * 255).toFixed(0).toString(16); 67 | let hex_b = (b * 255).toFixed(0).toString(16); 68 | return '#' + hex_r + hex_g + hex_b; 69 | }, 70 | 71 | rgbToHex(r, g, b) { 72 | r = (r * 255).toFixed(0); 73 | g = (g * 255).toFixed(0); 74 | b = (b * 255).toFixed(0); 75 | if(r == 0 && g == 0 && b == 0){ 76 | return '#000000'; 77 | } 78 | return '#' + ((r << 16) | (g << 8) | b).toString(16); 79 | }, 80 | 81 | hex_to_rgb: function(hex){ 82 | let b = this.component_from_hex(hex, 0) / 255.0; 83 | let g = this.component_from_hex(hex, 1) / 255.0; 84 | let r = this.component_from_hex(hex, 2) / 255.0; 85 | return {r, g, b}; 86 | }, 87 | 88 | hexToRgba(hex, opacity) { 89 | return {r:parseInt("0x" + hex.slice(1, 3)) / 255.0, g:parseInt("0x" + hex.slice(3, 5)) / 255.0, b:parseInt("0x" + hex.slice(5, 7)) / 255.0}; 90 | }, 91 | 92 | component_from_hex: function(hex, componentIndex) { 93 | return (hex >> (componentIndex * 8)) & 0xFF; 94 | }, 95 | 96 | hex_with_component: function(hex, componentIndex, value) { 97 | return value << (tmpComponent = componentIndex * 8) | (hex & ~(0xFF << tmpComponent)); 98 | } 99 | }; 100 | 101 | export default ColorMath; 102 | -------------------------------------------------------------------------------- /src/editor/utils/Utils.js: -------------------------------------------------------------------------------- 1 | export default class Utils { 2 | static _s_Id = -1; 3 | static _s_ShaderNodeId = 0; 4 | static nextId(){ 5 | return Utils._s_Id++; 6 | } 7 | static nextShaderNodeId(){ 8 | return Utils._s_ShaderNodeId++; 9 | } 10 | 11 | static getObjectType(type){ 12 | switch (type) { 13 | case 'Node': 14 | return 'Node'; 15 | case 'Geometry': 16 | case 'Box': 17 | case 'Sphere': 18 | case 'Plane': 19 | case 'SkyBox': 20 | return 'Geometry'; 21 | case 'Light': 22 | case 'DirectionalLight': 23 | case 'PointLight': 24 | case 'SpotLight': 25 | return 'Light'; 26 | default: 27 | return ''; 28 | } 29 | } 30 | 31 | /** 32 | * 复制一个对象。
33 | * @param {Object}[object] 34 | * @param {String}[filterKey 过滤key] 35 | * @param {Object}[filterValue 过滤key对应的value] 36 | * @returns {{}} 37 | */ 38 | static copyObj(object, filterKey, filterValue){ 39 | let result = {}; 40 | for(let k in object){ 41 | if(k == filterKey){ 42 | result[k] = filterValue; 43 | } 44 | else{ 45 | result[k] = object[k]; 46 | } 47 | } 48 | return result; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/editor/viewer/Viewer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3D视图编辑器。
3 | * @author JohnKkk 4 | * @date 2022年6月27日19点01分 5 | */ 6 | export default class Viewer { 7 | static S_VIEWER_EVENT_SELECTED = 'S_VIEWER_EVENT_SELECTED'; 8 | static S_VIEWER_EVENT_SELECTED2 = 'S_VIEWER_EVENT_SELECTED2'; 9 | static S_VIEWER_OBJECT_UPDATE = 'S_VIEWER_OBJECT_UPDATE'; 10 | static S_VIEWER_MATERIAL_DEF_COMPILE = 'S_VIEWER_MATERIAL_DEF_COMPILE'; 11 | // todo: 12 | // 封装Viewer部分常见操作 13 | } 14 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | // The Vue build version to load with the `import` command 2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 3 | import Vue from 'vue' 4 | import ProduceEdit from './router/produce' 5 | import Produce from './Produce' 6 | 7 | Vue.config.productionTip = false 8 | 9 | /* eslint-disable no-new */ 10 | new Vue({ 11 | el: '#Produce', 12 | router: ProduceEdit, 13 | components: { Produce }, 14 | template: '' 15 | }) 16 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import HelloWorld from '@/components/HelloWorld' 4 | 5 | Vue.use(Router) 6 | 7 | export default new Router({ 8 | routes: [ 9 | { 10 | path: '/', 11 | name: 'HelloWorld', 12 | component: HelloWorld 13 | } 14 | ] 15 | }) 16 | -------------------------------------------------------------------------------- /src/router/produce.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import ProduceEdit from 'vue-router' 3 | import Port from '@/components/Port' 4 | import vcolorpicker from 'vcolorpicker' 5 | import ContextMenu from '../components/ui/ContextMenu' 6 | 7 | Vue.component('VueContextMenu', ContextMenu) 8 | Vue.use(vcolorpicker) 9 | Vue.use(ProduceEdit) 10 | /** 11 | * Produce编辑器。
12 | * @author JhonKkk 13 | * @date 2021年8月13日17点36分 14 | */ 15 | export default new ProduceEdit({ 16 | routes: [ 17 | { 18 | path: '/', 19 | name: 'Port', 20 | component: Port 21 | } 22 | ] 23 | }) 24 | -------------------------------------------------------------------------------- /static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnLKkk/Produce/c1faed67e6365bb5e35724fe549f9d869a6c5140/static/.gitkeep -------------------------------------------------------------------------------- /static/MaterialDefinitionSource.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | MaterialDefinitionSource 6 | 7 | 9 | 10 | 11 | 18 | 19 |
20 |   
21 |     matDef:
22 | Def 8_mat{
23 | SubTechnology defaultSubDraw{
24 | Vs_Shader{
25 |             void main(){
26 | // VertexShaderOut_3 : Begin
27 | 
28 | 
29 | // CommonVert_2 : Begin
30 | vec3 CommonVert_2_inPosition = Context.InPosition;
31 | mat4 CommonVert_2_inMatrix = Context.ProjectViewModelMatrix;
32 | vec4 CommonVert_2_projPositionOut;
33 | CommonVert_2_projPositionOut=CommonVert_2_inMatrix* vec4(CommonVert_2_inPosition, 1.0f) ;
34 | // CommonVert_2 : End
35 | 
36 | vec4 VertexShaderOut_3_inPosition = CommonVert_2_projPositionOut;
37 |  Context.OutPosition =VertexShaderOut_3_inPosition;
38 | // VertexShaderOut_3 : End
39 | 
40 |             }
41 |         }
42 | Fs_Shader{
43 |             void main(){
44 | 
45 |             }
46 |         }
47 | Technology{
48 | Sub_Pass{
49 |             Pass defaultSubDraw{
50 |             }
51 |         }
52 | }
53 |   
54 | 
55 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /static/heighlight/default.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | Theme: Default 3 | Description: Original highlight.js style 4 | Author: (c) Ivan Sagalaev 5 | Maintainer: @highlightjs/core-team 6 | Website: https://highlightjs.org/ 7 | License: see project LICENSE 8 | Touched: 2021 9 | */pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#f3f3f3;color:#444}.hljs-comment{color:#697070}.hljs-punctuation,.hljs-tag{color:#444a}.hljs-tag .hljs-attr,.hljs-tag .hljs-name{color:#444}.hljs-attribute,.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-name,.hljs-selector-tag{font-weight:700}.hljs-deletion,.hljs-number,.hljs-quote,.hljs-selector-class,.hljs-selector-id,.hljs-string,.hljs-template-tag,.hljs-type{color:#800}.hljs-section,.hljs-title{color:#800;font-weight:700}.hljs-link,.hljs-operator,.hljs-regexp,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#ab5656}.hljs-literal{color:#695}.hljs-addition,.hljs-built_in,.hljs-bullet,.hljs-code{color:#397300}.hljs-meta{color:#1f7199}.hljs-meta .hljs-string{color:#38a}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700} 10 | -------------------------------------------------------------------------------- /test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Test 6 | 14 | 15 | 16 |
17 | 23 |
24 | 25 | 26 |
27 | 80 |
81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /test.txt: -------------------------------------------------------------------------------- 1 | Def 8_mat{ 2 | SubTechnology defaultSubDraw{ 3 | Vs_Shader{ 4 | void main(){ 5 | // VertexShaderOut_3 : Begin 6 | 7 | 8 | // TransformVector3_2 : Begin 9 | vec3 TransformVector3_2_inVec3 = Context.InPosition; 10 | mat4 TransformVector3_2_inMatrix4x4 = Context.ProjectViewModelMatrix; 11 | vec4 TransformVector3_2_vec4Out; 12 | TransformVector3_2_vec4Out=TransformVector3_2_inMatrix4x4* vec4(TransformVector3_2_inVec3, 1.0f) ; 13 | // TransformVector3_2 : End 14 | 15 | vec4 VertexShaderOut_3_inPosition = TransformVector3_2_vec4Out; 16 | Context.OutPosition =VertexShaderOut_3_inPosition; 17 | // VertexShaderOut_3 : End 18 | 19 | } 20 | } 21 | Fs_Shader{ 22 | void main(){ 23 | // FragmentShaderOut_4 : Begin 24 | // ConstructVec4_5 : Begin 25 | float ConstructVec4_5_inX = float(1); 26 | float ConstructVec4_5_inY = float(0); 27 | float ConstructVec4_5_inZ = float(0); 28 | float ConstructVec4_5_inW = float(1); 29 | vec4 ConstructVec4_5_Result = vec4( inX , inY , inZ , inW ); 30 | // ConstructVec4_5 : End 31 | 32 | vec4 FragmentShaderOut_4_inColor = ConstructVec4_5_Result; 33 | Context.OutColor =FragmentShaderOut_4_inColor; 34 | // FragmentShaderOut_4 : End 35 | 36 | } 37 | } 38 | Technology{ 39 | Sub_Pass{ 40 | Pass defaultSubDraw{ 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/e2e/custom-assertions/elementCount.js: -------------------------------------------------------------------------------- 1 | // A custom Nightwatch assertion. 2 | // The assertion name is the filename. 3 | // Example usage: 4 | // 5 | // browser.assert.elementCount(selector, count) 6 | // 7 | // For more information on custom assertions see: 8 | // http://nightwatchjs.org/guide#writing-custom-assertions 9 | 10 | exports.assertion = function (selector, count) { 11 | this.message = 'Testing if element <' + selector + '> has count: ' + count 12 | this.expected = count 13 | this.pass = function (val) { 14 | return val === this.expected 15 | } 16 | this.value = function (res) { 17 | return res.value 18 | } 19 | this.command = function (cb) { 20 | var self = this 21 | return this.api.execute(function (selector) { 22 | return document.querySelectorAll(selector).length 23 | }, [selector], function (res) { 24 | cb.call(self, res) 25 | }) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/e2e/nightwatch.conf.js: -------------------------------------------------------------------------------- 1 | require('babel-register') 2 | var config = require('../../config') 3 | 4 | // http://nightwatchjs.org/gettingstarted#settings-file 5 | module.exports = { 6 | src_folders: ['test/e2e/specs'], 7 | output_folder: 'test/e2e/reports', 8 | custom_assertions_path: ['test/e2e/custom-assertions'], 9 | 10 | selenium: { 11 | start_process: true, 12 | server_path: require('selenium-server').path, 13 | host: '127.0.0.1', 14 | port: 4444, 15 | cli_args: { 16 | 'webdriver.chrome.driver': require('chromedriver').path 17 | } 18 | }, 19 | 20 | test_settings: { 21 | default: { 22 | selenium_port: 4444, 23 | selenium_host: 'localhost', 24 | silent: true, 25 | globals: { 26 | devServerURL: 'http://localhost:' + (process.env.PORT || config.dev.port) 27 | } 28 | }, 29 | 30 | chrome: { 31 | desiredCapabilities: { 32 | browserName: 'chrome', 33 | javascriptEnabled: true, 34 | acceptSslCerts: true 35 | } 36 | }, 37 | 38 | firefox: { 39 | desiredCapabilities: { 40 | browserName: 'firefox', 41 | javascriptEnabled: true, 42 | acceptSslCerts: true 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test/e2e/runner.js: -------------------------------------------------------------------------------- 1 | // 1. start the dev server using production config 2 | process.env.NODE_ENV = 'testing' 3 | 4 | const webpack = require('webpack') 5 | const DevServer = require('webpack-dev-server') 6 | 7 | const webpackConfig = require('../../build/webpack.prod.conf') 8 | const devConfigPromise = require('../../build/webpack.dev.conf') 9 | 10 | let server 11 | 12 | devConfigPromise.then(devConfig => { 13 | const devServerOptions = devConfig.devServer 14 | const compiler = webpack(webpackConfig) 15 | server = new DevServer(compiler, devServerOptions) 16 | const port = devServerOptions.port 17 | const host = devServerOptions.host 18 | return server.listen(port, host) 19 | }) 20 | .then(() => { 21 | // 2. run the nightwatch test suite against it 22 | // to run in additional browsers: 23 | // 1. add an entry in test/e2e/nightwatch.conf.js under "test_settings" 24 | // 2. add it to the --env flag below 25 | // or override the environment flag, for example: `npm run e2e -- --env chrome,firefox` 26 | // For more information on Nightwatch's config file, see 27 | // http://nightwatchjs.org/guide#settings-file 28 | let opts = process.argv.slice(2) 29 | if (opts.indexOf('--config') === -1) { 30 | opts = opts.concat(['--config', 'test/e2e/nightwatch.conf.js']) 31 | } 32 | if (opts.indexOf('--env') === -1) { 33 | opts = opts.concat(['--env', 'chrome']) 34 | } 35 | 36 | const spawn = require('cross-spawn') 37 | const runner = spawn('./node_modules/.bin/nightwatch', opts, { stdio: 'inherit' }) 38 | 39 | runner.on('exit', function (code) { 40 | server.close() 41 | process.exit(code) 42 | }) 43 | 44 | runner.on('error', function (err) { 45 | server.close() 46 | throw err 47 | }) 48 | }) 49 | -------------------------------------------------------------------------------- /test/e2e/specs/test.js: -------------------------------------------------------------------------------- 1 | // For authoring Nightwatch tests, see 2 | // http://nightwatchjs.org/guide#usage 3 | 4 | module.exports = { 5 | 'default e2e tests': function (browser) { 6 | // automatically uses dev Server port from /config.index.js 7 | // default: http://localhost:8080 8 | // see nightwatch.conf.js 9 | const devServer = browser.globals.devServerURL 10 | 11 | browser 12 | .url(devServer) 13 | .waitForElementVisible('#app', 5000) 14 | .assert.elementPresent('.hello') 15 | .assert.containsText('h1', 'Welcome to Your Vue.js App') 16 | .assert.elementCount('img', 1) 17 | .end() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/unit/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "jest": true 4 | }, 5 | "globals": { 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/unit/jest.conf.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | module.exports = { 4 | rootDir: path.resolve(__dirname, '../../'), 5 | moduleFileExtensions: [ 6 | 'js', 7 | 'json', 8 | 'vue' 9 | ], 10 | moduleNameMapper: { 11 | '^@/(.*)$': '/src/$1' 12 | }, 13 | transform: { 14 | '^.+\\.js$': '/node_modules/babel-jest', 15 | '.*\\.(vue)$': '/node_modules/vue-jest' 16 | }, 17 | testPathIgnorePatterns: [ 18 | '/test/e2e' 19 | ], 20 | snapshotSerializers: ['/node_modules/jest-serializer-vue'], 21 | setupFiles: ['/test/unit/setup'], 22 | mapCoverage: true, 23 | coverageDirectory: '/test/unit/coverage', 24 | collectCoverageFrom: [ 25 | 'src/**/*.{js,vue}', 26 | '!src/main.js', 27 | '!src/router/index.js', 28 | '!**/node_modules/**' 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /test/unit/setup.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | Vue.config.productionTip = false 4 | -------------------------------------------------------------------------------- /test/unit/specs/HelloWorld.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import HelloWorld from '@/components/HelloWorld' 3 | 4 | describe('HelloWorld.vue', () => { 5 | it('should render correct contents', () => { 6 | const Constructor = Vue.extend(HelloWorld) 7 | const vm = new Constructor().$mount() 8 | expect(vm.$el.querySelector('.hello h1').textContent) 9 | .toEqual('Welcome to Your Vue.js App') 10 | }) 11 | }) 12 | --------------------------------------------------------------------------------