add anaglyph effect

This commit is contained in:
casperlamboo 2018-01-10 12:21:14 +01:00
parent 834ca531fd
commit 87acf98f51
8 changed files with 165 additions and 38 deletions

View File

@ -0,0 +1,36 @@
uniform sampler2D mapLeft;
uniform sampler2D mapRight;
varying vec2 vUv;
uniform mat3 colorMatrixLeft;
uniform mat3 colorMatrixRight;
float lin( float c ) {
return c <= 0.04045 ? c * 0.0773993808 :
pow( c * 0.9478672986 + 0.0521327014, 2.4 );
}
vec4 lin( vec4 c ) {
return vec4( lin( c.r ), lin( c.g ), lin( c.b ), c.a );
}
float dev( float c ) {
return c <= 0.0031308 ? c * 12.92 : pow( c, 0.41666 ) * 1.055 - 0.055;
}
void main() {
vec2 uv = vUv;
vec4 colorL = lin( texture2D( mapLeft, uv ) );
vec4 colorR = lin( texture2D( mapRight, uv ) );
vec3 color = clamp(
colorMatrixLeft * colorL.rgb +
colorMatrixRight * colorR.rgb, 0., 1. );
gl_FragColor = vec4(
dev( color.r ), dev( color.g ), dev( color.b ),
max( colorL.a, colorR.a ) );
}

View File

@ -0,0 +1,5 @@
varying vec2 vUv;
void main() {
vUv = vec2( uv.x, uv.y );
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}

View File

@ -16,7 +16,7 @@ import TwistTransformer from '../d3/transformers/TwistTransformer.js';
import SculptTransformer from '../d3/transformers/SculptTransformer.js';
import StampTransformer from '../d3/transformers/StampTransformer.js';
import SelectionBox from '../d3/SelectionBox.js';
import RenderChain from '../d3/RenderChain';
import RenderChain, { TOONSHADER_OUTLINE, TOONSHADER } from '../d3/RenderChain';
import BaseTransformer from '../d3/transformers/BaseTransformer.js';
import Camera from '../d3/Camera.js';
import ReactResizeDetector from 'react-resize-detector';
@ -62,8 +62,8 @@ class D3Panel extends React.Component {
componentWillMount() {
this.createScene();
const toonShader = hasExtensionsFor.toonShaderPreview;
this.renderChain = new RenderChain(this.renderer, this.scene, this.camera, toonShader, {
const shader = hasExtensionsFor.toonShaderPreview ? TOONSHADER_OUTLINE : TOONSHADER;
this.renderChain = new RenderChain(this.renderer, this.scene, this.camera, shader, {
UI: this.UIContainer,
shapes: this.shapesManager,
boundingBox: this.selectionBox,

71
src/d3/RenderChain.js vendored
View File

@ -1,43 +1,62 @@
import * as THREE from 'three';
import OutlinePass from './OutlinePass.js';
import RenderPass from './RenderPass.js';
import OutlinePass from './effects/OutlinePass.js';
import RenderPass from './effects/RenderPass.js';
import AnaglyphPass from './effects/AnaglyphPass.js';
import 'three/examples/js/shaders/CopyShader.js';
import 'three/examples/js/postprocessing/EffectComposer.js';
import 'three/examples/js/postprocessing/ShaderPass.js';
export const TOONSHADER_OUTLINE = 'toonshader-outline';
export const ANAGLYPH = 'anaglyph';
export const TOONSHADER = 'toonshader';
export default class RenderChain extends THREE.EffectComposer {
constructor(renderer, scene, camera, toonShader, groups) {
constructor(renderer, scene, camera, shader, groups) {
super(renderer);
this._groups = groups;
if (toonShader) {
const renderPass = new RenderPass(scene, camera, () => {
this._setVisible(this._initalValues, [groups.shapes, groups.plane, groups.boundingBox]);
});
this.addPass(renderPass);
switch (shader) {
case TOONSHADER_OUTLINE: {
const renderPass = new RenderPass(scene, camera, () => {
this._setVisible(this._initalValues, [groups.shapes, groups.plane, groups.boundingBox]);
});
this.addPass(renderPass);
const outlinePass = new OutlinePass(scene, camera, () => {
this._setVisible(this._initalValues, [groups.shapes]);
});
outlinePass.renderToScreen = true;
this.addPass(outlinePass);
const outlinePass = new OutlinePass(scene, camera, () => {
this._setVisible(this._initalValues, [groups.shapes]);
});
outlinePass.renderToScreen = true;
this.addPass(outlinePass);
const renderPassUI = new RenderPass(scene, camera, () => {
this._setVisible(this._initalValues, [groups.UI]);
});
renderPassUI.clear = false;
renderPassUI.renderToScreen = true;
this.addPass(renderPassUI);
} else {
const renderPass = new RenderPass(scene, camera);
renderPass.renderToScreen = true;
this.addPass(renderPass);
const renderPassUI = new RenderPass(scene, camera, () => {
this._setVisible(this._initalValues, [groups.UI]);
});
renderPassUI.clear = false;
renderPassUI.renderToScreen = true;
this.addPass(renderPassUI);
break;
}
case ANAGLYPH: {
const anaglyphPass = new AnaglyphPass(scene, camera);
anaglyphPass.renderToScreen = true;
this.addPass(anaglyphPass);
break;
}
case TOONSHADER:
default: {
const renderPass = new RenderPass(scene, camera);
renderPass.renderToScreen = true;
this.addPass(renderPass);
break;
}
}
this._renderer = renderer;
this._camera = camera;
this._scene = scene;
this._toonShader = toonShader;
this._shader = shader;
}
_getCurrentVisibleValues() {
@ -74,13 +93,13 @@ export default class RenderChain extends THREE.EffectComposer {
}
render() {
if (this._toonShader) {
if (this._shader === TOONSHADER_OUTLINE) {
this._initalValues = this._getCurrentVisibleValues();
}
super.render();
if (this._toonShader) {
if (this._shader === TOONSHADER_OUTLINE) {
const { shapes, UI, plane, boundingBox } = this._groups;
this._setVisible(this._initalValues, [shapes, UI, plane, boundingBox]);
}

View File

@ -1,6 +1,6 @@
import * as THREE from 'three';
import ShapesManager from './ShapesManager.js';
import RenderChain from './RenderChain.js';
import RenderChain, { TOONSHADER, TOONSHADER_OUTLINE } from './RenderChain.js';
import { hasExtensionsFor } from '../utils/webGLSupport.js';
import { CANVAS_SIZE } from '../constants/d2Constants.js';
@ -17,7 +17,7 @@ export default function createScene(state, canvas) {
scene.add(camera);
const shapesManager = new ShapesManager({ toonShader: hasExtensionsFor.toonShaderThumbnail });
const shapesManager = new ShapesManager();
shapesManager.update(state);
scene.add(shapesManager);
@ -37,7 +37,8 @@ export default function createScene(state, canvas) {
const renderer = new THREE.WebGLRenderer({ canvas, alpha: true });
const renderChain = new RenderChain(renderer, scene, camera, hasExtensionsFor.toonShaderThumbnail, {
const shader = hasExtensionsFor.toonShaderThumbnail ? TOONSHADER_OUTLINE : TOONSHADER;
const renderChain = new RenderChain(renderer, scene, camera, shader, {
plane,
UI: new THREE.Object3D(),
shapes: shapesManager,

66
src/d3/effects/AnaglyphPass.js vendored Normal file
View File

@ -0,0 +1,66 @@
import * as THREE from 'three';
import anaglyphVert from '../../../shaders/anaglyph_vert.glsl';
import anaglyphFrag from '../../../shaders/anaglyph_frag.glsl';
const COLOR_MATRIX_LEFT = new THREE.Matrix3().fromArray([
1.0671679973602295, -0.0016435992438346148, 0.0001777536963345483,
-0.028107794001698494, -0.00019593400065787137, -0.0002875397040043026,
-0.04279090091586113, 0.000015809757314855233, -0.00024287120322696865
]);
const COLOR_MATRIX_RIGHT = new THREE.Matrix3().fromArray([
-0.0355340838432312, -0.06440307199954987, 0.018319187685847282,
-0.10269022732973099, 0.8079727292060852, -0.04835830628871918,
0.0001224992738571018, -0.009558862075209618, 0.567823588848114
]);
export default class AnaglyphPass {
constructor(scene, camera) {
this.scene = scene;
this.camera = camera;
this.clear = true;
this.renderToScreen = false;
const params = {
minFilter: THREE.LinearFilter,
magFilter: THREE.NearestFilter,
format: THREE.RGBAFormat
};
this._stereo = new THREE.StereoCamera();
this._renderTargetL = new THREE.WebGLRenderTarget(1, 1, params);
this._renderTargetR = new THREE.WebGLRenderTarget(1, 1, params);
this._material = new THREE.ShaderMaterial({
uniforms: {
mapLeft: { value: this._renderTargetL.texture },
mapRight: { value: this._renderTargetR.texture },
colorMatrixLeft: { value: COLOR_MATRIX_LEFT },
colorMatrixRight: { value: COLOR_MATRIX_RIGHT }
},
vertexShader: anaglyphVert,
fragmentShader: anaglyphFrag
});
this._camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
this._scene = new THREE.Scene();
this._quad = new THREE.Mesh(new THREE.PlaneBufferGeometry(2, 2), this._material);
this._quad.frustumCulled = false;
this._scene.add(this._quad);
}
setSize(width, height, pixelRatio = 1) {
this._renderTargetL.setSize(width * pixelRatio, height * pixelRatio);
this._renderTargetR.setSize(width * pixelRatio, height * pixelRatio);
}
render(renderer, writeBuffer, readBuffer, delta, maskActive) {
this.scene.updateMatrixWorld();
this._stereo.update(this.camera);
renderer.render(this.scene, this._stereo.cameraL, this._renderTargetL, true);
renderer.render(this.scene, this._stereo.cameraR, this._renderTargetR, true);
renderer.render(this._scene, this._camera, this.renderToScreen ? null : readBuffer, this.clear);
}
}

View File

@ -1,10 +1,10 @@
import * as THREE from 'three';
import normalDepthVert from '../../shaders/normal_depth_vert.glsl';
import normalDepthFrag from '../../shaders/normal_depth_frag.glsl';
import edgeVert from '../../shaders/edge_vert.glsl';
import edgeFrag from '../../shaders/edge_frag.glsl';
import combineVert from '../../shaders/combine_vert.glsl';
import combineFrag from '../../shaders/combine_frag.glsl';
import normalDepthVert from '../../../shaders/normal_depth_vert.glsl';
import normalDepthFrag from '../../../shaders/normal_depth_frag.glsl';
import edgeVert from '../../../shaders/edge_vert.glsl';
import edgeFrag from '../../../shaders/edge_frag.glsl';
import combineVert from '../../../shaders/combine_vert.glsl';
import combineFrag from '../../../shaders/combine_frag.glsl';
export default class OutlinePass {
constructor(scene, camera, callbackBeforeRender) {