-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: mesh refarction but it's half working (maybe caustics issue)
- Loading branch information
Showing
19 changed files
with
1,610 additions
and
22 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
libs/angular-three-soba/abstractions/src/lib/edges/edges.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { NgIf } from '@angular/common'; | ||
import { Component, CUSTOM_ELEMENTS_SCHEMA, Input, OnInit } from '@angular/core'; | ||
import { extend, injectNgtRef, NgtAnyRecord, NgtRxStore } from 'angular-three'; | ||
import * as THREE from 'three'; | ||
import { LineBasicMaterial, LineSegments } from 'three'; | ||
|
||
extend({ LineSegments, LineBasicMaterial }); | ||
|
||
@Component({ | ||
selector: 'ngts-edges', | ||
standalone: true, | ||
template: ` | ||
<ngt-line-segments [ref]="edgesRef" [raycast]="noop" ngtCompound> | ||
<ng-container *ngIf="withChildren; else noChildren"> | ||
<ng-content /> | ||
</ng-container> | ||
<ng-template #noChildren> | ||
<ngt-line-basic-material [color]="color" /> | ||
</ng-template> | ||
</ngt-line-segments> | ||
`, | ||
imports: [NgIf], | ||
schemas: [CUSTOM_ELEMENTS_SCHEMA], | ||
}) | ||
export class NgtsEdges extends NgtRxStore implements OnInit { | ||
@Input() edgesRef = injectNgtRef<THREE.LineSegments>(); | ||
|
||
@Input() set threshold(threshold: number) { | ||
this.set({ threshold }); | ||
} | ||
|
||
@Input() set color(color: THREE.ColorRepresentation) { | ||
this.set({ color }); | ||
} | ||
|
||
@Input() set geometry(geometry: THREE.BufferGeometry) { | ||
this.set({ geometry }); | ||
} | ||
|
||
@Input() set userData(userData: NgtAnyRecord) { | ||
this.set({ userData }); | ||
} | ||
|
||
@Input() withChildren = false; | ||
|
||
readonly noop = () => null; | ||
|
||
override initialize(): void { | ||
super.initialize(); | ||
this.set({ | ||
threshold: 15, | ||
color: 'black', | ||
userData: {}, | ||
}); | ||
} | ||
|
||
ngOnInit(): void { | ||
this.setupGeometry(); | ||
} | ||
|
||
private setupGeometry(): void { | ||
this.hold(this.edgesRef.$, (segments) => { | ||
const parent = segments.parent as THREE.Mesh; | ||
if (parent) { | ||
const geom = this.get('geometry') || parent.geometry; | ||
const threshold = this.get('threshold'); | ||
if (geom !== segments.userData['currentGeom'] || threshold !== segments.userData['currentThreshold']) { | ||
segments.userData['currentGeom'] = geom; | ||
segments.userData['currentThreshold'] = threshold; | ||
segments.geometry = new THREE.EdgesGeometry(geom, threshold); | ||
} | ||
} | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export * from './lib/camera/camera-content'; | ||
export * from './lib/cube-camera/cube-camera'; | ||
export * from './lib/orthographic-camera/orthographic-camera'; | ||
export * from './lib/perspective-camera/perspective-camera'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
111 changes: 111 additions & 0 deletions
111
libs/angular-three-soba/cameras/src/lib/cube-camera/cube-camera.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import { NgIf, NgTemplateOutlet } from '@angular/common'; | ||
import { Component, ContentChild, CUSTOM_ELEMENTS_SCHEMA, ElementRef, inject, Input, ViewChild } from '@angular/core'; | ||
import { extend, injectBeforeRender, injectNgtRef, NgtArgs, NgtRxStore, NgtStore } from 'angular-three'; | ||
import { combineLatest, map } from 'rxjs'; | ||
import * as THREE from 'three'; | ||
import { CubeCamera, Group } from 'three'; | ||
import { NgtsCameraContent } from '../camera/camera-content'; | ||
|
||
extend({ Group, CubeCamera }); | ||
|
||
@Component({ | ||
selector: 'ngts-cube-camera', | ||
standalone: true, | ||
template: ` | ||
<ngt-group ngtCompound> | ||
<ngt-cube-camera [ref]="cameraRef" *args="get('cameraArgs')" /> | ||
<ngt-group #group> | ||
<ng-container | ||
*ngIf="cameraContent && cameraContent.ngtsCameraContent && get('fbo')" | ||
[ngTemplateOutlet]="cameraContent.template" | ||
[ngTemplateOutletContext]="{ fbo: get('fbo').texture, group }" | ||
/> | ||
</ngt-group> | ||
</ngt-group> | ||
`, | ||
imports: [NgIf, NgTemplateOutlet, NgtArgs], | ||
schemas: [CUSTOM_ELEMENTS_SCHEMA], | ||
}) | ||
export class NgtsCubeCamera extends NgtRxStore { | ||
@ViewChild('group', { static: true }) groupRef!: ElementRef<THREE.Group>; | ||
@ContentChild(NgtsCameraContent) cameraContent?: NgtsCameraContent; | ||
|
||
readonly cameraRef = injectNgtRef<THREE.CubeCamera>(); | ||
|
||
/** Number of frames to render, Infinity */ | ||
@Input() set frames(frames: number) { | ||
this.set({ frames }); | ||
} | ||
/** Resolution of the FBO, 256 */ | ||
@Input() set resolution(resolution: number) { | ||
this.set({ resolution }); | ||
} | ||
/** Camera near, 0.1 */ | ||
@Input() set near(near: number) { | ||
this.set({ near }); | ||
} | ||
/** Camera far, 1000 */ | ||
@Input() set far(far: number) { | ||
this.set({ far }); | ||
} | ||
/** Custom environment map that is temporarily set as the scenes background */ | ||
@Input() set envMap(envMap: THREE.Texture) { | ||
this.set({ envMap }); | ||
} | ||
/** Custom fog that is temporarily set as the scenes fog */ | ||
@Input() set fog(fog: THREE.Fog | THREE.FogExp2) { | ||
this.set({ fog }); | ||
} | ||
|
||
private readonly store = inject(NgtStore); | ||
|
||
override initialize(): void { | ||
super.initialize(); | ||
this.set({ | ||
frames: Infinity, | ||
resolution: 256, | ||
near: 0.1, | ||
far: 1000, | ||
}); | ||
} | ||
|
||
constructor() { | ||
super(); | ||
this.connect( | ||
'fbo', | ||
this.select('resolution').pipe( | ||
map((resolution) => { | ||
const fbo = new THREE.WebGLCubeRenderTarget(resolution); | ||
fbo.texture.encoding = this.store.get('gl').outputEncoding; | ||
fbo.texture.type = THREE.HalfFloatType; | ||
return fbo; | ||
}) | ||
) | ||
); | ||
this.connect('cameraArgs', combineLatest([this.select('near'), this.select('far'), this.select('fbo')])); | ||
|
||
let count = 0; | ||
let originalFog: THREE.Scene['fog']; | ||
let originalBackground: THREE.Scene['background']; | ||
injectBeforeRender(({ scene, gl }) => { | ||
const { frames, envMap, fog } = this.get(); | ||
if ( | ||
envMap && | ||
this.cameraRef.nativeElement && | ||
this.groupRef.nativeElement && | ||
(frames === Infinity || count < frames) | ||
) { | ||
this.groupRef.nativeElement.visible = false; | ||
originalFog = scene.fog; | ||
originalBackground = scene.background; | ||
scene.background = envMap || originalBackground; | ||
scene.fog = fog || originalFog; | ||
this.cameraRef.nativeElement.update(gl, scene); | ||
scene.fog = originalFog; | ||
scene.background = originalBackground; | ||
this.groupRef.nativeElement.visible = true; | ||
count++; | ||
} | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
export * from './lib/mesh-distort-material/mesh-distort-material'; | ||
export * from './lib/mesh-reflector-material/mesh-reflector-material'; | ||
export * from './lib/mesh-refraction-material/mesh-refraction-material'; | ||
export * from './lib/mesh-transmission-material/mesh-transmission-material'; | ||
export * from './lib/mesh-wobble-material/mesh-wobble-material'; |
120 changes: 115 additions & 5 deletions
120
...angular-three-soba/materials/src/lib/mesh-refraction-material/mesh-refraction-material.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,131 @@ | ||
import { NgIf } from '@angular/common'; | ||
import { Component, CUSTOM_ELEMENTS_SCHEMA, Input } from '@angular/core'; | ||
import { extend, injectNgtRef, NgtPush } from 'angular-three'; | ||
import { Component, CUSTOM_ELEMENTS_SCHEMA, inject, Input, OnInit } from '@angular/core'; | ||
import { extend, getLocalState, injectBeforeRender, injectNgtRef, NgtPush, NgtRxStore, NgtStore } from 'angular-three'; | ||
import { MeshRefractionMaterial } from 'angular-three-soba/shaders'; | ||
import { combineLatest, map } from 'rxjs'; | ||
import { MeshBVH, SAH } from 'three-mesh-bvh'; | ||
|
||
extend({ MeshRefractionMaterial }); | ||
|
||
const isCubeTexture = (def: THREE.CubeTexture | THREE.Texture): def is THREE.CubeTexture => | ||
def && (def as THREE.CubeTexture).isCubeTexture; | ||
|
||
@Component({ | ||
selector: 'ngts-mesh-refraction-material', | ||
standalone: true, | ||
template: ` | ||
<ngt-mesh-refraction-material> | ||
<ngt-mesh-refraction-material | ||
*ngIf="defines$ | ngtPush as defines" | ||
[ref]="materialRef" | ||
[defines]="defines" | ||
[resolution]="get('resolution')" | ||
[aberrationStrength]="get('aberrationStrength')" | ||
[envMap]="get('envMap')" | ||
[bounces]="get('bounces')" | ||
[ior]="get('ior')" | ||
[fresnel]="get('fresnel')" | ||
[color]="get('color')" | ||
[fastChroma]="get('fastChroma')" | ||
ngtCompound | ||
attach="material" | ||
> | ||
<ng-content /> | ||
</ngt-mesh-refraction-material> | ||
`, | ||
imports: [NgtPush, NgIf], | ||
schemas: [CUSTOM_ELEMENTS_SCHEMA], | ||
}) | ||
export class NgtsMeshRefractionMaterial { | ||
@Input() materialRef = injectNgtRef<typeof MeshRefractionMaterial>(); | ||
export class NgtsMeshRefractionMaterial extends NgtRxStore implements OnInit { | ||
@Input() materialRef = injectNgtRef<typeof MeshRefractionMaterial.prototype>(); | ||
/** Environment map */ | ||
@Input() set envMap(envMap: THREE.CubeTexture | THREE.Texture) { | ||
this.set({ envMap }); | ||
} | ||
/** Number of ray-cast bounces, it can be expensive to have too many, 2 */ | ||
@Input() set bounces(bounces: number) { | ||
this.set({ bounces }); | ||
} | ||
/** Refraction index, 2.4 */ | ||
@Input() set ior(ior: number) { | ||
this.set({ ior }); | ||
} | ||
/** Fresnel (strip light), 0 */ | ||
@Input() set fresnel(fresnel: number) { | ||
this.set({ fresnel }); | ||
} | ||
/** RGB shift intensity, can be expensive, 0 */ | ||
@Input() set aberrationStrength(aberrationStrength: number) { | ||
this.set({ aberrationStrength }); | ||
} | ||
/** Color, white */ | ||
@Input() set color(color: THREE.ColorRepresentation) { | ||
this.set({ color }); | ||
} | ||
/** If this is on it uses fewer ray casts for the RGB shift sacrificing physical accuracy, true */ | ||
@Input() set fastChroma(fastChroma: boolean) { | ||
this.set({ fastChroma }); | ||
} | ||
|
||
readonly defines$ = this.select('defines'); | ||
|
||
private readonly store = inject(NgtStore); | ||
|
||
override initialize(): void { | ||
super.initialize(); | ||
this.set({ | ||
aberrationStrength: 0, | ||
fastChroma: true, | ||
}); | ||
} | ||
|
||
constructor() { | ||
super(); | ||
this.connect( | ||
'defines', | ||
combineLatest([this.select('aberrationStrength'), this.select('fastChroma'), this.select('envMap')]).pipe( | ||
map(([aberrationStrength, fastChroma, envMap]) => { | ||
const temp = {} as { [key: string]: string }; | ||
// Sampler2D and SamplerCube need different defines | ||
const isCubeMap = isCubeTexture(envMap); | ||
const w = (isCubeMap ? envMap.image[0]?.width : envMap.image.width) ?? 1024; | ||
const cubeSize = w / 4; | ||
const _lodMax = Math.floor(Math.log2(cubeSize)); | ||
const _cubeSize = Math.pow(2, _lodMax); | ||
const width = 3 * Math.max(_cubeSize, 16 * 7); | ||
const height = 4 * _cubeSize; | ||
if (isCubeMap) temp['ENVMAP_TYPE_CUBEM'] = ''; | ||
temp['CUBEUV_TEXEL_WIDTH'] = `${1.0 / width}`; | ||
temp['CUBEUV_TEXEL_HEIGHT'] = `${1.0 / height}`; | ||
temp['CUBEUV_MAX_MIP'] = `${_lodMax}.0`; | ||
// Add defines from chromatic aberration | ||
if (aberrationStrength > 0) temp['CHROMATIC_ABERRATIONS'] = ''; | ||
if (fastChroma) temp['FAST_CHROMA'] = ''; | ||
return temp; | ||
}) | ||
) | ||
); | ||
this.connect('resolution', this.store.select('size').pipe(map((size) => [size.width, size.height]))); | ||
|
||
injectBeforeRender(({ camera }) => { | ||
if (this.materialRef.nativeElement) { | ||
(this.materialRef.nativeElement as any)!.viewMatrixInverse = camera.matrixWorld; | ||
(this.materialRef.nativeElement as any)!.projectionMatrixInverse = camera.projectionMatrixInverse; | ||
} | ||
}); | ||
} | ||
|
||
ngOnInit() { | ||
this.setupGeometry(); | ||
} | ||
|
||
private setupGeometry() { | ||
this.hold(this.materialRef.$, (material) => { | ||
const geometry = getLocalState(material).parent?.geometry; | ||
if (geometry) { | ||
(material as any).bvh.updateFrom( | ||
new MeshBVH(geometry.toNonIndexed(), { lazyGeneration: false, strategy: SAH } as any) | ||
); | ||
} | ||
}); | ||
} | ||
} |
Oops, something went wrong.