@takram/three-atmosphere
Version:
A Three.js and R3F implementation of Precomputed Atmospheric Scattering
145 lines (127 loc) • 3.98 kB
text/typescript
import {
GLSL3,
Matrix4,
Uniform,
Vector2,
type BufferGeometry,
type Group,
type Object3D,
type OrthographicCamera,
type PerspectiveCamera,
type Scene,
type WebGLRenderer
} from 'three'
import { define, resolveIncludes } from '@takram/three-geospatial'
import {
AtmosphereMaterialBase,
atmosphereMaterialParametersBaseDefaults,
type AtmosphereMaterialBaseParameters,
type AtmosphereMaterialBaseUniforms
} from './AtmosphereMaterialBase'
import functions from './shaders/functions.glsl?raw'
import parameters from './shaders/parameters.glsl?raw'
import fragmentShader from './shaders/stars.frag?raw'
import vertexShader from './shaders/stars.vert?raw'
declare module 'three' {
interface Camera {
isPerspectiveCamera?: boolean
}
}
export interface StarsMaterialParameters
extends AtmosphereMaterialBaseParameters {
pointSize?: number
radianceScale?: number
background?: boolean
}
export const starsMaterialParametersDefaults = {
...atmosphereMaterialParametersBaseDefaults,
pointSize: 1,
radianceScale: 1,
background: true
} satisfies StarsMaterialParameters
export interface StarsMaterialUniforms {
[key: string]: Uniform<unknown>
projectionMatrix: Uniform<Matrix4>
modelViewMatrix: Uniform<Matrix4>
viewMatrix: Uniform<Matrix4>
matrixWorld: Uniform<Matrix4>
cameraFar: Uniform<number>
pointSize: Uniform<number>
magnitudeRange: Uniform<Vector2>
radianceScale: Uniform<number>
}
export class StarsMaterial extends AtmosphereMaterialBase {
declare uniforms: AtmosphereMaterialBaseUniforms & StarsMaterialUniforms
pointSize: number
constructor(params?: StarsMaterialParameters) {
const { pointSize, radianceScale, background, ...others } = {
...starsMaterialParametersDefaults,
...params
}
super({
name: 'StarsMaterial',
glslVersion: GLSL3,
vertexShader: resolveIncludes(vertexShader, {
parameters
}),
fragmentShader: resolveIncludes(fragmentShader, {
parameters,
functions
}),
...others,
uniforms: {
projectionMatrix: new Uniform(new Matrix4()),
modelViewMatrix: new Uniform(new Matrix4()),
viewMatrix: new Uniform(new Matrix4()),
matrixWorld: new Uniform(new Matrix4()),
cameraFar: new Uniform(0),
pointSize: new Uniform(0),
magnitudeRange: new Uniform(new Vector2(-2, 8)),
radianceScale: new Uniform(radianceScale),
...others.uniforms
} satisfies StarsMaterialUniforms,
defines: {
PERSPECTIVE_CAMERA: '1'
}
})
this.pointSize = pointSize
this.background = background
}
override onBeforeRender(
renderer: WebGLRenderer,
scene: Scene,
camera: PerspectiveCamera | OrthographicCamera,
geometry: BufferGeometry,
object: Object3D,
group: Group
): void {
super.onBeforeRender(renderer, scene, camera, geometry, object, group)
const uniforms = this.uniforms
uniforms.projectionMatrix.value.copy(camera.projectionMatrix)
uniforms.modelViewMatrix.value.copy(camera.modelViewMatrix)
uniforms.viewMatrix.value.copy(camera.matrixWorldInverse)
uniforms.matrixWorld.value.copy(object.matrixWorld)
uniforms.cameraFar.value = camera.far
uniforms.pointSize.value = this.pointSize * renderer.getPixelRatio()
const isPerspectiveCamera = camera.isPerspectiveCamera === true
if ((this.defines.PERSPECTIVE_CAMERA != null) !== isPerspectiveCamera) {
if (isPerspectiveCamera) {
this.defines.PERSPECTIVE_CAMERA = '1'
} else {
delete this.defines.PERSPECTIVE_CAMERA
}
this.needsUpdate = true
}
}
get magnitudeRange(): Vector2 {
return this.uniforms.magnitudeRange.value
}
get radianceScale(): number {
return this.uniforms.radianceScale.value
}
set radianceScale(value: number) {
this.uniforms.radianceScale.value = value
}
('BACKGROUND')
background: boolean
}