post processing
This commit is contained in:
BIN
app/dist/.DS_Store
vendored
Normal file
BIN
app/dist/.DS_Store
vendored
Normal file
Binary file not shown.
1
app/dist/assets/index-B5Qt9EMX.js
vendored
1
app/dist/assets/index-B5Qt9EMX.js
vendored
@@ -1 +0,0 @@
|
||||
(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const e of document.querySelectorAll('link[rel="modulepreload"]'))i(e);new MutationObserver(e=>{for(const r of e)if(r.type==="childList")for(const o of r.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&i(o)}).observe(document,{childList:!0,subtree:!0});function s(e){const r={};return e.integrity&&(r.integrity=e.integrity),e.referrerPolicy&&(r.referrerPolicy=e.referrerPolicy),e.crossOrigin==="use-credentials"?r.credentials="include":e.crossOrigin==="anonymous"?r.credentials="omit":r.credentials="same-origin",r}function i(e){if(e.ep)return;e.ep=!0;const r=s(e);fetch(e.href,r)}})();
|
||||
1
app/dist/assets/index-BPBuaX9T.css
vendored
Normal file
1
app/dist/assets/index-BPBuaX9T.css
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*{margin:0;padding:0;box-sizing:border-box}html,body{height:100%;overflow:hidden;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;background:#000;color:#fff}#app{width:100vw;height:100vh;position:relative}.logo{position:absolute;top:2rem;left:2rem;z-index:100;font-size:1.5rem;font-weight:600;color:#fff;text-shadow:0 2px 4px rgba(0,0,0,.5);letter-spacing:.5px;-webkit-user-select:none;user-select:none}#three-canvas{width:100%;height:100%;display:block;cursor:crosshair}.home-button{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:100;background:#ffffff1a;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.2);border-radius:12px;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:1rem;font-weight:1000;color:#fff;letter-spacing:1px;padding:1rem 2rem;cursor:pointer;-webkit-user-select:none;user-select:none;transition:all .3s cubic-bezier(.4,0,.2,1);border:none;outline:none}.home-button:hover{background:#ffffff26;border:1px solid rgba(255,255,255,.3);transform:translate(-50%,-50%) translateY(-1px);box-shadow:0 4px 20px #00000026}.home-button:active{transform:translate(-50%,-50%) translateY(0);background:#fff3}.home-button span{display:block;position:relative;color:#ffffff26;filter:blur(.3px);-webkit-filter:blur(.3px)}@media (max-width: 768px){.logo{top:1rem;left:1rem;font-size:1.25rem}.home-button{padding:1.5rem 3rem;font-size:1.5rem;letter-spacing:3px}}
|
||||
4221
app/dist/assets/index-kpuvI5CD.js
vendored
Normal file
4221
app/dist/assets/index-kpuvI5CD.js
vendored
Normal file
File diff suppressed because one or more lines are too long
6
app/dist/index.html
vendored
6
app/dist/index.html
vendored
@@ -8,11 +8,15 @@
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<script type="module" crossorigin src="/assets/index-B5Qt9EMX.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-kpuvI5CD.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BPBuaX9T.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<div class="logo">AAF Systems</div>
|
||||
<button id="home-button" class="home-button">
|
||||
<span>Home</span>
|
||||
</button>
|
||||
<canvas id="three-canvas"></canvas>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
BIN
app/dist/models/main_model.glb
vendored
Normal file
BIN
app/dist/models/main_model.glb
vendored
Normal file
Binary file not shown.
18
app/node_modules/.vite/deps/_metadata.json
generated
vendored
18
app/node_modules/.vite/deps/_metadata.json
generated
vendored
@@ -1,25 +1,31 @@
|
||||
{
|
||||
"hash": "d7c7cf78",
|
||||
"hash": "a88ce823",
|
||||
"configHash": "3b37792f",
|
||||
"lockfileHash": "2e740449",
|
||||
"browserHash": "77a23b30",
|
||||
"lockfileHash": "5c312a08",
|
||||
"browserHash": "152c0a59",
|
||||
"optimized": {
|
||||
"cannon-es": {
|
||||
"src": "../../cannon-es/dist/cannon-es.js",
|
||||
"file": "cannon-es.js",
|
||||
"fileHash": "67229923",
|
||||
"fileHash": "8ff8e437",
|
||||
"needsInterop": false
|
||||
},
|
||||
"three": {
|
||||
"src": "../../three/build/three.module.js",
|
||||
"file": "three.js",
|
||||
"fileHash": "9d8610fe",
|
||||
"fileHash": "cb2e35a2",
|
||||
"needsInterop": false
|
||||
},
|
||||
"three/examples/jsm/loaders/GLTFLoader.js": {
|
||||
"src": "../../three/examples/jsm/loaders/GLTFLoader.js",
|
||||
"file": "three_examples_jsm_loaders_GLTFLoader__js.js",
|
||||
"fileHash": "54e38767",
|
||||
"fileHash": "c927b765",
|
||||
"needsInterop": false
|
||||
},
|
||||
"postprocessing": {
|
||||
"src": "../../postprocessing/build/index.js",
|
||||
"file": "postprocessing.js",
|
||||
"fileHash": "f93b9e9a",
|
||||
"needsInterop": false
|
||||
}
|
||||
},
|
||||
|
||||
16007
app/node_modules/.vite/deps/postprocessing.js
generated
vendored
Normal file
16007
app/node_modules/.vite/deps/postprocessing.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
7
app/node_modules/.vite/deps/postprocessing.js.map
generated
vendored
Normal file
7
app/node_modules/.vite/deps/postprocessing.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -6,6 +6,7 @@ import { LightingManager } from './lighting'
|
||||
import { ModelLoader } from './model-loader'
|
||||
import { PhysicsManager } from './physics'
|
||||
import { EventManager } from './event-manager'
|
||||
import { PostProcessingManager } from './post-processing'
|
||||
|
||||
class AAFHomepage {
|
||||
private scene: THREE.Scene
|
||||
@@ -20,6 +21,8 @@ class AAFHomepage {
|
||||
private lastTime: number = 0
|
||||
private modelLoader: ModelLoader
|
||||
private eventManager: EventManager
|
||||
private postProcessing!: PostProcessingManager
|
||||
private usePostProcessing: boolean = true
|
||||
|
||||
constructor() {
|
||||
this.scene = new THREE.Scene()
|
||||
@@ -85,6 +88,21 @@ class AAFHomepage {
|
||||
// Setup lighting
|
||||
LightingManager.setupLighting(this.scene)
|
||||
|
||||
// Initialize post-processing
|
||||
this.postProcessing = new PostProcessingManager(this.renderer, this.scene, this.camera)
|
||||
|
||||
// Setup window resize handler
|
||||
window.addEventListener('resize', () => {
|
||||
const width = window.innerWidth
|
||||
const height = window.innerHeight
|
||||
|
||||
this.camera.aspect = width / height
|
||||
this.camera.updateProjectionMatrix()
|
||||
|
||||
this.renderer.setSize(width, height)
|
||||
this.postProcessing.resize(width, height)
|
||||
})
|
||||
|
||||
// Load and create objects from the main model
|
||||
this.loadAndCreateObjects()
|
||||
|
||||
@@ -117,9 +135,16 @@ class AAFHomepage {
|
||||
clampedDeltaTime
|
||||
)
|
||||
|
||||
// Use post-processing rendering
|
||||
if (this.usePostProcessing) {
|
||||
this.postProcessing.update(clampedDeltaTime)
|
||||
this.postProcessing.render(clampedDeltaTime)
|
||||
} else {
|
||||
// Fallback to direct rendering
|
||||
this.renderer.render(this.scene, this.camera)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the application
|
||||
const app = new AAFHomepage()
|
||||
|
||||
121
app/src/motion-blur.ts
Normal file
121
app/src/motion-blur.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
import * as THREE from 'three'
|
||||
|
||||
export class MotionBlurEffect {
|
||||
private scene: THREE.Scene
|
||||
private camera: THREE.PerspectiveCamera
|
||||
private renderer: THREE.WebGLRenderer
|
||||
private renderTarget1: THREE.WebGLRenderTarget
|
||||
private renderTarget2: THREE.WebGLRenderTarget
|
||||
private blurMaterial: THREE.ShaderMaterial
|
||||
private quad: THREE.Mesh
|
||||
private intensity: number = 0.5
|
||||
private accumulation: number = 0.8
|
||||
|
||||
constructor(
|
||||
scene: THREE.Scene,
|
||||
camera: THREE.PerspectiveCamera,
|
||||
renderer: THREE.WebGLRenderer
|
||||
) {
|
||||
this.scene = scene
|
||||
this.camera = camera
|
||||
this.renderer = renderer
|
||||
|
||||
const size = renderer.getSize(new THREE.Vector2())
|
||||
|
||||
// Create render targets for accumulation
|
||||
this.renderTarget1 = new THREE.WebGLRenderTarget(size.x, size.y, {
|
||||
minFilter: THREE.LinearFilter,
|
||||
magFilter: THREE.LinearFilter,
|
||||
format: THREE.RGBAFormat,
|
||||
type: THREE.FloatType
|
||||
})
|
||||
|
||||
this.renderTarget2 = new THREE.WebGLRenderTarget(size.x, size.y, {
|
||||
minFilter: THREE.LinearFilter,
|
||||
magFilter: THREE.LinearFilter,
|
||||
format: THREE.RGBAFormat,
|
||||
type: THREE.FloatType
|
||||
})
|
||||
|
||||
// Motion blur shader material
|
||||
this.blurMaterial = new THREE.ShaderMaterial({
|
||||
uniforms: {
|
||||
tCurrent: { value: null },
|
||||
tPrevious: { value: null },
|
||||
intensity: { value: this.intensity },
|
||||
accumulation: { value: this.accumulation }
|
||||
},
|
||||
vertexShader: `
|
||||
varying vec2 vUv;
|
||||
void main() {
|
||||
vUv = uv;
|
||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
||||
}
|
||||
`,
|
||||
fragmentShader: `
|
||||
uniform sampler2D tCurrent;
|
||||
uniform sampler2D tPrevious;
|
||||
uniform float intensity;
|
||||
uniform float accumulation;
|
||||
varying vec2 vUv;
|
||||
|
||||
void main() {
|
||||
vec4 current = texture2D(tCurrent, vUv);
|
||||
vec4 previous = texture2D(tPrevious, vUv);
|
||||
|
||||
// Blend current frame with accumulated previous frames
|
||||
vec4 result = mix(current, previous, accumulation * intensity);
|
||||
|
||||
gl_FragColor = result;
|
||||
}
|
||||
`
|
||||
})
|
||||
|
||||
// Create fullscreen quad
|
||||
const geometry = new THREE.PlaneGeometry(2, 2)
|
||||
this.quad = new THREE.Mesh(geometry, this.blurMaterial)
|
||||
}
|
||||
|
||||
public render(deltaTime: number): THREE.WebGLRenderTarget {
|
||||
// Render current frame to renderTarget1
|
||||
this.renderer.setRenderTarget(this.renderTarget1)
|
||||
this.renderer.render(this.scene, this.camera)
|
||||
|
||||
// Apply motion blur by blending with previous frame
|
||||
this.blurMaterial.uniforms.tCurrent.value = this.renderTarget1.texture
|
||||
this.blurMaterial.uniforms.tPrevious.value = this.renderTarget2.texture
|
||||
|
||||
// Render blurred result to renderTarget2
|
||||
this.renderer.setRenderTarget(this.renderTarget2)
|
||||
this.renderer.render(this.quad, new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1))
|
||||
|
||||
// Swap render targets for next frame
|
||||
const temp = this.renderTarget1
|
||||
this.renderTarget1 = this.renderTarget2
|
||||
this.renderTarget2 = temp
|
||||
|
||||
return this.renderTarget1
|
||||
}
|
||||
|
||||
public setIntensity(intensity: number): void {
|
||||
this.intensity = intensity
|
||||
this.blurMaterial.uniforms.intensity.value = intensity
|
||||
}
|
||||
|
||||
public setAccumulation(accumulation: number): void {
|
||||
this.accumulation = accumulation
|
||||
this.blurMaterial.uniforms.accumulation.value = accumulation
|
||||
}
|
||||
|
||||
public resize(width: number, height: number): void {
|
||||
this.renderTarget1.setSize(width, height)
|
||||
this.renderTarget2.setSize(width, height)
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this.renderTarget1.dispose()
|
||||
this.renderTarget2.dispose()
|
||||
this.blurMaterial.dispose()
|
||||
this.quad.geometry.dispose()
|
||||
}
|
||||
}
|
||||
122
app/src/post-processing.ts
Normal file
122
app/src/post-processing.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
import * as THREE from 'three'
|
||||
import {
|
||||
EffectComposer,
|
||||
EffectPass,
|
||||
RenderPass,
|
||||
BloomEffect,
|
||||
SSAOEffect,
|
||||
DepthOfFieldEffect,
|
||||
NormalPass,
|
||||
SMAAEffect
|
||||
} from 'postprocessing'
|
||||
|
||||
export class PostProcessingManager {
|
||||
private composer: EffectComposer
|
||||
private bloomEffect: BloomEffect
|
||||
private ssaoEffect: SSAOEffect
|
||||
private depthOfFieldEffect: DepthOfFieldEffect
|
||||
private normalPass: NormalPass
|
||||
|
||||
constructor(
|
||||
renderer: THREE.WebGLRenderer,
|
||||
scene: THREE.Scene,
|
||||
camera: THREE.PerspectiveCamera
|
||||
) {
|
||||
// Create effect composer
|
||||
this.composer = new EffectComposer(renderer)
|
||||
|
||||
// Add render pass (renders the scene)
|
||||
const renderPass = new RenderPass(scene, camera)
|
||||
this.composer.addPass(renderPass)
|
||||
|
||||
// Create normal pass for SSAO
|
||||
this.normalPass = new NormalPass(scene, camera)
|
||||
this.composer.addPass(this.normalPass)
|
||||
|
||||
// Create bloom effect - enhanced for more dramatic glow
|
||||
this.bloomEffect = new BloomEffect({
|
||||
intensity: 1.2,
|
||||
luminanceThreshold: 0.1,
|
||||
luminanceSmoothing: 0.15,
|
||||
radius: 0.9,
|
||||
mipmapBlur: true
|
||||
})
|
||||
|
||||
// Create SSAO effect - enhanced for better ambient occlusion
|
||||
this.ssaoEffect = new SSAOEffect(camera, this.normalPass.texture, {
|
||||
intensity: 0.8,
|
||||
fade: 0.01,
|
||||
radius: 0.15,
|
||||
samples: 32,
|
||||
rings: 4,
|
||||
worldDistanceThreshold: 20,
|
||||
worldDistanceFalloff: 5,
|
||||
worldProximityThreshold: 0.0005,
|
||||
worldProximityFalloff: 0.001,
|
||||
luminanceInfluence: 0.7,
|
||||
bias: 0.02
|
||||
})
|
||||
|
||||
// Create depth of field effect - tighter focus for more dramatic effect
|
||||
this.depthOfFieldEffect = new DepthOfFieldEffect(camera, {
|
||||
focusDistance: 0.015, // Closer focus point
|
||||
focalLength: 0.12, // Shorter focal length for stronger blur
|
||||
bokehScale: 4.0, // Larger bokeh for more pronounced blur
|
||||
height: 480
|
||||
})
|
||||
|
||||
// Create SMAA effect for better antialiasing
|
||||
const smaaEffect = new SMAAEffect()
|
||||
|
||||
// Combine effects in a single pass for better performance
|
||||
const effectPass = new EffectPass(
|
||||
camera,
|
||||
this.bloomEffect,
|
||||
this.ssaoEffect,
|
||||
this.depthOfFieldEffect,
|
||||
smaaEffect
|
||||
)
|
||||
|
||||
this.composer.addPass(effectPass)
|
||||
}
|
||||
|
||||
public render(deltaTime?: number): void {
|
||||
this.composer.render(deltaTime)
|
||||
}
|
||||
|
||||
public resize(width: number, height: number): void {
|
||||
this.composer.setSize(width, height)
|
||||
}
|
||||
|
||||
// Control methods for real-time adjustments
|
||||
public setBloomIntensity(intensity: number): void {
|
||||
this.bloomEffect.intensity = intensity
|
||||
}
|
||||
|
||||
public setSSAOIntensity(intensity: number): void {
|
||||
this.ssaoEffect.intensity = intensity
|
||||
}
|
||||
|
||||
public setDepthOfFieldFocus(focusDistance: number): void {
|
||||
this.depthOfFieldEffect.circleOfConfusionMaterial.uniforms.focusDistance.value = focusDistance
|
||||
}
|
||||
|
||||
// Get the composer for advanced usage
|
||||
public getComposer(): EffectComposer {
|
||||
return this.composer
|
||||
}
|
||||
|
||||
// Update method for any per-frame updates
|
||||
public update(_deltaTime: number): void {
|
||||
// Add any custom update logic here if needed
|
||||
}
|
||||
|
||||
// Dispose method for cleanup
|
||||
public dispose(): void {
|
||||
this.composer.dispose()
|
||||
this.bloomEffect.dispose()
|
||||
this.ssaoEffect.dispose()
|
||||
this.depthOfFieldEffect.dispose()
|
||||
this.normalPass.dispose()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user