├── .gitignore ├── sample ├── res │ └── checkerboard.png ├── index.html ├── index.js └── TeapotGeometry.js ├── src ├── shaders │ ├── MagnifyingShaderVert.glsl │ ├── FXAAShaderVert.glsl │ ├── MagnifyingShaderFrag.glsl │ └── FXAAShaderFrag.glsl └── Magnify3d.js ├── rollup.config.js ├── LICENSE ├── webpack.config.sample.js ├── package.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | build/ 3 | .DS_Store 4 | package-lock.json 5 | -------------------------------------------------------------------------------- /sample/res/checkerboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amitdiamant/magnify-3d/HEAD/sample/res/checkerboard.png -------------------------------------------------------------------------------- /src/shaders/MagnifyingShaderVert.glsl: -------------------------------------------------------------------------------- 1 | void main() { 2 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 3 | } -------------------------------------------------------------------------------- /src/shaders/FXAAShaderVert.glsl: -------------------------------------------------------------------------------- 1 | varying vec2 vUv; 2 | 3 | void main() { 4 | vUv = uv; 5 | gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); 6 | } -------------------------------------------------------------------------------- /sample/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 |
13 | Wheel to change radius.
14 | Shift + Wheel to change zoom.
15 | Ctrl + Wheel to change exp. 16 |
17 | 18 | 19 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import nodeResolve from 'rollup-plugin-node-resolve'; 2 | import commonjs from 'rollup-plugin-commonjs'; 3 | import babel from 'rollup-plugin-babel'; 4 | import replace from 'rollup-plugin-replace'; 5 | import uglify from 'rollup-plugin-uglify'; 6 | import glsl from 'rollup-plugin-glsl'; 7 | 8 | export default { 9 | input: './src/Magnify3d.js', 10 | output: { 11 | file: 'build/Magnify3d.js', 12 | format: 'umd', 13 | name: 'Magnify3d', 14 | globals: { 15 | three: 'THREE', 16 | }, 17 | }, 18 | external: ['three'], 19 | plugins: [ 20 | nodeResolve(), 21 | commonjs({ 22 | include: 'node_modules/**', 23 | }), 24 | glsl({ 25 | include: 'src/shaders/*.glsl' 26 | }), 27 | babel({ 28 | exclude: 'node_modules/**', 29 | }), 30 | replace({ 31 | 'process.env.NODE_ENV': JSON.stringify('development'), 32 | }), 33 | uglify({ 34 | mangle: false, 35 | output: { 36 | comments: false, 37 | beautify: false, 38 | }, 39 | }), 40 | ], 41 | }; 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Amit Diamant 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /webpack.config.sample.js: -------------------------------------------------------------------------------- 1 | const HtmlwebpackPlugin = require('html-webpack-plugin'); 2 | const CleanWebpackPlugin = require('clean-webpack-plugin'); 3 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 4 | const path = require('path'); 5 | 6 | module.exports = { 7 | entry: { 8 | app: ['./sample/index.js'] 9 | }, 10 | module: { 11 | rules: [ 12 | { 13 | test: /.jsx?$/, 14 | exclude: [/node_modules/], 15 | loader: 'babel-loader' 16 | }, 17 | { 18 | test: /\.glsl$/, 19 | loader: 'webpack-glsl-loader' 20 | } 21 | ] 22 | }, 23 | plugins: [ 24 | new CleanWebpackPlugin(['build/sample']), 25 | new HtmlwebpackPlugin({ 26 | inject: 'body', 27 | template: './sample/index.html', 28 | title: 'Magnify-3d' 29 | }), 30 | new CopyWebpackPlugin( 31 | [ 32 | { from: path.join(__dirname, 'sample/res'), to: 'res' }, 33 | ] 34 | ), 35 | ], 36 | resolve: { 37 | modules: [ 38 | path.resolve('./src'), 39 | path.resolve('./src/shaders'), 40 | path.resolve('./sample'), 41 | 'node_modules' 42 | ], 43 | }, 44 | output: { 45 | filename: 'bundle.[hash].js', 46 | path: path.resolve(__dirname, "./build/sample") 47 | } 48 | }; 49 | -------------------------------------------------------------------------------- /src/shaders/MagnifyingShaderFrag.glsl: -------------------------------------------------------------------------------- 1 | #define AA_RANGE 2.0 2 | precision mediump float; 3 | 4 | uniform sampler2D zoomedTexture; 5 | uniform sampler2D originalTexture; 6 | uniform vec2 pos; 7 | uniform vec2 resolution; 8 | uniform vec2 mag_resolution; 9 | uniform float zoom; 10 | uniform float exp; 11 | uniform float radius; 12 | uniform float outlineThickness; 13 | uniform vec3 outlineColor; 14 | 15 | void main() { 16 | vec2 uv = gl_FragCoord.xy / mag_resolution.xy; 17 | vec2 pos_uv = pos.xy / mag_resolution.xy; 18 | 19 | float dist = distance(gl_FragCoord.xy, pos.xy); 20 | 21 | float z; 22 | vec2 p; 23 | 24 | if (dist < radius) { 25 | // https://www.wolframalpha.com/input/?i=plot+1.0+-+(pow(x+%2F+r,+e)+*+(1.0+-+(1.0+%2F+(z)))) 26 | z = 1.0 - (pow(dist / radius, exp) * (1.0 - (1.0 / (zoom)))); 27 | p = ((uv - pos_uv) / z) + pos_uv; 28 | gl_FragColor = vec4(vec3(texture2D(zoomedTexture, p)), 1.0); 29 | } else if (dist <= radius + outlineThickness) { 30 | float w = outlineThickness / 2.0; 31 | float alpha = smoothstep(0.0, AA_RANGE, dist - radius) - smoothstep(outlineThickness - AA_RANGE, outlineThickness, dist - radius); 32 | 33 | if (dist <= radius + outlineThickness / 2.0) { 34 | // Inside outline. 35 | gl_FragColor = mix(texture2D(zoomedTexture, uv), vec4(outlineColor, 1.0), alpha); 36 | } else { 37 | // Outside outline. 38 | gl_FragColor = mix(texture2D(originalTexture, gl_FragCoord.xy / resolution.xy), vec4(outlineColor, 1.0), alpha); 39 | } 40 | } else { 41 | gl_FragColor = texture2D(originalTexture, gl_FragCoord.xy / resolution.xy); 42 | } 43 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "magnify-3d", 3 | "version": "1.0.4", 4 | "description": "Real time optic magnifying glass library.", 5 | "main": "build/Magnify3d.js", 6 | "scripts": { 7 | "dev": "./node_modules/.bin/webpack-dev-server --config ./webpack.config.sample --devtool source-map --progress --hot --mode=development --host 0.0.0.0", 8 | "build": "rm -rf ./build && cross-env NODE_ENV=rollup rollup -c", 9 | "build-sample": "NODE_ENV=production webpack --progress --config ./webpack.config.sample --mode=production", 10 | "deploy-sample": "npm run build-sample && gh-pages -d build/sample" 11 | }, 12 | "author": "Amit Diamant", 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/amitdiamant/magnify-3d" 16 | }, 17 | "license": "MIT", 18 | "devDependencies": { 19 | "babel-cli": "6.23.0", 20 | "babel-core": "^6.26.3", 21 | "babel-loader": "^7.1.4", 22 | "clean-webpack-plugin": "^1.0.1", 23 | "copy-webpack-plugin": "^5.0.0", 24 | "cross-env": "2.0.1", 25 | "dat.gui": "^0.7.5", 26 | "gh-pages": "^2.0.1", 27 | "html-webpack-plugin": "^3.2.0", 28 | "npm-run-all": "4.0.1", 29 | "rollup": "^0.57.1", 30 | "rollup-plugin-babel": "^3.0.3", 31 | "rollup-plugin-commonjs": "^9.1.0", 32 | "rollup-plugin-glsl": "^1.3.0", 33 | "rollup-plugin-node-resolve": "^3.3.0", 34 | "rollup-plugin-replace": "^2.0.0", 35 | "rollup-plugin-uglify": "^3.0.0", 36 | "webpack": "4.29.3", 37 | "webpack-cli": "^3.2.3", 38 | "webpack-dev-server": "^3.1.14", 39 | "webpack-glsl-loader": "1.0.1", 40 | "three": "^0.92.0" 41 | }, 42 | "peerDependencies": { 43 | "three": "^0.92.0" 44 | }, 45 | "files": [ 46 | "package.json", 47 | "LICENSE", 48 | "README.md", 49 | "build/Magnify3d.js", 50 | "src", 51 | "webpack.config.sample.js" 52 | ], 53 | "keywords": [ 54 | "magnify", 55 | "magnify-3d", 56 | "magnifying", 57 | "magnifying glass", 58 | "zoom", 59 | "optic", 60 | "3d", 61 | "webgl" 62 | ] 63 | } 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [![version](https://img.shields.io/badge/version-1.0.4-green.svg)](https://semver.org) 3 | 4 | ## Magnify 3d 5 | Real time optic magnifying glass for [three.js](https://github.com/mrdoob/three.js). 6 | Get a high-res zoomed section of your 3d scene, with a single API. 7 | 8 | ## Demo 9 | - [Live Demo](https://amitdiamant.github.io/magnify-3d) 10 | - [Sample Code](sample/index.js#L165) 11 | 12 | ## Install 13 | ```$ npm install magnify-3d --save ``` 14 | 15 | ## Usage 16 | ```js 17 | import Magnify3d from 'magnify-3d'; 18 | 19 | const magnify3d = new Magnify3d(); 20 | 21 | magnify3d.render({ 22 | 23 | renderer: renderer, 24 | 25 | pos: { mouse.x, mouse.y }, 26 | 27 | renderSceneCB: (target) => { 28 | 29 | renderer.render(scene, camera, target); 30 | 31 | } 32 | 33 | }); 34 | ``` 35 | 36 | ## Options 37 | | Name | Type | Default | Mandatory | Description| 38 | | - | - | - | - | - | 39 | | `renderer` | WebGLRenderer | | V | The renderer used to render the original scene. | 40 | | `renderSceneCB` | function | | V | A callback function used for rendering the original scene on a zoomed target. | 41 | | `pos` | { x, y } | | V | Position of the magnifying glass in client coordinates. | 42 | | `zoom` | number | 2.0 | | Zoom factor of the magnifying glass. | 43 | | `exp` | number | 35.0 | | Exponent used to calculate the glass' shape. Higher `exp` value means flatter glass shape. | 44 | | `radius` | number | 100.0 | | Radius of the magnifying glass in pixels. | 45 | | `outlineColor` | hex | 0xcccccc | | Color of the glass' outline. | 46 | | `outlineThickness` | number | 8.0 | | Thickness of the glass' outline in pixels. Can be set to 0. | 47 | | `antialias` | Boolean | true | | Whether to add an antialiasing pass or not. | 48 | | `inputBuffer` | WebGLRenderTarget | | | Buffer filled with the original scene render. In case `inputBuffer` is not supplied, the canvas will be the input buffer.| 49 | | `outputBuffer` | WebGLRenderTarget | | | Render target. In case `outputBuffer` is not supplied, the output will be directly on the screen.| 50 | 51 | 52 | ## Contribute 53 | If you have a feature request, please add it as an issue or make a pull request. 54 | 55 | ## References 56 | - [three.js](https://github.com/mrdoob/three.js) 57 | - [Fast Approximate Anti-Aliasing](https://github.com/mrdoob/three.js/blob/dev/examples/js/shaders/FXAAShader.js) 58 | - [Teapot Geometry](https://github.com/mrdoob/three.js/blob/dev/examples/js/geometries/TeapotBufferGeometry.js) 59 | 60 | ## License 61 | [MIT](LICENSE) 62 | -------------------------------------------------------------------------------- /src/Magnify3d.js: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three'; 2 | import MagnifyingShaderFrag from './shaders/MagnifyingShaderFrag.glsl'; 3 | import MagnifyingShaderVert from './shaders/MagnifyingShaderVert.glsl'; 4 | import FXAAShaderFrag from './shaders/FXAAShaderFrag.glsl'; 5 | import FXAAShaderVert from './shaders/FXAAShaderVert.glsl'; 6 | 7 | export default class Magnify3d { 8 | constructor() { 9 | this.magnifyMaterial = new THREE.ShaderMaterial({ 10 | vertexShader: MagnifyingShaderVert, 11 | fragmentShader: MagnifyingShaderFrag, 12 | uniforms: { 13 | "zoomedTexture": { type: "t" }, 14 | "originalTexture": { type: "t" }, 15 | 'pos': { type: 'v2' }, 16 | 'outlineColor': { type: 'v3' }, 17 | 'mag_resolution': { type: 'v2' }, 18 | 'resolution': { type: 'v2' }, 19 | 'zoom': { type: 'f' }, 20 | 'radius': { type: 'f' }, 21 | 'outlineThickness': { type: 'f' }, 22 | 'exp': { type: 'f' } 23 | } 24 | }); 25 | 26 | this.magnifyMaterial.transparent = true; // Needed if inputBuffer is undefined. 27 | 28 | this.magnifyScene = this.createScene(this.magnifyMaterial); 29 | 30 | this.camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1); 31 | 32 | // Size is not really matter here. It gets updated inside `render`. 33 | this.zoomTarget = new THREE.WebGLRenderTarget(0, 0); 34 | 35 | // Antialiasing shader 36 | this.fxaaMaterial = new THREE.ShaderMaterial({ 37 | vertexShader: FXAAShaderVert, 38 | fragmentShader: FXAAShaderFrag, 39 | uniforms: { 40 | 'tDiffuse': { type: 't' }, 41 | 'resolution': { type: 'v2' } 42 | } 43 | }); 44 | 45 | this.fxaaMaterial.transparent = true; // Needed if inputBuffer is undefined. 46 | this.fxaaScene = this.createScene(this.fxaaMaterial); 47 | 48 | this.fxaaTarget = new THREE.WebGLRenderTarget(0, 0); 49 | 50 | this.outlineColor = new THREE.Color(); 51 | } 52 | 53 | createScene(material) { 54 | const quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), material ); 55 | 56 | const scene = new THREE.Scene(); 57 | scene.add(quad); 58 | 59 | return scene; 60 | } 61 | 62 | render({ 63 | renderer, 64 | renderSceneCB, 65 | pos = null, 66 | zoom = 2.0, 67 | exp = 35.0, 68 | radius = 100.0, 69 | outlineColor = 0xCCCCCC, 70 | outlineThickness = 8.0, 71 | antialias = true, 72 | inputBuffer = undefined, 73 | outputBuffer = undefined 74 | }) { 75 | 76 | if (!renderer) { 77 | console.warn('Magnify-3d: No renderer attached!'); 78 | return; 79 | } 80 | 81 | if (!pos) { 82 | // No pos - Just render original scene. 83 | renderSceneCB(outputBuffer); 84 | return; 85 | } 86 | 87 | const pixelRatio = renderer.getPixelRatio(); 88 | pos = { x: pos.x * pixelRatio, y: pos.y * pixelRatio }; 89 | 90 | let { width, height } = renderer.getSize(); 91 | 92 | width *= pixelRatio; 93 | height *= pixelRatio; 94 | 95 | const maxViewportWidth = renderer.context.getParameter(renderer.context.MAX_VIEWPORT_DIMS)[0]; 96 | const maxViewportHeight = renderer.context.getParameter(renderer.context.MAX_VIEWPORT_DIMS)[1]; 97 | 98 | let resWidth = width; 99 | let resHeight = height; 100 | if (width * zoom > maxViewportWidth) { 101 | resWidth = width * (width * zoom / maxViewportWidth); 102 | resHeight = height * (width * zoom / maxViewportWidth); 103 | } 104 | 105 | // Set shader uniforms. 106 | this.magnifyMaterial.uniforms['zoomedTexture'].value = this.zoomTarget.texture; 107 | this.magnifyMaterial.uniforms['originalTexture'].value = (inputBuffer && inputBuffer.texture) || inputBuffer; 108 | this.magnifyMaterial.uniforms['pos'].value = pos; 109 | this.magnifyMaterial.uniforms['outlineColor'].value = this.outlineColor.set(outlineColor); 110 | this.magnifyMaterial.uniforms['mag_resolution'].value = { x: resWidth, y: resHeight }; 111 | this.magnifyMaterial.uniforms['resolution'].value = { x: width, y: height }; 112 | this.magnifyMaterial.uniforms['zoom'].value = zoom; 113 | this.magnifyMaterial.uniforms['radius'].value = radius * pixelRatio; 114 | this.magnifyMaterial.uniforms['outlineThickness'].value = outlineThickness * pixelRatio; 115 | this.magnifyMaterial.uniforms['exp'].value = exp; 116 | 117 | // Make viewport centered according to pos. 118 | const zoomedViewport = [ 119 | -pos.x * (zoom - 1) * width / resWidth, 120 | -pos.y * (zoom - 1) * height / resHeight, 121 | width * width / resWidth * zoom, 122 | height * height / resHeight * zoom 123 | ]; 124 | 125 | this.zoomTarget.width = width; 126 | this.zoomTarget.height = height; 127 | this.zoomTarget.viewport.set(...zoomedViewport); 128 | 129 | const autoClearBackup = renderer.autoClear; 130 | renderer.autoClear = true; // Make sure autoClear is set. 131 | 132 | renderSceneCB(this.zoomTarget); 133 | 134 | if (antialias) { 135 | this.fxaaMaterial.uniforms['tDiffuse'].value = this.fxaaTarget.texture; 136 | this.fxaaMaterial.uniforms['resolution'].value = { x: 1 / width, y: 1 / height }; 137 | 138 | this.fxaaTarget.setSize(width, height); 139 | 140 | renderer.render(this.magnifyScene, this.camera, this.fxaaTarget); // Render magnify pass to fxaaTarget. 141 | renderer.render(this.fxaaScene, this.camera, outputBuffer); // Render final pass to output buffer. 142 | } else { 143 | renderer.render(this.magnifyScene, this.camera, outputBuffer); // Render magnify pass to outputBuffer. 144 | } 145 | 146 | renderer.autoClear = autoClearBackup; 147 | } 148 | }; 149 | -------------------------------------------------------------------------------- /sample/index.js: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three'; 2 | import * as dat from 'dat.gui'; 3 | import Magnify3d from '../src/Magnify3d'; 4 | import { TeapotBufferGeometry } from './TeapotGeometry'; 5 | 6 | // FPS monitor 7 | javascript:(function(){var script=document.createElement('script');script.onload=function(){var stats=new Stats();document.body.appendChild(stats.dom);requestAnimationFrame(function loop(){stats.update();requestAnimationFrame(loop)});};script.src='//mrdoob.github.io/stats.js/build/stats.min.js';document.head.appendChild(script);})() 8 | 9 | let camera, scene, renderer, defaultTarget, boxMesh1, boxMesh2; 10 | let magnify3d, params, gui; 11 | let shiftDown, ctrlDown; 12 | 13 | const MIN_ZOOM = 1; 14 | const MAX_ZOOM = 15; 15 | const MIN_EXP = 1; 16 | const MAX_EXP = 100; 17 | const MIN_RADIUS = 10; 18 | const MAX_RADIUS = 500; 19 | const MIN_OUTLINE_THICKNESS = 0; 20 | const MAX_OUTLINE_THICKNESS = 50; 21 | 22 | function initScene() { 23 | scene = new THREE.Scene(); 24 | 25 | const texture = new THREE.TextureLoader().load( 'res/checkerboard.png'); 26 | 27 | const checkerMaterial = new THREE.MeshBasicMaterial( { map: texture } ); 28 | const normalMaterial = new THREE.MeshNormalMaterial(); 29 | 30 | const boxGeometry = new THREE.BoxGeometry(20, 20, 20); 31 | boxMesh1 = new THREE.Mesh(boxGeometry, checkerMaterial); 32 | boxMesh1.position.x = 50; 33 | scene.add(boxMesh1); 34 | 35 | boxMesh2 = new THREE.Mesh(boxGeometry, checkerMaterial); 36 | boxMesh2.position.x = -50; 37 | scene.add(boxMesh2); 38 | 39 | const boxMesh3 = new THREE.Mesh(boxGeometry, normalMaterial); 40 | boxMesh3.position.x = 100; 41 | scene.add(boxMesh3); 42 | 43 | const boxMesh4 = new THREE.Mesh(boxGeometry, normalMaterial); 44 | boxMesh4.position.x = -100; 45 | scene.add(boxMesh4); 46 | 47 | const sphereGeometry = new THREE.SphereGeometry(10, 64, 64); 48 | 49 | const sphereMesh = new THREE.Mesh(sphereGeometry, normalMaterial); 50 | scene.add(sphereMesh); 51 | 52 | const teapotGeometry = new TeapotBufferGeometry(10, 32); 53 | const teapotMesh1 = new THREE.Mesh(teapotGeometry, normalMaterial); 54 | teapotMesh1.position.y = 50; 55 | scene.add(teapotMesh1); 56 | 57 | const teapotMesh2 = new THREE.Mesh(teapotGeometry, normalMaterial); 58 | teapotMesh2.position.y = -50; 59 | scene.add(teapotMesh2); 60 | } 61 | 62 | function initCamera() { 63 | camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.01, 1000); 64 | camera.position.set(0.0, 40.0, 250.0); 65 | camera.lookAt(0.0, 0.0, 0.0); 66 | } 67 | 68 | function initRenderer() { 69 | const pixelRatio = window.devicePixelRatio; 70 | 71 | renderer = new THREE.WebGLRenderer({ antialias: true, alpha: false }); 72 | 73 | renderer.setPixelRatio( pixelRatio ); 74 | renderer.setSize(window.innerWidth, window.innerHeight); 75 | 76 | const container = document.createElement('div'); 77 | container.appendChild(renderer.domElement); 78 | document.body.appendChild(container); 79 | 80 | defaultTarget = new THREE.WebGLRenderTarget(window.innerWidth * pixelRatio, window.innerHeight * pixelRatio); 81 | } 82 | 83 | function initEventListeners() { 84 | document.addEventListener('mousemove', (e) => { 85 | params.mouse = new THREE.Vector2(e.clientX, window.innerHeight - e.clientY); 86 | }); 87 | 88 | document.addEventListener('touchmove', (e) => { 89 | params.mouse = new THREE.Vector2(e.pageX, window.innerHeight - e.pageY); 90 | e.preventDefault(); 91 | e.stopPropagation(); 92 | }); 93 | 94 | window.addEventListener('resize', (e) => { 95 | renderer.setSize(window.innerWidth, window.innerHeight); 96 | camera.aspect = window.innerWidth / window.innerHeight; 97 | camera.clientWidth = window.innerWidth; 98 | camera.clientHeight = window.innerHeight; 99 | camera.updateProjectionMatrix(); 100 | }); 101 | 102 | function onMouseWheel(e) { 103 | e.preventDefault(); 104 | const delta = (e.wheelDelta && e.wheelDelta / 40) || -e.detail; 105 | 106 | if (shiftDown) { 107 | params.zoom = Math.min(Math.max(MIN_ZOOM, params.zoom + (delta / 10)), MAX_ZOOM); 108 | } else if (ctrlDown) { 109 | params.exp = Math.min(Math.max(MIN_EXP, params.exp + delta), MAX_EXP); 110 | } else { 111 | params.radius = Math.min(Math.max(MIN_RADIUS, params.radius + delta), MAX_RADIUS); 112 | } 113 | 114 | gui.updateDisplay(); 115 | } 116 | 117 | window.addEventListener( 'mousewheel', onMouseWheel ); 118 | window.addEventListener( 'DOMMouseScroll', onMouseWheel ); // firefox 119 | 120 | document.addEventListener('keydown', (e) => { 121 | const key = e.keyCode; 122 | switch (key) { 123 | case 16: 124 | shiftDown = true; 125 | break; 126 | case 17: 127 | ctrlDown = true; 128 | break; 129 | default: 130 | break; 131 | } 132 | }); 133 | 134 | document.addEventListener('keyup', (e) => { 135 | const key = e.keyCode; 136 | switch (key) { 137 | case 16: 138 | shiftDown = false; 139 | break; 140 | case 17: 141 | ctrlDown = false; 142 | break; 143 | default: 144 | break; 145 | } 146 | }); 147 | } 148 | 149 | function initGUI() { 150 | params = { 151 | zoom: 2.0, 152 | exp: 30.0, 153 | radius: 110.0, 154 | outlineThickness: 4.0, 155 | outlineColor: 0x555555 156 | } 157 | 158 | gui = new dat.GUI(); 159 | gui.add(params, 'radius', MIN_RADIUS, MAX_RADIUS); 160 | gui.add(params, 'zoom', MIN_ZOOM, MAX_ZOOM); 161 | gui.add(params, 'exp', MIN_EXP, MAX_EXP); 162 | gui.add(params, 'outlineThickness', MIN_OUTLINE_THICKNESS, MAX_OUTLINE_THICKNESS); 163 | gui.addColor(params, 'outlineColor'); 164 | } 165 | 166 | function init() { 167 | initScene(); 168 | initCamera(); 169 | initRenderer(); 170 | initEventListeners(); 171 | initGUI(); 172 | 173 | magnify3d = new Magnify3d(); 174 | } 175 | 176 | function renderSceneToTarget(tgt) { 177 | renderer.render(scene, camera, tgt); 178 | } 179 | 180 | function render() { 181 | renderSceneToTarget(defaultTarget); // Render original scene to target / screen (depends on defaultTarget). 182 | 183 | magnify3d.render({ 184 | renderer, 185 | renderSceneCB: renderSceneToTarget, 186 | pos: params.mouse, 187 | zoom: params.zoom, 188 | exp: params.exp, 189 | radius: params.radius, 190 | outlineThickness: params.outlineThickness, 191 | outlineColor: params.outlineColor, 192 | antialias: true, 193 | inputBuffer: defaultTarget, 194 | outputBuffer: undefined 195 | }); 196 | } 197 | 198 | function animate() { 199 | requestAnimationFrame(animate); 200 | 201 | boxMesh1.rotation.y += 0.01; 202 | boxMesh2.rotation.y -= 0.01; 203 | 204 | render(); 205 | } 206 | 207 | init(); 208 | animate(); 209 | -------------------------------------------------------------------------------- /sample/TeapotGeometry.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Eric Haines / http://erichaines.com/ 3 | * 4 | * Tessellates the famous Utah teapot database by Martin Newell into triangles. 5 | * 6 | * THREE.TeapotBufferGeometry = function ( size, segments, bottom, lid, body, fitLid, blinn ) 7 | * 8 | * defaults: size = 50, segments = 10, bottom = true, lid = true, body = true, 9 | * fitLid = false, blinn = true 10 | * 11 | * size is a relative scale: I've scaled the teapot to fit vertically between -1 and 1. 12 | * Think of it as a "radius". 13 | * segments - number of line segments to subdivide each patch edge; 14 | * 1 is possible but gives degenerates, so two is the real minimum. 15 | * bottom - boolean, if true (default) then the bottom patches are added. Some consider 16 | * adding the bottom heresy, so set this to "false" to adhere to the One True Way. 17 | * lid - to remove the lid and look inside, set to true. 18 | * body - to remove the body and leave the lid, set this and "bottom" to false. 19 | * fitLid - the lid is a tad small in the original. This stretches it a bit so you can't 20 | * see the teapot's insides through the gap. 21 | * blinn - Jim Blinn scaled the original data vertically by dividing by about 1.3 to look 22 | * nicer. If you want to see the original teapot, similar to the real-world model, set 23 | * this to false. True by default. 24 | * See http://en.wikipedia.org/wiki/File:Original_Utah_Teapot.jpg for the original 25 | * real-world teapot (from http://en.wikipedia.org/wiki/Utah_teapot). 26 | * 27 | * Note that the bottom (the last four patches) is not flat - blame Frank Crow, not me. 28 | * 29 | * The teapot should normally be rendered as a double sided object, since for some 30 | * patches both sides can be seen, e.g., the gap around the lid and inside the spout. 31 | * 32 | * Segments 'n' determines the number of triangles output. 33 | * Total triangles = 32*2*n*n - 8*n [degenerates at the top and bottom cusps are deleted] 34 | * 35 | * size_factor # triangles 36 | * 1 56 37 | * 2 240 38 | * 3 552 39 | * 4 992 40 | * 41 | * 10 6320 42 | * 20 25440 43 | * 30 57360 44 | * 45 | * Code converted from my ancient SPD software, http://tog.acm.org/resources/SPD/ 46 | * Created for the Udacity course "Interactive Rendering", http://bit.ly/ericity 47 | * Lesson: https://www.udacity.com/course/viewer#!/c-cs291/l-68866048/m-106482448 48 | * YouTube video on teapot history: https://www.youtube.com/watch?v=DxMfblPzFNc 49 | * 50 | * See https://en.wikipedia.org/wiki/Utah_teapot for the history of the teapot 51 | * 52 | */ 53 | /*global THREE */ 54 | 55 | import * as THREE from 'three'; 56 | 57 | export const TeapotBufferGeometry = function ( size, segments, bottom, lid, body, fitLid, blinn ) { 58 | 59 | // 32 * 4 * 4 Bezier spline patches 60 | var teapotPatches = [ 61 | /*rim*/ 62 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 63 | 3, 16, 17, 18, 7, 19, 20, 21, 11, 22, 23, 24, 15, 25, 26, 27, 64 | 18, 28, 29, 30, 21, 31, 32, 33, 24, 34, 35, 36, 27, 37, 38, 39, 65 | 30, 40, 41, 0, 33, 42, 43, 4, 36, 44, 45, 8, 39, 46, 47, 12, 66 | /*body*/ 67 | 12, 13, 14, 15, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 68 | 15, 25, 26, 27, 51, 60, 61, 62, 55, 63, 64, 65, 59, 66, 67, 68, 69 | 27, 37, 38, 39, 62, 69, 70, 71, 65, 72, 73, 74, 68, 75, 76, 77, 70 | 39, 46, 47, 12, 71, 78, 79, 48, 74, 80, 81, 52, 77, 82, 83, 56, 71 | 56, 57, 58, 59, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 72 | 59, 66, 67, 68, 87, 96, 97, 98, 91, 99, 100, 101, 95, 102, 103, 104, 73 | 68, 75, 76, 77, 98, 105, 106, 107, 101, 108, 109, 110, 104, 111, 112, 113, 74 | 77, 82, 83, 56, 107, 114, 115, 84, 110, 116, 117, 88, 113, 118, 119, 92, 75 | /*handle*/ 76 | 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 77 | 123, 136, 137, 120, 127, 138, 139, 124, 131, 140, 141, 128, 135, 142, 143, 132, 78 | 132, 133, 134, 135, 144, 145, 146, 147, 148, 149, 150, 151, 68, 152, 153, 154, 79 | 135, 142, 143, 132, 147, 155, 156, 144, 151, 157, 158, 148, 154, 159, 160, 68, 80 | /*spout*/ 81 | 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 82 | 164, 177, 178, 161, 168, 179, 180, 165, 172, 181, 182, 169, 176, 183, 184, 173, 83 | 173, 174, 175, 176, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 84 | 176, 183, 184, 173, 188, 197, 198, 185, 192, 199, 200, 189, 196, 201, 202, 193, 85 | /*lid*/ 86 | 203, 203, 203, 203, 204, 205, 206, 207, 208, 208, 208, 208, 209, 210, 211, 212, 87 | 203, 203, 203, 203, 207, 213, 214, 215, 208, 208, 208, 208, 212, 216, 217, 218, 88 | 203, 203, 203, 203, 215, 219, 220, 221, 208, 208, 208, 208, 218, 222, 223, 224, 89 | 203, 203, 203, 203, 221, 225, 226, 204, 208, 208, 208, 208, 224, 227, 228, 209, 90 | 209, 210, 211, 212, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 91 | 212, 216, 217, 218, 232, 241, 242, 243, 236, 244, 245, 246, 240, 247, 248, 249, 92 | 218, 222, 223, 224, 243, 250, 251, 252, 246, 253, 254, 255, 249, 256, 257, 258, 93 | 224, 227, 228, 209, 252, 259, 260, 229, 255, 261, 262, 233, 258, 263, 264, 237, 94 | /*bottom*/ 95 | 265, 265, 265, 265, 266, 267, 268, 269, 270, 271, 272, 273, 92, 119, 118, 113, 96 | 265, 265, 265, 265, 269, 274, 275, 276, 273, 277, 278, 279, 113, 112, 111, 104, 97 | 265, 265, 265, 265, 276, 280, 281, 282, 279, 283, 284, 285, 104, 103, 102, 95, 98 | 265, 265, 265, 265, 282, 286, 287, 266, 285, 288, 289, 270, 95, 94, 93, 92 99 | ]; 100 | 101 | var teapotVertices = [ 102 | 1.4, 0, 2.4, 103 | 1.4, - 0.784, 2.4, 104 | 0.784, - 1.4, 2.4, 105 | 0, - 1.4, 2.4, 106 | 1.3375, 0, 2.53125, 107 | 1.3375, - 0.749, 2.53125, 108 | 0.749, - 1.3375, 2.53125, 109 | 0, - 1.3375, 2.53125, 110 | 1.4375, 0, 2.53125, 111 | 1.4375, - 0.805, 2.53125, 112 | 0.805, - 1.4375, 2.53125, 113 | 0, - 1.4375, 2.53125, 114 | 1.5, 0, 2.4, 115 | 1.5, - 0.84, 2.4, 116 | 0.84, - 1.5, 2.4, 117 | 0, - 1.5, 2.4, 118 | - 0.784, - 1.4, 2.4, 119 | - 1.4, - 0.784, 2.4, 120 | - 1.4, 0, 2.4, 121 | - 0.749, - 1.3375, 2.53125, 122 | - 1.3375, - 0.749, 2.53125, 123 | - 1.3375, 0, 2.53125, 124 | - 0.805, - 1.4375, 2.53125, 125 | - 1.4375, - 0.805, 2.53125, 126 | - 1.4375, 0, 2.53125, 127 | - 0.84, - 1.5, 2.4, 128 | - 1.5, - 0.84, 2.4, 129 | - 1.5, 0, 2.4, 130 | - 1.4, 0.784, 2.4, 131 | - 0.784, 1.4, 2.4, 132 | 0, 1.4, 2.4, 133 | - 1.3375, 0.749, 2.53125, 134 | - 0.749, 1.3375, 2.53125, 135 | 0, 1.3375, 2.53125, 136 | - 1.4375, 0.805, 2.53125, 137 | - 0.805, 1.4375, 2.53125, 138 | 0, 1.4375, 2.53125, 139 | - 1.5, 0.84, 2.4, 140 | - 0.84, 1.5, 2.4, 141 | 0, 1.5, 2.4, 142 | 0.784, 1.4, 2.4, 143 | 1.4, 0.784, 2.4, 144 | 0.749, 1.3375, 2.53125, 145 | 1.3375, 0.749, 2.53125, 146 | 0.805, 1.4375, 2.53125, 147 | 1.4375, 0.805, 2.53125, 148 | 0.84, 1.5, 2.4, 149 | 1.5, 0.84, 2.4, 150 | 1.75, 0, 1.875, 151 | 1.75, - 0.98, 1.875, 152 | 0.98, - 1.75, 1.875, 153 | 0, - 1.75, 1.875, 154 | 2, 0, 1.35, 155 | 2, - 1.12, 1.35, 156 | 1.12, - 2, 1.35, 157 | 0, - 2, 1.35, 158 | 2, 0, 0.9, 159 | 2, - 1.12, 0.9, 160 | 1.12, - 2, 0.9, 161 | 0, - 2, 0.9, 162 | - 0.98, - 1.75, 1.875, 163 | - 1.75, - 0.98, 1.875, 164 | - 1.75, 0, 1.875, 165 | - 1.12, - 2, 1.35, 166 | - 2, - 1.12, 1.35, 167 | - 2, 0, 1.35, 168 | - 1.12, - 2, 0.9, 169 | - 2, - 1.12, 0.9, 170 | - 2, 0, 0.9, 171 | - 1.75, 0.98, 1.875, 172 | - 0.98, 1.75, 1.875, 173 | 0, 1.75, 1.875, 174 | - 2, 1.12, 1.35, 175 | - 1.12, 2, 1.35, 176 | 0, 2, 1.35, 177 | - 2, 1.12, 0.9, 178 | - 1.12, 2, 0.9, 179 | 0, 2, 0.9, 180 | 0.98, 1.75, 1.875, 181 | 1.75, 0.98, 1.875, 182 | 1.12, 2, 1.35, 183 | 2, 1.12, 1.35, 184 | 1.12, 2, 0.9, 185 | 2, 1.12, 0.9, 186 | 2, 0, 0.45, 187 | 2, - 1.12, 0.45, 188 | 1.12, - 2, 0.45, 189 | 0, - 2, 0.45, 190 | 1.5, 0, 0.225, 191 | 1.5, - 0.84, 0.225, 192 | 0.84, - 1.5, 0.225, 193 | 0, - 1.5, 0.225, 194 | 1.5, 0, 0.15, 195 | 1.5, - 0.84, 0.15, 196 | 0.84, - 1.5, 0.15, 197 | 0, - 1.5, 0.15, 198 | - 1.12, - 2, 0.45, 199 | - 2, - 1.12, 0.45, 200 | - 2, 0, 0.45, 201 | - 0.84, - 1.5, 0.225, 202 | - 1.5, - 0.84, 0.225, 203 | - 1.5, 0, 0.225, 204 | - 0.84, - 1.5, 0.15, 205 | - 1.5, - 0.84, 0.15, 206 | - 1.5, 0, 0.15, 207 | - 2, 1.12, 0.45, 208 | - 1.12, 2, 0.45, 209 | 0, 2, 0.45, 210 | - 1.5, 0.84, 0.225, 211 | - 0.84, 1.5, 0.225, 212 | 0, 1.5, 0.225, 213 | - 1.5, 0.84, 0.15, 214 | - 0.84, 1.5, 0.15, 215 | 0, 1.5, 0.15, 216 | 1.12, 2, 0.45, 217 | 2, 1.12, 0.45, 218 | 0.84, 1.5, 0.225, 219 | 1.5, 0.84, 0.225, 220 | 0.84, 1.5, 0.15, 221 | 1.5, 0.84, 0.15, 222 | - 1.6, 0, 2.025, 223 | - 1.6, - 0.3, 2.025, 224 | - 1.5, - 0.3, 2.25, 225 | - 1.5, 0, 2.25, 226 | - 2.3, 0, 2.025, 227 | - 2.3, - 0.3, 2.025, 228 | - 2.5, - 0.3, 2.25, 229 | - 2.5, 0, 2.25, 230 | - 2.7, 0, 2.025, 231 | - 2.7, - 0.3, 2.025, 232 | - 3, - 0.3, 2.25, 233 | - 3, 0, 2.25, 234 | - 2.7, 0, 1.8, 235 | - 2.7, - 0.3, 1.8, 236 | - 3, - 0.3, 1.8, 237 | - 3, 0, 1.8, 238 | - 1.5, 0.3, 2.25, 239 | - 1.6, 0.3, 2.025, 240 | - 2.5, 0.3, 2.25, 241 | - 2.3, 0.3, 2.025, 242 | - 3, 0.3, 2.25, 243 | - 2.7, 0.3, 2.025, 244 | - 3, 0.3, 1.8, 245 | - 2.7, 0.3, 1.8, 246 | - 2.7, 0, 1.575, 247 | - 2.7, - 0.3, 1.575, 248 | - 3, - 0.3, 1.35, 249 | - 3, 0, 1.35, 250 | - 2.5, 0, 1.125, 251 | - 2.5, - 0.3, 1.125, 252 | - 2.65, - 0.3, 0.9375, 253 | - 2.65, 0, 0.9375, 254 | - 2, - 0.3, 0.9, 255 | - 1.9, - 0.3, 0.6, 256 | - 1.9, 0, 0.6, 257 | - 3, 0.3, 1.35, 258 | - 2.7, 0.3, 1.575, 259 | - 2.65, 0.3, 0.9375, 260 | - 2.5, 0.3, 1.125, 261 | - 1.9, 0.3, 0.6, 262 | - 2, 0.3, 0.9, 263 | 1.7, 0, 1.425, 264 | 1.7, - 0.66, 1.425, 265 | 1.7, - 0.66, 0.6, 266 | 1.7, 0, 0.6, 267 | 2.6, 0, 1.425, 268 | 2.6, - 0.66, 1.425, 269 | 3.1, - 0.66, 0.825, 270 | 3.1, 0, 0.825, 271 | 2.3, 0, 2.1, 272 | 2.3, - 0.25, 2.1, 273 | 2.4, - 0.25, 2.025, 274 | 2.4, 0, 2.025, 275 | 2.7, 0, 2.4, 276 | 2.7, - 0.25, 2.4, 277 | 3.3, - 0.25, 2.4, 278 | 3.3, 0, 2.4, 279 | 1.7, 0.66, 0.6, 280 | 1.7, 0.66, 1.425, 281 | 3.1, 0.66, 0.825, 282 | 2.6, 0.66, 1.425, 283 | 2.4, 0.25, 2.025, 284 | 2.3, 0.25, 2.1, 285 | 3.3, 0.25, 2.4, 286 | 2.7, 0.25, 2.4, 287 | 2.8, 0, 2.475, 288 | 2.8, - 0.25, 2.475, 289 | 3.525, - 0.25, 2.49375, 290 | 3.525, 0, 2.49375, 291 | 2.9, 0, 2.475, 292 | 2.9, - 0.15, 2.475, 293 | 3.45, - 0.15, 2.5125, 294 | 3.45, 0, 2.5125, 295 | 2.8, 0, 2.4, 296 | 2.8, - 0.15, 2.4, 297 | 3.2, - 0.15, 2.4, 298 | 3.2, 0, 2.4, 299 | 3.525, 0.25, 2.49375, 300 | 2.8, 0.25, 2.475, 301 | 3.45, 0.15, 2.5125, 302 | 2.9, 0.15, 2.475, 303 | 3.2, 0.15, 2.4, 304 | 2.8, 0.15, 2.4, 305 | 0, 0, 3.15, 306 | 0.8, 0, 3.15, 307 | 0.8, - 0.45, 3.15, 308 | 0.45, - 0.8, 3.15, 309 | 0, - 0.8, 3.15, 310 | 0, 0, 2.85, 311 | 0.2, 0, 2.7, 312 | 0.2, - 0.112, 2.7, 313 | 0.112, - 0.2, 2.7, 314 | 0, - 0.2, 2.7, 315 | - 0.45, - 0.8, 3.15, 316 | - 0.8, - 0.45, 3.15, 317 | - 0.8, 0, 3.15, 318 | - 0.112, - 0.2, 2.7, 319 | - 0.2, - 0.112, 2.7, 320 | - 0.2, 0, 2.7, 321 | - 0.8, 0.45, 3.15, 322 | - 0.45, 0.8, 3.15, 323 | 0, 0.8, 3.15, 324 | - 0.2, 0.112, 2.7, 325 | - 0.112, 0.2, 2.7, 326 | 0, 0.2, 2.7, 327 | 0.45, 0.8, 3.15, 328 | 0.8, 0.45, 3.15, 329 | 0.112, 0.2, 2.7, 330 | 0.2, 0.112, 2.7, 331 | 0.4, 0, 2.55, 332 | 0.4, - 0.224, 2.55, 333 | 0.224, - 0.4, 2.55, 334 | 0, - 0.4, 2.55, 335 | 1.3, 0, 2.55, 336 | 1.3, - 0.728, 2.55, 337 | 0.728, - 1.3, 2.55, 338 | 0, - 1.3, 2.55, 339 | 1.3, 0, 2.4, 340 | 1.3, - 0.728, 2.4, 341 | 0.728, - 1.3, 2.4, 342 | 0, - 1.3, 2.4, 343 | - 0.224, - 0.4, 2.55, 344 | - 0.4, - 0.224, 2.55, 345 | - 0.4, 0, 2.55, 346 | - 0.728, - 1.3, 2.55, 347 | - 1.3, - 0.728, 2.55, 348 | - 1.3, 0, 2.55, 349 | - 0.728, - 1.3, 2.4, 350 | - 1.3, - 0.728, 2.4, 351 | - 1.3, 0, 2.4, 352 | - 0.4, 0.224, 2.55, 353 | - 0.224, 0.4, 2.55, 354 | 0, 0.4, 2.55, 355 | - 1.3, 0.728, 2.55, 356 | - 0.728, 1.3, 2.55, 357 | 0, 1.3, 2.55, 358 | - 1.3, 0.728, 2.4, 359 | - 0.728, 1.3, 2.4, 360 | 0, 1.3, 2.4, 361 | 0.224, 0.4, 2.55, 362 | 0.4, 0.224, 2.55, 363 | 0.728, 1.3, 2.55, 364 | 1.3, 0.728, 2.55, 365 | 0.728, 1.3, 2.4, 366 | 1.3, 0.728, 2.4, 367 | 0, 0, 0, 368 | 1.425, 0, 0, 369 | 1.425, 0.798, 0, 370 | 0.798, 1.425, 0, 371 | 0, 1.425, 0, 372 | 1.5, 0, 0.075, 373 | 1.5, 0.84, 0.075, 374 | 0.84, 1.5, 0.075, 375 | 0, 1.5, 0.075, 376 | - 0.798, 1.425, 0, 377 | - 1.425, 0.798, 0, 378 | - 1.425, 0, 0, 379 | - 0.84, 1.5, 0.075, 380 | - 1.5, 0.84, 0.075, 381 | - 1.5, 0, 0.075, 382 | - 1.425, - 0.798, 0, 383 | - 0.798, - 1.425, 0, 384 | 0, - 1.425, 0, 385 | - 1.5, - 0.84, 0.075, 386 | - 0.84, - 1.5, 0.075, 387 | 0, - 1.5, 0.075, 388 | 0.798, - 1.425, 0, 389 | 1.425, - 0.798, 0, 390 | 0.84, - 1.5, 0.075, 391 | 1.5, - 0.84, 0.075 392 | ]; 393 | 394 | THREE.BufferGeometry.call( this ); 395 | 396 | size = size || 50; 397 | 398 | // number of segments per patch 399 | segments = segments !== undefined ? Math.max( 2, Math.floor( segments ) || 10 ) : 10; 400 | 401 | // which parts should be visible 402 | bottom = bottom === undefined ? true : bottom; 403 | lid = lid === undefined ? true : lid; 404 | body = body === undefined ? true : body; 405 | 406 | // Should the lid be snug? It's not traditional, but we make it snug by default 407 | fitLid = fitLid === undefined ? true : fitLid; 408 | 409 | // Jim Blinn scaled the teapot down in size by about 1.3 for 410 | // some rendering tests. He liked the new proportions that he kept 411 | // the data in this form. The model was distributed with these new 412 | // proportions and became the norm. Trivia: comparing images of the 413 | // real teapot and the computer model, the ratio for the bowl of the 414 | // real teapot is more like 1.25, but since 1.3 is the traditional 415 | // value given, we use it here. 416 | var blinnScale = 1.3; 417 | blinn = blinn === undefined ? true : blinn; 418 | 419 | // scale the size to be the real scaling factor 420 | var maxHeight = 3.15 * ( blinn ? 1 : blinnScale ); 421 | 422 | var maxHeight2 = maxHeight / 2; 423 | var trueSize = size / maxHeight2; 424 | 425 | // Number of elements depends on what is needed. Subtract degenerate 426 | // triangles at tip of bottom and lid out in advance. 427 | var numTriangles = bottom ? ( 8 * segments - 4 ) * segments : 0; 428 | numTriangles += lid ? ( 16 * segments - 4 ) * segments : 0; 429 | numTriangles += body ? 40 * segments * segments : 0; 430 | 431 | var indices = new Uint32Array( numTriangles * 3 ); 432 | 433 | var numVertices = bottom ? 4 : 0; 434 | numVertices += lid ? 8 : 0; 435 | numVertices += body ? 20 : 0; 436 | numVertices *= ( segments + 1 ) * ( segments + 1 ); 437 | 438 | var vertices = new Float32Array( numVertices * 3 ); 439 | var normals = new Float32Array( numVertices * 3 ); 440 | var uvs = new Float32Array( numVertices * 2 ); 441 | 442 | // Bezier form 443 | var ms = new THREE.Matrix4(); 444 | ms.set( 445 | - 1.0, 3.0, - 3.0, 1.0, 446 | 3.0, - 6.0, 3.0, 0.0, 447 | - 3.0, 3.0, 0.0, 0.0, 448 | 1.0, 0.0, 0.0, 0.0 ); 449 | 450 | var g = []; 451 | var i, r, c; 452 | 453 | var sp = []; 454 | var tp = []; 455 | var dsp = []; 456 | var dtp = []; 457 | 458 | // M * G * M matrix, sort of see 459 | // http://www.cs.helsinki.fi/group/goa/mallinnus/curves/surfaces.html 460 | var mgm = []; 461 | 462 | var vert = []; 463 | var sdir = []; 464 | var tdir = []; 465 | 466 | var norm = new THREE.Vector3(); 467 | 468 | var tcoord; 469 | 470 | var sstep, tstep; 471 | var vertPerRow; 472 | 473 | var s, t, sval, tval, p; 474 | var dsval = 0; 475 | var dtval = 0; 476 | 477 | var normOut = new THREE.Vector3(); 478 | var v1, v2, v3, v4; 479 | 480 | var gmx = new THREE.Matrix4(); 481 | var tmtx = new THREE.Matrix4(); 482 | 483 | var vsp = new THREE.Vector4(); 484 | var vtp = new THREE.Vector4(); 485 | var vdsp = new THREE.Vector4(); 486 | var vdtp = new THREE.Vector4(); 487 | 488 | var vsdir = new THREE.Vector3(); 489 | var vtdir = new THREE.Vector3(); 490 | 491 | var mst = ms.clone(); 492 | mst.transpose(); 493 | 494 | // internal function: test if triangle has any matching vertices; 495 | // if so, don't save triangle, since it won't display anything. 496 | var notDegenerate = function ( vtx1, vtx2, vtx3 ) { 497 | 498 | // if any vertex matches, return false 499 | return ! ( ( ( vertices[ vtx1 * 3 ] === vertices[ vtx2 * 3 ] ) && 500 | ( vertices[ vtx1 * 3 + 1 ] === vertices[ vtx2 * 3 + 1 ] ) && 501 | ( vertices[ vtx1 * 3 + 2 ] === vertices[ vtx2 * 3 + 2 ] ) ) || 502 | ( ( vertices[ vtx1 * 3 ] === vertices[ vtx3 * 3 ] ) && 503 | ( vertices[ vtx1 * 3 + 1 ] === vertices[ vtx3 * 3 + 1 ] ) && 504 | ( vertices[ vtx1 * 3 + 2 ] === vertices[ vtx3 * 3 + 2 ] ) ) || 505 | ( ( vertices[ vtx2 * 3 ] === vertices[ vtx3 * 3 ] ) && 506 | ( vertices[ vtx2 * 3 + 1 ] === vertices[ vtx3 * 3 + 1 ] ) && 507 | ( vertices[ vtx2 * 3 + 2 ] === vertices[ vtx3 * 3 + 2 ] ) ) ); 508 | 509 | }; 510 | 511 | 512 | for ( i = 0; i < 3; i ++ ) { 513 | 514 | mgm[ i ] = new THREE.Matrix4(); 515 | 516 | } 517 | 518 | var minPatches = body ? 0 : 20; 519 | var maxPatches = bottom ? 32 : 28; 520 | 521 | vertPerRow = segments + 1; 522 | 523 | var surfCount = 0; 524 | 525 | var vertCount = 0; 526 | var normCount = 0; 527 | var uvCount = 0; 528 | 529 | var indexCount = 0; 530 | 531 | for ( var surf = minPatches; surf < maxPatches; surf ++ ) { 532 | 533 | // lid is in the middle of the data, patches 20-27, 534 | // so ignore it for this part of the loop if the lid is not desired 535 | if ( lid || ( surf < 20 || surf >= 28 ) ) { 536 | 537 | // get M * G * M matrix for x,y,z 538 | for ( i = 0; i < 3; i ++ ) { 539 | 540 | // get control patches 541 | for ( r = 0; r < 4; r ++ ) { 542 | 543 | for ( c = 0; c < 4; c ++ ) { 544 | 545 | // transposed 546 | g[ c * 4 + r ] = teapotVertices[ teapotPatches[ surf * 16 + r * 4 + c ] * 3 + i ]; 547 | 548 | // is the lid to be made larger, and is this a point on the lid 549 | // that is X or Y? 550 | if ( fitLid && ( surf >= 20 && surf < 28 ) && ( i !== 2 ) ) { 551 | 552 | // increase XY size by 7.7%, found empirically. I don't 553 | // increase Z so that the teapot will continue to fit in the 554 | // space -1 to 1 for Y (Y is up for the final model). 555 | g[ c * 4 + r ] *= 1.077; 556 | 557 | } 558 | 559 | // Blinn "fixed" the teapot by dividing Z by blinnScale, and that's the 560 | // data we now use. The original teapot is taller. Fix it: 561 | if ( ! blinn && ( i === 2 ) ) { 562 | 563 | g[ c * 4 + r ] *= blinnScale; 564 | 565 | } 566 | 567 | } 568 | 569 | } 570 | 571 | gmx.set( g[ 0 ], g[ 1 ], g[ 2 ], g[ 3 ], g[ 4 ], g[ 5 ], g[ 6 ], g[ 7 ], g[ 8 ], g[ 9 ], g[ 10 ], g[ 11 ], g[ 12 ], g[ 13 ], g[ 14 ], g[ 15 ] ); 572 | 573 | tmtx.multiplyMatrices( gmx, ms ); 574 | mgm[ i ].multiplyMatrices( mst, tmtx ); 575 | 576 | } 577 | 578 | // step along, get points, and output 579 | for ( sstep = 0; sstep <= segments; sstep ++ ) { 580 | 581 | s = sstep / segments; 582 | 583 | for ( tstep = 0; tstep <= segments; tstep ++ ) { 584 | 585 | t = tstep / segments; 586 | 587 | // point from basis 588 | // get power vectors and their derivatives 589 | for ( p = 4, sval = tval = 1.0; p --; ) { 590 | 591 | sp[ p ] = sval; 592 | tp[ p ] = tval; 593 | sval *= s; 594 | tval *= t; 595 | 596 | if ( p === 3 ) { 597 | 598 | dsp[ p ] = dtp[ p ] = 0.0; 599 | dsval = dtval = 1.0; 600 | 601 | } else { 602 | 603 | dsp[ p ] = dsval * ( 3 - p ); 604 | dtp[ p ] = dtval * ( 3 - p ); 605 | dsval *= s; 606 | dtval *= t; 607 | 608 | } 609 | 610 | } 611 | 612 | vsp.fromArray( sp ); 613 | vtp.fromArray( tp ); 614 | vdsp.fromArray( dsp ); 615 | vdtp.fromArray( dtp ); 616 | 617 | // do for x,y,z 618 | for ( i = 0; i < 3; i ++ ) { 619 | 620 | // multiply power vectors times matrix to get value 621 | tcoord = vsp.clone(); 622 | tcoord.applyMatrix4( mgm[ i ] ); 623 | vert[ i ] = tcoord.dot( vtp ); 624 | 625 | // get s and t tangent vectors 626 | tcoord = vdsp.clone(); 627 | tcoord.applyMatrix4( mgm[ i ] ); 628 | sdir[ i ] = tcoord.dot( vtp ); 629 | 630 | tcoord = vsp.clone(); 631 | tcoord.applyMatrix4( mgm[ i ] ); 632 | tdir[ i ] = tcoord.dot( vdtp ); 633 | 634 | } 635 | 636 | // find normal 637 | vsdir.fromArray( sdir ); 638 | vtdir.fromArray( tdir ); 639 | norm.crossVectors( vtdir, vsdir ); 640 | norm.normalize(); 641 | 642 | // if X and Z length is 0, at the cusp, so point the normal up or down, depending on patch number 643 | if ( vert[ 0 ] === 0 && vert[ 1 ] === 0 ) { 644 | 645 | // if above the middle of the teapot, normal points up, else down 646 | normOut.set( 0, vert[ 2 ] > maxHeight2 ? 1 : - 1, 0 ); 647 | 648 | } else { 649 | 650 | // standard output: rotate on X axis 651 | normOut.set( norm.x, norm.z, - norm.y ); 652 | 653 | } 654 | 655 | // store it all 656 | vertices[ vertCount ++ ] = trueSize * vert[ 0 ]; 657 | vertices[ vertCount ++ ] = trueSize * ( vert[ 2 ] - maxHeight2 ); 658 | vertices[ vertCount ++ ] = - trueSize * vert[ 1 ]; 659 | 660 | normals[ normCount ++ ] = normOut.x; 661 | normals[ normCount ++ ] = normOut.y; 662 | normals[ normCount ++ ] = normOut.z; 663 | 664 | uvs[ uvCount ++ ] = 1 - t; 665 | uvs[ uvCount ++ ] = 1 - s; 666 | 667 | } 668 | 669 | } 670 | 671 | // save the faces 672 | for ( sstep = 0; sstep < segments; sstep ++ ) { 673 | 674 | for ( tstep = 0; tstep < segments; tstep ++ ) { 675 | 676 | v1 = surfCount * vertPerRow * vertPerRow + sstep * vertPerRow + tstep; 677 | v2 = v1 + 1; 678 | v3 = v2 + vertPerRow; 679 | v4 = v1 + vertPerRow; 680 | 681 | // Normals and UVs cannot be shared. Without clone(), you can see the consequences 682 | // of sharing if you call geometry.applyMatrix( matrix ). 683 | if ( notDegenerate( v1, v2, v3 ) ) { 684 | 685 | indices[ indexCount ++ ] = v1; 686 | indices[ indexCount ++ ] = v2; 687 | indices[ indexCount ++ ] = v3; 688 | 689 | } 690 | if ( notDegenerate( v1, v3, v4 ) ) { 691 | 692 | indices[ indexCount ++ ] = v1; 693 | indices[ indexCount ++ ] = v3; 694 | indices[ indexCount ++ ] = v4; 695 | 696 | } 697 | 698 | } 699 | 700 | } 701 | 702 | // increment only if a surface was used 703 | surfCount ++; 704 | 705 | } 706 | 707 | } 708 | 709 | this.setIndex( new THREE.BufferAttribute( indices, 1 ) ); 710 | this.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) ); 711 | this.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) ); 712 | this.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) ); 713 | 714 | this.computeBoundingSphere(); 715 | 716 | }; 717 | 718 | 719 | TeapotBufferGeometry.prototype = Object.create( THREE.BufferGeometry.prototype ); 720 | TeapotBufferGeometry.prototype.constructor = TeapotBufferGeometry; -------------------------------------------------------------------------------- /src/shaders/FXAAShaderFrag.glsl: -------------------------------------------------------------------------------- 1 | precision highp float; 2 | 3 | uniform sampler2D tDiffuse; 4 | 5 | uniform vec2 resolution; 6 | 7 | varying vec2 vUv; 8 | 9 | // FXAA 3.11 implementation by NVIDIA, ported to WebGL by Agost Biro (biro@archilogic.com) 10 | 11 | //---------------------------------------------------------------------------------- 12 | // File: es3-kepler\FXAA\assets\shaders/FXAA_DefaultES.frag 13 | // SDK Version: v3.00 14 | // Email: gameworks@nvidia.com 15 | // Site: http://developer.nvidia.com/ 16 | // 17 | // Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. 18 | // 19 | // Redistribution and use in source and binary forms, with or without 20 | // modification, are permitted provided that the following conditions 21 | // are met: 22 | // * Redistributions of source code must retain the above copyright 23 | // notice, this list of conditions and the following disclaimer. 24 | // * Redistributions in binary form must reproduce the above copyright 25 | // notice, this list of conditions and the following disclaimer in the 26 | // documentation and/or other materials provided with the distribution. 27 | // * Neither the name of NVIDIA CORPORATION nor the names of its 28 | // contributors may be used to endorse or promote products derived 29 | // from this software without specific prior written permission. 30 | // 31 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 32 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 33 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 34 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 35 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 36 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 37 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 38 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 39 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 40 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 41 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 | // 43 | //---------------------------------------------------------------------------------- 44 | 45 | #define FXAA_PC 1 46 | #define FXAA_GLSL_100 1 47 | #define FXAA_QUALITY_PRESET 12 48 | 49 | #define FXAA_GREEN_AS_LUMA 1 50 | 51 | /*--------------------------------------------------------------------------*/ 52 | #ifndef FXAA_PC_CONSOLE 53 | // 54 | // The console algorithm for PC is included 55 | // for developers targeting really low spec machines. 56 | // Likely better to just run FXAA_PC, and use a really low preset. 57 | // 58 | #define FXAA_PC_CONSOLE 0 59 | #endif 60 | /*--------------------------------------------------------------------------*/ 61 | #ifndef FXAA_GLSL_120 62 | #define FXAA_GLSL_120 0 63 | #endif 64 | /*--------------------------------------------------------------------------*/ 65 | #ifndef FXAA_GLSL_130 66 | #define FXAA_GLSL_130 0 67 | #endif 68 | /*--------------------------------------------------------------------------*/ 69 | #ifndef FXAA_HLSL_3 70 | #define FXAA_HLSL_3 0 71 | #endif 72 | /*--------------------------------------------------------------------------*/ 73 | #ifndef FXAA_HLSL_4 74 | #define FXAA_HLSL_4 0 75 | #endif 76 | /*--------------------------------------------------------------------------*/ 77 | #ifndef FXAA_HLSL_5 78 | #define FXAA_HLSL_5 0 79 | #endif 80 | /*==========================================================================*/ 81 | #ifndef FXAA_GREEN_AS_LUMA 82 | // 83 | // For those using non-linear color, 84 | // and either not able to get luma in alpha, or not wanting to, 85 | // this enables FXAA to run using green as a proxy for luma. 86 | // So with this enabled, no need to pack luma in alpha. 87 | // 88 | // This will turn off AA on anything which lacks some amount of green. 89 | // Pure red and blue or combination of only R and B, will get no AA. 90 | // 91 | // Might want to lower the settings for both, 92 | // fxaaConsoleEdgeThresholdMin 93 | // fxaaQualityEdgeThresholdMin 94 | // In order to insure AA does not get turned off on colors 95 | // which contain a minor amount of green. 96 | // 97 | // 1 = On. 98 | // 0 = Off. 99 | // 100 | #define FXAA_GREEN_AS_LUMA 0 101 | #endif 102 | /*--------------------------------------------------------------------------*/ 103 | #ifndef FXAA_EARLY_EXIT 104 | // 105 | // Controls algorithm's early exit path. 106 | // On PS3 turning this ON adds 2 cycles to the shader. 107 | // On 360 turning this OFF adds 10ths of a millisecond to the shader. 108 | // Turning this off on console will result in a more blurry image. 109 | // So this defaults to on. 110 | // 111 | // 1 = On. 112 | // 0 = Off. 113 | // 114 | #define FXAA_EARLY_EXIT 1 115 | #endif 116 | /*--------------------------------------------------------------------------*/ 117 | #ifndef FXAA_DISCARD 118 | // 119 | // Only valid for PC OpenGL currently. 120 | // Probably will not work when FXAA_GREEN_AS_LUMA = 1. 121 | // 122 | // 1 = Use discard on pixels which don't need AA. 123 | // For APIs which enable concurrent TEX+ROP from same surface. 124 | // 0 = Return unchanged color on pixels which don't need AA. 125 | // 126 | #define FXAA_DISCARD 0 127 | #endif 128 | /*--------------------------------------------------------------------------*/ 129 | #ifndef FXAA_FAST_PIXEL_OFFSET 130 | // 131 | // Used for GLSL 120 only. 132 | // 133 | // 1 = GL API supports fast pixel offsets 134 | // 0 = do not use fast pixel offsets 135 | // 136 | #ifdef GL_EXT_gpu_shader4 137 | #define FXAA_FAST_PIXEL_OFFSET 1 138 | #endif 139 | #ifdef GL_NV_gpu_shader5 140 | #define FXAA_FAST_PIXEL_OFFSET 1 141 | #endif 142 | #ifdef GL_ARB_gpu_shader5 143 | #define FXAA_FAST_PIXEL_OFFSET 1 144 | #endif 145 | #ifndef FXAA_FAST_PIXEL_OFFSET 146 | #define FXAA_FAST_PIXEL_OFFSET 0 147 | #endif 148 | #endif 149 | /*--------------------------------------------------------------------------*/ 150 | #ifndef FXAA_GATHER4_ALPHA 151 | // 152 | // 1 = API supports gather4 on alpha channel. 153 | // 0 = API does not support gather4 on alpha channel. 154 | // 155 | #if (FXAA_HLSL_5 == 1) 156 | #define FXAA_GATHER4_ALPHA 1 157 | #endif 158 | #ifdef GL_ARB_gpu_shader5 159 | #define FXAA_GATHER4_ALPHA 1 160 | #endif 161 | #ifdef GL_NV_gpu_shader5 162 | #define FXAA_GATHER4_ALPHA 1 163 | #endif 164 | #ifndef FXAA_GATHER4_ALPHA 165 | #define FXAA_GATHER4_ALPHA 0 166 | #endif 167 | #endif 168 | 169 | 170 | /*============================================================================ 171 | FXAA QUALITY - TUNING KNOBS 172 | ------------------------------------------------------------------------------ 173 | NOTE the other tuning knobs are now in the shader function inputs! 174 | ============================================================================*/ 175 | #ifndef FXAA_QUALITY_PRESET 176 | // 177 | // Choose the quality preset. 178 | // This needs to be compiled into the shader as it effects code. 179 | // Best option to include multiple presets is to 180 | // in each shader define the preset, then include this file. 181 | // 182 | // OPTIONS 183 | // ----------------------------------------------------------------------- 184 | // 10 to 15 - default medium dither (10=fastest, 15=highest quality) 185 | // 20 to 29 - less dither, more expensive (20=fastest, 29=highest quality) 186 | // 39 - no dither, very expensive 187 | // 188 | // NOTES 189 | // ----------------------------------------------------------------------- 190 | // 12 = slightly faster then FXAA 3.9 and higher edge quality (default) 191 | // 13 = about same speed as FXAA 3.9 and better than 12 192 | // 23 = closest to FXAA 3.9 visually and performance wise 193 | // _ = the lowest digit is directly related to performance 194 | // _ = the highest digit is directly related to style 195 | // 196 | #define FXAA_QUALITY_PRESET 12 197 | #endif 198 | 199 | 200 | /*============================================================================ 201 | 202 | FXAA QUALITY - PRESETS 203 | 204 | ============================================================================*/ 205 | 206 | /*============================================================================ 207 | FXAA QUALITY - MEDIUM DITHER PRESETS 208 | ============================================================================*/ 209 | #if (FXAA_QUALITY_PRESET == 10) 210 | #define FXAA_QUALITY_PS 3 211 | #define FXAA_QUALITY_P0 1.5 212 | #define FXAA_QUALITY_P1 3.0 213 | #define FXAA_QUALITY_P2 12.0 214 | #endif 215 | /*--------------------------------------------------------------------------*/ 216 | #if (FXAA_QUALITY_PRESET == 11) 217 | #define FXAA_QUALITY_PS 4 218 | #define FXAA_QUALITY_P0 1.0 219 | #define FXAA_QUALITY_P1 1.5 220 | #define FXAA_QUALITY_P2 3.0 221 | #define FXAA_QUALITY_P3 12.0 222 | #endif 223 | /*--------------------------------------------------------------------------*/ 224 | #if (FXAA_QUALITY_PRESET == 12) 225 | #define FXAA_QUALITY_PS 5 226 | #define FXAA_QUALITY_P0 1.0 227 | #define FXAA_QUALITY_P1 1.5 228 | #define FXAA_QUALITY_P2 2.0 229 | #define FXAA_QUALITY_P3 4.0 230 | #define FXAA_QUALITY_P4 12.0 231 | #endif 232 | /*--------------------------------------------------------------------------*/ 233 | #if (FXAA_QUALITY_PRESET == 13) 234 | #define FXAA_QUALITY_PS 6 235 | #define FXAA_QUALITY_P0 1.0 236 | #define FXAA_QUALITY_P1 1.5 237 | #define FXAA_QUALITY_P2 2.0 238 | #define FXAA_QUALITY_P3 2.0 239 | #define FXAA_QUALITY_P4 4.0 240 | #define FXAA_QUALITY_P5 12.0 241 | #endif 242 | /*--------------------------------------------------------------------------*/ 243 | #if (FXAA_QUALITY_PRESET == 14) 244 | #define FXAA_QUALITY_PS 7 245 | #define FXAA_QUALITY_P0 1.0 246 | #define FXAA_QUALITY_P1 1.5 247 | #define FXAA_QUALITY_P2 2.0 248 | #define FXAA_QUALITY_P3 2.0 249 | #define FXAA_QUALITY_P4 2.0 250 | #define FXAA_QUALITY_P5 4.0 251 | #define FXAA_QUALITY_P6 12.0 252 | #endif 253 | /*--------------------------------------------------------------------------*/ 254 | #if (FXAA_QUALITY_PRESET == 15) 255 | #define FXAA_QUALITY_PS 8 256 | #define FXAA_QUALITY_P0 1.0 257 | #define FXAA_QUALITY_P1 1.5 258 | #define FXAA_QUALITY_P2 2.0 259 | #define FXAA_QUALITY_P3 2.0 260 | #define FXAA_QUALITY_P4 2.0 261 | #define FXAA_QUALITY_P5 2.0 262 | #define FXAA_QUALITY_P6 4.0 263 | #define FXAA_QUALITY_P7 12.0 264 | #endif 265 | 266 | /*============================================================================ 267 | FXAA QUALITY - LOW DITHER PRESETS 268 | ============================================================================*/ 269 | #if (FXAA_QUALITY_PRESET == 20) 270 | #define FXAA_QUALITY_PS 3 271 | #define FXAA_QUALITY_P0 1.5 272 | #define FXAA_QUALITY_P1 2.0 273 | #define FXAA_QUALITY_P2 8.0 274 | #endif 275 | /*--------------------------------------------------------------------------*/ 276 | #if (FXAA_QUALITY_PRESET == 21) 277 | #define FXAA_QUALITY_PS 4 278 | #define FXAA_QUALITY_P0 1.0 279 | #define FXAA_QUALITY_P1 1.5 280 | #define FXAA_QUALITY_P2 2.0 281 | #define FXAA_QUALITY_P3 8.0 282 | #endif 283 | /*--------------------------------------------------------------------------*/ 284 | #if (FXAA_QUALITY_PRESET == 22) 285 | #define FXAA_QUALITY_PS 5 286 | #define FXAA_QUALITY_P0 1.0 287 | #define FXAA_QUALITY_P1 1.5 288 | #define FXAA_QUALITY_P2 2.0 289 | #define FXAA_QUALITY_P3 2.0 290 | #define FXAA_QUALITY_P4 8.0 291 | #endif 292 | /*--------------------------------------------------------------------------*/ 293 | #if (FXAA_QUALITY_PRESET == 23) 294 | #define FXAA_QUALITY_PS 6 295 | #define FXAA_QUALITY_P0 1.0 296 | #define FXAA_QUALITY_P1 1.5 297 | #define FXAA_QUALITY_P2 2.0 298 | #define FXAA_QUALITY_P3 2.0 299 | #define FXAA_QUALITY_P4 2.0 300 | #define FXAA_QUALITY_P5 8.0 301 | #endif 302 | /*--------------------------------------------------------------------------*/ 303 | #if (FXAA_QUALITY_PRESET == 24) 304 | #define FXAA_QUALITY_PS 7 305 | #define FXAA_QUALITY_P0 1.0 306 | #define FXAA_QUALITY_P1 1.5 307 | #define FXAA_QUALITY_P2 2.0 308 | #define FXAA_QUALITY_P3 2.0 309 | #define FXAA_QUALITY_P4 2.0 310 | #define FXAA_QUALITY_P5 3.0 311 | #define FXAA_QUALITY_P6 8.0 312 | #endif 313 | /*--------------------------------------------------------------------------*/ 314 | #if (FXAA_QUALITY_PRESET == 25) 315 | #define FXAA_QUALITY_PS 8 316 | #define FXAA_QUALITY_P0 1.0 317 | #define FXAA_QUALITY_P1 1.5 318 | #define FXAA_QUALITY_P2 2.0 319 | #define FXAA_QUALITY_P3 2.0 320 | #define FXAA_QUALITY_P4 2.0 321 | #define FXAA_QUALITY_P5 2.0 322 | #define FXAA_QUALITY_P6 4.0 323 | #define FXAA_QUALITY_P7 8.0 324 | #endif 325 | /*--------------------------------------------------------------------------*/ 326 | #if (FXAA_QUALITY_PRESET == 26) 327 | #define FXAA_QUALITY_PS 9 328 | #define FXAA_QUALITY_P0 1.0 329 | #define FXAA_QUALITY_P1 1.5 330 | #define FXAA_QUALITY_P2 2.0 331 | #define FXAA_QUALITY_P3 2.0 332 | #define FXAA_QUALITY_P4 2.0 333 | #define FXAA_QUALITY_P5 2.0 334 | #define FXAA_QUALITY_P6 2.0 335 | #define FXAA_QUALITY_P7 4.0 336 | #define FXAA_QUALITY_P8 8.0 337 | #endif 338 | /*--------------------------------------------------------------------------*/ 339 | #if (FXAA_QUALITY_PRESET == 27) 340 | #define FXAA_QUALITY_PS 10 341 | #define FXAA_QUALITY_P0 1.0 342 | #define FXAA_QUALITY_P1 1.5 343 | #define FXAA_QUALITY_P2 2.0 344 | #define FXAA_QUALITY_P3 2.0 345 | #define FXAA_QUALITY_P4 2.0 346 | #define FXAA_QUALITY_P5 2.0 347 | #define FXAA_QUALITY_P6 2.0 348 | #define FXAA_QUALITY_P7 2.0 349 | #define FXAA_QUALITY_P8 4.0 350 | #define FXAA_QUALITY_P9 8.0 351 | #endif 352 | /*--------------------------------------------------------------------------*/ 353 | #if (FXAA_QUALITY_PRESET == 28) 354 | #define FXAA_QUALITY_PS 11 355 | #define FXAA_QUALITY_P0 1.0 356 | #define FXAA_QUALITY_P1 1.5 357 | #define FXAA_QUALITY_P2 2.0 358 | #define FXAA_QUALITY_P3 2.0 359 | #define FXAA_QUALITY_P4 2.0 360 | #define FXAA_QUALITY_P5 2.0 361 | #define FXAA_QUALITY_P6 2.0 362 | #define FXAA_QUALITY_P7 2.0 363 | #define FXAA_QUALITY_P8 2.0 364 | #define FXAA_QUALITY_P9 4.0 365 | #define FXAA_QUALITY_P10 8.0 366 | #endif 367 | /*--------------------------------------------------------------------------*/ 368 | #if (FXAA_QUALITY_PRESET == 29) 369 | #define FXAA_QUALITY_PS 12 370 | #define FXAA_QUALITY_P0 1.0 371 | #define FXAA_QUALITY_P1 1.5 372 | #define FXAA_QUALITY_P2 2.0 373 | #define FXAA_QUALITY_P3 2.0 374 | #define FXAA_QUALITY_P4 2.0 375 | #define FXAA_QUALITY_P5 2.0 376 | #define FXAA_QUALITY_P6 2.0 377 | #define FXAA_QUALITY_P7 2.0 378 | #define FXAA_QUALITY_P8 2.0 379 | #define FXAA_QUALITY_P9 2.0 380 | #define FXAA_QUALITY_P10 4.0 381 | #define FXAA_QUALITY_P11 8.0 382 | #endif 383 | 384 | /*============================================================================ 385 | FXAA QUALITY - EXTREME QUALITY 386 | ============================================================================*/ 387 | #if (FXAA_QUALITY_PRESET == 39) 388 | #define FXAA_QUALITY_PS 12 389 | #define FXAA_QUALITY_P0 1.0 390 | #define FXAA_QUALITY_P1 1.0 391 | #define FXAA_QUALITY_P2 1.0 392 | #define FXAA_QUALITY_P3 1.0 393 | #define FXAA_QUALITY_P4 1.0 394 | #define FXAA_QUALITY_P5 1.5 395 | #define FXAA_QUALITY_P6 2.0 396 | #define FXAA_QUALITY_P7 2.0 397 | #define FXAA_QUALITY_P8 2.0 398 | #define FXAA_QUALITY_P9 2.0 399 | #define FXAA_QUALITY_P10 4.0 400 | #define FXAA_QUALITY_P11 8.0 401 | #endif 402 | 403 | 404 | 405 | /*============================================================================ 406 | 407 | API PORTING 408 | 409 | ============================================================================*/ 410 | #if (FXAA_GLSL_100 == 1) || (FXAA_GLSL_120 == 1) || (FXAA_GLSL_130 == 1) 411 | #define FxaaBool bool 412 | #define FxaaDiscard discard 413 | #define FxaaFloat float 414 | #define FxaaFloat2 vec2 415 | #define FxaaFloat3 vec3 416 | #define FxaaFloat4 vec4 417 | #define FxaaHalf float 418 | #define FxaaHalf2 vec2 419 | #define FxaaHalf3 vec3 420 | #define FxaaHalf4 vec4 421 | #define FxaaInt2 ivec2 422 | #define FxaaSat(x) clamp(x, 0.0, 1.0) 423 | #define FxaaTex sampler2D 424 | #else 425 | #define FxaaBool bool 426 | #define FxaaDiscard clip(-1) 427 | #define FxaaFloat float 428 | #define FxaaFloat2 float2 429 | #define FxaaFloat3 float3 430 | #define FxaaFloat4 float4 431 | #define FxaaHalf half 432 | #define FxaaHalf2 half2 433 | #define FxaaHalf3 half3 434 | #define FxaaHalf4 half4 435 | #define FxaaSat(x) saturate(x) 436 | #endif 437 | /*--------------------------------------------------------------------------*/ 438 | #if (FXAA_GLSL_100 == 1) 439 | #define FxaaTexTop(t, p) texture2D(t, p, 0.0) 440 | #define FxaaTexOff(t, p, o, r) texture2D(t, p + (o * r), 0.0) 441 | #endif 442 | /*--------------------------------------------------------------------------*/ 443 | #if (FXAA_GLSL_120 == 1) 444 | // Requires, 445 | // #version 120 446 | // And at least, 447 | // #extension GL_EXT_gpu_shader4 : enable 448 | // (or set FXAA_FAST_PIXEL_OFFSET 1 to work like DX9) 449 | #define FxaaTexTop(t, p) texture2DLod(t, p, 0.0) 450 | #if (FXAA_FAST_PIXEL_OFFSET == 1) 451 | #define FxaaTexOff(t, p, o, r) texture2DLodOffset(t, p, 0.0, o) 452 | #else 453 | #define FxaaTexOff(t, p, o, r) texture2DLod(t, p + (o * r), 0.0) 454 | #endif 455 | #if (FXAA_GATHER4_ALPHA == 1) 456 | // use #extension GL_ARB_gpu_shader5 : enable 457 | #define FxaaTexAlpha4(t, p) textureGather(t, p, 3) 458 | #define FxaaTexOffAlpha4(t, p, o) textureGatherOffset(t, p, o, 3) 459 | #define FxaaTexGreen4(t, p) textureGather(t, p, 1) 460 | #define FxaaTexOffGreen4(t, p, o) textureGatherOffset(t, p, o, 1) 461 | #endif 462 | #endif 463 | /*--------------------------------------------------------------------------*/ 464 | #if (FXAA_GLSL_130 == 1) 465 | // Requires \#version 130\ or better 466 | #define FxaaTexTop(t, p) textureLod(t, p, 0.0) 467 | #define FxaaTexOff(t, p, o, r) textureLodOffset(t, p, 0.0, o) 468 | #if (FXAA_GATHER4_ALPHA == 1) 469 | // use #extension GL_ARB_gpu_shader5 : enable 470 | #define FxaaTexAlpha4(t, p) textureGather(t, p, 3) 471 | #define FxaaTexOffAlpha4(t, p, o) textureGatherOffset(t, p, o, 3) 472 | #define FxaaTexGreen4(t, p) textureGather(t, p, 1) 473 | #define FxaaTexOffGreen4(t, p, o) textureGatherOffset(t, p, o, 1) 474 | #endif 475 | #endif 476 | /*--------------------------------------------------------------------------*/ 477 | #if (FXAA_HLSL_3 == 1) 478 | #define FxaaInt2 float2 479 | #define FxaaTex sampler2D 480 | #define FxaaTexTop(t, p) tex2Dlod(t, float4(p, 0.0, 0.0)) 481 | #define FxaaTexOff(t, p, o, r) tex2Dlod(t, float4(p + (o * r), 0, 0)) 482 | #endif 483 | /*--------------------------------------------------------------------------*/ 484 | #if (FXAA_HLSL_4 == 1) 485 | #define FxaaInt2 int2 486 | struct FxaaTex { SamplerState smpl; Texture2D tex; }; 487 | #define FxaaTexTop(t, p) t.tex.SampleLevel(t.smpl, p, 0.0) 488 | #define FxaaTexOff(t, p, o, r) t.tex.SampleLevel(t.smpl, p, 0.0, o) 489 | #endif 490 | /*--------------------------------------------------------------------------*/ 491 | #if (FXAA_HLSL_5 == 1) 492 | #define FxaaInt2 int2 493 | struct FxaaTex { SamplerState smpl; Texture2D tex; }; 494 | #define FxaaTexTop(t, p) t.tex.SampleLevel(t.smpl, p, 0.0) 495 | #define FxaaTexOff(t, p, o, r) t.tex.SampleLevel(t.smpl, p, 0.0, o) 496 | #define FxaaTexAlpha4(t, p) t.tex.GatherAlpha(t.smpl, p) 497 | #define FxaaTexOffAlpha4(t, p, o) t.tex.GatherAlpha(t.smpl, p, o) 498 | #define FxaaTexGreen4(t, p) t.tex.GatherGreen(t.smpl, p) 499 | #define FxaaTexOffGreen4(t, p, o) t.tex.GatherGreen(t.smpl, p, o) 500 | #endif 501 | 502 | 503 | /*============================================================================ 504 | GREEN AS LUMA OPTION SUPPORT FUNCTION 505 | ============================================================================*/ 506 | #if (FXAA_GREEN_AS_LUMA == 0) 507 | FxaaFloat FxaaLuma(FxaaFloat4 rgba) { return rgba.w; } 508 | #else 509 | FxaaFloat FxaaLuma(FxaaFloat4 rgba) { return rgba.y; } 510 | #endif 511 | 512 | 513 | 514 | 515 | /*============================================================================ 516 | 517 | FXAA3 QUALITY - PC 518 | 519 | ============================================================================*/ 520 | #if (FXAA_PC == 1) 521 | /*--------------------------------------------------------------------------*/ 522 | FxaaFloat4 FxaaPixelShader( 523 | // 524 | // Use noperspective interpolation here (turn off perspective interpolation). 525 | // {xy} = center of pixel 526 | FxaaFloat2 pos, 527 | // 528 | // Used only for FXAA Console, and not used on the 360 version. 529 | // Use noperspective interpolation here (turn off perspective interpolation). 530 | // {xy_} = upper left of pixel 531 | // {_zw} = lower right of pixel 532 | FxaaFloat4 fxaaConsolePosPos, 533 | // 534 | // Input color texture. 535 | // {rgb_} = color in linear or perceptual color space 536 | // if (FXAA_GREEN_AS_LUMA == 0) 537 | // {__a} = luma in perceptual color space (not linear) 538 | FxaaTex tex, 539 | // 540 | // Only used on the optimized 360 version of FXAA Console. 541 | // For everything but 360, just use the same input here as for \tex\. 542 | // For 360, same texture, just alias with a 2nd sampler. 543 | // This sampler needs to have an exponent bias of -1. 544 | FxaaTex fxaaConsole360TexExpBiasNegOne, 545 | // 546 | // Only used on the optimized 360 version of FXAA Console. 547 | // For everything but 360, just use the same input here as for \tex\. 548 | // For 360, same texture, just alias with a 3nd sampler. 549 | // This sampler needs to have an exponent bias of -2. 550 | FxaaTex fxaaConsole360TexExpBiasNegTwo, 551 | // 552 | // Only used on FXAA Quality. 553 | // This must be from a constant/uniform. 554 | // {x_} = 1.0/screenWidthInPixels 555 | // {_y} = 1.0/screenHeightInPixels 556 | FxaaFloat2 fxaaQualityRcpFrame, 557 | // 558 | // Only used on FXAA Console. 559 | // This must be from a constant/uniform. 560 | // This effects sub-pixel AA quality and inversely sharpness. 561 | // Where N ranges between, 562 | // N = 0.50 (default) 563 | // N = 0.33 (sharper) 564 | // {x__} = -N/screenWidthInPixels 565 | // {_y_} = -N/screenHeightInPixels 566 | // {_z_} = N/screenWidthInPixels 567 | // {__w} = N/screenHeightInPixels 568 | FxaaFloat4 fxaaConsoleRcpFrameOpt, 569 | // 570 | // Only used on FXAA Console. 571 | // Not used on 360, but used on PS3 and PC. 572 | // This must be from a constant/uniform. 573 | // {x__} = -2.0/screenWidthInPixels 574 | // {_y_} = -2.0/screenHeightInPixels 575 | // {_z_} = 2.0/screenWidthInPixels 576 | // {__w} = 2.0/screenHeightInPixels 577 | FxaaFloat4 fxaaConsoleRcpFrameOpt2, 578 | // 579 | // Only used on FXAA Console. 580 | // Only used on 360 in place of fxaaConsoleRcpFrameOpt2. 581 | // This must be from a constant/uniform. 582 | // {x__} = 8.0/screenWidthInPixels 583 | // {_y_} = 8.0/screenHeightInPixels 584 | // {_z_} = -4.0/screenWidthInPixels 585 | // {__w} = -4.0/screenHeightInPixels 586 | FxaaFloat4 fxaaConsole360RcpFrameOpt2, 587 | // 588 | // Only used on FXAA Quality. 589 | // This used to be the FXAA_QUALITY_SUBPIX define. 590 | // It is here now to allow easier tuning. 591 | // Choose the amount of sub-pixel aliasing removal. 592 | // This can effect sharpness. 593 | // 1.00 - upper limit (softer) 594 | // 0.75 - default amount of filtering 595 | // 0.50 - lower limit (sharper, less sub-pixel aliasing removal) 596 | // 0.25 - almost off 597 | // 0.00 - completely off 598 | FxaaFloat fxaaQualitySubpix, 599 | // 600 | // Only used on FXAA Quality. 601 | // This used to be the FXAA_QUALITY_EDGE_THRESHOLD define. 602 | // It is here now to allow easier tuning. 603 | // The minimum amount of local contrast required to apply algorithm. 604 | // 0.333 - too little (faster) 605 | // 0.250 - low quality 606 | // 0.166 - default 607 | // 0.125 - high quality 608 | // 0.063 - overkill (slower) 609 | FxaaFloat fxaaQualityEdgeThreshold, 610 | // 611 | // Only used on FXAA Quality. 612 | // This used to be the FXAA_QUALITY_EDGE_THRESHOLD_MIN define. 613 | // It is here now to allow easier tuning. 614 | // Trims the algorithm from processing darks. 615 | // 0.0833 - upper limit (default, the start of visible unfiltered edges) 616 | // 0.0625 - high quality (faster) 617 | // 0.0312 - visible limit (slower) 618 | // Special notes when using FXAA_GREEN_AS_LUMA, 619 | // Likely want to set this to zero. 620 | // As colors that are mostly not-green 621 | // will appear very dark in the green channel! 622 | // Tune by looking at mostly non-green content, 623 | // then start at zero and increase until aliasing is a problem. 624 | FxaaFloat fxaaQualityEdgeThresholdMin, 625 | // 626 | // Only used on FXAA Console. 627 | // This used to be the FXAA_CONSOLE_EDGE_SHARPNESS define. 628 | // It is here now to allow easier tuning. 629 | // This does not effect PS3, as this needs to be compiled in. 630 | // Use FXAA_CONSOLE_PS3_EDGE_SHARPNESS for PS3. 631 | // Due to the PS3 being ALU bound, 632 | // there are only three safe values here: 2 and 4 and 8. 633 | // These options use the shaders ability to a free *|/ by 2|4|8. 634 | // For all other platforms can be a non-power of two. 635 | // 8.0 is sharper (default!!!) 636 | // 4.0 is softer 637 | // 2.0 is really soft (good only for vector graphics inputs) 638 | FxaaFloat fxaaConsoleEdgeSharpness, 639 | // 640 | // Only used on FXAA Console. 641 | // This used to be the FXAA_CONSOLE_EDGE_THRESHOLD define. 642 | // It is here now to allow easier tuning. 643 | // This does not effect PS3, as this needs to be compiled in. 644 | // Use FXAA_CONSOLE_PS3_EDGE_THRESHOLD for PS3. 645 | // Due to the PS3 being ALU bound, 646 | // there are only two safe values here: 1/4 and 1/8. 647 | // These options use the shaders ability to a free *|/ by 2|4|8. 648 | // The console setting has a different mapping than the quality setting. 649 | // Other platforms can use other values. 650 | // 0.125 leaves less aliasing, but is softer (default!!!) 651 | // 0.25 leaves more aliasing, and is sharper 652 | FxaaFloat fxaaConsoleEdgeThreshold, 653 | // 654 | // Only used on FXAA Console. 655 | // This used to be the FXAA_CONSOLE_EDGE_THRESHOLD_MIN define. 656 | // It is here now to allow easier tuning. 657 | // Trims the algorithm from processing darks. 658 | // The console setting has a different mapping than the quality setting. 659 | // This only applies when FXAA_EARLY_EXIT is 1. 660 | // This does not apply to PS3, 661 | // PS3 was simplified to avoid more shader instructions. 662 | // 0.06 - faster but more aliasing in darks 663 | // 0.05 - default 664 | // 0.04 - slower and less aliasing in darks 665 | // Special notes when using FXAA_GREEN_AS_LUMA, 666 | // Likely want to set this to zero. 667 | // As colors that are mostly not-green 668 | // will appear very dark in the green channel! 669 | // Tune by looking at mostly non-green content, 670 | // then start at zero and increase until aliasing is a problem. 671 | FxaaFloat fxaaConsoleEdgeThresholdMin, 672 | // 673 | // Extra constants for 360 FXAA Console only. 674 | // Use zeros or anything else for other platforms. 675 | // These must be in physical constant registers and NOT immediates. 676 | // Immediates will result in compiler un-optimizing. 677 | // {xyzw} = float4(1.0, -1.0, 0.25, -0.25) 678 | FxaaFloat4 fxaaConsole360ConstDir 679 | ) { 680 | /*--------------------------------------------------------------------------*/ 681 | FxaaFloat2 posM; 682 | posM.x = pos.x; 683 | posM.y = pos.y; 684 | #if (FXAA_GATHER4_ALPHA == 1) 685 | #if (FXAA_DISCARD == 0) 686 | FxaaFloat4 rgbyM = FxaaTexTop(tex, posM); 687 | #if (FXAA_GREEN_AS_LUMA == 0) 688 | #define lumaM rgbyM.w 689 | #else 690 | #define lumaM rgbyM.y 691 | #endif 692 | #endif 693 | #if (FXAA_GREEN_AS_LUMA == 0) 694 | FxaaFloat4 luma4A = FxaaTexAlpha4(tex, posM); 695 | FxaaFloat4 luma4B = FxaaTexOffAlpha4(tex, posM, FxaaInt2(-1, -1)); 696 | #else 697 | FxaaFloat4 luma4A = FxaaTexGreen4(tex, posM); 698 | FxaaFloat4 luma4B = FxaaTexOffGreen4(tex, posM, FxaaInt2(-1, -1)); 699 | #endif 700 | #if (FXAA_DISCARD == 1) 701 | #define lumaM luma4A.w 702 | #endif 703 | #define lumaE luma4A.z 704 | #define lumaS luma4A.x 705 | #define lumaSE luma4A.y 706 | #define lumaNW luma4B.w 707 | #define lumaN luma4B.z 708 | #define lumaW luma4B.x 709 | #else 710 | FxaaFloat4 rgbyM = FxaaTexTop(tex, posM); 711 | #if (FXAA_GREEN_AS_LUMA == 0) 712 | #define lumaM rgbyM.w 713 | #else 714 | #define lumaM rgbyM.y 715 | #endif 716 | #if (FXAA_GLSL_100 == 1) 717 | FxaaFloat lumaS = FxaaLuma(FxaaTexOff(tex, posM, FxaaFloat2( 0.0, 1.0), fxaaQualityRcpFrame.xy)); 718 | FxaaFloat lumaE = FxaaLuma(FxaaTexOff(tex, posM, FxaaFloat2( 1.0, 0.0), fxaaQualityRcpFrame.xy)); 719 | FxaaFloat lumaN = FxaaLuma(FxaaTexOff(tex, posM, FxaaFloat2( 0.0,-1.0), fxaaQualityRcpFrame.xy)); 720 | FxaaFloat lumaW = FxaaLuma(FxaaTexOff(tex, posM, FxaaFloat2(-1.0, 0.0), fxaaQualityRcpFrame.xy)); 721 | #else 722 | FxaaFloat lumaS = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 0, 1), fxaaQualityRcpFrame.xy)); 723 | FxaaFloat lumaE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1, 0), fxaaQualityRcpFrame.xy)); 724 | FxaaFloat lumaN = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 0,-1), fxaaQualityRcpFrame.xy)); 725 | FxaaFloat lumaW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 0), fxaaQualityRcpFrame.xy)); 726 | #endif 727 | #endif 728 | /*--------------------------------------------------------------------------*/ 729 | FxaaFloat maxSM = max(lumaS, lumaM); 730 | FxaaFloat minSM = min(lumaS, lumaM); 731 | FxaaFloat maxESM = max(lumaE, maxSM); 732 | FxaaFloat minESM = min(lumaE, minSM); 733 | FxaaFloat maxWN = max(lumaN, lumaW); 734 | FxaaFloat minWN = min(lumaN, lumaW); 735 | FxaaFloat rangeMax = max(maxWN, maxESM); 736 | FxaaFloat rangeMin = min(minWN, minESM); 737 | FxaaFloat rangeMaxScaled = rangeMax * fxaaQualityEdgeThreshold; 738 | FxaaFloat range = rangeMax - rangeMin; 739 | FxaaFloat rangeMaxClamped = max(fxaaQualityEdgeThresholdMin, rangeMaxScaled); 740 | FxaaBool earlyExit = range < rangeMaxClamped; 741 | /*--------------------------------------------------------------------------*/ 742 | if(earlyExit) 743 | #if (FXAA_DISCARD == 1) 744 | FxaaDiscard; 745 | #else 746 | return rgbyM; 747 | #endif 748 | /*--------------------------------------------------------------------------*/ 749 | #if (FXAA_GATHER4_ALPHA == 0) 750 | #if (FXAA_GLSL_100 == 1) 751 | FxaaFloat lumaNW = FxaaLuma(FxaaTexOff(tex, posM, FxaaFloat2(-1.0,-1.0), fxaaQualityRcpFrame.xy)); 752 | FxaaFloat lumaSE = FxaaLuma(FxaaTexOff(tex, posM, FxaaFloat2( 1.0, 1.0), fxaaQualityRcpFrame.xy)); 753 | FxaaFloat lumaNE = FxaaLuma(FxaaTexOff(tex, posM, FxaaFloat2( 1.0,-1.0), fxaaQualityRcpFrame.xy)); 754 | FxaaFloat lumaSW = FxaaLuma(FxaaTexOff(tex, posM, FxaaFloat2(-1.0, 1.0), fxaaQualityRcpFrame.xy)); 755 | #else 756 | FxaaFloat lumaNW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1,-1), fxaaQualityRcpFrame.xy)); 757 | FxaaFloat lumaSE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1, 1), fxaaQualityRcpFrame.xy)); 758 | FxaaFloat lumaNE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1,-1), fxaaQualityRcpFrame.xy)); 759 | FxaaFloat lumaSW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 1), fxaaQualityRcpFrame.xy)); 760 | #endif 761 | #else 762 | FxaaFloat lumaNE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(1, -1), fxaaQualityRcpFrame.xy)); 763 | FxaaFloat lumaSW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 1), fxaaQualityRcpFrame.xy)); 764 | #endif 765 | /*--------------------------------------------------------------------------*/ 766 | FxaaFloat lumaNS = lumaN + lumaS; 767 | FxaaFloat lumaWE = lumaW + lumaE; 768 | FxaaFloat subpixRcpRange = 1.0/range; 769 | FxaaFloat subpixNSWE = lumaNS + lumaWE; 770 | FxaaFloat edgeHorz1 = (-2.0 * lumaM) + lumaNS; 771 | FxaaFloat edgeVert1 = (-2.0 * lumaM) + lumaWE; 772 | /*--------------------------------------------------------------------------*/ 773 | FxaaFloat lumaNESE = lumaNE + lumaSE; 774 | FxaaFloat lumaNWNE = lumaNW + lumaNE; 775 | FxaaFloat edgeHorz2 = (-2.0 * lumaE) + lumaNESE; 776 | FxaaFloat edgeVert2 = (-2.0 * lumaN) + lumaNWNE; 777 | /*--------------------------------------------------------------------------*/ 778 | FxaaFloat lumaNWSW = lumaNW + lumaSW; 779 | FxaaFloat lumaSWSE = lumaSW + lumaSE; 780 | FxaaFloat edgeHorz4 = (abs(edgeHorz1) * 2.0) + abs(edgeHorz2); 781 | FxaaFloat edgeVert4 = (abs(edgeVert1) * 2.0) + abs(edgeVert2); 782 | FxaaFloat edgeHorz3 = (-2.0 * lumaW) + lumaNWSW; 783 | FxaaFloat edgeVert3 = (-2.0 * lumaS) + lumaSWSE; 784 | FxaaFloat edgeHorz = abs(edgeHorz3) + edgeHorz4; 785 | FxaaFloat edgeVert = abs(edgeVert3) + edgeVert4; 786 | /*--------------------------------------------------------------------------*/ 787 | FxaaFloat subpixNWSWNESE = lumaNWSW + lumaNESE; 788 | FxaaFloat lengthSign = fxaaQualityRcpFrame.x; 789 | FxaaBool horzSpan = edgeHorz >= edgeVert; 790 | FxaaFloat subpixA = subpixNSWE * 2.0 + subpixNWSWNESE; 791 | /*--------------------------------------------------------------------------*/ 792 | if(!horzSpan) lumaN = lumaW; 793 | if(!horzSpan) lumaS = lumaE; 794 | if(horzSpan) lengthSign = fxaaQualityRcpFrame.y; 795 | FxaaFloat subpixB = (subpixA * (1.0/12.0)) - lumaM; 796 | /*--------------------------------------------------------------------------*/ 797 | FxaaFloat gradientN = lumaN - lumaM; 798 | FxaaFloat gradientS = lumaS - lumaM; 799 | FxaaFloat lumaNN = lumaN + lumaM; 800 | FxaaFloat lumaSS = lumaS + lumaM; 801 | FxaaBool pairN = abs(gradientN) >= abs(gradientS); 802 | FxaaFloat gradient = max(abs(gradientN), abs(gradientS)); 803 | if(pairN) lengthSign = -lengthSign; 804 | FxaaFloat subpixC = FxaaSat(abs(subpixB) * subpixRcpRange); 805 | /*--------------------------------------------------------------------------*/ 806 | FxaaFloat2 posB; 807 | posB.x = posM.x; 808 | posB.y = posM.y; 809 | FxaaFloat2 offNP; 810 | offNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x; 811 | offNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y; 812 | if(!horzSpan) posB.x += lengthSign * 0.5; 813 | if( horzSpan) posB.y += lengthSign * 0.5; 814 | /*--------------------------------------------------------------------------*/ 815 | FxaaFloat2 posN; 816 | posN.x = posB.x - offNP.x * FXAA_QUALITY_P0; 817 | posN.y = posB.y - offNP.y * FXAA_QUALITY_P0; 818 | FxaaFloat2 posP; 819 | posP.x = posB.x + offNP.x * FXAA_QUALITY_P0; 820 | posP.y = posB.y + offNP.y * FXAA_QUALITY_P0; 821 | FxaaFloat subpixD = ((-2.0)*subpixC) + 3.0; 822 | FxaaFloat lumaEndN = FxaaLuma(FxaaTexTop(tex, posN)); 823 | FxaaFloat subpixE = subpixC * subpixC; 824 | FxaaFloat lumaEndP = FxaaLuma(FxaaTexTop(tex, posP)); 825 | /*--------------------------------------------------------------------------*/ 826 | if(!pairN) lumaNN = lumaSS; 827 | FxaaFloat gradientScaled = gradient * 1.0/4.0; 828 | FxaaFloat lumaMM = lumaM - lumaNN * 0.5; 829 | FxaaFloat subpixF = subpixD * subpixE; 830 | FxaaBool lumaMLTZero = lumaMM < 0.0; 831 | /*--------------------------------------------------------------------------*/ 832 | lumaEndN -= lumaNN * 0.5; 833 | lumaEndP -= lumaNN * 0.5; 834 | FxaaBool doneN = abs(lumaEndN) >= gradientScaled; 835 | FxaaBool doneP = abs(lumaEndP) >= gradientScaled; 836 | if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P1; 837 | if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P1; 838 | FxaaBool doneNP = (!doneN) || (!doneP); 839 | if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P1; 840 | if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P1; 841 | /*--------------------------------------------------------------------------*/ 842 | if(doneNP) { 843 | if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); 844 | if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); 845 | if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; 846 | if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; 847 | doneN = abs(lumaEndN) >= gradientScaled; 848 | doneP = abs(lumaEndP) >= gradientScaled; 849 | if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P2; 850 | if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P2; 851 | doneNP = (!doneN) || (!doneP); 852 | if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P2; 853 | if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P2; 854 | /*--------------------------------------------------------------------------*/ 855 | #if (FXAA_QUALITY_PS > 3) 856 | if(doneNP) { 857 | if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); 858 | if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); 859 | if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; 860 | if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; 861 | doneN = abs(lumaEndN) >= gradientScaled; 862 | doneP = abs(lumaEndP) >= gradientScaled; 863 | if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P3; 864 | if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P3; 865 | doneNP = (!doneN) || (!doneP); 866 | if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P3; 867 | if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P3; 868 | /*--------------------------------------------------------------------------*/ 869 | #if (FXAA_QUALITY_PS > 4) 870 | if(doneNP) { 871 | if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); 872 | if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); 873 | if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; 874 | if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; 875 | doneN = abs(lumaEndN) >= gradientScaled; 876 | doneP = abs(lumaEndP) >= gradientScaled; 877 | if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P4; 878 | if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P4; 879 | doneNP = (!doneN) || (!doneP); 880 | if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P4; 881 | if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P4; 882 | /*--------------------------------------------------------------------------*/ 883 | #if (FXAA_QUALITY_PS > 5) 884 | if(doneNP) { 885 | if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); 886 | if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); 887 | if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; 888 | if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; 889 | doneN = abs(lumaEndN) >= gradientScaled; 890 | doneP = abs(lumaEndP) >= gradientScaled; 891 | if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P5; 892 | if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P5; 893 | doneNP = (!doneN) || (!doneP); 894 | if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P5; 895 | if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P5; 896 | /*--------------------------------------------------------------------------*/ 897 | #if (FXAA_QUALITY_PS > 6) 898 | if(doneNP) { 899 | if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); 900 | if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); 901 | if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; 902 | if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; 903 | doneN = abs(lumaEndN) >= gradientScaled; 904 | doneP = abs(lumaEndP) >= gradientScaled; 905 | if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P6; 906 | if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P6; 907 | doneNP = (!doneN) || (!doneP); 908 | if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P6; 909 | if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P6; 910 | /*--------------------------------------------------------------------------*/ 911 | #if (FXAA_QUALITY_PS > 7) 912 | if(doneNP) { 913 | if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); 914 | if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); 915 | if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; 916 | if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; 917 | doneN = abs(lumaEndN) >= gradientScaled; 918 | doneP = abs(lumaEndP) >= gradientScaled; 919 | if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P7; 920 | if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P7; 921 | doneNP = (!doneN) || (!doneP); 922 | if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P7; 923 | if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P7; 924 | /*--------------------------------------------------------------------------*/ 925 | #if (FXAA_QUALITY_PS > 8) 926 | if(doneNP) { 927 | if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); 928 | if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); 929 | if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; 930 | if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; 931 | doneN = abs(lumaEndN) >= gradientScaled; 932 | doneP = abs(lumaEndP) >= gradientScaled; 933 | if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P8; 934 | if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P8; 935 | doneNP = (!doneN) || (!doneP); 936 | if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P8; 937 | if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P8; 938 | /*--------------------------------------------------------------------------*/ 939 | #if (FXAA_QUALITY_PS > 9) 940 | if(doneNP) { 941 | if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); 942 | if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); 943 | if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; 944 | if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; 945 | doneN = abs(lumaEndN) >= gradientScaled; 946 | doneP = abs(lumaEndP) >= gradientScaled; 947 | if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P9; 948 | if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P9; 949 | doneNP = (!doneN) || (!doneP); 950 | if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P9; 951 | if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P9; 952 | /*--------------------------------------------------------------------------*/ 953 | #if (FXAA_QUALITY_PS > 10) 954 | if(doneNP) { 955 | if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); 956 | if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); 957 | if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; 958 | if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; 959 | doneN = abs(lumaEndN) >= gradientScaled; 960 | doneP = abs(lumaEndP) >= gradientScaled; 961 | if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P10; 962 | if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P10; 963 | doneNP = (!doneN) || (!doneP); 964 | if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P10; 965 | if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P10; 966 | /*--------------------------------------------------------------------------*/ 967 | #if (FXAA_QUALITY_PS > 11) 968 | if(doneNP) { 969 | if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); 970 | if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); 971 | if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; 972 | if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; 973 | doneN = abs(lumaEndN) >= gradientScaled; 974 | doneP = abs(lumaEndP) >= gradientScaled; 975 | if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P11; 976 | if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P11; 977 | doneNP = (!doneN) || (!doneP); 978 | if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P11; 979 | if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P11; 980 | /*--------------------------------------------------------------------------*/ 981 | #if (FXAA_QUALITY_PS > 12) 982 | if(doneNP) { 983 | if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); 984 | if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); 985 | if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; 986 | if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; 987 | doneN = abs(lumaEndN) >= gradientScaled; 988 | doneP = abs(lumaEndP) >= gradientScaled; 989 | if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P12; 990 | if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P12; 991 | doneNP = (!doneN) || (!doneP); 992 | if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P12; 993 | if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P12; 994 | /*--------------------------------------------------------------------------*/ 995 | } 996 | #endif 997 | /*--------------------------------------------------------------------------*/ 998 | } 999 | #endif 1000 | /*--------------------------------------------------------------------------*/ 1001 | } 1002 | #endif 1003 | /*--------------------------------------------------------------------------*/ 1004 | } 1005 | #endif 1006 | /*--------------------------------------------------------------------------*/ 1007 | } 1008 | #endif 1009 | /*--------------------------------------------------------------------------*/ 1010 | } 1011 | #endif 1012 | /*--------------------------------------------------------------------------*/ 1013 | } 1014 | #endif 1015 | /*--------------------------------------------------------------------------*/ 1016 | } 1017 | #endif 1018 | /*--------------------------------------------------------------------------*/ 1019 | } 1020 | #endif 1021 | /*--------------------------------------------------------------------------*/ 1022 | } 1023 | #endif 1024 | /*--------------------------------------------------------------------------*/ 1025 | } 1026 | /*--------------------------------------------------------------------------*/ 1027 | FxaaFloat dstN = posM.x - posN.x; 1028 | FxaaFloat dstP = posP.x - posM.x; 1029 | if(!horzSpan) dstN = posM.y - posN.y; 1030 | if(!horzSpan) dstP = posP.y - posM.y; 1031 | /*--------------------------------------------------------------------------*/ 1032 | FxaaBool goodSpanN = (lumaEndN < 0.0) != lumaMLTZero; 1033 | FxaaFloat spanLength = (dstP + dstN); 1034 | FxaaBool goodSpanP = (lumaEndP < 0.0) != lumaMLTZero; 1035 | FxaaFloat spanLengthRcp = 1.0/spanLength; 1036 | /*--------------------------------------------------------------------------*/ 1037 | FxaaBool directionN = dstN < dstP; 1038 | FxaaFloat dst = min(dstN, dstP); 1039 | FxaaBool goodSpan = directionN ? goodSpanN : goodSpanP; 1040 | FxaaFloat subpixG = subpixF * subpixF; 1041 | FxaaFloat pixelOffset = (dst * (-spanLengthRcp)) + 0.5; 1042 | FxaaFloat subpixH = subpixG * fxaaQualitySubpix; 1043 | /*--------------------------------------------------------------------------*/ 1044 | FxaaFloat pixelOffsetGood = goodSpan ? pixelOffset : 0.0; 1045 | FxaaFloat pixelOffsetSubpix = max(pixelOffsetGood, subpixH); 1046 | if(!horzSpan) posM.x += pixelOffsetSubpix * lengthSign; 1047 | if( horzSpan) posM.y += pixelOffsetSubpix * lengthSign; 1048 | #if (FXAA_DISCARD == 1) 1049 | return FxaaTexTop(tex, posM); 1050 | #else 1051 | return FxaaFloat4(FxaaTexTop(tex, posM).xyz, lumaM); 1052 | #endif 1053 | } 1054 | /*==========================================================================*/ 1055 | #endif 1056 | 1057 | void main() { 1058 | gl_FragColor = FxaaPixelShader( 1059 | vUv, 1060 | vec4(0.0), 1061 | tDiffuse, 1062 | tDiffuse, 1063 | tDiffuse, 1064 | resolution, 1065 | vec4(0.0), 1066 | vec4(0.0), 1067 | vec4(0.0), 1068 | 0.75, 1069 | 0.166, 1070 | 0.0833, 1071 | 0.0, 1072 | 0.0, 1073 | 0.0, 1074 | vec4(0.0) 1075 | ); 1076 | 1077 | // TODO avoid querying texture twice for same texel 1078 | gl_FragColor.a = texture2D(tDiffuse, vUv).a; 1079 | } --------------------------------------------------------------------------------