Merge pull request #5 from tengge1/dev

Dev
This commit is contained in:
tengge1 2018-12-26 22:07:34 +08:00 committed by GitHub
commit ac4d7bf1bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 413 additions and 27 deletions

View File

@ -26,7 +26,7 @@
## v0.1.1 即将更新
1. 修复mmd动画和音频不同步问题。支持多个mmd模型与模型动画、相机动画同步。
2. 新增点阵化特效、颜色偏移特效、残影特效、背景虚化、快速近似抗锯齿(FXAA)、毛刺特效。
2. 新增点阵化特效、颜色偏移特效、残影特效、背景虚化、快速近似抗锯齿(FXAA)、毛刺特效、半色调特效
3. 新增粒子、预设体、角色面板。(暂未实现具体功能)
## 主要功能
@ -58,6 +58,8 @@
![image](images/scene20181223.png)
[点击此处](images/README.md)查看更多截图。
## 相关链接
* Three.js官网https://threejs.org/

View File

@ -46,6 +46,9 @@
<script src="assets/js/shaders/AfterimageShader.js"></script>
<script src="assets/js/shaders/BokehShader.js"></script>
<script src="assets/js/shaders/DigitalGlitch.js"></script>
<script src="assets/js/shaders/HalftoneShader.js"></script>
<script src="assets/js/shaders/DepthLimitedBlurShader.js"></script>
<script src="assets/js/shaders/UnpackDepthRGBAShader.js"></script>
<!-- postprocessing -->
<script src="assets/js/postprocessing/EffectComposer.js"></script>
@ -56,6 +59,7 @@
<script src="assets/js/postprocessing/BokehPass.js"></script>
<script src="assets/js/postprocessing/OutlinePass.js"></script>
<script src="assets/js/postprocessing/GlitchPass.js"></script>
<script src="assets/js/postprocessing/HalftonePass.js"></script>
<!-- controls -->
<script src="assets/js/controls/FirstPersonControls.js"></script>

View File

@ -113,6 +113,8 @@ AfterimageComponent.prototype.onChange = function () {
damp: damp.getValue()
},
});
this.app.call(`postProcessingChanged`, this);
};
export default AfterimageComponent;

View File

@ -145,6 +145,8 @@ BokehComponent.prototype.onChange = function () {
maxBlur: maxBlur.getValue(),
},
});
this.app.call(`postProcessingChanged`, this);
};
export default BokehComponent;

View File

@ -113,6 +113,8 @@ DotScreenComponent.prototype.onChange = function () {
scale: scale.getValue(),
},
});
this.app.call(`postProcessingChanged`, this);
};
export default DotScreenComponent;

View File

@ -97,6 +97,8 @@ FxaaComponent.prototype.onChange = function () {
enabled: enabled.getValue(),
},
});
this.app.call(`postProcessingChanged`, this);
};
export default FxaaComponent;

View File

@ -112,6 +112,8 @@ GlitchComponent.prototype.onChange = function () {
wild: wild.getValue()
},
});
this.app.call(`postProcessingChanged`, this);
};
export default GlitchComponent;

View File

@ -0,0 +1,263 @@
import BaseComponent from '../BaseComponent';
/**
* 半色调特效组件
* @author tengge / https://github.com/tengge1
* @param {*} options
*/
function HalftoneComponent(options) {
BaseComponent.call(this, options);
this.selected = null;
}
HalftoneComponent.prototype = Object.create(BaseComponent.prototype);
HalftoneComponent.prototype.constructor = HalftoneComponent;
HalftoneComponent.prototype.render = function () {
var data = {
xtype: 'div',
id: 'panel',
scope: this.id,
parent: this.parent,
cls: 'Panel',
style: {
display: 'none'
},
children: [{
xtype: 'row',
children: [{
xtype: 'label',
style: {
color: '#555',
fontWeight: 'bold',
width: '100%'
},
text: '半色调特效'
}]
}, {
xtype: 'row',
children: [{
xtype: 'label',
text: '启用状态'
}, {
xtype: 'checkbox',
id: 'enabled',
scope: this.id,
value: false,
onChange: this.onChange.bind(this)
}]
}, {
xtype: 'row',
children: [{
xtype: 'label',
text: '形状'
}, {
xtype: 'select',
id: 'shape',
scope: this.id,
options: {
1: '点',
2: '椭圆',
3: '线',
4: '正方形'
},
value: 1,
onChange: this.onChange.bind(this)
}]
}, {
xtype: 'row',
children: [{
xtype: 'label',
text: '半径'
}, {
xtype: 'number',
id: 'radius',
scope: this.id,
range: [1, 25],
value: 4,
onChange: this.onChange.bind(this)
}]
}, {
xtype: 'row',
children: [{
xtype: 'label',
text: '红色偏转'
}, {
xtype: 'number',
id: 'rotateR',
scope: this.id,
value: 15,
onChange: this.onChange.bind(this)
}]
}, {
xtype: 'row',
children: [{
xtype: 'label',
text: '绿色偏转'
}, {
xtype: 'number',
id: 'rotateG',
scope: this.id,
value: 45,
onChange: this.onChange.bind(this)
}]
}, {
xtype: 'row',
children: [{
xtype: 'label',
text: '蓝色偏转'
}, {
xtype: 'number',
id: 'rotateB',
scope: this.id,
value: 30,
onChange: this.onChange.bind(this)
}]
}, {
xtype: 'row',
children: [{
xtype: 'label',
text: '分散'
}, {
xtype: 'number',
id: 'scatter',
scope: this.id,
value: 0,
onChange: this.onChange.bind(this)
}]
}, {
xtype: 'row',
children: [{
xtype: 'label',
text: '混合'
}, {
xtype: 'number',
id: 'blending',
scope: this.id,
range: [0, 1],
value: 1,
onChange: this.onChange.bind(this)
}]
}, {
xtype: 'row',
children: [{
xtype: 'label',
text: '混合模式'
}, {
xtype: 'select',
id: 'blendingMode',
scope: this.id,
options: {
1: '线性',
2: '乘法',
3: '相加',
4: '变亮',
5: '变暗'
},
value: 1,
onChange: this.onChange.bind(this)
}]
}, {
xtype: 'row',
children: [{
xtype: 'label',
text: '灰阶'
}, {
xtype: 'checkbox',
id: 'greyscale',
scope: this.id,
value: false,
onChange: this.onChange.bind(this)
}]
}]
};
var control = UI.create(data);
control.render();
this.app.on(`objectSelected.${this.id}`, this.onObjectSelected.bind(this));
this.app.on(`objectChanged.${this.id}`, this.onObjectChanged.bind(this));
};
HalftoneComponent.prototype.onObjectSelected = function () {
this.updateUI();
};
HalftoneComponent.prototype.onObjectChanged = function () {
this.updateUI();
};
HalftoneComponent.prototype.updateUI = function () {
var container = UI.get('panel', this.id);
var editor = this.app.editor;
if (editor.selected && editor.selected instanceof THREE.Scene) {
container.dom.style.display = '';
} else {
container.dom.style.display = 'none';
return;
}
this.selected = editor.selected;
var enabled = UI.get('enabled', this.id);
var shape = UI.get('shape', this.id);
var radius = UI.get('radius', this.id);
var rotateR = UI.get('rotateR', this.id);
var rotateB = UI.get('rotateB', this.id);
var rotateG = UI.get('rotateG', this.id);
var scatter = UI.get('scatter', this.id);
var blending = UI.get('blending', this.id);
var blendingMode = UI.get('blendingMode', this.id);
var greyscale = UI.get('greyscale', this.id);
var scene = this.selected;
var postProcessing = scene.userData.postProcessing || {};
if (postProcessing.halftone) {
enabled.setValue(postProcessing.halftone.enabled);
shape.setValue(postProcessing.halftone.shape);
radius.setValue(postProcessing.halftone.radius);
rotateR.setValue(postProcessing.halftone.rotateR);
rotateB.setValue(postProcessing.halftone.rotateB);
rotateG.setValue(postProcessing.halftone.rotateG);
scatter.setValue(postProcessing.halftone.scatter);
blending.setValue(postProcessing.halftone.blending);
blendingMode.setValue(postProcessing.halftone.blendingMode);
greyscale.setValue(postProcessing.halftone.greyscale);
}
};
HalftoneComponent.prototype.onChange = function () {
var enabled = UI.get('enabled', this.id);
var shape = UI.get('shape', this.id);
var radius = UI.get('radius', this.id);
var rotateR = UI.get('rotateR', this.id);
var rotateB = UI.get('rotateB', this.id);
var rotateG = UI.get('rotateG', this.id);
var scatter = UI.get('scatter', this.id);
var blending = UI.get('blending', this.id);
var blendingMode = UI.get('blendingMode', this.id);
var greyscale = UI.get('greyscale', this.id);
var scene = this.selected;
scene.userData.postProcessing = scene.userData.postProcessing || {};
Object.assign(scene.userData.postProcessing, {
halftone: {
enabled: enabled.getValue(),
shape: shape.getValue(),
radius: radius.getValue(),
rotateR: rotateR.getValue(),
rotateB: rotateB.getValue(),
rotateG: rotateG.getValue(),
scatter: scatter.getValue(),
blending: blending.getValue(),
blendingMode: blendingMode.getValue(),
greyscale: greyscale.getValue()
},
});
this.app.call(`postProcessingChanged`, this);
};
export default HalftoneComponent;

View File

@ -113,6 +113,8 @@ RgbShiftComponent.prototype.onChange = function () {
amount: amount.getValue()
},
});
this.app.call(`postProcessingChanged`, this);
};
export default RgbShiftComponent;

View File

@ -33,6 +33,7 @@ import AfterimageComponent from '../../component/postProcessing/AfterimageCompon
import BokehComponent from '../../component/postProcessing/BokehComponent';
import FxaaComponent from '../../component/postProcessing/FxaaComponent';
import GlitchComponent from '../../component/postProcessing/GlitchComponent';
import HalftoneComponent from '../../component/postProcessing/HalftoneComponent';
/**
* 属性面板
@ -71,6 +72,7 @@ PropertyPanel.prototype.render = function () {
new BokehComponent({ app: this.app }),
new FxaaComponent({ app: this.app }),
new GlitchComponent({ app: this.app }),
new HalftoneComponent({ app: this.app }),
new SkyComponent({ app: this.app }),
new PerlinTerrainComponent({ app: this.app }),
new AudioListenerComponent({ app: this.app }),

View File

@ -10,6 +10,7 @@ function OutlineEffect(app) {
this.init();
this.app.on(`sceneLoaded.${this.id}`, this.onSceneLoaded.bind(this));
this.app.on(`postProcessingChanged.${this.id}`, this.onPostProcessingChanged.bind(this));
};
OutlineEffect.prototype = Object.create(BaseEffect.prototype);
@ -36,39 +37,107 @@ OutlineEffect.prototype.init = function () {
}
var composer = new THREE.EffectComposer(renderer);
composer.passes.length = 0;
var renderPass1 = new THREE.RenderPass(scene, camera);
renderPass1.clear = true;
composer.addPass(renderPass1);
var effects = [];
var postProcessing = this.app.editor.scene.userData.postProcessing || {};
var renderPass2 = new THREE.RenderPass(sceneHelpers, camera);
renderPass2.clear = false;
composer.addPass(renderPass2);
var effect = new THREE.RenderPass(scene, camera);
effect.clear = true;
composer.addPass(effect);
effects.push(effect);
var outlinePass = new THREE.OutlinePass(new THREE.Vector2(renderer.domElement.width, renderer.domElement.height), scene, camera);
outlinePass.edgeStrength = params.edgeStrength;
outlinePass.edgeGlow = params.edgeGlow;
outlinePass.edgeThickness = params.edgeThickness;
outlinePass.pulsePeriod = params.pulsePeriod;
// outlinePass.usePatternTexture = true;
outlinePass.visibleEdgeColor.set(params.visibleEdgeColor);
outlinePass.hiddenEdgeColor.set(params.hiddenEdgeColor);
composer.addPass(outlinePass);
effect = new THREE.RenderPass(sceneHelpers, camera);
effect.clear = false;
composer.addPass(effect);
effects.push(effect);
var loader = new THREE.TextureLoader();
effect = new THREE.OutlinePass(new THREE.Vector2(renderer.domElement.width, renderer.domElement.height), scene, camera);
effect.edgeStrength = 10;
effect.edgeGlow = 0.4;
effect.edgeThickness = 1.8;
effect.pulsePeriod = 2;
effect.visibleEdgeColor.set('#ffffff');
effect.hiddenEdgeColor.set('#190a05');
composer.addPass(effect);
effects.push(effect);
// loader.load('assets/textures/tri_pattern.jpg', texture => {
// outlinePass.patternTexture = texture;
// texture.wrapS = THREE.RepeatWrapping;
// texture.wrapT = THREE.RepeatWrapping;
// });
this.outlinePass = effect;
var effectFXAA = new THREE.ShaderPass(THREE.FXAAShader);
effectFXAA.uniforms['resolution'].value.set(1 / renderer.domElement.width, 1 / renderer.domElement.height);
effectFXAA.renderToScreen = true;
composer.addPass(effectFXAA);
// 后期处理
if (postProcessing.fxaa && postProcessing.fxaa.enabled) {
effect = new THREE.ShaderPass(THREE.FXAAShader);
effect.uniforms['resolution'].value.set(1 / renderer.domElement.width, 1 / renderer.domElement.height);
composer.addPass(effect);
effects.push(effect);
}
if (postProcessing.dotScreen && postProcessing.dotScreen.enabled) {
effect = new THREE.ShaderPass(THREE.DotScreenShader);
effect.uniforms['scale'].value = postProcessing.dotScreen.scale;
composer.addPass(effect);
effects.push(effect);
}
if (postProcessing.rgbShift && postProcessing.rgbShift.enabled) {
effect = new THREE.ShaderPass(THREE.RGBShiftShader);
effect.uniforms['amount'].value = postProcessing.rgbShift.amount;
composer.addPass(effect);
effects.push(effect);
}
if (postProcessing.afterimage && postProcessing.afterimage.enabled) {
effect = new THREE.AfterimagePass();
effect.uniforms['damp'].value = postProcessing.afterimage.damp;
composer.addPass(effect);
effects.push(effect);
}
if (postProcessing.halftone && postProcessing.halftone.enabled) {
effect = new THREE.HalftonePass(
renderer.domElement.width,
renderer.domElement.height, {
shape: postProcessing.halftone.shape,
radius: postProcessing.halftone.radius,
rotateR: postProcessing.halftone.rotateR * (Math.PI / 180),
rotateB: postProcessing.halftone.rotateB * (Math.PI / 180),
rotateG: postProcessing.halftone.rotateG * (Math.PI / 180),
scatter: postProcessing.halftone.scatter,
blending: postProcessing.halftone.blending,
blendingMode: postProcessing.halftone.blendingMode,
greyscale: postProcessing.halftone.greyscale,
});
composer.addPass(effect);
effects.push(effect);
}
if (postProcessing.bokeh && postProcessing.bokeh.enabled) {
effect = new THREE.BokehPass(scene, camera, {
focus: postProcessing.bokeh.focus,
aperture: postProcessing.bokeh.aperture / 100000,
maxblur: postProcessing.bokeh.maxBlur,
width: renderer.domElement.width,
height: renderer.domElement.height
});
composer.addPass(effect);
effects.push(effect);
}
if (postProcessing.glitch && postProcessing.glitch.enabled) {
effect = new THREE.GlitchPass();
effect.goWild = postProcessing.glitch.wild;
composer.addPass(effect);
effects.push(effect);
}
for (var i = 0; i < effects.length; i++) {
if (i === effects.length - 1) {
effects[i].renderToScreen = true;
} else {
effects[i].renderToScreen = false;
}
}
this.outlinePass = outlinePass;
this.composer = composer;
};
@ -86,4 +155,8 @@ OutlineEffect.prototype.onSceneLoaded = function () {
this.init();
};
OutlineEffect.prototype.onPostProcessingChanged = function () {
this.init();
};
export default OutlineEffect;

View File

@ -72,6 +72,7 @@ var EventList = [
'refreshScriptEditor', // 刷新脚本编辑器事件
'sceneLoaded', // 场景载入
'postProcessingChanged', // 后期处理设置改变
// 场景编辑区
'transformControlsChange', // 变形控件改变

View File

@ -55,6 +55,24 @@ PlayerRenderer.prototype.create = function (scene, camera, renderer) {
effects.push(effect);
}
if (postProcessing.halftone && postProcessing.halftone.enabled) {
effect = new THREE.HalftonePass(
renderer.domElement.width,
renderer.domElement.height, {
shape: postProcessing.halftone.shape,
radius: postProcessing.halftone.radius,
rotateR: postProcessing.halftone.rotateR * (Math.PI / 180),
rotateB: postProcessing.halftone.rotateB * (Math.PI / 180),
rotateG: postProcessing.halftone.rotateG * (Math.PI / 180),
scatter: postProcessing.halftone.scatter,
blending: postProcessing.halftone.blending,
blendingMode: postProcessing.halftone.blendingMode,
greyscale: postProcessing.halftone.greyscale,
});
composer.addPass(effect);
effects.push(effect);
}
if (postProcessing.bokeh && postProcessing.bokeh.enabled) {
effect = new THREE.BokehPass(scene, camera, {
focus: postProcessing.bokeh.focus,

11
images/README.md Normal file
View File

@ -0,0 +1,11 @@
# 更多截图
![image](scene20181223.png)
![image](scene20181215.png)
![image](scene20181007.png)
![image](scene20180919.png)
![image](scene20180917.png)

View File

Before

Width:  |  Height:  |  Size: 1.7 MiB

After

Width:  |  Height:  |  Size: 1.7 MiB

View File

Before

Width:  |  Height:  |  Size: 854 KiB

After

Width:  |  Height:  |  Size: 854 KiB

View File

Before

Width:  |  Height:  |  Size: 1021 KiB

After

Width:  |  Height:  |  Size: 1021 KiB