├── .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 | [](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 | }
--------------------------------------------------------------------------------