212 lines
8.8 KiB
Nim
212 lines
8.8 KiB
Nim
# The contents of this file are subject to the Common Public Attribution License
|
|
# Version 1.0 (the “License”); you may not use this file except in compliance
|
|
# with the License. You may obtain a copy of the License at
|
|
# https://myou.dev/licenses/LICENSE-CPAL. The License is based on the Mozilla
|
|
# Public License Version 1.1 but Sections 14 and 15 have been added to cover use
|
|
# of software over a computer network and provide for limited attribution for
|
|
# the Original Developer. In addition, Exhibit A has been modified to be
|
|
# consistent with Exhibit B.
|
|
#
|
|
# Software distributed under the License is distributed on an “AS IS” basis,
|
|
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
|
|
# the specific language governing rights and limitations under the License.
|
|
#
|
|
# The Original Code is Myou Engine.
|
|
#
|
|
# the Original Developer is the Initial Developer.
|
|
#
|
|
# The Initial Developer of the Original Code is the Myou Engine developers.
|
|
# All portions of the code written by the Myou Engine developers are Copyright
|
|
# (c) 2024. All Rights Reserved.
|
|
#
|
|
# Alternatively, the contents of this file may be used under the terms of the
|
|
# GNU Affero General Public License version 3 (the [AGPL-3] License), in which
|
|
# case the provisions of [AGPL-3] License are applicable instead of those above.
|
|
#
|
|
# If you wish to allow use of your version of this file only under the terms of
|
|
# the [AGPL-3] License and not to allow others to use your version of this file
|
|
# under the CPAL, indicate your decision by deleting the provisions above and
|
|
# replace them with the notice and other provisions required by the [AGPL-3]
|
|
# License. If you do not delete the provisions above, a recipient may use your
|
|
# version of this file under either the CPAL or the [AGPL-3] License.
|
|
|
|
import ../types
|
|
import std/strformat
|
|
import vmath except Quat
|
|
|
|
when defined(nimdoc):
|
|
type TYPES* = ProbeInfluenceType | ProbeParallaxType | CubemapProbe | CubemapProbeUniform | SH9Uniform
|
|
|
|
# Forward declarations and ob type methods
|
|
proc newCubemapProbe*(engine: MyouEngine, name: string="camera", scene: Scene = nil,
|
|
influence_type: ProbeInfluenceType = SphereInfluence,
|
|
influence_distance: float32 = 2.5,
|
|
falloff: float32 = 0.2,
|
|
intensity: float32 = 1,
|
|
clipping_start: float32 = 0.8,
|
|
clipping_end: float32 = 40,
|
|
parallax_type: ProbeParallaxType = NoParallax,
|
|
parallax_distance: float32 = 0.0, # 0 means auto
|
|
): CubemapProbe
|
|
func getCubemapSideMatrix*(side: int, position = vec3()): Mat4
|
|
proc render_cubemap*(self: CubemapProbe, use_roughness_prefiltering = false, mipmap_shader: Material = nil)
|
|
proc render_background_cubemap*(scene: Scene, use_roughness_prefiltering = false, mipmap_shader: Material = nil, world_to_cube_matrix: Mat4 = mat4(), upload_UBO = true)
|
|
|
|
method is_cubemap_probe*(self: GameObject): bool {.base.} =
|
|
return false
|
|
method get_cubemap_probe*(self: GameObject): CubemapProbe {.base.} =
|
|
return nil
|
|
method is_cubemap_probe*(self: CubemapProbe): bool =
|
|
return true
|
|
method get_cubemap_probe*(self: CubemapProbe): CubemapProbe =
|
|
return self
|
|
# End forward declarations and ob type methods
|
|
|
|
import ./gameobject
|
|
import ../postprocessing/effect_shaders
|
|
import ../graphics/framebuffer
|
|
import ../graphics/render
|
|
import ../scene
|
|
import ../graphics/texture
|
|
import ../graphics/ubo
|
|
import arr_ref
|
|
|
|
|
|
proc newCubemapProbe*(engine: MyouEngine, name: string="camera", scene: Scene = nil,
|
|
influence_type: ProbeInfluenceType = SphereInfluence,
|
|
influence_distance: float32 = 2.5,
|
|
falloff: float32 = 0.2,
|
|
intensity: float32 = 1,
|
|
clipping_start: float32 = 0.8,
|
|
clipping_end: float32 = 40,
|
|
parallax_type: ProbeParallaxType = NoParallax,
|
|
parallax_distance: float32 = 0.0, # 0 means auto
|
|
): CubemapProbe =
|
|
var self = new CubemapProbe
|
|
discard procCall(self.GameObject.initGameObject(engine, name))
|
|
self.ubo_index = -1
|
|
self.influence_type = influence_type
|
|
self.influence_distance = influence_distance
|
|
self.falloff = falloff
|
|
self.intensity = intensity
|
|
self.clipping_start = clipping_start
|
|
self.clipping_end = clipping_end
|
|
self.parallax_type = parallax_type
|
|
self.parallax_distance = if parallax_distance != 0:
|
|
parallax_distance
|
|
else:
|
|
influence_distance
|
|
self.update_strategy = UpdateOnFirstUse
|
|
return self
|
|
|
|
|
|
func getCubemapSideMatrix*(side: int, position = vec3()): Mat4 =
|
|
const CUBEMAP_DIRECTIONS = [
|
|
vec3(1, 0, 0),
|
|
vec3(-1, 0, 0),
|
|
vec3(0, -1, 0), # NOTE: Y is reversed! because cubemaps
|
|
vec3(0, 1, 0), # have left handed coordinates
|
|
vec3(0, 0, 1),
|
|
vec3(0, 0, -1),
|
|
]
|
|
const CUBEMAP_UP_VECTORS = [
|
|
vec3(0, -1, 0),
|
|
vec3(0, -1, 0),
|
|
vec3(0, 0, -1), # reversed here too
|
|
vec3(0, 0, 1), #
|
|
vec3(0, -1, 0),
|
|
vec3(0, -1, 0),
|
|
]
|
|
let dir = CUBEMAP_DIRECTIONS[side]
|
|
let up = CUBEMAP_UP_VECTORS[side]
|
|
let side = cross(up,-dir)
|
|
return mat4(
|
|
vec4(side, position.x),
|
|
vec4(up, position.y),
|
|
vec4(-dir, position.z),
|
|
vec4(0,0,0,1))
|
|
|
|
template getCubemapSideAxis*(side: int): int = side div 2
|
|
|
|
const MIN_ROUGHNESS_LOD = 1
|
|
|
|
var roughness_prefilter: Material = nil
|
|
|
|
proc make_roughness_prefilter(engine: MyouEngine) =
|
|
roughness_prefilter = engine.newEffectShader(@["cube"],
|
|
texture_types = @[TexCube],
|
|
library=staticRead("../shaders/cube_prefilter.glsl"),
|
|
code = &"""
|
|
float roughness = inputs[0].lod/(inputs[0].px_lod-{MIN_ROUGHNESS_LOD.float32});
|
|
outColor = vec4(PrefilterEnvMap(cube, roughness, normalize(coord3D)), 1.0);
|
|
""",
|
|
)
|
|
|
|
template get_roughness_prefilter(engine: MyouEngine): Material =
|
|
if roughness_prefilter == nil:
|
|
make_roughness_prefilter(engine)
|
|
roughness_prefilter
|
|
|
|
proc render_cubemap*(self: CubemapProbe, use_roughness_prefiltering = false, mipmap_shader: Material = nil) =
|
|
if self.ubo_index == -1:
|
|
self.scene.ensure_cubemaps()
|
|
let cube2world = self.world_matrix * scale(vec3(self.influence_distance))
|
|
let world2cube = cube2world.inverse
|
|
if not defined(release):
|
|
assert self.ubo_index < self.scene.max_cubemaps, "max_cubemaps is too low, make sure you call calculate_max_lights_and_cubemaps()"
|
|
# self.scene.cubemap_UBO.storage(CubemapProbeUniform)[self.ubo_index] = CubemapProbeUniform(
|
|
self.scene.cubemap_UBO.byte_storage.to(CubemapProbeUniform)[self.ubo_index] = CubemapProbeUniform(
|
|
world2cube: world2cube,
|
|
resolution: self.cubemap.width.float32,
|
|
# resolution_inverse_squared: (1/(self.cubemap.width^2)).float32,
|
|
falloff_inv: 1/max(0.0001, self.falloff),
|
|
intensity: self.intensity,
|
|
influence_type: self.influence_type.float32,
|
|
parallax_type: self.parallax_type.float32,
|
|
par_dist_rel_inv: 1 / (self.parallax_distance / self.influence_distance),
|
|
roughness_lod: (self.cubemap.texture.mipmapHigh - MIN_ROUGHNESS_LOD).float32,
|
|
)
|
|
self.engine.renderer.draw_cubemap(self.scene,
|
|
self.cubemap,
|
|
cube2world,
|
|
world2cube,
|
|
self.clipping_start,
|
|
self.clipping_end,
|
|
false)
|
|
let mipmap_shader = if use_roughness_prefiltering and mipmap_shader == nil:
|
|
self.engine.get_roughness_prefilter()
|
|
else:
|
|
mipmap_shader
|
|
self.cubemap.generate_mipmap(mipmap_shader)
|
|
self.cubemap.disable()
|
|
|
|
proc render_background_cubemap*(scene: Scene, use_roughness_prefiltering = false, mipmap_shader: Material = nil, world_to_cube_matrix: Mat4 = mat4(), upload_UBO = true) =
|
|
if scene.background_cubemap == nil:
|
|
scene.ensure_cubemaps()
|
|
if not defined(release):
|
|
assert 0 < scene.max_cubemaps, "max_cubemaps is too low, make sure you call calculate_max_lights_and_cubemaps()"
|
|
scene.cubemap_UBO.storage(CubemapProbeUniform)[0] = CubemapProbeUniform(
|
|
world2cube: world_to_cube_matrix,
|
|
resolution: scene.background_cubemap.width.float32,
|
|
# resolution_inverse_squared: (1/(scene.background_cubemap.width^2)).float32,
|
|
falloff_inv: 1,
|
|
intensity: 1,
|
|
parallax_type: -1,
|
|
roughness_lod: (scene.background_cubemap.texture.mipmapHigh - MIN_ROUGHNESS_LOD).float32,
|
|
)
|
|
scene.engine.renderer.draw_cubemap(scene,
|
|
scene.background_cubemap, mat4(), mat4(), 1, 100, true)
|
|
let mipmap_shader = if use_roughness_prefiltering and mipmap_shader == nil:
|
|
scene.engine.get_roughness_prefilter()
|
|
else:
|
|
mipmap_shader
|
|
scene.background_cubemap.generate_mipmap(mipmap_shader)
|
|
if upload_UBO:
|
|
scene.cubemap_UBO.update()
|
|
|
|
proc generate_cubemap_mipmaps*(scene: Scene, cubemap: Framebuffer, use_roughness_prefiltering = false, mipmap_shader: Material = nil) =
|
|
let mipmap_shader = if use_roughness_prefiltering and mipmap_shader == nil:
|
|
scene.engine.get_roughness_prefilter()
|
|
else:
|
|
mipmap_shader
|
|
cubemap.generate_mipmap(mipmap_shader)
|