├── README.md ├── .gitignore ├── light2D ├── ecma-script │ ├── the-only-pack-to-draw-light │ │ ├── scripts │ │ │ ├── start.js │ │ │ ├── configs │ │ │ │ ├── webpack.config.dev.js │ │ │ │ ├── webpack.config.prod.js │ │ │ │ └── webpack.config.js │ │ │ └── build.js │ │ ├── src │ │ │ ├── gpu │ │ │ │ ├── shader │ │ │ │ │ ├── trival │ │ │ │ │ │ ├── f.js │ │ │ │ │ │ └── v.js │ │ │ │ │ ├── draw │ │ │ │ │ │ ├── v.js │ │ │ │ │ │ └── f.js │ │ │ │ │ └── flat │ │ │ │ │ │ ├── v.js │ │ │ │ │ │ └── f.js │ │ │ │ ├── util │ │ │ │ │ ├── buffer.js │ │ │ │ │ ├── frame-buffer.js │ │ │ │ │ ├── base.js │ │ │ │ │ ├── texture.js │ │ │ │ │ ├── shader.js │ │ │ │ │ ├── vertex-buffer.js │ │ │ │ │ ├── program.js │ │ │ │ │ └── scene.js │ │ │ │ ├── index.js │ │ │ │ ├── sdf │ │ │ │ │ ├── plane.js │ │ │ │ │ ├── circle.js │ │ │ │ │ ├── rect.js │ │ │ │ │ └── base.js │ │ │ │ └── render │ │ │ │ │ └── index.js │ │ │ └── cpu │ │ │ │ ├── index.js │ │ │ │ ├── util │ │ │ │ └── float2.js │ │ │ │ ├── sdf │ │ │ │ ├── plane.js │ │ │ │ ├── circle.js │ │ │ │ ├── rect.js │ │ │ │ └── base.js │ │ │ │ ├── light.js │ │ │ │ └── render │ │ │ │ └── index.js │ │ ├── index.js │ │ ├── .babelrc │ │ ├── index.html │ │ ├── demo.js │ │ ├── package.json │ │ ├── ReadMe.md │ │ └── dist │ │ │ ├── index.min.js │ │ │ └── demo.min.js │ └── light │ │ ├── index.js │ │ ├── package.json │ │ ├── package-lock.json │ │ └── ReadMe.md ├── metal │ ├── RayTracking │ │ ├── Assets.xcassets │ │ │ ├── Contents.json │ │ │ └── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ ├── Info.plist │ │ ├── Base.lproj │ │ │ ├── Main.storyboard │ │ │ └── LaunchScreen.storyboard │ │ ├── AppDelegate.swift │ │ ├── ViewController.swift │ │ └── shaders.metal │ └── RayTracking.xcodeproj │ │ ├── xcuserdata │ │ └── gaoboyuan.xcuserdatad │ │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ ├── xcuserdata │ │ │ └── gaoboyuan.xcuserdatad │ │ │ │ └── UserInterfaceState.xcuserstate │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ │ └── project.pbxproj └── README.md └── water └── ReadMe.md /README.md: -------------------------------------------------------------------------------- 1 | ## The 人人有图形学抄 Project 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *DS_Store 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/scripts/start.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /water/ReadMe.md: -------------------------------------------------------------------------------- 1 | ## The 人人有水画Project 2 | 3 | ### 又™流行画水了 4 | 5 | > 现在是画水时代 -- LYP 6 | 7 | 你群有病 -------------------------------------------------------------------------------- /light2D/ecma-script/light/index.js: -------------------------------------------------------------------------------- 1 | import { OPDrawLight } from './index'; 2 | 3 | const Light = OPDrawLight; 4 | 5 | export { Light }; -------------------------------------------------------------------------------- /light2D/metal/RayTracking/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/gpu/shader/trival/f.js: -------------------------------------------------------------------------------- 1 | export default ` 2 | void main() { 3 | gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); 4 | } 5 | `; -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/index.js: -------------------------------------------------------------------------------- 1 | import CPU from './src/cpu'; 2 | import GPU from './src/gpu'; 3 | 4 | export const OPDrawLight = { 5 | ...GPU, 6 | ...CPU, 7 | }; 8 | -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env" 4 | ], 5 | "plugins": [ 6 | "@babel/plugin-proposal-class-properties" 7 | ] 8 | } -------------------------------------------------------------------------------- /light2D/metal/RayTracking.xcodeproj/xcuserdata/gaoboyuan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Not supported. 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/scripts/configs/webpack.config.dev.js: -------------------------------------------------------------------------------- 1 | const base = require('./webpack.config'); 2 | const merge = require('webpack-merge'); 3 | 4 | module.exports = merge(base, { 5 | mode: 'development' 6 | }); -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/gpu/util/buffer.js: -------------------------------------------------------------------------------- 1 | import { GlBase } from './base'; 2 | 3 | export class Buffer extends GlBase { 4 | constructor(ctx) { 5 | super(ctx); 6 | this._raw = ctx.createBuffer(); 7 | } 8 | } -------------------------------------------------------------------------------- /light2D/metal/RayTracking.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/gpu/util/frame-buffer.js: -------------------------------------------------------------------------------- 1 | import { GlBase } from './base'; 2 | 3 | /** 4 | * FrameBufferObject 5 | * @date 9102/02/04 6 | * @author antimoron 7 | */ 8 | export class FrameBuffer extends GlBase { 9 | _texture; 10 | } -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/gpu/shader/trival/v.js: -------------------------------------------------------------------------------- 1 | export default ` 2 | attribute vec4 aVertexPosition; 3 | 4 | uniform mat4 uModelViewMatrix; 5 | uniform mat4 uProjectionMatrix; 6 | 7 | void main() { 8 | gl_Position = aVertexPosition; 9 | } 10 | `; -------------------------------------------------------------------------------- /light2D/metal/RayTracking.xcodeproj/project.xcworkspace/xcuserdata/gaoboyuan.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntiMoron/EveryoneCG/HEAD/light2D/metal/RayTracking.xcodeproj/project.xcworkspace/xcuserdata/gaoboyuan.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /light2D/metal/RayTracking.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/gpu/shader/draw/v.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author antimoron 3 | */ 4 | export default ` 5 | attribute vec4 aVertexPosition; 6 | attribute vec2 aTextureCoord; 7 | 8 | varying highp vec2 vTextureCoord; 9 | 10 | void main() { 11 | gl_Position = aVertexPosition; 12 | vTextureCoord = aTextureCoord; 13 | } 14 | `; -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/gpu/shader/flat/v.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author antimoron 3 | */ 4 | export default ` 5 | attribute vec4 aVertexPosition; 6 | attribute vec2 aTextureCoord; 7 | 8 | varying highp vec2 vTextureCoord; 9 | 10 | void main() { 11 | gl_Position = aVertexPosition; 12 | vTextureCoord = aTextureCoord; 13 | } 14 | `; -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/gpu/shader/flat/f.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author antimoron 3 | */ 4 | export default ` 5 | varying highp vec2 vTextureCoord; 6 | uniform sampler2D uSampler; 7 | precision highp float; 8 | 9 | void main(void) { 10 | // gl_FragColor = vec4(1,0,0,1); 11 | gl_FragColor = texture2D(uSampler, vTextureCoord); 12 | } 13 | `; -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/cpu/index.js: -------------------------------------------------------------------------------- 1 | import { Circle } from './sdf/circle'; 2 | import { Plane } from './sdf/plane'; 3 | import { Rect } from './sdf/rect'; 4 | import { render } from './render'; 5 | 6 | export default { 7 | cpu: { 8 | SDF: { 9 | Circle, Plane, Rect, 10 | }, 11 | render, 12 | } 13 | }; -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/gpu/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | import { render } from './render'; 5 | import { Rect } from './sdf/rect'; 6 | import { Circle } from './sdf/circle'; 7 | import { Plane } from './sdf/plane'; 8 | 9 | export default { 10 | gpu: { 11 | SDF: { 12 | Circle, Plane, Rect, 13 | }, 14 | render, 15 | } 16 | }; -------------------------------------------------------------------------------- /light2D/README.md: -------------------------------------------------------------------------------- 1 | # The 人人有光画 Project 2 | 3 | 更多详情请查看这个Issue. 4 | 5 | [https://github.com/AntiMoron/CopyLight2D/issues/1](https://github.com/AntiMoron/CopyLight2D/issues/1) 6 | 7 | 8 | ## JS党福利 9 | 10 | 你想5分钟画光,可以直接以npm集成的方式进行(恶俗) 11 | 详情查看: 12 | https://github.com/AntiMoron/CopyLight2D/tree/master/ecma-script/the-only-pack-to-draw-light 13 | 14 | 15 | ![](https://user-images.githubusercontent.com/6587734/52172954-41527e80-27b5-11e9-95d3-b3d1756743cc.png) 16 | -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/gpu/util/base.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @date 9102/02/04 3 | * @author antimoron 4 | */ 5 | export class GlBase { 6 | /** 7 | * 传入一个glContext 8 | * @param {glContext} glCtx 9 | */ 10 | constructor(glCtx) { 11 | this._gl = glCtx; 12 | } 13 | 14 | get context() { 15 | return this._gl; 16 | } 17 | 18 | // 返回gl对象原始内容 19 | get raw() { 20 | return this._raw; 21 | } 22 | } -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/cpu/util/float2.js: -------------------------------------------------------------------------------- 1 | export function addf2(a, b) { 2 | return { 3 | x: a.x + b.x, 4 | y: a.y + b.y, 5 | }; 6 | } 7 | 8 | export function mulf2(a, b) { 9 | return { 10 | x: a.x * b, 11 | y: a.y * b 12 | }; 13 | } 14 | 15 | export function subf2(a, b) { 16 | return addf2(a, mulf2(b, -1)); 17 | } 18 | 19 | export function divf2(a, b) { 20 | return mulf2(a, 1.0 / b); 21 | } 22 | -------------------------------------------------------------------------------- /light2D/metal/RayTracking.xcodeproj/xcuserdata/gaoboyuan.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | RayTracking.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /light2D/ecma-script/light/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "light-render", 3 | "version": "1.0.1", 4 | "description": "Nice 2D light rendering with pretty good ray tracing effect. Providing both CPU & GPU ways.", 5 | "main": "index.js", 6 | "private": false, 7 | "scripts": {}, 8 | "author": "anti2moron@gmail.com", 9 | "license": "GPL", 10 | "dependencies": { 11 | "the-only-one-pack-to-draw-light": "^1.0.5" 12 | }, 13 | "homepage": "https://github.com/AntiMoron/CopyLight2D/tree/master/light2D/ecma-script/light" 14 | } 15 | -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/cpu/sdf/plane.js: -------------------------------------------------------------------------------- 1 | import { SDF } from './base' 2 | 3 | /** 4 | * 虚拟物体 5 | * 用于描述一个平面 6 | * @date 9012/02/03 7 | * @author antimoron 8 | */ 9 | export class Plane extends SDF { 10 | constructor(props, pxy, normal) { 11 | super(props); 12 | this._pxy = pxy; 13 | this._normal = normal; 14 | this.getSourceDistance = this.getSourceDistance.bind(this); 15 | } 16 | 17 | getSourceDistance(xy) { 18 | const { 19 | _pxy: pxy, 20 | _normal: normal 21 | } = this; 22 | return (xy.x - pxy.x) * normal.x + (xy.y - pxy.y) * normal.y; 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/scripts/build.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const chalk = require('chalk'); 3 | const config = require('./configs/webpack.config.prod'); 4 | 5 | function compile() { 6 | return webpack(config, (_, e) => { 7 | const { compilation: { errors, warnings } } = e; 8 | console.log(chalk.magentaBright(warnings)); 9 | if (!!errors && errors != '') { 10 | console.log(chalk.yellow('compile failed!!!\r\n'), 11 | chalk.red(`${errors}`), 12 | chalk.cyanBright(_)); 13 | } else { 14 | console.log("compile success!!"); 15 | } 16 | }); 17 | } 18 | compile(); -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/demo.js: -------------------------------------------------------------------------------- 1 | import { OPDrawLight } from './index'; 2 | 3 | const { 4 | gpu: { 5 | SDF: { 6 | Circle, 7 | Plane, 8 | }, 9 | render 10 | } 11 | } = OPDrawLight; 12 | 13 | const c = new Circle({ 14 | emissive: 20, 15 | reflectivity: 0, 16 | eta: 0, 17 | }, { x: 0.5, y: -0.5 }, .05) 18 | const i = new Circle({ 19 | emissive: 0, 20 | reflectivity: .2, 21 | eta: 1.5, 22 | }, { x: 0.5, y: 0.5 }, 0.2); 23 | const j = new Plane({ 24 | emissive: 0, 25 | reflectivity: .2, 26 | eta: 1.45, 27 | }, { x: 0.5, y: .5 }, { x: .0, y: -1.0 }); 28 | 29 | // 渲染 30 | render(document.getElementById('cv'), c.union(i.intersect(j))); -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/scripts/configs/webpack.config.prod.js: -------------------------------------------------------------------------------- 1 | const base = require('./webpack.config'); 2 | const merge = require('webpack-merge'); 3 | const os = require('os'); 4 | const UglifyJsparallelPlugin = require('webpack-uglify-parallel'); 5 | 6 | module.exports = merge(base, { 7 | // production 会触发编译bug.[Cannot read property 'minify' of undefined] 8 | mode: 'none', 9 | plugins: [ 10 | new UglifyJsparallelPlugin({ 11 | workers: os.cpus().length, 12 | mangle: true, 13 | compressor: { 14 | warnings: false, 15 | drop_console: true, 16 | drop_debugger: true 17 | } 18 | }) 19 | ] 20 | }) -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/cpu/sdf/circle.js: -------------------------------------------------------------------------------- 1 | import { SDF } from './base' 2 | import { subf2 } from '../util/float2'; 3 | /** 4 | * 虚拟物体 5 | * 用于描述一个圆 6 | * @date 9012/02/03 7 | * @author antimoron 8 | */ 9 | export class Circle extends SDF { 10 | constructor(props, center, radius) { 11 | super(props); 12 | this._center = center; 13 | this._radius = radius; 14 | this.getSourceDistance = this.getSourceDistance.bind(this); 15 | } 16 | 17 | getSourceDistance(xy) { 18 | const { 19 | _center: center, 20 | _radius: radius 21 | } = this; 22 | let u = subf2(xy, center) 23 | return Math.sqrt(u.x * u.x + u.y * u.y) - radius; 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/scripts/configs/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const os = require('os'); 3 | module.exports = { 4 | entry: { 5 | index: path.resolve(__dirname, '../../index.js'), 6 | demo: path.resolve(__dirname, '../../demo.js'), 7 | }, 8 | output: { 9 | path: path.resolve(__dirname, '../../dist'), 10 | filename: '[name].min.js', 11 | library: 'theonlypacktodrawlight', 12 | libraryTarget: 'umd' 13 | }, 14 | module: { 15 | rules: [ 16 | { 17 | test: /\.js$/, 18 | use: [{ 19 | loader: 'babel-loader' 20 | }], 21 | exclude: /node_modules/ 22 | } 23 | ] 24 | }, 25 | plugins: [ 26 | ] 27 | }; -------------------------------------------------------------------------------- /light2D/ecma-script/light/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "light", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "gl-matrix": { 8 | "version": "3.0.0", 9 | "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.0.0.tgz", 10 | "integrity": "sha512-PD4mVH/C/Zs64kOozeFnKY8ybhgwxXXQYGWdB4h68krAHknWJgk9uKOn6z8YElh5//vs++90pb6csrTIDWnexA==" 11 | }, 12 | "the-only-one-pack-to-draw-light": { 13 | "version": "1.0.4", 14 | "resolved": "https://registry.npmjs.org/the-only-one-pack-to-draw-light/-/the-only-one-pack-to-draw-light-1.0.4.tgz", 15 | "integrity": "sha512-Z6owAhs+Cepjj17Xq4+9+m5gPFYISDnMin5HV1Hic6Pca1BhAfe3c4pMDXsdOeOc+LvQCU5amznbdWLzqa9XgQ==", 16 | "requires": { 17 | "gl-matrix": "3.0.0" 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/cpu/sdf/rect.js: -------------------------------------------------------------------------------- 1 | import { SDF } from './base'; 2 | /** 3 | * 虚拟物体 4 | * 用于描述一个矩形 5 | * @date 9012/02/03 6 | * @author antimoron 7 | */ 8 | export class Rect extends SDF { 9 | constructor(props, center, theta, s) { 10 | super(props); 11 | this._center = center; 12 | this._theta = theta; 13 | this._s = s; 14 | this.getSourceDistance = this.getSourceDistance.bind(this); 15 | } 16 | 17 | getSourceDistance(xy) { 18 | const { 19 | _center: center, 20 | _theta: theta, 21 | _s: s 22 | } = this; 23 | const costheta = Math.cos(theta), sintheta = Math.sin(theta); 24 | const dx = Math.abs((xy.x - center.x) * costheta + (xy.y - center.y) * sintheta) - s.x; 25 | const dy = Math.abs((xy.y - center.y) * costheta - (xy.x - center.x) * sintheta) - s.y; 26 | const ax = Math.max(dx, 0), ay = Math.max(dy, 0); 27 | return Math.min(Math.max(dx, dy), 0) + Math.sqrt(ax * ax + ay * ay); 28 | } 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/gpu/sdf/plane.js: -------------------------------------------------------------------------------- 1 | import { SDF } from './base' 2 | 3 | /** 4 | * 虚拟物体 5 | * 用于描述一个平面 6 | * @date 9012/02/04 7 | * @author antimoron 8 | */ 9 | export class Plane extends SDF { 10 | constructor(props, pxy, normal) { 11 | super(props); 12 | this._pxy = pxy; 13 | this._normal = normal; 14 | } 15 | 16 | get gpuDesc() { 17 | const { 18 | _props: { 19 | emissive = 0, 20 | reflectivity = 0, 21 | eta = 0 22 | } = {}, 23 | _pxy: { 24 | x: px, 25 | y: py 26 | } = {}, 27 | _normal: { 28 | x: nx, 29 | y: ny 30 | } = {}, 31 | } = this; 32 | return `createLS(planeSDF(xy, vec2(${this.floatize(px)}, ${this.floatize(py)}), vec2(${this.floatize(nx)}, ${this.floatize(ny)})), ${this.floatize(emissive)}, ${this.floatize(reflectivity)}, ${this.floatize(eta)})`; 33 | // return [ 34 | // 2.0, emissive, reflectivity, eta, 35 | // px, py, nx, ny, 36 | // ]; 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "the-only-one-pack-to-draw-light", 3 | "version": "1.0.5", 4 | "description": "你需要的唯一的一个包去CPU画光,~[有卡爆风险]~ 已支持GPU渲染不会卡爆了", 5 | "main": "dist/index.min.js", 6 | "private": false, 7 | "scripts": { 8 | "build": "node ./scripts/build.js", 9 | "start": "rimraf ./dist/* && npm-run-all --parallel dev:examples serve", 10 | "dev:examples": "webpack --watch --config ./scripts/configs/webpack.config.dev.js", 11 | "serve": "serve ./ -p 3332" 12 | }, 13 | "author": "anti2moron@gmail.com", 14 | "license": "GPL", 15 | "devDependencies": { 16 | "@babel/core": "^7.2.2", 17 | "@babel/plugin-proposal-class-properties": "^7.3.0", 18 | "@babel/preset-env": "^7.3.1", 19 | "babel-loader": "^8.0.5", 20 | "chalk": "^2.4.2", 21 | "npm-run-all": "^4.1.5", 22 | "os": "^0.1.1", 23 | "path": "^0.12.7", 24 | "rimraf": "^2.6.3", 25 | "serve": "^10.1.2", 26 | "webpack": "^4.29.1", 27 | "webpack-cli": "^3.2.3", 28 | "webpack-merge": "^4.2.1", 29 | "webpack-uglify-parallel": "^0.1.4" 30 | }, 31 | "files": [ 32 | "dist" 33 | ], 34 | "dependencies": { 35 | "gl-matrix": "^3.0.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/gpu/sdf/circle.js: -------------------------------------------------------------------------------- 1 | import { SDF } from './base' 2 | /** 3 | * 虚拟物体 4 | * 用于描述一个圆 5 | * @date 9012/02/03 6 | * @author antimoron 7 | */ 8 | export class Circle extends SDF { 9 | constructor(props, center, radius) { 10 | super(props); 11 | // 6 floats + 1 type 12 | // emissive 13 | // reflectivity 14 | // eta 15 | // center: {x,y} 16 | // radius 17 | this._center = center; 18 | this._radius = radius; 19 | } 20 | 21 | get gpuDesc() { 22 | const { 23 | _props: { 24 | emissive = 0, 25 | reflectivity = 0, 26 | eta = 0 27 | } = {}, 28 | _center: { 29 | x: cx, 30 | y: cy 31 | } = {}, 32 | _radius: radius 33 | } = this; 34 | return `createLS(circleSDF(xy, vec2(${this.floatize(cx)}, ${this.floatize(cy)}), ${this.floatize(radius)}), ${this.floatize(emissive)}, ${this.floatize(reflectivity)}, ${this.floatize(eta)})`; 35 | // return [ 36 | // 1.0, emissive, reflectivity, eta, 37 | // cx, cy, radius, 0 38 | // ]; 39 | } 40 | } -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/gpu/util/texture.js: -------------------------------------------------------------------------------- 1 | import { GlBase } from './base'; 2 | 3 | export class Texture extends GlBase { 4 | /** 5 | * 创建一个纹理 6 | * @param {*} ctx glContext 7 | * @param {*} width 宽度 8 | * @param {*} height 高度 9 | */ 10 | constructor(ctx, width = 1, height = 1) { 11 | super(ctx); 12 | this._width = width; 13 | this._height = height; 14 | const gl = ctx; 15 | this._raw = gl.createTexture(); 16 | if (!this._raw) { 17 | throw 'Texture create failure.'; 18 | } 19 | 20 | gl.bindTexture(gl.TEXTURE_2D, this._raw); 21 | // 创建一个纹理 22 | const level = 0; 23 | const internalFormat = gl.RGBA; 24 | const border = 0; 25 | const srcFormat = gl.RGBA; 26 | const srcType = gl.UNSIGNED_BYTE; 27 | gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, 28 | width, height, border, srcFormat, srcType, 29 | null); 30 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); 31 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 32 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/gpu/sdf/rect.js: -------------------------------------------------------------------------------- 1 | import { SDF } from './base'; 2 | /** 3 | * 虚拟物体 4 | * 用于描述一个矩形 5 | * @date 9012/02/03 6 | * @author antimoron 7 | */ 8 | export class Rect extends SDF { 9 | constructor(props, center, theta, s) { 10 | super(props); 11 | this._center = center; 12 | this._theta = theta; 13 | this._s = s; 14 | } 15 | 16 | get gpuDesc() { 17 | const { 18 | _props: { 19 | emissive = 0, 20 | reflectivity = 0, 21 | eta = 0 22 | } = {}, 23 | _center: { 24 | x: cx, 25 | y: cy 26 | } = {}, 27 | _s: { 28 | x: sx, 29 | y: sy, 30 | }, 31 | _theta: theta, 32 | } = this; 33 | return `createLS(boxSDF(xy, vec2(${this.floatize(cx)}, ${this.floatize(cy)}), ${this.floatize(theta)}, vec2(${this.floatize(sx)}, ${this.floatize(sy)})), ${this.floatize(emissive)}, ${this.floatize(reflectivity)}, ${this.floatize(eta)})`; 34 | // return [ 35 | // 3.0, emissive, reflectivity, eta, 36 | // cx, cy, sx, sy, 37 | // theta, 0, 0, 0 38 | // ]; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/gpu/sdf/base.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 虚拟物体 3 | * 用于跟GPU描述一个物体 4 | * @date 9012/02/04 5 | * @author antimoron 6 | */ 7 | export class SDF { 8 | /** 9 | * 记录光场用的一些属性 10 | * @param {object} props 11 | */ 12 | constructor(props) { 13 | this._props = { ...props }; 14 | } 15 | 16 | // TODO: 环形检测,检测好了记得骂人蠢 17 | // 记录操作构建图形场景 18 | // 传{ t: 'u(nion) | i(ntersect) | s(ubtract)', to: SDF} 19 | _opQueue = []; 20 | 21 | floatize = (n) => { 22 | let nn = n + ''; 23 | return nn.indexOf('.') >= 0 ? nn : nn + '.0'; 24 | } 25 | 26 | /** 27 | * 合并两个光 28 | */ 29 | union = (o) => { 30 | if (!o) { return; } 31 | this._opQueue.push({ 32 | t: 'u', 33 | to: o 34 | }); 35 | return this; 36 | } 37 | /** 38 | * 交集两个光 39 | */ 40 | intersect = (o) => { 41 | if (!o) { return; } 42 | this._opQueue.push({ 43 | t: 'i', 44 | to: o 45 | }); 46 | return this; 47 | } 48 | /** 49 | * 减法两个光 50 | * 注意没有交换律 51 | */ 52 | subtract = (o) => { 53 | if (!o) { return; } 54 | this._opQueue.push({ 55 | t: 's', 56 | to: o 57 | }); 58 | return this; 59 | } 60 | 61 | get gpuDesc() { 62 | return null; 63 | } 64 | } -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/ReadMe.md: -------------------------------------------------------------------------------- 1 | ### 好了方便人人有光画我做了个npm包 2 | 3 | ```bash 4 | npm i -S the-only-one-pack-to-draw-light 5 | ``` 6 | 7 | 你需要的唯一的一个包去CPU/GPU画光 8 | 9 | ![](https://user-images.githubusercontent.com/6587734/52172954-41527e80-27b5-11e9-95d3-b3d1756743cc.png) 10 | 11 | 用法如下: 12 | 13 | ```javascript 14 | import { OPDrawLight } from 'the-only-one-pack-to-draw-light'; 15 | 16 | // 要用cpu绘图改为true 17 | const useCPU = false; 18 | const Kit = useCPU ? OPDrawLight.cpu : OPDrawLight.gpu; 19 | 20 | const { 21 | SDF: { 22 | Circle, 23 | Plane, 24 | Rect, 25 | }, 26 | render 27 | } = Kit; 28 | 29 | const c = new Circle({ 30 | emissive: 20, 31 | reflectivity: 0, 32 | eta: 0, 33 | }, { x: 0.5, y: -0.5 }, .05) 34 | const i = new Circle({ 35 | emissive: 0, 36 | reflectivity: .2, 37 | eta: 1.5, 38 | }, { x: 0.5, y: 0.87 }, 0.2); 39 | const j = new Plane({ 40 | emissive: 0, 41 | reflectivity: .2, 42 | eta: 1.45, 43 | }, { x: 0.5, y: .5 }, { x: .0, y: -1.0 }); 44 | 45 | // 渲染 46 | render(document.getElementById('cv'), c.union(i.intersect(j))); 47 | ``` 48 | 49 | #### render参数 50 | 51 | ##### cv: HTMLCanvasElement, Canvas DOM 52 | 53 | ##### objs SDF树,根据SDF构建场景 54 | 55 | SDF类型 56 | 57 | - Circle(props, center, radius) 58 | - Rect(props, center, theta, s) 59 | - Plane(props, pxy, normal) 60 | 61 | SDF 方法 62 | 63 | - union: 合并两个光 64 | - intersect:交集两个光 65 | - subtract:减法两个光 (注意没有交换律) 66 | 67 | ##### opts: 渲染参数 68 | 69 | - N 默认64.0, 代表采样率,越高越准确 70 | - MAX_STEP 最大步进次数,默认'64', 71 | - MAX_DISTANCE 最大步进距离,根据场景实际情况定,默认'10.0' -------------------------------------------------------------------------------- /light2D/metal/RayTracking/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /light2D/metal/RayTracking/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/gpu/util/shader.js: -------------------------------------------------------------------------------- 1 | import { GlBase } from './base' 2 | 3 | export class Shader extends GlBase { 4 | /** 5 | * 创建一个webgl shader对象 6 | * @param {glContext} glCtx webgl context. 7 | * @param {string} type 'vert' | 'frag' 8 | * @param {string} source shader代码 9 | */ 10 | constructor(glCtx, type, source) { 11 | super(glCtx); 12 | this._type = type; 13 | this._source = source; 14 | this._raw = this._loadShader(); 15 | } 16 | 17 | _loadShader() { 18 | const { 19 | _type: type, 20 | _source: source, 21 | } = this; 22 | const gl = this.context; 23 | let shaderType = null; 24 | switch (type) { 25 | case 'vert': 26 | shaderType = gl.VERTEX_SHADER; 27 | break; 28 | case 'frag': 29 | shaderType = gl.FRAGMENT_SHADER; 30 | break; 31 | default: 32 | throw new Error('Not supported.'); 33 | } 34 | if (!shaderType) { 35 | throw new Error('Not supported.'); 36 | } 37 | const shaderId = gl.createShader(shaderType); 38 | if (!shaderId) { 39 | throw new Error('shader failed.'); 40 | } 41 | gl.shaderSource(shaderId, source); 42 | gl.compileShader(shaderId); 43 | // 拿下编译结果,有问题抛 44 | if (!gl.getShaderParameter(shaderId, gl.COMPILE_STATUS)) { 45 | const errorLog = gl.getShaderInfoLog(shaderId); 46 | gl.deleteShader(shaderId); 47 | throw new Error('Shader compile failure: \n\n' + errorLog); 48 | } 49 | return shaderId; 50 | } 51 | } -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/cpu/sdf/base.js: -------------------------------------------------------------------------------- 1 | import { LightSource } from '../light'; 2 | 3 | /** 4 | * 虚拟物体 5 | * 用于描述一个物体 6 | * @date 9012/02/03 7 | * @author antimoron 8 | */ 9 | export class SDF { 10 | /** 11 | * 记录光场用的一些属性 12 | * @param {object} props 13 | */ 14 | constructor(props) { 15 | this._props = { ...props }; 16 | this.getLightSource = this.getLightSource.bind(this); 17 | } 18 | 19 | // TODO: 环形检测,检测好了记得骂人蠢 20 | // 记录操作构建图形场景 21 | // 传{ t: 'u(nion) | i(ntersect) | s(ubtract)', to: SDF} 22 | _opQueue = []; 23 | 24 | /** 25 | * 合并两个光 26 | */ 27 | union = (o) => { 28 | if (!o) { return; } 29 | this._opQueue.push({ 30 | t: 'u', 31 | to: o 32 | }); 33 | return this; 34 | } 35 | /** 36 | * 交集两个光 37 | */ 38 | intersect = (o) => { 39 | if (!o) { return; } 40 | this._opQueue.push({ 41 | t: 'i', 42 | to: o 43 | }); 44 | return this; 45 | } 46 | /** 47 | * 减法两个光 48 | * 注意没有交换律 49 | */ 50 | subtract = (o) => { 51 | if (!o) { return; } 52 | this._opQueue.push({ 53 | t: 's', 54 | to: o 55 | }); 56 | return this; 57 | } 58 | 59 | // 获取光距 60 | getSourceDistance(_) { 61 | return 0; 62 | } 63 | 64 | // 获取光源 65 | getLightSource(xy) { 66 | const props = { 67 | ...this._props, 68 | sourceDistance: this.getSourceDistance(xy) 69 | } 70 | const ls = new LightSource(); 71 | for (const key in props) { 72 | ls[key] = props[key]; 73 | } 74 | return ls; 75 | } 76 | } -------------------------------------------------------------------------------- /light2D/metal/RayTracking/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/gpu/util/vertex-buffer.js: -------------------------------------------------------------------------------- 1 | import { Buffer } from './buffer' 2 | 3 | export class VertexBuffer extends Buffer { 4 | /** 5 | * 6 | * @param {glContext} ctx 7 | * @param {number[]} positions 8 | * @param {number} positionComponentCount 9 | * @param {number[]} texcoords 10 | * @param {number} texcoordComponentCount 11 | */ 12 | constructor(ctx, positions, positionComponentCount, 13 | texcoords, texcoordComponentCount) { 14 | super(ctx); 15 | const gl = ctx; 16 | // 先绑定顶点数据 17 | this._positionComponentCount = positionComponentCount; 18 | this._vertexCount = positions.length / positionComponentCount; 19 | gl.bindBuffer(gl.ARRAY_BUFFER, this._raw); 20 | gl.bufferData(gl.ARRAY_BUFFER, 21 | new Float32Array(positions), 22 | gl.STATIC_DRAW); 23 | // 创建纹理用的buffer 24 | if (texcoords) { 25 | this._texBuffer = gl.createBuffer(); 26 | gl.bindBuffer(gl.ARRAY_BUFFER, this._texBuffer); 27 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(texcoords), gl.STATIC_DRAW); 28 | this._texcoordComponentCount = texcoordComponentCount; 29 | } 30 | } 31 | /** 32 | * 纹理buffer 33 | */ 34 | _texBuffer = null; 35 | 36 | /** 37 | * 返回顶点个数 38 | */ 39 | get vertexCount() { 40 | return this._vertexCount; 41 | } 42 | /** 43 | * 返回每个顶点的float个数 44 | */ 45 | get positionComponentCount() { 46 | return this._positionComponentCount; 47 | } 48 | /** 49 | * 拿到纹理每个数据里float个数 50 | */ 51 | get texcoordComponentCount() { 52 | return this._texcoordComponentCount; 53 | } 54 | /** 55 | * 返回纹理坐标buffer 56 | */ 57 | get texcoordBuffer() { 58 | return this._texBuffer; 59 | } 60 | } -------------------------------------------------------------------------------- /light2D/metal/RayTracking/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/gpu/util/program.js: -------------------------------------------------------------------------------- 1 | import { GlBase } from './base'; 2 | import { Shader } from './shader'; 3 | 4 | /** 5 | * 一堆slotname 6 | */ 7 | export const VERT_POS = 'aVertexPosition'; 8 | export const VERT_TEX = 'aTextureCoord'; 9 | export const CAM_PROJ = 'uProjectionMatrix'; 10 | export const CAM_MODEL = 'uModelViewMatrix'; 11 | export const SAMPLER = 'uSampler'; 12 | export const SAMPLER2 = 'uSampler2'; 13 | export const SHADER_TEXTURESIZE = 'uTextureSize'; 14 | 15 | export class Program extends GlBase { 16 | /** 17 | * 18 | * @param {*} ctx 19 | * @param {string} vert shader代码 20 | * @param {string} frag shader代码 21 | * @param {*} attributeNames attribute名字 22 | * @param {*} uniformNames uniform名字 23 | */ 24 | constructor(ctx, vert, frag, 25 | attributeNames, uniformNames) { 26 | super(ctx); 27 | this._vert = new Shader(ctx, 'vert', vert); 28 | this._frag = new Shader(ctx, 'frag', frag); 29 | this._raw = ctx.createProgram(); 30 | ctx.attachShader(this._raw, this._vert.raw); 31 | ctx.attachShader(this._raw, this._frag.raw); 32 | ctx.linkProgram(this._raw); 33 | const gl = ctx; 34 | // 如果程序链接阶段异常 则抛出报错 35 | if (!gl.getProgramParameter(this._raw, gl.LINK_STATUS)) { 36 | throw 'Unable to initialize the shader program: ' + 37 | gl.getProgramInfoLog(this._raw); 38 | } 39 | 40 | this._programStructure = { 41 | attribLocations: (attributeNames || []).reduce((pre, attrName, _) => { 42 | pre.set(attrName, this._gl.getAttribLocation(this._raw, attrName)); 43 | return pre; 44 | }, new Map()), 45 | uniformLocations: (uniformNames || []).reduce((pre, unif, _) => { 46 | pre.set(unif, this._gl.getUniformLocation(this._raw, unif)); 47 | return pre; 48 | }, new Map()), 49 | } 50 | } 51 | /** 52 | * 用当前program 53 | */ 54 | use() { 55 | this._gl.useProgram(this.raw); 56 | } 57 | // 记录shader中绑定结构slot位置 58 | _programStructure = null; 59 | /** 60 | * 程序结构 61 | */ 62 | get structure() { 63 | return this._programStructure; 64 | } 65 | } -------------------------------------------------------------------------------- /light2D/metal/RayTracking/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // RayTracking 4 | // 5 | // Created by gaoboyuan on 2019/2/2. 6 | // Copyright © 2019 gaoboyuan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /light2D/ecma-script/light/ReadMe.md: -------------------------------------------------------------------------------- 1 | ### Light-Render 2 | 3 | Nice 2D light rendering with pretty good ray tracing effect. Providing both CPU & GPU ways. 4 | 5 | Features included in this package: 6 | 7 | - Monte Carlo integral 8 | - Ray Tracing 9 | - Jittered sampling 10 | 11 | Thanks for [Miloyip](https://github.com/miloyip)'s [sharing](https://zhuanlan.zhihu.com/p/30745861). Also he's the author of [RapidJson](https://github.com/Tencent/rapidjson) which is a really effecient json parsing library. 12 | 13 | ### Install 14 | 15 | ```bash 16 | npm i -S light-render 17 | ``` 18 | 19 | ![](https://user-images.githubusercontent.com/6587734/52172954-41527e80-27b5-11e9-95d3-b3d1756743cc.png) 20 | 21 | A quick glance at `Light` with a short demo: 22 | 23 | ```javascript 24 | import { Light } from 'light-render'; 25 | 26 | // Whether to render in CPU. 27 | const useCPU = false; 28 | const Kit = useCPU ? Light.cpu : Light.gpu; 29 | 30 | const { 31 | SDF: { 32 | Circle, 33 | Plane, 34 | Rect, 35 | }, 36 | render 37 | } = Kit; 38 | 39 | const c = new Circle({ 40 | emissive: 20, 41 | reflectivity: 0, 42 | eta: 0, 43 | }, { x: 0.5, y: -0.5 }, .05) 44 | const i = new Circle({ 45 | emissive: 0, 46 | reflectivity: .2, 47 | eta: 1.5, 48 | }, { x: 0.5, y: 0.87 }, 0.2); 49 | const j = new Plane({ 50 | emissive: 0, 51 | reflectivity: .2, 52 | eta: 1.45, 53 | }, { x: 0.5, y: .5 }, { x: .0, y: -1.0 }); 54 | 55 | // Rendering method. 56 | render(document.getElementById('cv'), c.union(i.intersect(j))); 57 | ``` 58 | 59 | #### render arguments 60 | 61 | Declaration: 62 | 63 | ```javascript 64 | function render(cv, objs, opts) 65 | ``` 66 | 67 | ##### cv: HTMLCanvasElement 68 | 69 | Canvas DOM 70 | 71 | ##### objs 72 | 73 | objects that being described in sdf. 74 | 75 | > What's SDF? It's a kind of model that can build a scene in this senario called `Signed Distance Field`. 76 | 77 | SDF constructors: 78 | 79 | - Circle(props, center, radius) 80 | - Rect(props, center, theta, s) 81 | - Plane(props, pxy, normal) 82 | 83 | SDF methods: 84 | 85 | - union(o) 86 | - intersect(o) 87 | - subtract(o) 88 | 89 | ##### opts: options for rendering 90 | 91 | - N Times to sample. `64.0` by default 92 | - MAX_STEP Maximum steps for ray tracing. `10` by default. 93 | - MAX_DISTANCE Maximum distance for ray tracing. `10.0` by default. 94 | -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/cpu/light.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 用于描述一个光源 3 | * @date 9012/02/03 4 | * @author antimoron 5 | */ 6 | export class LightSource { 7 | // 光源距离 8 | sourceDistance = 0; 9 | // 光(头)强 10 | emissive = 0; 11 | // 反射率 12 | // 如果反射率超过 1,总能量就变多,不符合能量守恒。少于 1 代表形状吸收了能量。 13 | reflectivity = 0; 14 | // 介质折射率 15 | // 如果光线从外至内,调用 \texttt{refract()} 时,传入 1 / \eta ;从内至外则传入 \eta 。 16 | eta = 0; 17 | // 是否三色散射 18 | triray = false; 19 | 20 | /** 21 | * 构造一个光源 22 | * 分别用于方便构建的4种模式 23 | * humble 就比较谦虚 24 | * awesome 表示带个反射 25 | * badass 会多带个折射 26 | * asdfasdfasdfasdfasdf 5个asdf,方便你在小白面前脸滚键盘都能做出效果 27 | * @param {string} other 'humble' | 'awesome' | 'badass' | 'asdfasfdasdfasdfasdf' 28 | * 当为另一个light source时候为复制 29 | */ 30 | constructor(other) { 31 | if (typeof other === 'string') { 32 | const mode = other; 33 | switch (mode) { 34 | case 'humble': 35 | break; 36 | case 'awesome': 37 | this.reflectivity = 0.5; 38 | break; 39 | case 'badass': 40 | this.reflectivity = 0.8; 41 | this.refract = 1.5; 42 | break; 43 | case 'asdfasdfasdfasdfasdf': 44 | default: 45 | this.reflectivity = 0.8; 46 | this.triray = true; 47 | break; 48 | } 49 | } else if (!!other) { 50 | this.sourceDistance = other.sourceDistance; 51 | this.emissive = other.emissive; 52 | this.reflectivity = other.reflectivity; 53 | this.eta = other.eta; 54 | this.triray = other.triray; 55 | } 56 | } 57 | 58 | /** 59 | * 合并两个光 60 | */ 61 | union = (o) => { 62 | return new LightSource(this.sourceDistance < o.sourceDistance ? this : o); 63 | } 64 | /** 65 | * 交集两个光 66 | */ 67 | intersect = (o) => { 68 | const r = new LightSource(this.sourceDistance > o.sourceDistance ? o : this); 69 | r.sourceDistance = this.sourceDistance > o.sourceDistance ? this.sourceDistance : o.sourceDistance; 70 | return r; 71 | } 72 | /** 73 | * 减法两个光 74 | * 注意没有交换律 75 | */ 76 | subtract = (o) => { 77 | const r = new LightSource(this); 78 | r.sourceDistance = (this.sourceDistance > -o.sourceDistance) ? this.sourceDistance : -o.sourceDistance; 79 | return r; 80 | } 81 | }; -------------------------------------------------------------------------------- /light2D/metal/RayTracking/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // RayTracking 4 | // 5 | // Created by gaoboyuan on 2019/2/2. 6 | // Copyright © 2019 gaoboyuan. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Metal 11 | import MetalKit 12 | 13 | class ViewController: UIViewController { 14 | 15 | var device: MTLDevice! 16 | 17 | var metalLayer: CAMetalLayer! 18 | 19 | var vertexBuffer: MTLBuffer! 20 | 21 | var pipelineState: MTLRenderPipelineState! 22 | 23 | var commandQueue: MTLCommandQueue! 24 | 25 | // 保持60FPS 26 | var timer: CADisplayLink! 27 | 28 | override func viewDidLoad() { 29 | super.viewDidLoad() 30 | 31 | // 创建个device(类似d3d11device) 32 | device = MTLCreateSystemDefaultDevice() 33 | // 创建个layer (需要这样一个CALayer作为画布) 34 | metalLayer = CAMetalLayer() 35 | // 一些常规配置 36 | metalLayer.device = device 37 | metalLayer.pixelFormat = .bgra8Unorm 38 | metalLayer.framebufferOnly = true 39 | metalLayer.frame = view.layer.frame 40 | view.layer.addSublayer(metalLayer) 41 | 42 | // 创建个vertex data buffer(OGLES 的 VAO). 43 | let vertexData: [Float] = [ 44 | -1.0, -1.0, 45 | -1.0, 1.0, 46 | 1.0, -1.0, 47 | 1.0, 1.0, 48 | ] 49 | 50 | let dataSize = vertexData.count * MemoryLayout.size(ofValue: vertexData[0]) // 1 51 | vertexBuffer = device.makeBuffer(bytes: vertexData, length: dataSize, options: []) // 2 52 | 53 | // 创建 Render Pipeline 54 | // shader里写的函数要在CPU端预先定义下 55 | // 先创建一个对应precompiled shader的library 56 | // 直接读工程中的metal文件 57 | let defaultLibrary = device.makeDefaultLibrary()! 58 | let fragmentProgram = defaultLibrary.makeFunction(name: "basic_fragment") 59 | let vertexProgram = defaultLibrary.makeFunction(name: "basic_vertex") 60 | 61 | // 为啥这些shader object 都要在cpu端定义下呢? 62 | 63 | // 创建对应的pipeline描述,根据对应描述创建pipeline,和d3d11有点像 64 | // 不是structure..因为兼容OC,是个NSObject 65 | let pipelineStateDescriptor = MTLRenderPipelineDescriptor() 66 | pipelineStateDescriptor.vertexFunction = vertexProgram 67 | pipelineStateDescriptor.fragmentFunction = fragmentProgram 68 | pipelineStateDescriptor.colorAttachments[0].pixelFormat = .bgra8Unorm 69 | 70 | 71 | // 拿对应的描述创建pipeline 72 | // 什么情况下会失败有待查明 73 | pipelineState = try! device.makeRenderPipelineState(descriptor: pipelineStateDescriptor) 74 | 75 | // 创建一个command队列,发送GPU消息 76 | commandQueue = device.makeCommandQueue() 77 | 78 | // Create a Display Link 79 | // Create a Render Pass Descriptor 80 | // Create a Command Buffer 81 | // Create a Render Command Encoder 82 | // Commit your Command Buffer 83 | 84 | // timer = CADisplayLink(target: self, selector: #selector(gameloop)) 85 | // timer.add(to: RunLoop.main, forMode: .default) 86 | 87 | render() 88 | } 89 | 90 | func render() { 91 | guard let drawable = metalLayer?.nextDrawable() else { return } 92 | let renderPassDescriptor = MTLRenderPassDescriptor() 93 | renderPassDescriptor.colorAttachments[0].texture = drawable.texture 94 | renderPassDescriptor.colorAttachments[0].loadAction = .clear 95 | renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColor( 96 | red: 0.0, 97 | green: 104.0/255.0, 98 | blue: 55.0/255.0, 99 | alpha: 1.0) 100 | // 队列需要拿到一个command buffer(类似于OGL ES里每个对象都是和一个GLBuffer绑定) 101 | // 这个在每一帧里执行是不是有点浪费,一会儿试试挪到外面去 102 | let commandBuffer = commandQueue.makeCommandBuffer()! 103 | // RenderPass 每帧的设定 104 | let renderEncoder = commandBuffer 105 | .makeRenderCommandEncoder(descriptor: renderPassDescriptor)! 106 | renderEncoder.setRenderPipelineState(pipelineState) 107 | renderEncoder.setVertexBuffer(vertexBuffer, offset: 0, index: 0) 108 | renderEncoder 109 | .drawPrimitives(type: .triangleStrip, vertexStart: 0, vertexCount: 4, instanceCount: 1) 110 | renderEncoder.endEncoding() 111 | commandBuffer.present(drawable) 112 | commandBuffer.commit() 113 | } 114 | 115 | @objc func gameloop() { 116 | // autoreleasepool { 117 | self.render() 118 | // } 119 | } 120 | 121 | } 122 | 123 | -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/gpu/render/index.js: -------------------------------------------------------------------------------- 1 | import { Scene } from '../util/scene' 2 | import vs from '../shader/draw/v'; 3 | import fs from '../shader/draw/f'; 4 | import { VERT_POS } from '../util/program'; 5 | 6 | /** 7 | * 给一个canvas和SDF对象,画出值 8 | * @param {*} cv HTML canvas element 9 | * @param {*} objs SDF对象树 10 | * @param {object} opts 属性 11 | */ 12 | export function render(cv, objs, opts) { 13 | if (!cv) { 14 | throw new Error('canvas element not available.'); 15 | } 16 | const context = cv.getContext('webgl'); 17 | if (!context) { 18 | throw new Error('Webgl not supported on current browser.'); 19 | } 20 | 21 | let elements = new Set(); 22 | const flattenTree = (objs) => { 23 | if (!objs) { return; } 24 | elements.add(objs); 25 | const { 26 | _opQueue: queue 27 | } = objs; 28 | for (const cmd of queue) { 29 | const { 30 | t: type, 31 | to 32 | } = cmd; 33 | switch (type) { 34 | case 'u': 35 | flattenTree(to); 36 | break; 37 | case 'i': 38 | flattenTree(to); 39 | break; 40 | case 's': 41 | flattenTree(to); 42 | break; 43 | } 44 | } 45 | }; 46 | // 平铺所有元素 47 | flattenTree(objs); 48 | elements = [...elements]; 49 | // 提前返回 50 | if (elements.length === 0) { 51 | return; 52 | } 53 | 54 | // let sdfs = []; 55 | // let ops = []; 56 | 57 | // 找到组合顺序 58 | // const adaptSDF = (o) => { 59 | // if (!o) { return; } 60 | // const { 61 | // _opQueue: queue 62 | // } = o; 63 | // const elemIdx = elements.findIndex(_ => _ === o); 64 | // if (elemIdx < 0) { return; } 65 | // // 补齐16个float表示一个sdf 66 | // const desc = o.gpuDesc; 67 | // for (let i = desc.length; i < 16; i++) { 68 | // desc.push(0); 69 | // } 70 | 71 | // sdfs[elemIdx] = desc; 72 | // if (queue.length === 0) { 73 | // return; 74 | // } 75 | // for (const cmd of queue) { 76 | // const { 77 | // t: type, 78 | // to 79 | // } = cmd; 80 | // const datas = [0, 0, 0, 0]; 81 | // switch (type) { 82 | // case 'u': 83 | // datas[0] = 1; 84 | // break; 85 | // case 'i': 86 | // datas[0] = 2; 87 | // break; 88 | // case 's': 89 | // datas[0] = 3; 90 | // break; 91 | // } 92 | // datas[1] = elemIdx; 93 | // datas[2] = elements.findIndex(_ => _ === to); 94 | // ops.push(datas); 95 | // adaptSDF(to); 96 | // } 97 | // } 98 | // adaptSDF(objs); 99 | // sdfs = sdfs.reduce((pre, cur) => { 100 | // return pre.concat(cur); 101 | // }, []); 102 | // ops = ops.reduce((pre, cur) => { 103 | // return pre.concat(cur); 104 | // }, []); 105 | 106 | const scene = new Scene(context); 107 | 108 | const sceneCodeGenerator = (o) => { 109 | if (!o) { return; } 110 | const { 111 | _opQueue: queue 112 | } = o; 113 | const elemIdx = elements.findIndex(_ => _ === o); 114 | if (queue.length === 0) { 115 | return `a${elemIdx}`; 116 | } 117 | for (const cmd of queue) { 118 | const { 119 | t: type, 120 | to 121 | } = cmd; 122 | switch (type) { 123 | case 'u': 124 | return `unionOp(a${elemIdx}, ${sceneCodeGenerator(to)})`; 125 | case 'i': 126 | return `intersectOp(a${elemIdx}, ${sceneCodeGenerator(to)})`; 127 | case 's': 128 | return `subtractOp(a${elemIdx}, ${sceneCodeGenerator(to)})`; 129 | } 130 | } 131 | }; 132 | // 动态生成shader,还要防止递归调用 133 | const defs = elements.map((o, idx) => { 134 | return `LightSource a${idx} = ${o.gpuDesc};`; 135 | }).join('\n'); 136 | const fragShaderSoucePart = defs + `\nreturn ${sceneCodeGenerator(objs)};`; 137 | const { N, MAX_STEP, MAX_DISTANCE } = opts || { 138 | N: '64.0', 139 | MAX_STEP: '64', 140 | MAX_DISTANCE: '10.0', 141 | }; 142 | const fragShaderSouce = fs(cv.width, cv.height, fragShaderSoucePart, N, MAX_STEP, MAX_DISTANCE); 143 | console.log(fragShaderSoucePart); 144 | const flat2D = scene.createGlProgram(vs, fragShaderSouce, 145 | [VERT_POS]); 146 | scene.bindProgram(flat2D); 147 | const screenRect = scene.createVertices([ 148 | -1.0, 1.0, 149 | 1.0, 1.0, 150 | -1.0, -1.0, 151 | 1.0, -1.0,], 2, 152 | [0, 1.0, 153 | 1.0, 1.0, 154 | 0, 0, 155 | 1.0, 0,], 2); 156 | scene.clear(); 157 | scene.draw(screenRect, 'trianglestrip'); 158 | } -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/cpu/render/index.js: -------------------------------------------------------------------------------- 1 | import { addf2, mulf2 } from '../util/float2'; 2 | 3 | // let N = 32; 4 | // let MAX_STEP = 10; 5 | // let MAX_DISTANCE = 4.0; 6 | let EPSILON = 1e-6; 7 | let BIAS = 1e-4; 8 | 9 | /** 10 | * 接纳处理好的图形 11 | * @param {*} xy 12 | * @param {*} o 13 | */ 14 | function adaptSDF(xy, o) { 15 | const { 16 | _opQueue: queue 17 | } = o; 18 | let ls = o.getLightSource(xy); 19 | if (queue.length === 0) { 20 | return ls; 21 | } 22 | for (const cmd of queue) { 23 | const { 24 | t: type, 25 | to 26 | } = cmd; 27 | switch (type) { 28 | case 'u': 29 | ls = ls.union(adaptSDF(xy, to)); 30 | break; 31 | case 'i': 32 | ls = ls.intersect(adaptSDF(xy, to)); 33 | break; 34 | case 's': 35 | ls = ls.subtract(adaptSDF(xy, to)); 36 | break; 37 | } 38 | } 39 | return ls; 40 | } 41 | 42 | function scene(xy, objs) { 43 | return adaptSDF(xy, objs); 44 | } 45 | 46 | 47 | // 说是计算法线 48 | function gradient(xy, objs) { 49 | return { 50 | x: (scene({ x: xy.x + EPSILON, y: xy.y }, objs).sourceDistance 51 | - scene({ x: xy.x - EPSILON, y: xy.y }, objs).sourceDistance) * (0.5 / EPSILON), 52 | y: (scene({ x: xy.x, y: xy.y + EPSILON }, objs).sourceDistance 53 | - scene({ x: xy.x, y: xy.y - EPSILON }, objs).sourceDistance) * (0.5 / EPSILON) 54 | }; 55 | } 56 | 57 | /** 58 | * 折射函数 59 | * @param {*} ixy 60 | * @param {*} nxy 61 | */ 62 | function reflect(ixy, nxy) { 63 | const idotn2 = (ixy.x * nxy.x + ixy.y * nxy.y) * 2.0; 64 | return { 65 | x: ixy.x - idotn2 * nxy.x, 66 | y: ixy.y - idotn2 * nxy.y 67 | }; 68 | } 69 | 70 | /** 71 | * 折射函数 72 | * @param {*} ixy 73 | * @param {*} nxy 74 | * @param {*} eta 75 | */ 76 | function refract(ixy, nxy, eta) { 77 | const idotn = ixy.x * nxy.x + ixy.y * nxy.y; 78 | const k = 1.0 - eta * eta * (1.0 - idotn * idotn); 79 | const a = eta * idotn + Math.sqrt(k); 80 | return { 81 | x: eta * ixy.x - a * nxy.x, 82 | y: eta * ixy.y - a * nxy.y 83 | }; 84 | } 85 | 86 | /** 87 | * ray tracing 88 | * @param {*} o 89 | * @param {*} d 90 | * @param {*} objs 要渲染的对象 91 | * @param {*} depth 92 | */ 93 | function trace(o, d, objs, depth, MAX_STEP, MAX_DISTANCE) { 94 | let t = .0; 95 | // 判断是场景内还是外,间eta注释 96 | const s = scene(o, objs).sourceDistance > .0 ? 1 : -1; 97 | for (let i = 0; i < MAX_STEP && t < MAX_DISTANCE; i++) { 98 | let xy = addf2(mulf2(d, t), o); 99 | const sd = scene(xy, objs); 100 | sd.sourceDistance *= s; 101 | if (sd.sourceDistance < EPSILON) { 102 | // 反射 103 | let sum = sd.emissive; 104 | if (depth < 3) { 105 | let refl = sd.reflectivity; 106 | if (sd.reflectivity > .0 || sd.eta > .0) { 107 | let normal = gradient(xy, objs); 108 | normal = mulf2(normal, s);// 在内的话,要反转法线 109 | // normal = normalize(normal); 110 | if (sd.eta > .0) { 111 | const etaRange = refract(d, normal, s < .0 ? sd.eta : 1.0 / sd.eta); 112 | sum += (1.0 - refl) * trace(xy - normal * BIAS, etaRange, objs, depth + 1, MAX_STEP, MAX_DISTANCE); 113 | } 114 | if (refl > .0) { 115 | const refl2 = reflect(d, normal); 116 | sum += refl * trace(xy + normal * BIAS, refl2, objs, depth + 1, MAX_STEP, MAX_DISTANCE); 117 | } 118 | } 119 | } 120 | return sum; 121 | } 122 | t += sd.sourceDistance; 123 | } 124 | return .0; 125 | } 126 | 127 | /** 128 | * 采样(x,y)的颜色 129 | * jitter sampling. 130 | * @param {*} xy x,y像素点 131 | * @param {Array} objs 填入一堆SDF对象 132 | */ 133 | function sample(xy, objs, N, MAX_STEP, MAX_DISTANCE) { 134 | let sum = .0; 135 | for (let i = 0; i < N; i++) { 136 | let a = Math.PI * 2.0 * (i + Math.random()) / N; 137 | sum += trace(xy, { x: Math.cos(a), y: Math.sin(a) }, objs, 0, MAX_STEP, MAX_DISTANCE); 138 | } 139 | return sum / 64.0; 140 | } 141 | 142 | 143 | /** 144 | * 给一个canvas和SDF对象,画出值 145 | * @param {*} cv HTML canvas element 146 | * @param {*} objs SDF对象树 147 | * @param {*} opts 参数 148 | */ 149 | export function render(cv, objs, opts) { 150 | if (!cv) { 151 | throw new Error('canvas element not available.'); 152 | } 153 | const context = cv.getContext('2d'); 154 | if (!context) { 155 | throw new Error('Canvas not supported on current browser.'); 156 | } 157 | const W = cv.width, H = cv.height; 158 | const imgData = context.createImageData(W, H); 159 | 160 | let { N, MAX_STEP, MAX_DISTANCE } = opts || { 161 | N: 64, 162 | MAX_STEP: 64, 163 | MAX_DISTANCE: 10.0, 164 | }; 165 | 166 | N = +N; MAX_STEP = +MAX_STEP; MAX_DISTANCE = +MAX_DISTANCE; 167 | 168 | for (let i = 0; i < H; i++) { 169 | for (let j = 0; j < W; j++) { 170 | const idx = i * W + j; 171 | const gray = Math.floor(sample({ x: 1.0 * j / W, y: 1.0 * i / H }, objs) * 255.0, 0, N, MAX_STEP, MAX_DISTANCE); 172 | imgData.data[idx * 4] = gray; 173 | imgData.data[idx * 4 + 1] = gray; 174 | imgData.data[idx * 4 + 2] = gray; 175 | imgData.data[idx * 4 + 3] = 255; 176 | } 177 | } 178 | context.putImageData(imgData, 0, 0); 179 | } -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/gpu/util/scene.js: -------------------------------------------------------------------------------- 1 | import { GlBase } from './base' 2 | import { Program } from './program'; 3 | import { VERT_POS, VERT_TEX } from './program'; 4 | import { Texture } from './texture'; 5 | import { VertexBuffer } from './vertex-buffer'; 6 | /** 7 | * 场景 8 | */ 9 | export class Scene extends GlBase { 10 | constructor(ctx) { 11 | super(ctx); 12 | } 13 | 14 | /** 15 | * 创建个gl程序 16 | * @param {string} vert 顶点着色器源码 17 | * @param {string} frag 片段着色器源码 18 | * @param {string[]} attributeNames 结构名 有要求自己记得第几个是做什么用的 19 | * @param {string[]} uniformNames 常量名 有要求自己记得第几个是做什么用的 20 | */ 21 | createGlProgram(vert, frag, 22 | attributeNames, uniformNames) { 23 | return new Program(this._gl, vert, frag, attributeNames, uniformNames); 24 | } 25 | /** 26 | * 创建顶点数据 27 | * @param {number[]} positions 28 | * @param {number} positionComponentCount 顶点包含float个数 29 | * @param {number[]} texcoords 纹理坐标 30 | * @param {number} texcoordComponentCount 每个顶点包含float个数 31 | */ 32 | createVertices(positions, positionComponentCount, 33 | texcoords = null, texcoordComponentCount = null) { 34 | return new VertexBuffer(this._gl, positions, 35 | positionComponentCount, texcoords, texcoordComponentCount); 36 | } 37 | 38 | clear() { 39 | const gl = this._gl; 40 | // Set clear color to black, fully opaque 41 | gl.clearColor(0.0, 0.0, 0.0, 1.0); 42 | // Clear the color buffer with specified clear color 43 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 44 | } 45 | 46 | /** 47 | * 绑定顶点数据 48 | * @param {VertexBuffer} vertices 顶点数据 49 | */ 50 | bindVertices(vertices) { 51 | const gl = this._gl; 52 | const type = gl.FLOAT; // the data in the buffer is 32bit floats 53 | const normalize = false; // don't normalize 54 | const stride = 0; // how many bytes to get from one set of values to the next 55 | const offset = 0; // how many bytes inside the buffer to start from 56 | //开启对应VAO并绑定顶点数据 57 | gl.bindBuffer(gl.ARRAY_BUFFER, vertices.raw); 58 | const positionSlot = this._currentProgram.structure.attribLocations.get(VERT_POS); 59 | gl.vertexAttribPointer(positionSlot, 60 | vertices.positionComponentCount, 61 | type, normalize, stride, offset); 62 | gl.enableVertexAttribArray(positionSlot); 63 | // 绑定纹理坐标buffer 64 | const texSlot = this._currentProgram.structure.attribLocations.get(VERT_TEX); 65 | if (texSlot !== null && texSlot !== undefined) { 66 | gl.bindBuffer(gl.ARRAY_BUFFER, vertices.texcoordBuffer); 67 | gl.vertexAttribPointer(texSlot, vertices.texcoordComponentCount, type, true, stride, offset); 68 | gl.enableVertexAttribArray(texSlot); 69 | } 70 | } 71 | /** 72 | * 绑定gl program 73 | * @param {Program} program 一个program 74 | * @param {[number, number]} textureSize 75 | * @param {Map} otherParam 76 | */ 77 | bindProgram(program, textureSize = null, otherParam = null) { 78 | this._gl.useProgram(program.raw); 79 | this._currentProgram = program; 80 | if (textureSize && textureSize.length >= 2 && program.structure.uniformLocations.get(SHADER_TEXTURESIZE)) { 81 | this._gl.uniform2f(program.structure.uniformLocations.get(SHADER_TEXTURESIZE), textureSize[0], textureSize[1]) 82 | } 83 | if (otherParam) { 84 | for (const key in otherParam) { 85 | const v = otherParam[key]; 86 | let isInteger = false; 87 | if (key.charAt(0) === 'i') { 88 | isInteger = true; 89 | } 90 | if (program.structure.uniformLocations.get(key)) { 91 | if (typeof v === 'number') { 92 | if (isInteger) { 93 | this._gl.uniform1i(program.structure.uniformLocations.get(key), v); 94 | } else { 95 | this._gl.uniform1f(program.structure.uniformLocations.get(key), v); 96 | } 97 | } else if (typeof v === 'object' && Object.prototype.toString.call(v) === '[object Array]') { 98 | if (isInteger) { 99 | this._gl.uniform1iv(program.structure.uniformLocations.get(key), new Int32Array(v)); 100 | } else { 101 | this._gl.uniform1fv(program.structure.uniformLocations.get(key), new Float32Array(v)); 102 | } 103 | } 104 | } 105 | } 106 | } 107 | } 108 | 109 | /** 110 | * 创建frame buffer. 111 | * @param {number} width 宽 112 | * @param {number} height 高 113 | */ 114 | createFrameBuffer(width, height) { 115 | return new FrameBuffer(this._gl, width, height); 116 | } 117 | /** 118 | * 绑定一帧 119 | * @param {FrameBuffer} framebuffer 一帧缓存 120 | */ 121 | bindFrameBuffer(framebuffer) { 122 | const gl = this._gl; 123 | if (!framebuffer) { 124 | gl.bindFramebuffer(gl.FRAMEBUFFER, null); 125 | return; 126 | } 127 | framebuffer.use(); 128 | gl.clearColor(0.0, 0.0, 0.0, 1.0); 129 | // Clear the color buffer with specified clear color 130 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 131 | } 132 | /** 133 | * 创建纹理 134 | * @param {number} width 宽 135 | * @param {number} height 高 136 | */ 137 | createTexture(width = 1, height = 1) { 138 | return new Texture(this._gl, width, height); 139 | } 140 | // /** 141 | // * 根据canvas创建纹理 142 | // * @param canvas canvas 143 | // */ 144 | // createTextureFromCanvas(canvas) { 145 | // return new Texture(this._gl, canvas); 146 | // } 147 | /** 148 | * 绑定的纹理 149 | * @param {Texture} tex 绑定的纹理 150 | * @param {string} uniformName 绑定uniform位置 151 | */ 152 | bindTexture(tex, uniformName = null) { 153 | const gl = this._gl; 154 | // Tell WebGL we want to affect texture unit 0 155 | gl.activeTexture(uniformName === SAMPLER2 ? gl.TEXTURE1 : gl.TEXTURE0); 156 | // Bind the texture to texture unit 0 157 | gl.bindTexture(gl.TEXTURE_2D, tex.raw); 158 | // Tell the shader we bound the texture to texture unit 0 159 | gl.uniform1i(this._currentProgram.structure.uniformLocations.get(uniformName ? uniformName : SAMPLER), 160 | uniformName === SAMPLER2 ? 1 : 0); 161 | } 162 | 163 | /** 164 | * 绘制一个顶点buffer 165 | * @param {VertexBuffer} vertices 绘制一个顶点buffer 166 | * @param {string} primitiveType 原节点 167 | */ 168 | draw(vertices, primitiveType) { 169 | this.bindVertices(vertices); 170 | const gl = this._gl; 171 | let glPrimitiveType = null; 172 | switch (primitiveType) { 173 | case 'line': 174 | glPrimitiveType = gl.LINES; 175 | break; 176 | case 'linestrip': 177 | glPrimitiveType = gl.LINE_STRIP; 178 | break; 179 | case 'triangle': 180 | glPrimitiveType = gl.TRIANGLES; 181 | break; 182 | case 'trianglestrip': 183 | glPrimitiveType = gl.TRIANGLE_STRIP; 184 | break; 185 | default: break; 186 | } 187 | gl.drawArrays(glPrimitiveType, 0, vertices.vertexCount); 188 | } 189 | 190 | getError() { 191 | return this._gl.getError(); 192 | } 193 | } -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/src/gpu/shader/draw/f.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author antimoron 3 | */ 4 | export default function (width, height, sceneCode, N = '64.0', MAX_STEP = '64', MAX_DISTANCE = '10.0') { 5 | return ` 6 | precision highp float; 7 | // uniform float sdfs[128]; 8 | // uniform int iSdfOps[64]; 9 | // uniform int iSdfCount; // sdf 数量 10 | 11 | const float N = ${N}; 12 | const int MAX_STEP = ${MAX_STEP}; 13 | const float MAX_DISTANCE = ${MAX_DISTANCE}; 14 | const float EPSILON = 1e-6; 15 | const float BIAS = 1e-4; 16 | 17 | 18 | // 定义一个光源 19 | struct LightSource { 20 | // 光源距离 21 | float sourceDistance; 22 | // 光(头)强 23 | float emissive; 24 | // 反射率 25 | // 如果反射率超过 1,总能量就变多,不符合能量守恒。少于 1 代表形状吸收了能量。 26 | float reflectivity; 27 | // 介质折射率 28 | // 如果光线从外至内,调用 \texttt{refract()} 时,传入 1 / \eta ;从内至外则传入 \eta 。 29 | float eta; 30 | }; 31 | 32 | 33 | // 合并两个LightSource 34 | LightSource unionOp(LightSource a, LightSource b) { 35 | if(a.sourceDistance < b.sourceDistance) { 36 | return a; 37 | } 38 | return b; 39 | } 40 | 41 | LightSource intersectOp(LightSource a, LightSource b) { 42 | LightSource r = a; 43 | if(a.sourceDistance > b.sourceDistance) { 44 | r = b; 45 | } 46 | r.sourceDistance = a.sourceDistance > b.sourceDistance ? a.sourceDistance : b.sourceDistance; 47 | return r; 48 | } 49 | 50 | LightSource subtractOp(LightSource a, LightSource b) { 51 | LightSource r = a; 52 | r.sourceDistance = (a.sourceDistance > -b.sourceDistance) ? a.sourceDistance : -b.sourceDistance; 53 | return r; 54 | } 55 | 56 | 57 | // 一个圆形光源 58 | float circleSDF(vec2 xy, vec2 center, float radius) { 59 | vec2 u = xy - center; 60 | return sqrt(u.x * u.x + u.y * u.y) - radius; 61 | } 62 | 63 | // 抄这 https://zhuanlan.zhihu.com/p/30816284 64 | float boxSDF(vec2 xy, vec2 center, float theta, vec2 s) { 65 | float costheta = cos(theta), sintheta = sin(theta); 66 | float dx = abs((xy.x - center.x) * costheta + (xy.y - center.y) * sintheta) - s.x; 67 | float dy = abs((xy.y - center.y) * costheta - (xy.x - center.x) * sintheta) - s.y; 68 | float ax = max(dx, .0), ay = max(dy, .0 ); 69 | return min(max(dx, dy), .0) + sqrt(ax * ax + ay * ay); 70 | } 71 | 72 | // 抄这个 https://github.com/miloyip/light2d/blob/master/refraction.c 73 | float planeSDF(vec2 xy, vec2 pxy, vec2 normal) { 74 | return (xy.x - pxy.x) * normal.x + (xy.y - pxy.y) * normal.y; 75 | } 76 | 77 | LightSource createLS(float sd, float emissive, float reflectivity, float eta) { 78 | LightSource ret; 79 | ret.sourceDistance = sd; 80 | ret.emissive = emissive; 81 | ret.reflectivity = reflectivity; 82 | ret.eta = eta; 83 | return ret; 84 | } 85 | 86 | LightSource scene(vec2 xy) { 87 | ${sceneCode}; 88 | } 89 | 90 | // 说是计算法线 91 | vec2 gradient(vec2 xy) { 92 | vec2 xy00 = vec2(xy.x + EPSILON, xy.y); 93 | vec2 xy01 = vec2(xy.x - EPSILON, xy.y); 94 | vec2 xy10 = vec2(xy.x, xy.y + EPSILON); 95 | vec2 xy11 = vec2(xy.x, xy.y - EPSILON); 96 | float hEp = 0.5 / EPSILON; 97 | return vec2((scene(xy00).sourceDistance - scene(xy01).sourceDistance) * hEp, 98 | (scene(xy10).sourceDistance - scene(xy11).sourceDistance) * hEp); 99 | } 100 | 101 | // /** 102 | // * 折射函数 103 | // * @param {*} ixy 104 | // * @param {*} nxy 105 | // */ 106 | // vec2 reflect(vec2 ixy, vec2 nxy) { 107 | // float idotn2 = (ixy.x * nxy.x + ixy.y * nxy.y) * 2.0; 108 | // return vec2(ixy.x - idotn2 * nxy.x, 109 | // ixy.y - idotn2 * nxy.y); 110 | // } 111 | 112 | // /** 113 | // * 折射函数 114 | // * @param {*} ixy 115 | // * @param {*} nxy 116 | // * @param {*} eta 117 | // */ 118 | // vec2 refract(vec2 ixy, vec2 nxy, float eta) { 119 | // float idotn = ixy.x * nxy.x + ixy.y * nxy.y; 120 | // float k = 1.0 - eta * eta * (1.0 - idotn * idotn); 121 | // float a = eta * idotn + sqrt(k); 122 | // return vec2(eta * ixy.x - a * nxy.x, 123 | // eta * ixy.y - a * nxy.y); 124 | // } 125 | 126 | 127 | /** 128 | * ray tracing 129 | * @param {*} o 130 | * @param {*} d 131 | * @param {*} depth 132 | */ 133 | float trace0(vec2 o, vec2 d) { 134 | float t = .0; 135 | // 判断是场景内还是外,间eta注释 136 | float s = scene(o).sourceDistance > .0 ? 1.0 : -1.0; 137 | for (int i = 0; i < MAX_STEP; i++) { 138 | if(t >= MAX_DISTANCE) { break; } 139 | vec2 xy = d * t + o; 140 | LightSource sd = scene(xy); 141 | sd.sourceDistance = sd.sourceDistance * s; 142 | if (sd.sourceDistance < EPSILON) { 143 | // 反射 144 | return sd.emissive; 145 | } 146 | t += sd.sourceDistance; 147 | } 148 | return .0; 149 | } 150 | 151 | /** 152 | * ray tracing 153 | * @param {*} o 154 | * @param {*} d 155 | * @param {*} depth 156 | */ 157 | float trace1(vec2 o, vec2 d) { 158 | float t = .0; 159 | // 判断是场景内还是外,间eta注释 160 | float s = scene(o).sourceDistance > .0 ? 1.0 : -1.0; 161 | for (int i = 0; i < MAX_STEP; i++) { 162 | if(t >= MAX_DISTANCE) { break; } 163 | vec2 xy = d * t + o; 164 | LightSource sd = scene(xy); 165 | sd.sourceDistance = sd.sourceDistance * s; 166 | if (sd.sourceDistance < EPSILON) { 167 | // 反射 168 | float sum = sd.emissive; 169 | float refl = sd.reflectivity; 170 | if (sd.reflectivity > .0 || sd.eta > .0) { 171 | vec2 normal = gradient(xy); 172 | normal = normal * s;// 在内的话,要反转法线 173 | normal = normalize(normal); 174 | if (sd.eta > .0) { 175 | vec2 etaRange = refract(d, normal, s < .0 ? sd.eta : 1.0 / sd.eta); 176 | sum += (1.0 - refl) * trace0(xy - normal * BIAS, etaRange); 177 | } 178 | if (refl > .0) { 179 | vec2 refl2 = reflect(d, normal); 180 | sum += refl * trace0(xy + normal * BIAS, refl2); 181 | } 182 | } 183 | return sum; 184 | } 185 | t += sd.sourceDistance; 186 | } 187 | return .0; 188 | } 189 | 190 | /** 191 | * ray tracing 192 | * @param {*} o 193 | * @param {*} d 194 | * @param {*} depth 195 | */ 196 | float trace2(vec2 o, vec2 d) { 197 | float t = .0; 198 | // 判断是场景内还是外,间eta注释 199 | float s = scene(o).sourceDistance > .0 ? 1.0 : -1.0; 200 | for (int i = 0; i < MAX_STEP; i++) { 201 | if(t >= MAX_DISTANCE) { break; } 202 | vec2 xy = d * t + o; 203 | LightSource sd = scene(xy); 204 | sd.sourceDistance = sd.sourceDistance * s; 205 | if (sd.sourceDistance < EPSILON) { 206 | // 反射 207 | float sum = sd.emissive; 208 | float refl = sd.reflectivity; 209 | if (sd.reflectivity > .0 || sd.eta > .0) { 210 | vec2 normal = gradient(xy); 211 | normal = normal * s;// 在内的话,要反转法线 212 | normal = normalize(normal); 213 | if (sd.eta > .0) { 214 | vec2 etaRange = refract(d, normal, s < .0 ? sd.eta : 1.0 / sd.eta); 215 | sum += (1.0 - refl) * trace1(xy - normal * BIAS, etaRange); 216 | } 217 | if (refl > .0) { 218 | vec2 refl2 = reflect(d, normal); 219 | sum += refl * trace1(xy + normal * BIAS, refl2); 220 | } 221 | } 222 | return sum; 223 | } 224 | t += sd.sourceDistance; 225 | } 226 | return .0; 227 | } 228 | 229 | /** 230 | * ray tracing 231 | * @param {*} o 232 | * @param {*} d 233 | * @param {*} depth 234 | */ 235 | float trace(vec2 o, vec2 d) { 236 | float t = .0; 237 | // 判断是场景内还是外,间eta注释 238 | float s = scene(o).sourceDistance > .0 ? 1.0 : -1.0; 239 | for (int i = 0; i < MAX_STEP; i++) { 240 | if(t >= MAX_DISTANCE) { break; } 241 | vec2 xy = d * t + o; 242 | LightSource sd = scene(xy); 243 | sd.sourceDistance = sd.sourceDistance * s; 244 | if (sd.sourceDistance < EPSILON) { 245 | // 反射 246 | float sum = sd.emissive; 247 | float refl = sd.reflectivity; 248 | if (sd.reflectivity > .0 || sd.eta > .0) { 249 | vec2 normal = gradient(xy); 250 | normal = normal * s;// 在内的话,要反转法线 251 | normal = normalize(normal); 252 | if (sd.eta > .0) { 253 | vec2 etaRange = refract(d, normal, s < .0 ? sd.eta : 1.0 / sd.eta); 254 | sum += (1.0 - refl) * trace2(xy - normal * BIAS, etaRange); 255 | } 256 | if (refl > .0) { 257 | vec2 refl2 = reflect(d, normal); 258 | sum += refl * trace2(xy + normal * BIAS, refl2); 259 | } 260 | } 261 | return sum; 262 | } 263 | t += sd.sourceDistance; 264 | } 265 | return .0; 266 | } 267 | 268 | // 随机数 269 | // 从这抄的: https://thebookofshaders.com/10/ 270 | float rand (vec2 st) { 271 | return fract(sin(dot(st, 272 | vec2(12.9898, 78.233)))* 273 | 43758.5453123); 274 | } 275 | 276 | 277 | /** 278 | * 采样(x,y)的颜色 279 | * jitter sampling. 280 | * @param {*} xy x,y像素点 281 | */ 282 | float sample(vec2 xy) { 283 | float sum = .0; 284 | for (float i = .0; i < N; i += 1.0) { 285 | float a = 6.2831852 * (i + rand(xy)) / N; 286 | sum += trace(xy, vec2(cos(a), sin(a))); 287 | } 288 | return sum / N; 289 | } 290 | 291 | void main(void) { 292 | float width = ${parseInt(width, 10)}.0; 293 | float height = ${parseInt(height, 10)}.0; 294 | vec2 xy = vec2(gl_FragCoord.x / width, 1.0 - gl_FragCoord.y / height); 295 | float gray = sample(xy); 296 | gl_FragColor = vec4(gray, gray, gray, 1); 297 | } 298 | `; 299 | }; -------------------------------------------------------------------------------- /light2D/metal/RayTracking/shaders.metal: -------------------------------------------------------------------------------- 1 | // 2 | // Shaders.metal 3 | // RayTracking 4 | // 5 | // Created by gaoboyuan on 2019/2/2. 6 | // Copyright © 2019 gaoboyuan. All rights reserved. 7 | // 8 | 9 | #include 10 | using namespace metal; 11 | 12 | #define MAX_STEP 64 13 | #define MAX_DISTANCE 5.0f 14 | #define EPSILON 1e-6f 15 | #define N 64 16 | 17 | // 函数代表从 o 位置从单位矢量 d 方向接收到的光。 18 | // 反射递归次数为3次 19 | #define MAX_DEPTH 3 20 | // Quote: 21 | // 另外,由于我们要向反射方向追踪,如果用原来的相交点,追踪时就为立即遇到 \texttt{r.sd < EPSILON} 而停止, 22 | // 所以我们稍微把相交点往法线方向偏移 \texttt{BIAS} 的距离,只要 \texttt{BIAS} > \texttt{EPSILON} , 23 | // 就可以避免这个问题。但太大的话也会造成误差 24 | #define BIAS 1e-4f 25 | 26 | vertex 27 | float4 basic_vertex(const device 28 | packed_float2 *vertex_array [[ buffer(0) ]], 29 | unsigned int vid [[ vertex_id ]]) { 30 | return float4(vertex_array[vid], 1.0); 31 | } 32 | 33 | // 随机数 34 | // 从这抄的: https://thebookofshaders.com/10/ 35 | float rand (float2 st) { 36 | return fract(sin(dot(st, 37 | float2(12.9898, 78.233)))* 38 | 43758.5453123); 39 | } 40 | 41 | // 定义一个光源 42 | typedef struct LightSource { 43 | // 光源距离 44 | float sourceDistance; 45 | // 光(头)强 46 | float emissive; 47 | // 反射率 48 | // 如果反射率超过 1,总能量就变多,不符合能量守恒。少于 1 代表形状吸收了能量。 49 | float reflectivity; 50 | // 介质折射率 51 | // 如果光线从外至内,调用 \texttt{refract()} 时,传入 1 / \eta ;从内至外则传入 \eta 。 52 | float eta; 53 | } LightSource; 54 | 55 | // 合并两个LightSource 56 | LightSource unionOp(LightSource a, LightSource b) { 57 | return a.sourceDistance < b.sourceDistance ? a : b; 58 | } 59 | 60 | 61 | LightSource intersectOp(LightSource a, LightSource b) { 62 | LightSource r = a.sourceDistance > b.sourceDistance ? b : a; 63 | r.sourceDistance = a.sourceDistance > b.sourceDistance ? a.sourceDistance : b.sourceDistance; 64 | return r; 65 | } 66 | 67 | LightSource subtractOp(LightSource a, LightSource b) { 68 | LightSource r = a; 69 | r.sourceDistance = (a.sourceDistance > -b.sourceDistance) ? a.sourceDistance : -b.sourceDistance; 70 | return r; 71 | } 72 | 73 | 74 | // 一个圆形光源 75 | float circleSDF(float2 xy, float2 center, float radius) { 76 | float2 u = xy - center; 77 | return sqrt(u.x * u.x + u.y * u.y) - radius; 78 | } 79 | 80 | // 抄这 https://zhuanlan.zhihu.com/p/30816284 81 | float boxSDF(float2 xy, float2 center, float theta, float2 s) { 82 | float costheta = cos(theta), sintheta = sin(theta); 83 | float dx = abs((xy.x - center.x) * costheta + (xy.y - center.y) * sintheta) - s.x; 84 | float dy = abs((xy.y - center.y) * costheta - (xy.x - center.x) * sintheta) - s.y; 85 | float ax = max(dx, 0.0f), ay = max(dy, 0.0f); 86 | return min(max(dx, dy), 0.0f) + sqrt(ax * ax + ay * ay); 87 | } 88 | 89 | // 抄这个 https://github.com/miloyip/light2d/blob/master/refraction.c 90 | float planeSDF(float2 xy, float2 pxy, float2 normal) { 91 | return (xy.x - pxy.x) * normal.x + (xy.y - pxy.y) * normal.y; 92 | } 93 | 94 | // 场景 95 | // 参数为对xy进行采样 96 | LightSource scene(float2 xy, float rgbRefra) { 97 | // // 一次画3圆 98 | // LightSource r1 = { circleSDF(xy, float2(0.4f, 0.5f), 0.01f), 4.0f, 0, 0 }; 99 | // LightSource r2 = { circleSDF(xy, float2(0.6f, 0.5f), 0.01f), 4.0f, 0, 0 }; 100 | //// LightSource r3 = { circleSDF(xy, float2(0.7f, 0.5f), 0.10f), 0.0f, .3 }; 101 | // LightSource box = {boxSDF(xy, float2(0.3f, 0.3f), 0, float2(0.1f, 0.1f)), 0, 0.9f, 1.5}; 102 | //// LightSource box2 = {boxSDF(xy, float2(0.7f, 0.3f), 0, float2(0.1f, 0.1f)), 0, 0.9f, 1.5}; 103 | // return unionOp(unionOp(r1, r2), box); 104 | // return unionOp(unionOp(unionOp(r1, r2), box), box2); 105 | // return unionOp(unionOp(unionOp(unionOp(r1, r2), r3), box), box2); 106 | LightSource a = { circleSDF(xy, float2(-0.2f, -0.2f), 0.1f), 10.0f, 0.0f, 0.0f }; 107 | LightSource b = { boxSDF(xy, float2(0.5f, 0.5f), 0.0f, float2(0.3, 0.2f)), 0.0f, 0.9f, 1.5f }; 108 | LightSource c = { circleSDF(xy, float2(0.5f, -0.5f), 0.05f), 20.0f, 0.0f, 0.0f }; 109 | LightSource d = { circleSDF(xy, float2(0.5f, 0.2f), 0.35f), 0.0f, 0.2f, 1.5f }; 110 | LightSource e = { circleSDF(xy, float2(0.5f, 0.8f), 0.35f), 0.0f, 0.2f, 1.5f }; 111 | LightSource f = { boxSDF(xy, float2(0.5f, 0.5f), 0.0f, float2(0.2, 0.1f)), 0.0f, 0.2f, 1.5f }; 112 | LightSource g = { circleSDF(xy, float2(0.5f, 0.12f), 0.35f), 0.0f, 0.2f, 1.5f }; 113 | LightSource h = { circleSDF(xy, float2(0.5f, 0.87f), 0.35f), 0.0f, 0.2f, 1.5f }; 114 | LightSource i = { circleSDF(xy, float2(0.5f, 0.5f), 0.2f), 0.0f, 0.2f, rgbRefra }; 115 | LightSource j = { planeSDF(xy, float2(0.5f, 0.5f), float2(0.0f, -1.0f)), 0.0f, 0.2f, rgbRefra }; 116 | // return unionOp(a, b); 117 | // return unionOp(c, intersectOp(d, e)); 118 | // return unionOp(c, subtractOp(f, unionOp(g, h))); 119 | return unionOp(c, intersectOp(i, j)); 120 | 121 | } 122 | 123 | // 说是计算法线 124 | float2 gradient(float2 xy) { 125 | return float2((scene(float2(xy.x + EPSILON, xy.y), 0).sourceDistance 126 | - scene(float2(xy.x - EPSILON, xy.y), 0).sourceDistance) * (0.5f / EPSILON), 127 | (scene(float2(xy.x, xy.y + EPSILON), 0).sourceDistance 128 | - scene(float2(xy.x, xy.y - EPSILON), 0).sourceDistance) * (0.5f / EPSILON)); 129 | } 130 | 131 | 132 | float trace0(float2 o, float2 d) { 133 | float t = 0.0f; 134 | // 判断是场景内还是外,间eta注释 135 | float sign = scene(o, 0).sourceDistance > 0.0f ? 1.0f : -1.0f; 136 | for (int i = 0; i < MAX_STEP && t < MAX_DISTANCE; i++) { 137 | float2 xy = d * t + o; 138 | LightSource sd = scene(xy, 0); 139 | if (sd.sourceDistance * sign < EPSILON) { 140 | // 反射 141 | float sum = sd.emissive; 142 | return sum; 143 | } 144 | t += sd.sourceDistance * sign; 145 | } 146 | return 0.0f; 147 | } 148 | 149 | 150 | float trace1(float2 o, float2 d, float rfr) { 151 | float t = 0.0f; 152 | // 判断是场景内还是外,间eta注释 153 | float s = scene(o, rfr).sourceDistance > 0.0f ? 1.0f : -1.0f; 154 | for (int i = 0; i < MAX_STEP && t < MAX_DISTANCE; i++) { 155 | float2 xy = d * t + o; 156 | LightSource sd = scene(xy, rfr); 157 | sd.sourceDistance *= s; 158 | if (sd.sourceDistance < EPSILON) { 159 | // 反射 160 | float sum = sd.emissive; 161 | float refl = sd.reflectivity; 162 | if (sd.reflectivity > 0.0f || sd.eta > 0) { 163 | float2 normal = gradient(xy); 164 | // normal *= sign;// 在内的话,要反转法线 165 | normal = normalize(normal); 166 | if (sd.eta > 0.0f) { 167 | float2 etaRange = refract(d, normal, s < 0.0f ? sd.eta : 1.0f / sd.eta); 168 | sum += (1.0f - refl) * trace0(xy - normal * BIAS, etaRange); 169 | } 170 | if (refl > 0.0f) { 171 | float2 refl2 = reflect(d, normal); 172 | sum += refl * trace0(xy + normal * BIAS, refl2); 173 | } 174 | } 175 | return sum; 176 | } 177 | t += sd.sourceDistance; 178 | } 179 | return 0.0f; 180 | } 181 | 182 | float trace2(float2 o, float2 d, float rfr) { 183 | float t = 0.0f; 184 | // 判断是场景内还是外,间eta注释 185 | float s = scene(o, rfr).sourceDistance > 0.0f ? 1.0f : -1.0f; 186 | for (int i = 0; i < MAX_STEP && t < MAX_DISTANCE; i++) { 187 | float2 xy = d * t + o; 188 | LightSource sd = scene(xy, rfr); 189 | sd.sourceDistance *= s; 190 | if (sd.sourceDistance < EPSILON) { 191 | // 反射 192 | float sum = sd.emissive; 193 | float refl = sd.reflectivity; 194 | if (sd.reflectivity > 0.0f || sd.eta > 0) { 195 | float2 normal = gradient(xy); 196 | normal *= s;// 在内的话,要反转法线 197 | normal = normalize(normal); 198 | if (sd.eta > 0.0f) { 199 | float2 etaRange = refract(d, normal, s < 0.0f ? sd.eta : 1.0f / sd.eta); 200 | sum += (1.0f - refl) * trace1(xy - normal * BIAS, etaRange, rfr); 201 | } 202 | if (refl > 0.0f) { 203 | float2 refl2 = reflect(d, normal); 204 | sum += refl * trace1(xy + normal * BIAS, refl2, rfr); 205 | } 206 | } 207 | return sum; 208 | } 209 | t += sd.sourceDistance; 210 | } 211 | return 0.0f; 212 | } 213 | 214 | // WTM... shader里不能写递归 215 | float trace(float2 o, float2 d, float rfr) { 216 | float t = 0.0f; 217 | // 判断是场景内还是外,间eta注释 218 | float s = scene(o, rfr).sourceDistance > 0.0f ? 1.0f : -1.0f; 219 | for (int i = 0; i < MAX_STEP && t < MAX_DISTANCE; i++) { 220 | float2 xy = d * t + o; 221 | LightSource sd = scene(xy, rfr); 222 | sd.sourceDistance *= s; 223 | if (sd.sourceDistance < EPSILON) { 224 | // 反射 225 | float sum = sd.emissive; 226 | float refl = sd.reflectivity; 227 | if (sd.reflectivity > 0.0f || sd.eta > 0) { 228 | float2 normal = gradient(xy); 229 | normal *= s;// 在内的话,要反转法线 230 | normal = normalize(normal); 231 | if (sd.eta > 0.0f) { 232 | float2 etaRange = refract(d, normal, s < 0.0f ? sd.eta : 1.0f / sd.eta); 233 | sum += (1.0f - refl) * trace2(xy - normal * BIAS, etaRange, rfr); 234 | } 235 | if (refl > 0.0f) { 236 | float2 refl2 = reflect(d, normal); 237 | sum += refl * trace2(xy + normal * BIAS, refl2, rfr); 238 | } 239 | } 240 | return sum; 241 | } 242 | t += sd.sourceDistance; 243 | } 244 | return 0.0f; 245 | } 246 | 247 | // 采样(x,y)的颜色 248 | float sample(float2 xy, float rfr) { 249 | float sum = 0.0f; 250 | for (int i = 0; i < N; i++) { 251 | float a = 6.28 * (i + rand(xy)) / N; 252 | sum += trace(xy, float2(cos(a), sin(a)), rfr); 253 | } 254 | return sum / 64.0; 255 | } 256 | 257 | 258 | fragment 259 | float4 basic_fragment(float2 pointCoord [[point_coord]], 260 | float4 position [[position]]) { 261 | const float W = 376; 262 | float2 xy = position.xy / W; 263 | float r = min(sample(xy, 1.3), 1.0f); 264 | float g = min(sample(xy, 1.4), 1.0f); 265 | float b = min(sample(xy, 1.5), 1.0f); 266 | // return float4(gray, gray, gray, 1); 267 | return float4(r, g, b, 1); 268 | } 269 | -------------------------------------------------------------------------------- /light2D/metal/RayTracking.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 661D955B22056D9C0048946B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 661D955A22056D9C0048946B /* AppDelegate.swift */; }; 11 | 661D955D22056D9C0048946B /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 661D955C22056D9C0048946B /* ViewController.swift */; }; 12 | 661D956022056D9C0048946B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 661D955E22056D9C0048946B /* Main.storyboard */; }; 13 | 661D956222056D9E0048946B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 661D956122056D9E0048946B /* Assets.xcassets */; }; 14 | 661D956522056D9E0048946B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 661D956322056D9E0048946B /* LaunchScreen.storyboard */; }; 15 | 661D956D22057D3E0048946B /* shaders.metal in Sources */ = {isa = PBXBuildFile; fileRef = 661D956C22057D3E0048946B /* shaders.metal */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXFileReference section */ 19 | 661D955722056D9C0048946B /* RayTracking.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RayTracking.app; sourceTree = BUILT_PRODUCTS_DIR; }; 20 | 661D955A22056D9C0048946B /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 21 | 661D955C22056D9C0048946B /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 22 | 661D955F22056D9C0048946B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 23 | 661D956122056D9E0048946B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 24 | 661D956422056D9E0048946B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 25 | 661D956622056D9E0048946B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 26 | 661D956C22057D3E0048946B /* shaders.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = shaders.metal; sourceTree = ""; }; 27 | /* End PBXFileReference section */ 28 | 29 | /* Begin PBXFrameworksBuildPhase section */ 30 | 661D955422056D9C0048946B /* Frameworks */ = { 31 | isa = PBXFrameworksBuildPhase; 32 | buildActionMask = 2147483647; 33 | files = ( 34 | ); 35 | runOnlyForDeploymentPostprocessing = 0; 36 | }; 37 | /* End PBXFrameworksBuildPhase section */ 38 | 39 | /* Begin PBXGroup section */ 40 | 661D954E22056D9C0048946B = { 41 | isa = PBXGroup; 42 | children = ( 43 | 661D955922056D9C0048946B /* RayTracking */, 44 | 661D955822056D9C0048946B /* Products */, 45 | ); 46 | sourceTree = ""; 47 | }; 48 | 661D955822056D9C0048946B /* Products */ = { 49 | isa = PBXGroup; 50 | children = ( 51 | 661D955722056D9C0048946B /* RayTracking.app */, 52 | ); 53 | name = Products; 54 | sourceTree = ""; 55 | }; 56 | 661D955922056D9C0048946B /* RayTracking */ = { 57 | isa = PBXGroup; 58 | children = ( 59 | 661D955A22056D9C0048946B /* AppDelegate.swift */, 60 | 661D955C22056D9C0048946B /* ViewController.swift */, 61 | 661D955E22056D9C0048946B /* Main.storyboard */, 62 | 661D956122056D9E0048946B /* Assets.xcassets */, 63 | 661D956322056D9E0048946B /* LaunchScreen.storyboard */, 64 | 661D956622056D9E0048946B /* Info.plist */, 65 | 661D956C22057D3E0048946B /* shaders.metal */, 66 | ); 67 | path = RayTracking; 68 | sourceTree = ""; 69 | }; 70 | /* End PBXGroup section */ 71 | 72 | /* Begin PBXNativeTarget section */ 73 | 661D955622056D9C0048946B /* RayTracking */ = { 74 | isa = PBXNativeTarget; 75 | buildConfigurationList = 661D956922056D9E0048946B /* Build configuration list for PBXNativeTarget "RayTracking" */; 76 | buildPhases = ( 77 | 661D955322056D9C0048946B /* Sources */, 78 | 661D955422056D9C0048946B /* Frameworks */, 79 | 661D955522056D9C0048946B /* Resources */, 80 | ); 81 | buildRules = ( 82 | ); 83 | dependencies = ( 84 | ); 85 | name = RayTracking; 86 | productName = RayTracking; 87 | productReference = 661D955722056D9C0048946B /* RayTracking.app */; 88 | productType = "com.apple.product-type.application"; 89 | }; 90 | /* End PBXNativeTarget section */ 91 | 92 | /* Begin PBXProject section */ 93 | 661D954F22056D9C0048946B /* Project object */ = { 94 | isa = PBXProject; 95 | attributes = { 96 | LastSwiftUpdateCheck = 1010; 97 | LastUpgradeCheck = 1010; 98 | ORGANIZATIONNAME = gaoboyuan; 99 | TargetAttributes = { 100 | 661D955622056D9C0048946B = { 101 | CreatedOnToolsVersion = 10.1; 102 | }; 103 | }; 104 | }; 105 | buildConfigurationList = 661D955222056D9C0048946B /* Build configuration list for PBXProject "RayTracking" */; 106 | compatibilityVersion = "Xcode 9.3"; 107 | developmentRegion = en; 108 | hasScannedForEncodings = 0; 109 | knownRegions = ( 110 | en, 111 | Base, 112 | ); 113 | mainGroup = 661D954E22056D9C0048946B; 114 | productRefGroup = 661D955822056D9C0048946B /* Products */; 115 | projectDirPath = ""; 116 | projectRoot = ""; 117 | targets = ( 118 | 661D955622056D9C0048946B /* RayTracking */, 119 | ); 120 | }; 121 | /* End PBXProject section */ 122 | 123 | /* Begin PBXResourcesBuildPhase section */ 124 | 661D955522056D9C0048946B /* Resources */ = { 125 | isa = PBXResourcesBuildPhase; 126 | buildActionMask = 2147483647; 127 | files = ( 128 | 661D956522056D9E0048946B /* LaunchScreen.storyboard in Resources */, 129 | 661D956222056D9E0048946B /* Assets.xcassets in Resources */, 130 | 661D956022056D9C0048946B /* Main.storyboard in Resources */, 131 | ); 132 | runOnlyForDeploymentPostprocessing = 0; 133 | }; 134 | /* End PBXResourcesBuildPhase section */ 135 | 136 | /* Begin PBXSourcesBuildPhase section */ 137 | 661D955322056D9C0048946B /* Sources */ = { 138 | isa = PBXSourcesBuildPhase; 139 | buildActionMask = 2147483647; 140 | files = ( 141 | 661D956D22057D3E0048946B /* shaders.metal in Sources */, 142 | 661D955D22056D9C0048946B /* ViewController.swift in Sources */, 143 | 661D955B22056D9C0048946B /* AppDelegate.swift in Sources */, 144 | ); 145 | runOnlyForDeploymentPostprocessing = 0; 146 | }; 147 | /* End PBXSourcesBuildPhase section */ 148 | 149 | /* Begin PBXVariantGroup section */ 150 | 661D955E22056D9C0048946B /* Main.storyboard */ = { 151 | isa = PBXVariantGroup; 152 | children = ( 153 | 661D955F22056D9C0048946B /* Base */, 154 | ); 155 | name = Main.storyboard; 156 | sourceTree = ""; 157 | }; 158 | 661D956322056D9E0048946B /* LaunchScreen.storyboard */ = { 159 | isa = PBXVariantGroup; 160 | children = ( 161 | 661D956422056D9E0048946B /* Base */, 162 | ); 163 | name = LaunchScreen.storyboard; 164 | sourceTree = ""; 165 | }; 166 | /* End PBXVariantGroup section */ 167 | 168 | /* Begin XCBuildConfiguration section */ 169 | 661D956722056D9E0048946B /* Debug */ = { 170 | isa = XCBuildConfiguration; 171 | buildSettings = { 172 | ALWAYS_SEARCH_USER_PATHS = NO; 173 | CLANG_ANALYZER_NONNULL = YES; 174 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 175 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 176 | CLANG_CXX_LIBRARY = "libc++"; 177 | CLANG_ENABLE_MODULES = YES; 178 | CLANG_ENABLE_OBJC_ARC = YES; 179 | CLANG_ENABLE_OBJC_WEAK = YES; 180 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 181 | CLANG_WARN_BOOL_CONVERSION = YES; 182 | CLANG_WARN_COMMA = YES; 183 | CLANG_WARN_CONSTANT_CONVERSION = YES; 184 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 185 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 186 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 187 | CLANG_WARN_EMPTY_BODY = YES; 188 | CLANG_WARN_ENUM_CONVERSION = YES; 189 | CLANG_WARN_INFINITE_RECURSION = YES; 190 | CLANG_WARN_INT_CONVERSION = YES; 191 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 192 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 193 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 194 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 195 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 196 | CLANG_WARN_STRICT_PROTOTYPES = YES; 197 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 198 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 199 | CLANG_WARN_UNREACHABLE_CODE = YES; 200 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 201 | CODE_SIGN_IDENTITY = "iPhone Developer"; 202 | COPY_PHASE_STRIP = NO; 203 | DEBUG_INFORMATION_FORMAT = dwarf; 204 | ENABLE_STRICT_OBJC_MSGSEND = YES; 205 | ENABLE_TESTABILITY = YES; 206 | GCC_C_LANGUAGE_STANDARD = gnu11; 207 | GCC_DYNAMIC_NO_PIC = NO; 208 | GCC_NO_COMMON_BLOCKS = YES; 209 | GCC_OPTIMIZATION_LEVEL = 0; 210 | GCC_PREPROCESSOR_DEFINITIONS = ( 211 | "DEBUG=1", 212 | "$(inherited)", 213 | ); 214 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 215 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 216 | GCC_WARN_UNDECLARED_SELECTOR = YES; 217 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 218 | GCC_WARN_UNUSED_FUNCTION = YES; 219 | GCC_WARN_UNUSED_VARIABLE = YES; 220 | IPHONEOS_DEPLOYMENT_TARGET = 12.1; 221 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 222 | MTL_FAST_MATH = YES; 223 | ONLY_ACTIVE_ARCH = YES; 224 | SDKROOT = iphoneos; 225 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 226 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 227 | }; 228 | name = Debug; 229 | }; 230 | 661D956822056D9E0048946B /* Release */ = { 231 | isa = XCBuildConfiguration; 232 | buildSettings = { 233 | ALWAYS_SEARCH_USER_PATHS = NO; 234 | CLANG_ANALYZER_NONNULL = YES; 235 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 236 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 237 | CLANG_CXX_LIBRARY = "libc++"; 238 | CLANG_ENABLE_MODULES = YES; 239 | CLANG_ENABLE_OBJC_ARC = YES; 240 | CLANG_ENABLE_OBJC_WEAK = YES; 241 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 242 | CLANG_WARN_BOOL_CONVERSION = YES; 243 | CLANG_WARN_COMMA = YES; 244 | CLANG_WARN_CONSTANT_CONVERSION = YES; 245 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 246 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 247 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 248 | CLANG_WARN_EMPTY_BODY = YES; 249 | CLANG_WARN_ENUM_CONVERSION = YES; 250 | CLANG_WARN_INFINITE_RECURSION = YES; 251 | CLANG_WARN_INT_CONVERSION = YES; 252 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 253 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 254 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 255 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 256 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 257 | CLANG_WARN_STRICT_PROTOTYPES = YES; 258 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 259 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 260 | CLANG_WARN_UNREACHABLE_CODE = YES; 261 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 262 | CODE_SIGN_IDENTITY = "iPhone Developer"; 263 | COPY_PHASE_STRIP = NO; 264 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 265 | ENABLE_NS_ASSERTIONS = NO; 266 | ENABLE_STRICT_OBJC_MSGSEND = YES; 267 | GCC_C_LANGUAGE_STANDARD = gnu11; 268 | GCC_NO_COMMON_BLOCKS = YES; 269 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 270 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 271 | GCC_WARN_UNDECLARED_SELECTOR = YES; 272 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 273 | GCC_WARN_UNUSED_FUNCTION = YES; 274 | GCC_WARN_UNUSED_VARIABLE = YES; 275 | IPHONEOS_DEPLOYMENT_TARGET = 12.1; 276 | MTL_ENABLE_DEBUG_INFO = NO; 277 | MTL_FAST_MATH = YES; 278 | SDKROOT = iphoneos; 279 | SWIFT_COMPILATION_MODE = wholemodule; 280 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 281 | VALIDATE_PRODUCT = YES; 282 | }; 283 | name = Release; 284 | }; 285 | 661D956A22056D9E0048946B /* Debug */ = { 286 | isa = XCBuildConfiguration; 287 | buildSettings = { 288 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 289 | CODE_SIGN_STYLE = Automatic; 290 | DEVELOPMENT_TEAM = C5B8G7C5FD; 291 | INFOPLIST_FILE = RayTracking/Info.plist; 292 | LD_RUNPATH_SEARCH_PATHS = ( 293 | "$(inherited)", 294 | "@executable_path/Frameworks", 295 | ); 296 | PRODUCT_BUNDLE_IDENTIFIER = cn.antimoron.RayTracking; 297 | PRODUCT_NAME = "$(TARGET_NAME)"; 298 | SWIFT_VERSION = 4.2; 299 | TARGETED_DEVICE_FAMILY = "1,2"; 300 | }; 301 | name = Debug; 302 | }; 303 | 661D956B22056D9E0048946B /* Release */ = { 304 | isa = XCBuildConfiguration; 305 | buildSettings = { 306 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 307 | CODE_SIGN_STYLE = Automatic; 308 | DEVELOPMENT_TEAM = C5B8G7C5FD; 309 | INFOPLIST_FILE = RayTracking/Info.plist; 310 | LD_RUNPATH_SEARCH_PATHS = ( 311 | "$(inherited)", 312 | "@executable_path/Frameworks", 313 | ); 314 | PRODUCT_BUNDLE_IDENTIFIER = cn.antimoron.RayTracking; 315 | PRODUCT_NAME = "$(TARGET_NAME)"; 316 | SWIFT_VERSION = 4.2; 317 | TARGETED_DEVICE_FAMILY = "1,2"; 318 | }; 319 | name = Release; 320 | }; 321 | /* End XCBuildConfiguration section */ 322 | 323 | /* Begin XCConfigurationList section */ 324 | 661D955222056D9C0048946B /* Build configuration list for PBXProject "RayTracking" */ = { 325 | isa = XCConfigurationList; 326 | buildConfigurations = ( 327 | 661D956722056D9E0048946B /* Debug */, 328 | 661D956822056D9E0048946B /* Release */, 329 | ); 330 | defaultConfigurationIsVisible = 0; 331 | defaultConfigurationName = Release; 332 | }; 333 | 661D956922056D9E0048946B /* Build configuration list for PBXNativeTarget "RayTracking" */ = { 334 | isa = XCConfigurationList; 335 | buildConfigurations = ( 336 | 661D956A22056D9E0048946B /* Debug */, 337 | 661D956B22056D9E0048946B /* Release */, 338 | ); 339 | defaultConfigurationIsVisible = 0; 340 | defaultConfigurationName = Release; 341 | }; 342 | /* End XCConfigurationList section */ 343 | }; 344 | rootObject = 661D954F22056D9C0048946B /* Project object */; 345 | } 346 | -------------------------------------------------------------------------------- /light2D/ecma-script/the-only-pack-to-draw-light/dist/index.min.js: -------------------------------------------------------------------------------- 1 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.theonlypacktodrawlight=e():t.theonlypacktodrawlight=e()}(window,function(){return function(t){function e(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,e),o.l=!0,o.exports}var n={};return e.m=t,e.c=n,e.d=function(t,n,r){e.o(t,n)||Object.defineProperty(t,n,{enumerable:!0,get:r})},e.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},e.t=function(t,n){if(1&n&&(t=e(t)),8&n)return t;if(4&n&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(e.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&n&&"string"!=typeof t)for(var o in t)e.d(r,o,function(e){return t[e]}.bind(null,o));return r},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,"a",n),n},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=0)}([function(t,e,n){"use strict";function r(t){for(var e=1;ee.sourceDistance?e:n);return r.sourceDistance=n.sourceDistance>e.sourceDistance?n.sourceDistance:e.sourceDistance,r}),o(this,"subtract",function(e){var r=new t(n);return r.sourceDistance=n.sourceDistance>-e.sourceDistance?n.sourceDistance:-e.sourceDistance,r}),"string"==typeof e){switch(e){case"humble":break;case"awesome":this.reflectivity=.5;break;case"badass":this.reflectivity=.8,this.refract=1.5;break;case"asdfasdfasdfasdfasdf":default:this.reflectivity=.8,this.triray=!0}}else e&&(this.sourceDistance=e.sourceDistance,this.emissive=e.emissive,this.reflectivity=e.reflectivity,this.eta=e.eta,this.triray=e.triray)}},function(t,e,n){"use strict";function r(t,e){return{x:t.x+e.x,y:t.y+e.y}}function o(t,e){return{x:t.x*e,y:t.y*e}}function i(t,e){return r(t,o(e,-1))}function c(t,e){return o(t,1/e)}n.r(e),n.d(e,"addf2",function(){return r}),n.d(e,"mulf2",function(){return o}),n.d(e,"subf2",function(){return i}),n.d(e,"divf2",function(){return c})},function(t,e,n){"use strict";function r(t){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){for(var n=0;n0?1:-1,v=0;v0||m.eta>0){var x=i(d,n);if(x=Object(l.mulf2)(x,h),m.eta>0){var S=u(e,x,h<0?m.eta:1/m.eta);_+=(1-g)*a(d-x*p,S,n,r+1,f,s)}if(g>0){var w=c(e,x);_+=g*a(d+x*p,w,n,r+1,f,s)}}}return _}b+=m.sourceDistance}return 0}function f(t,e,n,r,o){for(var i=0,c=0;c2&&void 0!==arguments[2]?arguments[2]:null,r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null;return new h.VertexBuffer(this._gl,t,e,n,r)}},{key:"clear",value:function(){var t=this._gl;t.clearColor(0,0,0,1),t.clear(t.COLOR_BUFFER_BIT|t.DEPTH_BUFFER_BIT)}},{key:"bindVertices",value:function(t){var e=this._gl,n=e.FLOAT,r=!1,o=0,i=0;e.bindBuffer(e.ARRAY_BUFFER,t.raw);var c=this._currentProgram.structure.attribLocations.get(p.VERT_POS);e.vertexAttribPointer(c,t.positionComponentCount,n,r,o,i),e.enableVertexAttribArray(c);var u=this._currentProgram.structure.attribLocations.get(p.VERT_TEX);null!==u&&void 0!==u&&(e.bindBuffer(e.ARRAY_BUFFER,t.texcoordBuffer),e.vertexAttribPointer(u,t.texcoordComponentCount,n,!0,o,i),e.enableVertexAttribArray(u))}},{key:"bindProgram",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;if(this._gl.useProgram(t.raw),this._currentProgram=t,e&&e.length>=2&&t.structure.uniformLocations.get(SHADER_TEXTURESIZE)&&this._gl.uniform2f(t.structure.uniformLocations.get(SHADER_TEXTURESIZE),e[0],e[1]),n)for(var o in n){var i=n[o],c=!1;"i"===o.charAt(0)&&(c=!0),t.structure.uniformLocations.get(o)&&("number"==typeof i?c?this._gl.uniform1i(t.structure.uniformLocations.get(o),i):this._gl.uniform1f(t.structure.uniformLocations.get(o),i):"object"===r(i)&&"[object Array]"===Object.prototype.toString.call(i)&&(c?this._gl.uniform1iv(t.structure.uniformLocations.get(o),new Int32Array(i)):this._gl.uniform1fv(t.structure.uniformLocations.get(o),new Float32Array(i))))}}},{key:"createFrameBuffer",value:function(t,e){return new FrameBuffer(this._gl,t,e)}},{key:"bindFrameBuffer",value:function(t){var e=this._gl;if(!t)return void e.bindFramebuffer(e.FRAMEBUFFER,null);t.use(),e.clearColor(0,0,0,1),e.clear(e.COLOR_BUFFER_BIT|e.DEPTH_BUFFER_BIT)}},{key:"createTexture",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1;return new b.Texture(this._gl,t,e)}},{key:"bindTexture",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,n=this._gl;n.activeTexture(e===SAMPLER2?n.TEXTURE1:n.TEXTURE0),n.bindTexture(n.TEXTURE_2D,t.raw),n.uniform1i(this._currentProgram.structure.uniformLocations.get(e||SAMPLER),e===SAMPLER2?1:0)}},{key:"draw",value:function(t,e){this.bindVertices(t);var n=this._gl,r=null;switch(e){case"line":r=n.LINES;break;case"linestrip":r=n.LINE_STRIP;break;case"triangle":r=n.TRIANGLES;break;case"trianglestrip":r=n.TRIANGLE_STRIP}n.drawArrays(r,0,t.vertexCount)}},{key:"getError",value:function(){return this._gl.getError()}}]),e}(y.GlBase)},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:1,c=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1;o(this,e),n=i(this,u(e).call(this,t)),n._width=r,n._height=c;var a=t;if(n._raw=a.createTexture(),!n._raw)throw"Texture create failure.";a.bindTexture(a.TEXTURE_2D,n._raw);var f=a.RGBA,s=a.RGBA,l=a.UNSIGNED_BYTE;return a.texImage2D(a.TEXTURE_2D,0,f,r,c,0,s,l,null),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_S,a.CLAMP_TO_EDGE),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_T,a.CLAMP_TO_EDGE),n}return a(e,t),e}(s.GlBase)},function(t,e,n){"use strict";function r(t){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){for(var n=0;n3&&void 0!==arguments[3]?arguments[3]:"64.0",o=arguments.length>4&&void 0!==arguments[4]?arguments[4]:"64",i=arguments.length>5&&void 0!==arguments[5]?arguments[5]:"10.0";return"\nprecision highp float;\n// uniform float sdfs[128];\n// uniform int iSdfOps[64];\n// uniform int iSdfCount; // sdf 数量\n\nconst float N = ".concat(r,";\nconst int MAX_STEP = ").concat(o,";\nconst float MAX_DISTANCE = ").concat(i,";\nconst float EPSILON = 1e-6;\nconst float BIAS = 1e-4;\n\n\n// 定义一个光源\nstruct LightSource {\n // 光源距离\n float sourceDistance;\n // 光(头)强\n float emissive;\n // 反射率\n // 如果反射率超过 1,总能量就变多,不符合能量守恒。少于 1 代表形状吸收了能量。\n float reflectivity;\n // 介质折射率\n // 如果光线从外至内,调用 \texttt{refract()} 时,传入 1 / eta ;从内至外则传入 eta 。\n float eta;\n};\n\n\n// 合并两个LightSource\nLightSource unionOp(LightSource a, LightSource b) {\n if(a.sourceDistance < b.sourceDistance) {\n return a;\n }\n return b;\n}\n\nLightSource intersectOp(LightSource a, LightSource b) {\n LightSource r = a;\n if(a.sourceDistance > b.sourceDistance) {\n r = b;\n }\n r.sourceDistance = a.sourceDistance > b.sourceDistance ? a.sourceDistance : b.sourceDistance;\n return r;\n}\n\nLightSource subtractOp(LightSource a, LightSource b) {\n LightSource r = a;\n r.sourceDistance = (a.sourceDistance > -b.sourceDistance) ? a.sourceDistance : -b.sourceDistance;\n return r;\n}\n\n\n// 一个圆形光源\nfloat circleSDF(vec2 xy, vec2 center, float radius) {\n vec2 u = xy - center;\n return sqrt(u.x * u.x + u.y * u.y) - radius;\n}\n\n// 抄这 https://zhuanlan.zhihu.com/p/30816284\nfloat boxSDF(vec2 xy, vec2 center, float theta, vec2 s) {\n float costheta = cos(theta), sintheta = sin(theta);\n float dx = abs((xy.x - center.x) * costheta + (xy.y - center.y) * sintheta) - s.x;\n float dy = abs((xy.y - center.y) * costheta - (xy.x - center.x) * sintheta) - s.y;\n float ax = max(dx, .0), ay = max(dy, .0 );\n return min(max(dx, dy), .0) + sqrt(ax * ax + ay * ay);\n}\n\n// 抄这个 https://github.com/miloyip/light2d/blob/master/refraction.c\nfloat planeSDF(vec2 xy, vec2 pxy, vec2 normal) {\n return (xy.x - pxy.x) * normal.x + (xy.y - pxy.y) * normal.y;\n}\n\nLightSource createLS(float sd, float emissive, float reflectivity, float eta) {\n LightSource ret;\n ret.sourceDistance = sd;\n ret.emissive = emissive;\n ret.reflectivity = reflectivity;\n ret.eta = eta;\n return ret;\n}\n\nLightSource scene(vec2 xy) {\n ").concat(n,";\n}\n\n// 说是计算法线\nvec2 gradient(vec2 xy) {\n vec2 xy00 = vec2(xy.x + EPSILON, xy.y);\n vec2 xy01 = vec2(xy.x - EPSILON, xy.y);\n vec2 xy10 = vec2(xy.x, xy.y + EPSILON);\n vec2 xy11 = vec2(xy.x, xy.y - EPSILON);\n float hEp = 0.5 / EPSILON;\n return vec2((scene(xy00).sourceDistance - scene(xy01).sourceDistance) * hEp,\n (scene(xy10).sourceDistance - scene(xy11).sourceDistance) * hEp);\n}\n\n// /**\n// * 折射函数\n// * @param {*} ixy\n// * @param {*} nxy\n// */\n// vec2 reflect(vec2 ixy, vec2 nxy) {\n// float idotn2 = (ixy.x * nxy.x + ixy.y * nxy.y) * 2.0;\n// return vec2(ixy.x - idotn2 * nxy.x,\n// ixy.y - idotn2 * nxy.y);\n// }\n\n// /**\n// * 折射函数\n// * @param {*} ixy\n// * @param {*} nxy\n// * @param {*} eta\n// */\n// vec2 refract(vec2 ixy, vec2 nxy, float eta) {\n// float idotn = ixy.x * nxy.x + ixy.y * nxy.y;\n// float k = 1.0 - eta * eta * (1.0 - idotn * idotn);\n// float a = eta * idotn + sqrt(k);\n// return vec2(eta * ixy.x - a * nxy.x,\n// eta * ixy.y - a * nxy.y);\n// }\n\n\n/**\n* ray tracing\n* @param {*} o\n* @param {*} d\n* @param {*} depth\n*/\nfloat trace0(vec2 o, vec2 d) {\n float t = .0;\n // 判断是场景内还是外,间eta注释\n float s = scene(o).sourceDistance > .0 ? 1.0 : -1.0;\n for (int i = 0; i < MAX_STEP; i++) {\n if(t >= MAX_DISTANCE) { break; }\n vec2 xy = d * t + o;\n LightSource sd = scene(xy);\n sd.sourceDistance = sd.sourceDistance * s;\n if (sd.sourceDistance < EPSILON) {\n // 反射\n return sd.emissive;\n }\n t += sd.sourceDistance;\n }\n return .0;\n}\n\n/**\n* ray tracing\n* @param {*} o\n* @param {*} d\n* @param {*} depth\n*/\nfloat trace1(vec2 o, vec2 d) {\n float t = .0;\n // 判断是场景内还是外,间eta注释\n float s = scene(o).sourceDistance > .0 ? 1.0 : -1.0;\n for (int i = 0; i < MAX_STEP; i++) {\n if(t >= MAX_DISTANCE) { break; }\n vec2 xy = d * t + o;\n LightSource sd = scene(xy);\n sd.sourceDistance = sd.sourceDistance * s;\n if (sd.sourceDistance < EPSILON) {\n // 反射\n float sum = sd.emissive;\n float refl = sd.reflectivity;\n if (sd.reflectivity > .0 || sd.eta > .0) {\n vec2 normal = gradient(xy);\n normal = normal * s;// 在内的话,要反转法线\n normal = normalize(normal);\n if (sd.eta > .0) {\n vec2 etaRange = refract(d, normal, s < .0 ? sd.eta : 1.0 / sd.eta);\n sum += (1.0 - refl) * trace0(xy - normal * BIAS, etaRange);\n }\n if (refl > .0) {\n vec2 refl2 = reflect(d, normal);\n sum += refl * trace0(xy + normal * BIAS, refl2);\n }\n }\n return sum;\n }\n t += sd.sourceDistance;\n }\n return .0;\n}\n\n/**\n* ray tracing\n* @param {*} o\n* @param {*} d\n* @param {*} depth\n*/\nfloat trace2(vec2 o, vec2 d) {\n float t = .0;\n // 判断是场景内还是外,间eta注释\n float s = scene(o).sourceDistance > .0 ? 1.0 : -1.0;\n for (int i = 0; i < MAX_STEP; i++) {\n if(t >= MAX_DISTANCE) { break; }\n vec2 xy = d * t + o;\n LightSource sd = scene(xy);\n sd.sourceDistance = sd.sourceDistance * s;\n if (sd.sourceDistance < EPSILON) {\n // 反射\n float sum = sd.emissive;\n float refl = sd.reflectivity;\n if (sd.reflectivity > .0 || sd.eta > .0) {\n vec2 normal = gradient(xy);\n normal = normal * s;// 在内的话,要反转法线\n normal = normalize(normal);\n if (sd.eta > .0) {\n vec2 etaRange = refract(d, normal, s < .0 ? sd.eta : 1.0 / sd.eta);\n sum += (1.0 - refl) * trace1(xy - normal * BIAS, etaRange);\n }\n if (refl > .0) {\n vec2 refl2 = reflect(d, normal);\n sum += refl * trace1(xy + normal * BIAS, refl2);\n }\n }\n return sum;\n }\n t += sd.sourceDistance;\n }\n return .0;\n}\n\n/**\n* ray tracing\n* @param {*} o\n* @param {*} d\n* @param {*} depth\n*/\nfloat trace(vec2 o, vec2 d) {\n float t = .0;\n // 判断是场景内还是外,间eta注释\n float s = scene(o).sourceDistance > .0 ? 1.0 : -1.0;\n for (int i = 0; i < MAX_STEP; i++) {\n if(t >= MAX_DISTANCE) { break; }\n vec2 xy = d * t + o;\n LightSource sd = scene(xy);\n sd.sourceDistance = sd.sourceDistance * s;\n if (sd.sourceDistance < EPSILON) {\n // 反射\n float sum = sd.emissive;\n float refl = sd.reflectivity;\n if (sd.reflectivity > .0 || sd.eta > .0) {\n vec2 normal = gradient(xy);\n normal = normal * s;// 在内的话,要反转法线\n normal = normalize(normal);\n if (sd.eta > .0) {\n vec2 etaRange = refract(d, normal, s < .0 ? sd.eta : 1.0 / sd.eta);\n sum += (1.0 - refl) * trace2(xy - normal * BIAS, etaRange);\n }\n if (refl > .0) {\n vec2 refl2 = reflect(d, normal);\n sum += refl * trace2(xy + normal * BIAS, refl2);\n }\n }\n return sum;\n }\n t += sd.sourceDistance;\n }\n return .0;\n}\n\n// 随机数\n// 从这抄的: https://thebookofshaders.com/10/\nfloat rand (vec2 st) {\n return fract(sin(dot(st,\n vec2(12.9898, 78.233)))*\n 43758.5453123);\n}\n\n\n/**\n* 采样(x,y)的颜色\n* jitter sampling.\n* @param {*} xy x,y像素点\n*/\nfloat sample(vec2 xy) {\n float sum = .0;\n for (float i = .0; i < N; i += 1.0) {\n float a = 6.2831852 * (i + rand(xy)) / N;\n sum += trace(xy, vec2(cos(a), sin(a)));\n }\n return sum / N;\n}\n\nvoid main(void) {\n float width = ").concat(parseInt(t,10),".0;\n float height = ").concat(parseInt(e,10),".0;\n vec2 xy = vec2(gl_FragCoord.x / width, 1.0 - gl_FragCoord.y / height);\n float gray = sample(xy);\n gl_FragColor = vec4(gray, gray, gray, 1);\n}\n")}},function(t,e,n){"use strict";function r(t){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){for(var n=0;n=0?e:e+".0"}),u(this,"union",function(t){if(t)return n._opQueue.push({t:"u",to:t}),n}),u(this,"intersect",function(t){if(t)return n._opQueue.push({t:"i",to:t}),n}),u(this,"subtract",function(t){if(t)return n._opQueue.push({t:"s",to:t}),n}),this._props=r({},e)}return c(t,[{key:"gpuDesc",get:function(){return null}}]),t}()},function(t,e,n){"use strict";function r(t){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){for(var n=0;ne.sourceDistance?e:n);return r.sourceDistance=n.sourceDistance>e.sourceDistance?n.sourceDistance:e.sourceDistance,r}),o(this,"subtract",function(e){var r=new t(n);return r.sourceDistance=n.sourceDistance>-e.sourceDistance?n.sourceDistance:-e.sourceDistance,r}),"string"==typeof e){switch(e){case"humble":break;case"awesome":this.reflectivity=.5;break;case"badass":this.reflectivity=.8,this.refract=1.5;break;case"asdfasdfasdfasdfasdf":default:this.reflectivity=.8,this.triray=!0}}else e&&(this.sourceDistance=e.sourceDistance,this.emissive=e.emissive,this.reflectivity=e.reflectivity,this.eta=e.eta,this.triray=e.triray)}},function(t,e,n){"use strict";function r(t,e){return{x:t.x+e.x,y:t.y+e.y}}function o(t,e){return{x:t.x*e,y:t.y*e}}function i(t,e){return r(t,o(e,-1))}function c(t,e){return o(t,1/e)}n.r(e),n.d(e,"addf2",function(){return r}),n.d(e,"mulf2",function(){return o}),n.d(e,"subf2",function(){return i}),n.d(e,"divf2",function(){return c})},function(t,e,n){"use strict";function r(t){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){for(var n=0;n0?1:-1,v=0;v0||m.eta>0){var x=i(d,n);if(x=Object(l.mulf2)(x,h),m.eta>0){var S=u(e,x,h<0?m.eta:1/m.eta);g+=(1-_)*a(d-x*p,S,n,r+1,f,s)}if(_>0){var w=c(e,x);g+=_*a(d+x*p,w,n,r+1,f,s)}}}return g}b+=m.sourceDistance}return 0}function f(t,e,n,r,o){for(var i=0,c=0;c2&&void 0!==arguments[2]?arguments[2]:null,r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null;return new h.VertexBuffer(this._gl,t,e,n,r)}},{key:"clear",value:function(){var t=this._gl;t.clearColor(0,0,0,1),t.clear(t.COLOR_BUFFER_BIT|t.DEPTH_BUFFER_BIT)}},{key:"bindVertices",value:function(t){var e=this._gl,n=e.FLOAT,r=!1,o=0,i=0;e.bindBuffer(e.ARRAY_BUFFER,t.raw);var c=this._currentProgram.structure.attribLocations.get(p.VERT_POS);e.vertexAttribPointer(c,t.positionComponentCount,n,r,o,i),e.enableVertexAttribArray(c);var u=this._currentProgram.structure.attribLocations.get(p.VERT_TEX);null!==u&&void 0!==u&&(e.bindBuffer(e.ARRAY_BUFFER,t.texcoordBuffer),e.vertexAttribPointer(u,t.texcoordComponentCount,n,!0,o,i),e.enableVertexAttribArray(u))}},{key:"bindProgram",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;if(this._gl.useProgram(t.raw),this._currentProgram=t,e&&e.length>=2&&t.structure.uniformLocations.get(SHADER_TEXTURESIZE)&&this._gl.uniform2f(t.structure.uniformLocations.get(SHADER_TEXTURESIZE),e[0],e[1]),n)for(var o in n){var i=n[o],c=!1;"i"===o.charAt(0)&&(c=!0),t.structure.uniformLocations.get(o)&&("number"==typeof i?c?this._gl.uniform1i(t.structure.uniformLocations.get(o),i):this._gl.uniform1f(t.structure.uniformLocations.get(o),i):"object"===r(i)&&"[object Array]"===Object.prototype.toString.call(i)&&(c?this._gl.uniform1iv(t.structure.uniformLocations.get(o),new Int32Array(i)):this._gl.uniform1fv(t.structure.uniformLocations.get(o),new Float32Array(i))))}}},{key:"createFrameBuffer",value:function(t,e){return new FrameBuffer(this._gl,t,e)}},{key:"bindFrameBuffer",value:function(t){var e=this._gl;if(!t)return void e.bindFramebuffer(e.FRAMEBUFFER,null);t.use(),e.clearColor(0,0,0,1),e.clear(e.COLOR_BUFFER_BIT|e.DEPTH_BUFFER_BIT)}},{key:"createTexture",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1;return new b.Texture(this._gl,t,e)}},{key:"bindTexture",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,n=this._gl;n.activeTexture(e===SAMPLER2?n.TEXTURE1:n.TEXTURE0),n.bindTexture(n.TEXTURE_2D,t.raw),n.uniform1i(this._currentProgram.structure.uniformLocations.get(e||SAMPLER),e===SAMPLER2?1:0)}},{key:"draw",value:function(t,e){this.bindVertices(t);var n=this._gl,r=null;switch(e){case"line":r=n.LINES;break;case"linestrip":r=n.LINE_STRIP;break;case"triangle":r=n.TRIANGLES;break;case"trianglestrip":r=n.TRIANGLE_STRIP}n.drawArrays(r,0,t.vertexCount)}},{key:"getError",value:function(){return this._gl.getError()}}]),e}(y.GlBase)},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:1,c=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1;o(this,e),n=i(this,u(e).call(this,t)),n._width=r,n._height=c;var a=t;if(n._raw=a.createTexture(),!n._raw)throw"Texture create failure.";a.bindTexture(a.TEXTURE_2D,n._raw);var f=a.RGBA,s=a.RGBA,l=a.UNSIGNED_BYTE;return a.texImage2D(a.TEXTURE_2D,0,f,r,c,0,s,l,null),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_S,a.CLAMP_TO_EDGE),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_T,a.CLAMP_TO_EDGE),n}return a(e,t),e}(s.GlBase)},function(t,e,n){"use strict";function r(t){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){for(var n=0;n3&&void 0!==arguments[3]?arguments[3]:"64.0",o=arguments.length>4&&void 0!==arguments[4]?arguments[4]:"64",i=arguments.length>5&&void 0!==arguments[5]?arguments[5]:"10.0";return"\nprecision highp float;\n// uniform float sdfs[128];\n// uniform int iSdfOps[64];\n// uniform int iSdfCount; // sdf 数量\n\nconst float N = ".concat(r,";\nconst int MAX_STEP = ").concat(o,";\nconst float MAX_DISTANCE = ").concat(i,";\nconst float EPSILON = 1e-6;\nconst float BIAS = 1e-4;\n\n\n// 定义一个光源\nstruct LightSource {\n // 光源距离\n float sourceDistance;\n // 光(头)强\n float emissive;\n // 反射率\n // 如果反射率超过 1,总能量就变多,不符合能量守恒。少于 1 代表形状吸收了能量。\n float reflectivity;\n // 介质折射率\n // 如果光线从外至内,调用 \texttt{refract()} 时,传入 1 / eta ;从内至外则传入 eta 。\n float eta;\n};\n\n\n// 合并两个LightSource\nLightSource unionOp(LightSource a, LightSource b) {\n if(a.sourceDistance < b.sourceDistance) {\n return a;\n }\n return b;\n}\n\nLightSource intersectOp(LightSource a, LightSource b) {\n LightSource r = a;\n if(a.sourceDistance > b.sourceDistance) {\n r = b;\n }\n r.sourceDistance = a.sourceDistance > b.sourceDistance ? a.sourceDistance : b.sourceDistance;\n return r;\n}\n\nLightSource subtractOp(LightSource a, LightSource b) {\n LightSource r = a;\n r.sourceDistance = (a.sourceDistance > -b.sourceDistance) ? a.sourceDistance : -b.sourceDistance;\n return r;\n}\n\n\n// 一个圆形光源\nfloat circleSDF(vec2 xy, vec2 center, float radius) {\n vec2 u = xy - center;\n return sqrt(u.x * u.x + u.y * u.y) - radius;\n}\n\n// 抄这 https://zhuanlan.zhihu.com/p/30816284\nfloat boxSDF(vec2 xy, vec2 center, float theta, vec2 s) {\n float costheta = cos(theta), sintheta = sin(theta);\n float dx = abs((xy.x - center.x) * costheta + (xy.y - center.y) * sintheta) - s.x;\n float dy = abs((xy.y - center.y) * costheta - (xy.x - center.x) * sintheta) - s.y;\n float ax = max(dx, .0), ay = max(dy, .0 );\n return min(max(dx, dy), .0) + sqrt(ax * ax + ay * ay);\n}\n\n// 抄这个 https://github.com/miloyip/light2d/blob/master/refraction.c\nfloat planeSDF(vec2 xy, vec2 pxy, vec2 normal) {\n return (xy.x - pxy.x) * normal.x + (xy.y - pxy.y) * normal.y;\n}\n\nLightSource createLS(float sd, float emissive, float reflectivity, float eta) {\n LightSource ret;\n ret.sourceDistance = sd;\n ret.emissive = emissive;\n ret.reflectivity = reflectivity;\n ret.eta = eta;\n return ret;\n}\n\nLightSource scene(vec2 xy) {\n ").concat(n,";\n}\n\n// 说是计算法线\nvec2 gradient(vec2 xy) {\n vec2 xy00 = vec2(xy.x + EPSILON, xy.y);\n vec2 xy01 = vec2(xy.x - EPSILON, xy.y);\n vec2 xy10 = vec2(xy.x, xy.y + EPSILON);\n vec2 xy11 = vec2(xy.x, xy.y - EPSILON);\n float hEp = 0.5 / EPSILON;\n return vec2((scene(xy00).sourceDistance - scene(xy01).sourceDistance) * hEp,\n (scene(xy10).sourceDistance - scene(xy11).sourceDistance) * hEp);\n}\n\n// /**\n// * 折射函数\n// * @param {*} ixy\n// * @param {*} nxy\n// */\n// vec2 reflect(vec2 ixy, vec2 nxy) {\n// float idotn2 = (ixy.x * nxy.x + ixy.y * nxy.y) * 2.0;\n// return vec2(ixy.x - idotn2 * nxy.x,\n// ixy.y - idotn2 * nxy.y);\n// }\n\n// /**\n// * 折射函数\n// * @param {*} ixy\n// * @param {*} nxy\n// * @param {*} eta\n// */\n// vec2 refract(vec2 ixy, vec2 nxy, float eta) {\n// float idotn = ixy.x * nxy.x + ixy.y * nxy.y;\n// float k = 1.0 - eta * eta * (1.0 - idotn * idotn);\n// float a = eta * idotn + sqrt(k);\n// return vec2(eta * ixy.x - a * nxy.x,\n// eta * ixy.y - a * nxy.y);\n// }\n\n\n/**\n* ray tracing\n* @param {*} o\n* @param {*} d\n* @param {*} depth\n*/\nfloat trace0(vec2 o, vec2 d) {\n float t = .0;\n // 判断是场景内还是外,间eta注释\n float s = scene(o).sourceDistance > .0 ? 1.0 : -1.0;\n for (int i = 0; i < MAX_STEP; i++) {\n if(t >= MAX_DISTANCE) { break; }\n vec2 xy = d * t + o;\n LightSource sd = scene(xy);\n sd.sourceDistance = sd.sourceDistance * s;\n if (sd.sourceDistance < EPSILON) {\n // 反射\n return sd.emissive;\n }\n t += sd.sourceDistance;\n }\n return .0;\n}\n\n/**\n* ray tracing\n* @param {*} o\n* @param {*} d\n* @param {*} depth\n*/\nfloat trace1(vec2 o, vec2 d) {\n float t = .0;\n // 判断是场景内还是外,间eta注释\n float s = scene(o).sourceDistance > .0 ? 1.0 : -1.0;\n for (int i = 0; i < MAX_STEP; i++) {\n if(t >= MAX_DISTANCE) { break; }\n vec2 xy = d * t + o;\n LightSource sd = scene(xy);\n sd.sourceDistance = sd.sourceDistance * s;\n if (sd.sourceDistance < EPSILON) {\n // 反射\n float sum = sd.emissive;\n float refl = sd.reflectivity;\n if (sd.reflectivity > .0 || sd.eta > .0) {\n vec2 normal = gradient(xy);\n normal = normal * s;// 在内的话,要反转法线\n normal = normalize(normal);\n if (sd.eta > .0) {\n vec2 etaRange = refract(d, normal, s < .0 ? sd.eta : 1.0 / sd.eta);\n sum += (1.0 - refl) * trace0(xy - normal * BIAS, etaRange);\n }\n if (refl > .0) {\n vec2 refl2 = reflect(d, normal);\n sum += refl * trace0(xy + normal * BIAS, refl2);\n }\n }\n return sum;\n }\n t += sd.sourceDistance;\n }\n return .0;\n}\n\n/**\n* ray tracing\n* @param {*} o\n* @param {*} d\n* @param {*} depth\n*/\nfloat trace2(vec2 o, vec2 d) {\n float t = .0;\n // 判断是场景内还是外,间eta注释\n float s = scene(o).sourceDistance > .0 ? 1.0 : -1.0;\n for (int i = 0; i < MAX_STEP; i++) {\n if(t >= MAX_DISTANCE) { break; }\n vec2 xy = d * t + o;\n LightSource sd = scene(xy);\n sd.sourceDistance = sd.sourceDistance * s;\n if (sd.sourceDistance < EPSILON) {\n // 反射\n float sum = sd.emissive;\n float refl = sd.reflectivity;\n if (sd.reflectivity > .0 || sd.eta > .0) {\n vec2 normal = gradient(xy);\n normal = normal * s;// 在内的话,要反转法线\n normal = normalize(normal);\n if (sd.eta > .0) {\n vec2 etaRange = refract(d, normal, s < .0 ? sd.eta : 1.0 / sd.eta);\n sum += (1.0 - refl) * trace1(xy - normal * BIAS, etaRange);\n }\n if (refl > .0) {\n vec2 refl2 = reflect(d, normal);\n sum += refl * trace1(xy + normal * BIAS, refl2);\n }\n }\n return sum;\n }\n t += sd.sourceDistance;\n }\n return .0;\n}\n\n/**\n* ray tracing\n* @param {*} o\n* @param {*} d\n* @param {*} depth\n*/\nfloat trace(vec2 o, vec2 d) {\n float t = .0;\n // 判断是场景内还是外,间eta注释\n float s = scene(o).sourceDistance > .0 ? 1.0 : -1.0;\n for (int i = 0; i < MAX_STEP; i++) {\n if(t >= MAX_DISTANCE) { break; }\n vec2 xy = d * t + o;\n LightSource sd = scene(xy);\n sd.sourceDistance = sd.sourceDistance * s;\n if (sd.sourceDistance < EPSILON) {\n // 反射\n float sum = sd.emissive;\n float refl = sd.reflectivity;\n if (sd.reflectivity > .0 || sd.eta > .0) {\n vec2 normal = gradient(xy);\n normal = normal * s;// 在内的话,要反转法线\n normal = normalize(normal);\n if (sd.eta > .0) {\n vec2 etaRange = refract(d, normal, s < .0 ? sd.eta : 1.0 / sd.eta);\n sum += (1.0 - refl) * trace2(xy - normal * BIAS, etaRange);\n }\n if (refl > .0) {\n vec2 refl2 = reflect(d, normal);\n sum += refl * trace2(xy + normal * BIAS, refl2);\n }\n }\n return sum;\n }\n t += sd.sourceDistance;\n }\n return .0;\n}\n\n// 随机数\n// 从这抄的: https://thebookofshaders.com/10/\nfloat rand (vec2 st) {\n return fract(sin(dot(st,\n vec2(12.9898, 78.233)))*\n 43758.5453123);\n}\n\n\n/**\n* 采样(x,y)的颜色\n* jitter sampling.\n* @param {*} xy x,y像素点\n*/\nfloat sample(vec2 xy) {\n float sum = .0;\n for (float i = .0; i < N; i += 1.0) {\n float a = 6.2831852 * (i + rand(xy)) / N;\n sum += trace(xy, vec2(cos(a), sin(a)));\n }\n return sum / N;\n}\n\nvoid main(void) {\n float width = ").concat(parseInt(t,10),".0;\n float height = ").concat(parseInt(e,10),".0;\n vec2 xy = vec2(gl_FragCoord.x / width, 1.0 - gl_FragCoord.y / height);\n float gray = sample(xy);\n gl_FragColor = vec4(gray, gray, gray, 1);\n}\n")}},function(t,e,n){"use strict";function r(t){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){for(var n=0;n=0?e:e+".0"}),u(this,"union",function(t){if(t)return n._opQueue.push({t:"u",to:t}),n}),u(this,"intersect",function(t){if(t)return n._opQueue.push({t:"i",to:t}),n}),u(this,"subtract",function(t){if(t)return n._opQueue.push({t:"s",to:t}),n}),this._props=r({},e)}return c(t,[{key:"gpuDesc",get:function(){return null}}]),t}()},function(t,e,n){"use strict";function r(t){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){for(var n=0;n