Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ Untold Engine is well-suited for:
- [Camera System](docs/API/UsingCameraSystem.md)
- [Rendering System](docs/API/UsingRenderingSystem.md)
- [Lighting System](docs/API/UsingLightingSystem.md)
- [Light Portals](docs/API/UsingLightPortals.md)
- [Materials](docs/API/UsingMaterials.md)
- [Input System](docs/API/UsingInputSystem.md)
- [Physics System](docs/API/UsingPhysicsSystem.md)
Expand Down
2 changes: 2 additions & 0 deletions Sources/CShaderTypes/ShaderTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ typedef struct{
simd_float3 up;
simd_float2 bounds;
float intensity;
float range;
float nearSourceSuppressionRadius;
bool twoSided;

}AreaLightUniform;
Expand Down
47 changes: 43 additions & 4 deletions Sources/UntoldEngine/Mesh/Skeleton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,11 @@ class Skeleton {
/// Computes local joint transforms based on an animation clip
private func computeLocalPose(at time: Float, with animationClip: AnimationClip) -> [simd_float4x4] {
jointPaths.indices.map { index in
animationClip.getPose(at: time * animationClip.speed, jointPath: jointPaths[index])
animationClip.getPose(
at: time * animationClip.speed,
jointPath: jointPaths[index],
fallback: restTransform[index]
)
?? restTransform[index]
}
}
Expand Down Expand Up @@ -300,10 +304,45 @@ class AnimationClip {

/// Retrieves the interpolated pose for a joint at a specific time
func getPose(at time: Float, jointPath: String) -> float4x4? {
getPose(at: time, jointPath: jointPath, fallback: .identity)
}

/// Retrieves the interpolated pose while preserving rest-pose channels that are
/// not authored by the clip. Many skeletal clips animate rotation only for most
/// joints; those joints must keep their rest translation offsets. The runtime
/// format does not store scale animation, so keep the rest-pose local scale too.
func getPose(at time: Float, jointPath: String, fallback: float4x4) -> float4x4? {
guard let animation = jointAnimation[jointPath] else { return nil }
let rotation = animation.getRotation(at: time) ?? simd_quatf(simd_float4x4.identity)
let translation = animation.getTranslation(at: time) ?? simd_float3(repeating: 0)
return float4x4(translation: translation) * float4x4(rotation)
let fallbackScale = Self.localScale(from: fallback)
let fallbackRotation = Self.localRotation(from: fallback, scale: fallbackScale)
let rotation = animation.getRotation(at: time) ?? fallbackRotation
let translation = animation.getTranslation(at: time) ?? simd_float3(
fallback.columns.3.x,
fallback.columns.3.y,
fallback.columns.3.z
)
return float4x4(translation: translation) * float4x4(rotation) * float4x4(scale: fallbackScale)
}

private static func localScale(from matrix: float4x4) -> SIMD3<Float> {
SIMD3<Float>(
simd_length(SIMD3<Float>(matrix.columns.0.x, matrix.columns.0.y, matrix.columns.0.z)),
simd_length(SIMD3<Float>(matrix.columns.1.x, matrix.columns.1.y, matrix.columns.1.z)),
simd_length(SIMD3<Float>(matrix.columns.2.x, matrix.columns.2.y, matrix.columns.2.z))
)
}

private static func localRotation(from matrix: float4x4, scale: SIMD3<Float>) -> simd_quatf {
let epsilon: Float = 0.000001
let sx = max(scale.x, epsilon)
let sy = max(scale.y, epsilon)
let sz = max(scale.z, epsilon)
let rotationMatrix = matrix_float3x3(columns: (
SIMD3<Float>(matrix.columns.0.x, matrix.columns.0.y, matrix.columns.0.z) / sx,
SIMD3<Float>(matrix.columns.1.x, matrix.columns.1.y, matrix.columns.1.z) / sy,
SIMD3<Float>(matrix.columns.2.x, matrix.columns.2.y, matrix.columns.2.z) / sz
))
return simd_normalize(simd_quatf(rotationMatrix))
}

// MARK: - Private Helpers
Expand Down
14 changes: 14 additions & 0 deletions Sources/UntoldEngine/Renderer/Pipelines/RenderPipeLines.swift
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,19 @@ public func InitIBLPreFilterPipeline() -> RenderPipeline? {
)
}

public func InitXRIBLCubePreFilterPipeline() -> RenderPipeline? {
CreatePipeline(
vertexShader: "vertexIBLPreFilterShader",
fragmentShader: "fragmentXRIBLCubePreFilterShader",
vertexDescriptor: createIBLPreFilterVertexDescriptor(),
colorFormats: [wf.ibl, wf.ibl, wf.ibl],
depthFormat: .invalid,
depthCompareFunction: .less,
depthEnabled: false,
name: "XR IBL Cube Pre-Filter Pipeline"
)
}

public func InitLookPipeline() -> RenderPipeline? {
CreatePipeline(
vertexShader: "vertexLookShader",
Expand Down Expand Up @@ -920,6 +933,7 @@ public func DefaultPipeLines() -> [(RenderPipelineType, RenderPipelineInitBlock)
(.ssaoUpsample, InitSSAOUpsamplePipeline),
(.environment, InitEnvironmentPipeline),
(.iblPreFilter, InitIBLPreFilterPipeline),
(.xrIBLCubePreFilter, InitXRIBLCubePreFilterPipeline),
(.gaussianTBDRInitialize, InitGaussianTBDRInitializePipeline),
(.gaussianTBDRDraw, InitGaussianTBDRDrawPipeline),
(.gaussianTBDRPostprocess, InitGaussianTBDRPostprocessPipeline),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public extension RenderPipelineType {
static let ssaoUpsample: RenderPipelineType = "ssaoUpsample"
static let environment: RenderPipelineType = "environment"
static let iblPreFilter: RenderPipelineType = "iblPreFilter"
static let xrIBLCubePreFilter: RenderPipelineType = "xrIBLCubePreFilter"
static let gaussianTBDRInitialize: RenderPipelineType = "gaussianTBDRInitialize"
static let gaussianTBDRDraw: RenderPipelineType = "gaussianTBDRDraw"
static let gaussianTBDRPostprocess: RenderPipelineType = "gaussianTBDRPostprocess"
Expand Down
67 changes: 67 additions & 0 deletions Sources/UntoldEngine/Renderer/PostProcessRenderPasses.swift
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,70 @@ func executeIBLPreFilterPass(uCommandBuffer: MTLCommandBuffer, _ envTexture: MTL
}
}
}

public func executeXRIBLCubePreFilterPass(
commandBuffer: MTLCommandBuffer,
environmentCubeTexture: MTLTexture,
target: RuntimeEnvironmentLightingTextureSet
) -> Bool {
guard environmentCubeTexture.textureType == .typeCube else {
Logger.logWarning(message: "[XRLighting] Environment probe texture is not a cube texture")
return false
}

guard let iblPrefilterPipeline = PipelineManager.shared.renderPipelinesByType[.xrIBLCubePreFilter] else {
handleError(.pipelineStateNulled, "xrIBLCubePreFilterPipeline is nil")
return false
}

guard iblPrefilterPipeline.success,
let pipelineState = iblPrefilterPipeline.pipelineState
else {
return false
}

let renderPassDescriptor = MTLRenderPassDescriptor()
renderPassDescriptor.renderTargetWidth = target.irradianceMap.width
renderPassDescriptor.renderTargetHeight = target.irradianceMap.height

renderPassDescriptor.colorAttachments[0].texture = target.irradianceMap
renderPassDescriptor.colorAttachments[0].loadAction = .dontCare
renderPassDescriptor.colorAttachments[0].storeAction = .store

renderPassDescriptor.colorAttachments[1].texture = target.specularMap
renderPassDescriptor.colorAttachments[1].loadAction = .dontCare
renderPassDescriptor.colorAttachments[1].storeAction = .store

renderPassDescriptor.colorAttachments[2].texture = target.brdfMap
renderPassDescriptor.colorAttachments[2].loadAction = .dontCare
renderPassDescriptor.colorAttachments[2].storeAction = .store

guard let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor) else {
return false
}

renderEncoder.setRenderPipelineState(pipelineState)
renderEncoder.pushDebugGroup("XR IBL Cube Pre-Filter Pass")
renderEncoder.label = "XR IBL Cube Pre-Filter Pass"
renderEncoder.setVertexBuffer(bufferResources.quadVerticesBuffer, offset: 0, index: 0)
renderEncoder.setVertexBuffer(bufferResources.quadTexCoordsBuffer, offset: 0, index: 1)
renderEncoder.setFragmentTexture(environmentCubeTexture, index: 0)
renderEncoder.drawIndexedPrimitivesTracked(
type: .triangle,
indexCount: 6,
indexType: .uint16,
indexBuffer: bufferResources.quadIndexBuffer!,
indexBufferOffset: 0
)
renderEncoder.popDebugGroup()
renderEncoder.endEncoding()

guard let blitEncoder = commandBuffer.makeBlitCommandEncoder() else {
return false
}
blitEncoder.label = "XR IBL Specular Mipmap Generation"
blitEncoder.generateMipmaps(for: target.specularMap)
blitEncoder.endEncoding()

return true
}
34 changes: 19 additions & 15 deletions Sources/UntoldEngine/Renderer/RenderPasses.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1961,9 +1961,10 @@ public enum RenderPasses {
renderEncoder.setFragmentBytes(&csmUniforms, length: MemoryLayout<CSMUniforms>.stride, index: Int(lightPassLightOrthoViewMatrixIndex.rawValue))

renderEncoder.setFragmentTexture(textureResources.csmShadowMap, index: Int(lightPassShadowTextureIndex.rawValue))
renderEncoder.setFragmentTexture(textureResources.irradianceMap, index: Int(lightPassIBLIrradianceTextureIndex.rawValue))
renderEncoder.setFragmentTexture(textureResources.specularMap, index: Int(lightPassIBLSpecularTextureIndex.rawValue))
renderEncoder.setFragmentTexture(textureResources.iblBRDFMap, index: Int(lightPassIBLBRDFMapTextureIndex.rawValue))
let environmentLighting = resolveCurrentEnvironmentLighting()
renderEncoder.setFragmentTexture(environmentLighting.irradianceMap, index: Int(lightPassIBLIrradianceTextureIndex.rawValue))
renderEncoder.setFragmentTexture(environmentLighting.specularMap, index: Int(lightPassIBLSpecularTextureIndex.rawValue))
renderEncoder.setFragmentTexture(environmentLighting.brdfMap, index: Int(lightPassIBLBRDFMapTextureIndex.rawValue))
renderEncoder.setFragmentTexture(textureResources.areaTextureLTCMag, index: Int(lightPassAreaLTCMagTextureIndex.rawValue))
renderEncoder.setFragmentTexture(textureResources.areaTextureLTCMat, index: Int(lightPassAreaLTCMatTextureIndex.rawValue))

Expand Down Expand Up @@ -2000,8 +2001,8 @@ public enum RenderPasses {
)

var brdfParameters = IBLParamsUniform()
brdfParameters.applyIBL = applyIBL
brdfParameters.ambientIntensity = ambientIntensity
brdfParameters.applyIBL = environmentLighting.applyIBL
brdfParameters.ambientIntensity = environmentLighting.ambientIntensity
renderEncoder.setFragmentBytes(&brdfParameters, length: MemoryLayout<IBLParamsUniform>.stride, index: Int(lightPassIBLParamIndex.rawValue))

var lightPassRotationAngle = envRotationAngle
Expand Down Expand Up @@ -2676,20 +2677,22 @@ public enum RenderPasses {

renderEncoder.setFragmentTexture(textureResources.areaTextureLTCMag, index: Int(lightPassAreaLTCMagTextureIndex.rawValue))

let environmentLighting = resolveCurrentEnvironmentLighting()

// ibl
renderEncoder.setFragmentTexture(
textureResources.irradianceMap, index: Int(lightPassIBLIrradianceTextureIndex.rawValue)
environmentLighting.irradianceMap, index: Int(lightPassIBLIrradianceTextureIndex.rawValue)
)
renderEncoder.setFragmentTexture(
textureResources.specularMap, index: Int(lightPassIBLSpecularTextureIndex.rawValue)
environmentLighting.specularMap, index: Int(lightPassIBLSpecularTextureIndex.rawValue)
)
renderEncoder.setFragmentTexture(
textureResources.iblBRDFMap, index: Int(lightPassIBLBRDFMapTextureIndex.rawValue)
environmentLighting.brdfMap, index: Int(lightPassIBLBRDFMapTextureIndex.rawValue)
)

var brdfParameters = IBLParamsUniform()
brdfParameters.applyIBL = applyIBL
brdfParameters.ambientIntensity = ambientIntensity
brdfParameters.applyIBL = environmentLighting.applyIBL
brdfParameters.ambientIntensity = environmentLighting.ambientIntensity

renderEncoder.setFragmentBytes(
&brdfParameters, length: MemoryLayout<IBLParamsUniform>.stride,
Expand Down Expand Up @@ -2983,16 +2986,17 @@ public enum RenderPasses {
textureResources.areaTextureLTCMag,
index: Int(transparencyPassAreaLTCMagTextureIndex.rawValue)
)
let environmentLighting = resolveCurrentEnvironmentLighting()
renderEncoder.setFragmentTexture(
textureResources.irradianceMap,
environmentLighting.irradianceMap,
index: Int(transparencyPassIBLIrradianceTextureIndex.rawValue)
)
renderEncoder.setFragmentTexture(
textureResources.specularMap,
environmentLighting.specularMap,
index: Int(transparencyPassIBLSpecularTextureIndex.rawValue)
)
renderEncoder.setFragmentTexture(
textureResources.iblBRDFMap,
environmentLighting.brdfMap,
index: Int(transparencyPassIBLBRDFMapTextureIndex.rawValue)
)
renderEncoder.setFragmentTexture(
Expand All @@ -3001,8 +3005,8 @@ public enum RenderPasses {
)

var iblParameters = IBLParamsUniform()
iblParameters.applyIBL = applyIBL
iblParameters.ambientIntensity = ambientIntensity
iblParameters.applyIBL = environmentLighting.applyIBL
iblParameters.ambientIntensity = environmentLighting.ambientIntensity
renderEncoder.setFragmentBytes(
&iblParameters,
length: MemoryLayout<IBLParamsUniform>.stride,
Expand Down
Loading
Loading