Merge pull request #358 from DigitalPulseSoftware/phong-lighting

Add phong lighting support
This commit is contained in:
Jérôme Leclercq 2022-02-02 18:55:39 +01:00 committed by GitHub
commit 29cd77db55
110 changed files with 3963 additions and 1222 deletions

View File

@ -1,44 +1,44 @@
[layout(std140)]
struct ViewerData
{
projectionMatrix: mat4<f32>,
invProjectionMatrix: mat4<f32>,
viewMatrix: mat4<f32>,
invViewMatrix: mat4<f32>,
viewProjMatrix: mat4<f32>,
invViewProjMatrix: mat4<f32>,
renderTargetSize: vec2<f32>,
invRenderTargetSize: vec2<f32>,
eyePosition: vec3<f32>
projectionMatrix: mat4[f32],
invProjectionMatrix: mat4[f32],
viewMatrix: mat4[f32],
invViewMatrix: mat4[f32],
viewProjMatrix: mat4[f32],
invViewProjMatrix: mat4[f32],
renderTargetSize: vec2[f32],
invRenderTargetSize: vec2[f32],
eyePosition: vec3[f32]
}
external
{
[set(0), binding(0)] viewerData: uniform<ViewerData>,
[set(0), binding(1)] colorTexture: sampler2D<f32>,
[set(0), binding(0)] viewerData: uniform[ViewerData],
[set(0), binding(1)] colorTexture: sampler2D[f32],
}
struct FragIn
{
[builtin(fragcoord)] fragcoord: vec4<f32>,
[location(0)] uv: vec2<f32>
[builtin(fragcoord)] fragcoord: vec4[f32],
[location(0)] uv: vec2[f32]
}
struct FragOut
{
[location(0)] color: vec4<f32>
[location(0)] color: vec4[f32]
}
struct VertIn
{
[location(0)] pos: vec2<f32>,
[location(1)] uv: vec2<f32>
[location(0)] pos: vec2[f32],
[location(1)] uv: vec2[f32]
}
struct VertOut
{
[builtin(position)] position: vec4<f32>,
[location(0)] uv: vec2<f32>
[builtin(position)] position: vec4[f32],
[location(0)] uv: vec2[f32]
}
[entry(frag)]
@ -50,19 +50,19 @@ fn main(input: FragIn) -> FragOut
let color = colorTexture.Sample(input.uv).rgb;
color *= BrightMiddleGrey / BrightLuminance;
color *= vec3<f32>(1.0, 1.0, 1.0) + (color / (BrightThreshold*BrightThreshold));
color -= vec3<f32>(0.5, 0.5, 0.5);
color /= vec3<f32>(1.0, 1.0, 1.0) + color;*/
color *= vec3[f32](1.0, 1.0, 1.0) + (color / (BrightThreshold*BrightThreshold));
color -= vec3[f32](0.5, 0.5, 0.5);
color /= vec3[f32](1.0, 1.0, 1.0) + color;*/
let output: FragOut;
//output.color = vec4<f32>(max(color, vec3<f32>(0.0, 0.0, 0.0)), 1.0);
//output.color = vec4[f32](max(color, vec3[f32](0.0, 0.0, 0.0)), 1.0);
let color = colorTexture.Sample(input.uv).rgb;
let brightness = dot(color, vec3<f32>(0.2126, 0.7152, 0.0722));
let brightness = dot(color, vec3[f32](0.2126, 0.7152, 0.0722));
if (brightness > 1.0)
output.color = vec4<f32>(color, 1.0);
output.color = vec4[f32](color, 1.0);
else
output.color = vec4<f32>(0.0, 0.0, 0.0, 1.0);
output.color = vec4[f32](0.0, 0.0, 0.0, 1.0);
return output;
}
@ -71,7 +71,7 @@ fn main(input: FragIn) -> FragOut
fn main(input: VertIn) -> VertOut
{
let output: VertOut;
output.position = vec4<f32>(input.pos, 0.0, 1.0);
output.position = vec4[f32](input.pos, 0.0, 1.0);
output.uv = input.uv;
return output;

View File

@ -1,44 +1,44 @@
[layout(std140)]
struct ViewerData
{
projectionMatrix: mat4<f32>,
invProjectionMatrix: mat4<f32>,
viewMatrix: mat4<f32>,
invViewMatrix: mat4<f32>,
viewProjMatrix: mat4<f32>,
invViewProjMatrix: mat4<f32>,
renderTargetSize: vec2<f32>,
invRenderTargetSize: vec2<f32>,
eyePosition: vec3<f32>
projectionMatrix: mat4[f32],
invProjectionMatrix: mat4[f32],
viewMatrix: mat4[f32],
invViewMatrix: mat4[f32],
viewProjMatrix: mat4[f32],
invViewProjMatrix: mat4[f32],
renderTargetSize: vec2[f32],
invRenderTargetSize: vec2[f32],
eyePosition: vec3[f32]
}
external
{
[set(0), binding(0)] viewerData: uniform<ViewerData>,
//[set(0), binding(1)] colorTexture: sampler2D<f32>,
[set(0), binding(2)] bloomTexture: sampler2D<f32>,
[set(0), binding(0)] viewerData: uniform[ViewerData],
//[set(0), binding(1)] colorTexture: sampler2D[f32],
[set(0), binding(2)] bloomTexture: sampler2D[f32],
}
struct FragIn
{
[location(0)] uv: vec2<f32>
[location(0)] uv: vec2[f32]
}
struct FragOut
{
[location(0)] color: vec4<f32>
[location(0)] color: vec4[f32]
}
struct VertIn
{
[location(0)] pos: vec2<f32>,
[location(1)] uv: vec2<f32>,
[location(0)] pos: vec2[f32],
[location(1)] uv: vec2[f32],
}
struct VertOut
{
[location(0)] uv: vec2<f32>,
[builtin(position)] position: vec4<f32>
[location(0)] uv: vec2[f32],
[builtin(position)] position: vec4[f32]
}
[entry(frag)]
@ -54,7 +54,7 @@ fn main(input: FragIn) -> FragOut
fn main(input: VertIn) -> VertOut
{
let output: VertOut;
output.position = vec4<f32>(input.pos, 0.0, 1.0);
output.position = vec4[f32](input.pos, 0.0, 1.0);
output.uv = input.uv;
return output;

View File

@ -6,52 +6,52 @@ option AlphaTest: bool = false;
struct BasicSettings
{
AlphaThreshold: f32,
DiffuseColor: vec4<f32>
DiffuseColor: vec4[f32]
}
[layout(std140)]
struct InstanceData
{
worldMatrix: mat4<f32>,
invWorldMatrix: mat4<f32>
worldMatrix: mat4[f32],
invWorldMatrix: mat4[f32]
}
[layout(std140)]
struct ViewerData
{
projectionMatrix: mat4<f32>,
invProjectionMatrix: mat4<f32>,
viewMatrix: mat4<f32>,
invViewMatrix: mat4<f32>,
viewProjMatrix: mat4<f32>,
invViewProjMatrix: mat4<f32>,
renderTargetSize: vec2<f32>,
invRenderTargetSize: vec2<f32>,
eyePosition: vec3<f32>
projectionMatrix: mat4[f32],
invProjectionMatrix: mat4[f32],
viewMatrix: mat4[f32],
invViewMatrix: mat4[f32],
viewProjMatrix: mat4[f32],
invViewProjMatrix: mat4[f32],
renderTargetSize: vec2[f32],
invRenderTargetSize: vec2[f32],
eyePosition: vec3[f32]
}
external
{
[binding(0)] settings: uniform<BasicSettings>,
[binding(1)] MaterialDiffuseMap: sampler2D<f32>,
[binding(2)] MaterialAlphaMap: sampler2D<f32>,
[binding(3)] TextureOverlay: sampler2D<f32>,
[binding(4)] instanceData: uniform<InstanceData>,
[binding(5)] viewerData: uniform<ViewerData>,
[binding(0)] settings: uniform[BasicSettings],
[binding(1)] MaterialDiffuseMap: sampler2D[f32],
[binding(2)] MaterialAlphaMap: sampler2D[f32],
[binding(3)] TextureOverlay: sampler2D[f32],
[binding(4)] instanceData: uniform[InstanceData],
[binding(5)] viewerData: uniform[ViewerData],
}
struct InputData
{
[location(0)] normal: vec3<f32>,
[location(1)] uv: vec2<f32>,
[location(2)] pos: vec3<f32>
[location(0)] normal: vec3[f32],
[location(1)] uv: vec2[f32],
[location(2)] pos: vec3[f32]
}
struct OutputData
{
[location(0)] diffuseMap: vec4<f32>,
[location(1)] normalMap: vec4<f32>,
[location(2)] positionMap: vec4<f32>
[location(0)] diffuseMap: vec4[f32],
[location(1)] normalMap: vec4[f32],
[location(2)] positionMap: vec4[f32]
}
[entry(frag)]
@ -72,7 +72,7 @@ fn main(input: InputData) -> OutputData
let output: OutputData;
output.diffuseMap = diffuseColor;
output.normalMap = vec4<f32>((vec3<f32>(1.0, 1.0, 1.0) + input.normal) * 0.5, 1.0);
output.positionMap = vec4<f32>(input.pos, 1.0);
output.normalMap = vec4[f32]((vec3[f32](1.0, 1.0, 1.0) + input.normal) * 0.5, 1.0);
output.positionMap = vec4[f32](input.pos, 1.0);
return output;
}

View File

@ -2,61 +2,61 @@
struct BasicSettings
{
AlphaThreshold: f32,
DiffuseColor: vec4<f32>
DiffuseColor: vec4[f32]
}
[layout(std140)]
struct InstanceData
{
worldMatrix: mat4<f32>,
invWorldMatrix: mat4<f32>
worldMatrix: mat4[f32],
invWorldMatrix: mat4[f32]
}
[layout(std140)]
struct ViewerData
{
projectionMatrix: mat4<f32>,
invProjectionMatrix: mat4<f32>,
viewMatrix: mat4<f32>,
invViewMatrix: mat4<f32>,
viewProjMatrix: mat4<f32>,
invViewProjMatrix: mat4<f32>,
renderTargetSize: vec2<f32>,
invRenderTargetSize: vec2<f32>,
eyePosition: vec3<f32>
projectionMatrix: mat4[f32],
invProjectionMatrix: mat4[f32],
viewMatrix: mat4[f32],
invViewMatrix: mat4[f32],
viewProjMatrix: mat4[f32],
invViewProjMatrix: mat4[f32],
renderTargetSize: vec2[f32],
invRenderTargetSize: vec2[f32],
eyePosition: vec3[f32]
}
external
{
[binding(0)] settings: uniform<BasicSettings>,
[binding(4)] instanceData: uniform<InstanceData>,
[binding(5)] viewerData: uniform<ViewerData>,
[binding(0)] settings: uniform[BasicSettings],
[binding(4)] instanceData: uniform[InstanceData],
[binding(5)] viewerData: uniform[ViewerData],
}
struct InputData
{
[location(0)] pos: vec3<f32>,
[location(1)] normal: vec3<f32>,
[location(2)] uv: vec2<f32>
[location(0)] pos: vec3[f32],
[location(1)] normal: vec3[f32],
[location(2)] uv: vec2[f32]
}
struct OutputData
{
[location(0)] normal: vec3<f32>,
[location(1)] uv: vec2<f32>,
[location(2)] pos: vec3<f32>,
[builtin(position)] position: vec4<f32>
[location(0)] normal: vec3[f32],
[location(1)] uv: vec2[f32],
[location(2)] pos: vec3[f32],
[builtin(position)] position: vec4[f32]
}
[entry(vert)]
fn main(input: InputData) -> OutputData
{
let worldPos = instanceData.worldMatrix * vec4<f32>(input.pos, 1.0);
let worldPos = instanceData.worldMatrix * vec4[f32](input.pos, 1.0);
let output: OutputData;
output.uv = input.uv;
output.normal = input.normal;
output.pos = worldPos.xyz;
output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4<f32>(input.pos, 1.0);
output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4[f32](input.pos, 1.0);
return output;
}

View File

@ -1,28 +1,28 @@
external
{
[binding(0)] colorTexture: sampler2D<f32>
[binding(0)] colorTexture: sampler2D[f32]
}
struct FragIn
{
[location(0)] uv: vec2<f32>
[location(0)] uv: vec2[f32]
}
struct FragOut
{
[location(0)] color: vec4<f32>
[location(0)] color: vec4[f32]
}
struct VertIn
{
[location(0)] pos: vec2<f32>,
[location(1)] uv: vec2<f32>
[location(0)] pos: vec2[f32],
[location(1)] uv: vec2[f32]
}
struct VertOut
{
[location(0)] vertUV: vec2<f32>,
[builtin(position)] position: vec4<f32>
[location(0)] vertUV: vec2[f32],
[builtin(position)] position: vec4[f32]
}
[entry(frag)]
@ -32,7 +32,7 @@ fn main(input: FragIn) -> FragOut
let output: FragOut;
output.color = colorTexture.Sample(input.uv);
//output.color = pow(colorTexture.Sample(input.uv), vec4<f32>(1.0 / gamma, 1.0 / gamma, 1.0 / gamma, 1.0));
//output.color = pow(colorTexture.Sample(input.uv), vec4[f32](1.0 / gamma, 1.0 / gamma, 1.0 / gamma, 1.0));
return output;
}
@ -40,7 +40,7 @@ fn main(input: FragIn) -> FragOut
fn main(input: VertIn) -> VertOut
{
let output: VertOut;
output.position = vec4<f32>(input.pos, 0.0, 1.0);
output.position = vec4[f32](input.pos, 0.0, 1.0);
output.vertUV = input.uv;
return output;
}

View File

@ -1,51 +1,51 @@
[layout(std140)]
struct ViewerData
{
projectionMatrix: mat4<f32>,
invProjectionMatrix: mat4<f32>,
viewMatrix: mat4<f32>,
invViewMatrix: mat4<f32>,
viewProjMatrix: mat4<f32>,
invViewProjMatrix: mat4<f32>,
renderTargetSize: vec2<f32>,
invRenderTargetSize: vec2<f32>,
eyePosition: vec3<f32>
projectionMatrix: mat4[f32],
invProjectionMatrix: mat4[f32],
viewMatrix: mat4[f32],
invViewMatrix: mat4[f32],
viewProjMatrix: mat4[f32],
invViewProjMatrix: mat4[f32],
renderTargetSize: vec2[f32],
invRenderTargetSize: vec2[f32],
eyePosition: vec3[f32]
}
[layout(std140)]
struct BlurData
{
direction: vec2<f32>,
direction: vec2[f32],
sizeFactor: f32
}
external
{
[set(0), binding(0)] viewerData: uniform<ViewerData>,
[set(0), binding(1)] colorTexture: sampler2D<f32>,
[set(0), binding(2)] blurData: uniform<BlurData>
[set(0), binding(0)] viewerData: uniform[ViewerData],
[set(0), binding(1)] colorTexture: sampler2D[f32],
[set(0), binding(2)] blurData: uniform[BlurData]
}
struct FragIn
{
[location(0)] uv: vec2<f32>
[location(0)] uv: vec2[f32]
}
struct FragOut
{
[location(0)] color: vec4<f32>
[location(0)] color: vec4[f32]
}
struct VertIn
{
[location(0)] pos: vec2<f32>,
[location(1)] uv: vec2<f32>,
[location(0)] pos: vec2[f32],
[location(1)] uv: vec2[f32],
}
struct VertOut
{
[location(0)] uv: vec2<f32>,
[builtin(position)] position: vec4<f32>
[location(0)] uv: vec2[f32],
[builtin(position)] position: vec4[f32]
}
[entry(frag)]
@ -62,7 +62,7 @@ fn main(input: FragIn) -> FragOut
color += colorTexture.Sample(input.uv - blurData.direction * 3.2307692308 * invTargetSize).rgb * 0.0702702703;
let output: FragOut;
output.color = vec4<f32>(color, 1.0);
output.color = vec4[f32](color, 1.0);
return output;
}
@ -71,7 +71,7 @@ fn main(input: FragIn) -> FragOut
fn main(input: VertIn) -> VertOut
{
let output: VertOut;
output.position = vec4<f32>(input.pos, 0.0, 1.0);
output.position = vec4[f32](input.pos, 0.0, 1.0);
output.uv = input.uv;
return output;

View File

@ -1,15 +1,15 @@
[layout(std140)]
struct ViewerData
{
projectionMatrix: mat4<f32>,
invProjectionMatrix: mat4<f32>,
viewMatrix: mat4<f32>,
invViewMatrix: mat4<f32>,
viewProjMatrix: mat4<f32>,
invViewProjMatrix: mat4<f32>,
renderTargetSize: vec2<f32>,
invRenderTargetSize: vec2<f32>,
eyePosition: vec3<f32>
projectionMatrix: mat4[f32],
invProjectionMatrix: mat4[f32],
viewMatrix: mat4[f32],
invViewMatrix: mat4[f32],
viewProjMatrix: mat4[f32],
invViewProjMatrix: mat4[f32],
renderTargetSize: vec2[f32],
invRenderTargetSize: vec2[f32],
eyePosition: vec3[f32]
}
[layout(std140)]
@ -19,38 +19,38 @@ struct Settings
decay: f32,
density: f32,
weight: f32,
lightPosition: vec2<f32>, //< TODO: Switch to world position
lightPosition: vec2[f32], //< TODO: Switch to world position
}
const SampleCount: i32 = 200;
external
{
[set(0), binding(0)] viewerData: uniform<ViewerData>,
[set(0), binding(1)] settings: uniform<Settings>,
[set(0), binding(2)] occluderTexture: sampler2D<f32>
[set(0), binding(0)] viewerData: uniform[ViewerData],
[set(0), binding(1)] settings: uniform[Settings],
[set(0), binding(2)] occluderTexture: sampler2D[f32]
}
struct FragIn
{
[location(0)] uv: vec2<f32>
[location(0)] uv: vec2[f32]
}
struct FragOut
{
[location(0)] color: vec4<f32>
[location(0)] color: vec4[f32]
}
struct VertIn
{
[location(0)] pos: vec2<f32>,
[location(1)] uv: vec2<f32>
[location(0)] pos: vec2[f32],
[location(1)] uv: vec2[f32]
}
struct VertOut
{
[builtin(position)] position: vec4<f32>,
[location(0)] uv: vec2<f32>
[builtin(position)] position: vec4[f32],
[location(0)] uv: vec2[f32]
}
[entry(frag)]
@ -62,7 +62,7 @@ fn main(input: FragIn) -> FragOut
let uv = input.uv;
let outputColor = vec4<f32>(0.0, 0.0, 0.0, 1.0);
let outputColor = vec4[f32](0.0, 0.0, 0.0, 1.0);
for i in 0 -> SampleCount
{
@ -85,7 +85,7 @@ fn main(input: FragIn) -> FragOut
fn main(input: VertIn) -> VertOut
{
let output: VertOut;
output.position = vec4<f32>(input.pos, 0.0, 1.0);
output.position = vec4[f32](input.pos, 0.0, 1.0);
output.uv = input.uv;
return output;

View File

@ -1,8 +1,8 @@
[layout(std140)]
struct PointLight
{
color: vec3<f32>,
position: vec3<f32>,
color: vec3[f32],
position: vec3[f32],
radius: f32,
invRadius: f32,
@ -11,11 +11,11 @@ struct PointLight
[layout(std140)]
struct SpotLight
{
transformMatrix: mat4<f32>,
transformMatrix: mat4[f32],
color: vec3<f32>,
position: vec3<f32>,
direction: vec3<f32>,
color: vec3[f32],
position: vec3[f32],
direction: vec3[f32],
radius: f32,
invRadius: f32,
@ -27,63 +27,63 @@ struct SpotLight
[layout(std140)]
struct ViewerData
{
projectionMatrix: mat4<f32>,
invProjectionMatrix: mat4<f32>,
viewMatrix: mat4<f32>,
invViewMatrix: mat4<f32>,
viewProjMatrix: mat4<f32>,
invViewProjMatrix: mat4<f32>,
renderTargetSize: vec2<f32>,
invRenderTargetSize: vec2<f32>,
eyePosition: vec3<f32>
projectionMatrix: mat4[f32],
invProjectionMatrix: mat4[f32],
viewMatrix: mat4[f32],
invViewMatrix: mat4[f32],
viewProjMatrix: mat4[f32],
invViewProjMatrix: mat4[f32],
renderTargetSize: vec2[f32],
invRenderTargetSize: vec2[f32],
eyePosition: vec3[f32]
}
[set(0)]
external
{
[binding(0)] viewerData: uniform<ViewerData>,
[binding(1)] colorTexture: sampler2D<f32>,
[binding(2)] normalTexture: sampler2D<f32>,
[binding(3)] positionTexture: sampler2D<f32>,
[binding(0)] viewerData: uniform[ViewerData],
[binding(1)] colorTexture: sampler2D[f32],
[binding(2)] normalTexture: sampler2D[f32],
[binding(3)] positionTexture: sampler2D[f32],
}
[set(1)]
external
{
[binding(0)] lightParameters: uniform<SpotLight>,
[binding(0)] lightParameters: uniform[SpotLight],
}
struct FragIn
{
[builtin(fragcoord)] fragcoord: vec4<f32>
[builtin(fragcoord)] fragcoord: vec4[f32]
}
struct FragOut
{
[location(0)] color: vec4<f32>
[location(0)] color: vec4[f32]
}
struct VertIn
{
[location(0)] pos: vec3<f32>
[location(0)] pos: vec3[f32]
}
struct VertOut
{
[builtin(position)] position: vec4<f32>
[builtin(position)] position: vec4[f32]
}
[entry(frag)]
fn main(input: FragIn) -> FragOut
{
let fragcoord = input.fragcoord.xy * viewerData.invRenderTargetSize;
let normal = normalTexture.Sample(fragcoord).xyz * 2.0 - vec3<f32>(1.0, 1.0, 1.0);
let normal = normalTexture.Sample(fragcoord).xyz * 2.0 - vec3[f32](1.0, 1.0, 1.0);
let position = positionTexture.Sample(fragcoord).xyz;
let attenuation = compute_attenuation(position, normal);
let output: FragOut;
output.color = vec4<f32>(lightParameters.color, 1.0) * attenuation * colorTexture.Sample(fragcoord);
output.color = vec4[f32](lightParameters.color, 1.0) * attenuation * colorTexture.Sample(fragcoord);
return output;
}
@ -92,12 +92,12 @@ fn main(input: FragIn) -> FragOut
fn main(input: VertIn) -> VertOut
{
let output: VertOut;
output.position = viewerData.projectionMatrix * viewerData.viewMatrix * lightParameters.transformMatrix * vec4<f32>(input.pos, 1.0);
output.position = viewerData.projectionMatrix * viewerData.viewMatrix * lightParameters.transformMatrix * vec4[f32](input.pos, 1.0);
return output;
}
fn compute_attenuation(worldPos: vec3<f32>, normal: vec3<f32>) -> f32
fn compute_attenuation(worldPos: vec3[f32], normal: vec3[f32]) -> f32
{
let distance = length(lightParameters.position - worldPos);

View File

@ -1,32 +1,32 @@
[layout(std140)]
struct ViewerData
{
projectionMatrix: mat4<f32>,
invProjectionMatrix: mat4<f32>,
viewMatrix: mat4<f32>,
invViewMatrix: mat4<f32>,
viewProjMatrix: mat4<f32>,
invViewProjMatrix: mat4<f32>,
renderTargetSize: vec2<f32>,
invRenderTargetSize: vec2<f32>,
eyePosition: vec3<f32>
projectionMatrix: mat4[f32],
invProjectionMatrix: mat4[f32],
viewMatrix: mat4[f32],
invViewMatrix: mat4[f32],
viewProjMatrix: mat4[f32],
invViewProjMatrix: mat4[f32],
renderTargetSize: vec2[f32],
invRenderTargetSize: vec2[f32],
eyePosition: vec3[f32]
}
external
{
[binding(0)] viewerData: uniform<ViewerData>,
[binding(1)] skybox: samplerCube<f32>
[binding(0)] viewerData: uniform[ViewerData],
[binding(1)] skybox: samplerCube[f32]
}
struct VertOut
{
[location(0)] uvw: vec3<f32>,
[builtin(position)] position: vec4<f32>
[location(0)] uvw: vec3[f32],
[builtin(position)] position: vec4[f32]
}
struct FragOut
{
[location(0)] color: vec4<f32>,
[location(0)] color: vec4[f32],
[builtin(fragdepth)] depth: f32
}
@ -43,7 +43,7 @@ fn main(input: VertOut) -> FragOut
struct VertIn
{
[location(0)] position: vec3<f32>
[location(0)] position: vec3[f32]
}
[entry(vert)]
@ -51,10 +51,10 @@ fn main(input: VertIn) -> VertOut
{
// Set translation part to zero
let rotationMat = viewerData.viewMatrix;
rotationMat[3].xyz = vec3<f32>(0.0, 0.0, 0.0);
rotationMat[3].xyz = vec3[f32](0.0, 0.0, 0.0);
let output: VertOut;
output.position = viewerData.projectionMatrix * rotationMat * vec4<f32>(input.position, 1.0);
output.position = viewerData.projectionMatrix * rotationMat * vec4[f32](input.position, 1.0);
output.uvw = input.position.xyz;
return output;

View File

@ -1,43 +1,43 @@
[layout(std140)]
struct ViewerData
{
projectionMatrix: mat4<f32>,
invProjectionMatrix: mat4<f32>,
viewMatrix: mat4<f32>,
invViewMatrix: mat4<f32>,
viewProjMatrix: mat4<f32>,
invViewProjMatrix: mat4<f32>,
renderTargetSize: vec2<f32>,
invRenderTargetSize: vec2<f32>,
eyePosition: vec3<f32>
projectionMatrix: mat4[f32],
invProjectionMatrix: mat4[f32],
viewMatrix: mat4[f32],
invViewMatrix: mat4[f32],
viewProjMatrix: mat4[f32],
invViewProjMatrix: mat4[f32],
renderTargetSize: vec2[f32],
invRenderTargetSize: vec2[f32],
eyePosition: vec3[f32]
}
external
{
[set(0), binding(0)] viewerData: uniform<ViewerData>,
[set(0), binding(1)] inputTexture: sampler2D<f32>
[set(0), binding(0)] viewerData: uniform[ViewerData],
[set(0), binding(1)] inputTexture: sampler2D[f32]
}
struct FragIn
{
[location(0)] uv: vec2<f32>,
[location(0)] uv: vec2[f32],
}
struct FragOut
{
[location(0)] color: vec4<f32>
[location(0)] color: vec4[f32]
}
struct VertIn
{
[location(0)] pos: vec2<f32>,
[location(1)] uv: vec2<f32>,
[location(0)] pos: vec2[f32],
[location(1)] uv: vec2[f32],
}
struct VertOut
{
[location(0)] uv: vec2<f32>,
[builtin(position)] position: vec4<f32>
[location(0)] uv: vec2[f32],
[builtin(position)] position: vec4[f32]
}
[entry(frag)]
@ -48,10 +48,10 @@ fn main(input: FragIn) -> FragOut
let hdrColor = inputTexture.Sample(input.uv).rgb;
// reinhard tone mapping
let mapped = vec3<f32>(1.0, 1.0, 1.0) - exp(-hdrColor * exposure);
let mapped = vec3[f32](1.0, 1.0, 1.0) - exp(-hdrColor * exposure);
let output: FragOut;
output.color = vec4<f32>(mapped, 1.0);
output.color = vec4[f32](mapped, 1.0);
return output;
}
@ -60,7 +60,7 @@ fn main(input: FragIn) -> FragOut
fn main(input: VertIn) -> VertOut
{
let output: VertOut;
output.position = vec4<f32>(input.pos, 0.0, 1.0);
output.position = vec4[f32](input.pos, 0.0, 1.0);
output.uv = input.uv;
return output;

View File

@ -17,8 +17,8 @@ constexpr std::size_t BloomSubdivisionCount = 5;
[layout(std140)]
struct PointLight
{
color: vec3<f32>,
position: vec3<f32>,
color: vec3[f32],
position: vec3[f32],
constant: f32,
linear: f32,
@ -28,9 +28,9 @@ struct PointLight
[layout(std140)]
struct SpotLight
{
color: vec3<f32>,
position: vec3<f32>,
direction: vec3<f32>,
color: vec3[f32],
position: vec3[f32],
direction: vec3[f32],
constant: f32,
linear: f32,
@ -130,7 +130,11 @@ int main()
std::shared_ptr<Nz::GraphicalMesh> cubeMeshGfx = std::make_shared<Nz::GraphicalMesh>(*cubeMesh);
Nz::RenderPipelineLayoutInfo skyboxPipelineLayoutInfo;
Nz::Graphics::FillViewerPipelineLayout(skyboxPipelineLayoutInfo, 0);
skyboxPipelineLayoutInfo.bindings.push_back({
0, 0,
Nz::ShaderBindingType::UniformBuffer,
Nz::ShaderStageType_All
});
auto& textureBinding = skyboxPipelineLayoutInfo.bindings.emplace_back();
textureBinding.setIndex = 0;
@ -259,7 +263,11 @@ int main()
Nz::RenderPipelineLayoutInfo lightingPipelineLayoutInfo;
Nz::Graphics::FillViewerPipelineLayout(lightingPipelineLayoutInfo, 0);
lightingPipelineLayoutInfo.bindings.push_back({
0, 0,
Nz::ShaderBindingType::UniformBuffer,
Nz::ShaderStageType_All
});
for (unsigned int i = 0; i < 3; ++i)
{
@ -291,9 +299,9 @@ int main()
[layout(std140)]
struct SpotLight
{
color: vec3<f32>,
position: vec3<f32>,
direction: vec3<f32>,
color: vec3[f32],
position: vec3[f32],
direction: vec3[f32],
constant: f32,
linear: f32,
@ -353,7 +361,11 @@ int main()
// Bloom data
Nz::RenderPipelineLayoutInfo fullscreenPipelineLayoutInfoViewer;
Nz::Graphics::FillViewerPipelineLayout(fullscreenPipelineLayoutInfoViewer, 0);
fullscreenPipelineLayoutInfoViewer.bindings.push_back({
0, 0,
Nz::ShaderBindingType::UniformBuffer,
Nz::ShaderStageType_All
});
fullscreenPipelineLayoutInfoViewer.bindings.push_back({
0, 1,
@ -432,7 +444,11 @@ int main()
std::shared_ptr<Nz::ShaderBinding> bloomBlitBinding;
Nz::RenderPipelineLayoutInfo bloomBlendPipelineLayoutInfo;
Nz::Graphics::FillViewerPipelineLayout(bloomBlendPipelineLayoutInfo, 0);
bloomBlendPipelineLayoutInfo.bindings.push_back({
0, 0,
Nz::ShaderBindingType::UniformBuffer,
Nz::ShaderStageType_All
});
/*bloomBlendPipelineLayoutInfo.bindings.push_back({
0, 1,
@ -838,12 +854,14 @@ int main()
planeModel.BuildElement(forwardPassIndex, planeInstance, elements);
std::vector<Nz::Pointer<const Nz::RenderElement>> elementPointers;
std::vector<Nz::ElementRenderer::RenderStates> renderStates(elements.size());
elementPointers.reserve(elements.size());
for (const auto& element : elements)
elementPointers.emplace_back(element.get());
submeshRenderer.Prepare(viewerInstance, *submeshRendererData, *currentFrame, elementPointers.data(), elementPointers.size());
submeshRenderer.Render(viewerInstance, *submeshRendererData, builder, elementPointers.data(), elementPointers.size());
submeshRenderer.Prepare(viewerInstance, *submeshRendererData, *currentFrame, elementPointers.size(), elementPointers.data(), renderStates.data());
submeshRenderer.PrepareEnd(*currentFrame, *spriteRendererData);
submeshRenderer.Render(viewerInstance, *submeshRendererData, builder, elementPointers.size(), elementPointers.data());
});
Nz::FramePass& lightingPass = graph.AddPass("Lighting pass");
@ -902,12 +920,14 @@ int main()
flareSprite.BuildElement(forwardPassIndex, flareInstance, elements);
std::vector<Nz::Pointer<const Nz::RenderElement>> elementPointers;
std::vector<Nz::ElementRenderer::RenderStates> renderStates(elements.size());
elementPointers.reserve(elements.size());
for (const auto& element : elements)
elementPointers.emplace_back(element.get());
spritechainRenderer.Prepare(viewerInstance, *spriteRendererData, *currentFrame, elementPointers.data(), elementPointers.size());
spritechainRenderer.Render(viewerInstance, *spriteRendererData, builder, elementPointers.data(), elementPointers.size());
spritechainRenderer.Prepare(viewerInstance, *spriteRendererData, *currentFrame, elementPointers.size(), elementPointers.data(), renderStates.data());
spritechainRenderer.Render(viewerInstance, *spriteRendererData, builder, elementPointers.size(), elementPointers.data());
});
forwardPass.SetExecutionCallback([&]
{
@ -930,12 +950,15 @@ int main()
flareSprite.BuildElement(forwardPassIndex, flareInstance, elements);
std::vector<Nz::Pointer<const Nz::RenderElement>> elementPointers;
std::vector<Nz::ElementRenderer::RenderStates> renderStates(elements.size());
elementPointers.reserve(elements.size());
for (const auto& element : elements)
elementPointers.emplace_back(element.get());
spritechainRenderer.Prepare(viewerInstance, *spriteRendererData, *currentFrame, elementPointers.data(), elementPointers.size());
spritechainRenderer.Render(viewerInstance, *spriteRendererData, builder, elementPointers.data(), elementPointers.size());
spritechainRenderer.Prepare(viewerInstance, *spriteRendererData, *currentFrame, elementPointers.size(), elementPointers.data(), renderStates.data());
spritechainRenderer.PrepareEnd(*currentFrame, *spriteRendererData);
spritechainRenderer.Render(viewerInstance, *spriteRendererData, builder, elementPointers.size(), elementPointers.data());
});
occluderPass.AddOutput(occluderTexture);

View File

@ -29,7 +29,7 @@ int main()
Nz::MeshParams meshParams;
meshParams.center = true;
meshParams.matrix = Nz::Matrix4f::Rotate(Nz::EulerAnglesf(0.f, -90.f, 0.f)) * Nz::Matrix4f::Scale(Nz::Vector3f(0.002f));
meshParams.vertexDeclaration = Nz::VertexDeclaration::Get(Nz::VertexLayout::XYZ_UV);
meshParams.vertexDeclaration = Nz::VertexDeclaration::Get(Nz::VertexLayout::XYZ_Normal_UV_Tangent);
std::shared_ptr<Nz::RenderDevice> device = Nz::Graphics::Instance()->GetRenderDevice();
@ -63,16 +63,19 @@ int main()
std::shared_ptr<Nz::Material> material = std::make_shared<Nz::Material>();
std::shared_ptr<Nz::MaterialPass> materialPass = std::make_shared<Nz::MaterialPass>(Nz::BasicMaterial::GetSettings());
std::shared_ptr<Nz::MaterialPass> materialPass = std::make_shared<Nz::MaterialPass>(Nz::PhongLightingMaterial::GetSettings());
materialPass->EnableDepthBuffer(true);
materialPass->EnableFaceCulling(true);
material->AddPass("ForwardPass", materialPass);
Nz::BasicMaterial basicMat(*materialPass);
basicMat.EnableAlphaTest(false);
basicMat.SetAlphaMap(Nz::Texture::LoadFromFile(resourceDir / "alphatile.png", texParams));
basicMat.SetDiffuseMap(Nz::Texture::LoadFromFile(resourceDir / "Spaceship/Texture/diffuse.png", texParams));
std::shared_ptr<Nz::Texture> normalMap = Nz::Texture::LoadFromFile(resourceDir / "Spaceship/Texture/normal.png", texParams);
Nz::PhongLightingMaterial phongMat(*materialPass);
phongMat.EnableAlphaTest(false);
phongMat.SetAlphaMap(Nz::Texture::LoadFromFile(resourceDir / "alphatile.png", texParams));
phongMat.SetDiffuseMap(Nz::Texture::LoadFromFile(resourceDir / "Spaceship/Texture/diffuse.png", texParams));
phongMat.SetNormalMap(Nz::Texture::LoadFromFile(resourceDir / "Spaceship/Texture/normal.png", texParams));
Nz::Model model(std::move(gfxMesh), spaceshipMesh->GetAABB());
model.UpdateScissorBox(Nz::Recti(0, 0, 1920, 1080));
@ -94,11 +97,18 @@ int main()
Nz::WorldInstancePtr modelInstance2 = std::make_shared<Nz::WorldInstance>();
modelInstance2->UpdateWorldMatrix(Nz::Matrix4f::Translate(Nz::Vector3f::Forward() * 2 + Nz::Vector3f::Right()));
model.UpdateScissorBox(Nz::Recti(Nz::Vector2i(window.GetSize())));
Nz::ForwardFramePipeline framePipeline;
framePipeline.RegisterViewer(&camera, 0);
framePipeline.RegisterInstancedDrawable(modelInstance, &model, 0xFFFFFFFF);
framePipeline.RegisterInstancedDrawable(modelInstance2, &model, 0xFFFFFFFF);
std::shared_ptr<Nz::PointLight> light = std::make_shared<Nz::PointLight>();
light->UpdateColor(Nz::Color::Green);
framePipeline.RegisterLight(light, 0xFFFFFFFF);
Nz::Vector3f viewerPos = Nz::Vector3f::Zero();
Nz::EulerAnglesf camAngles(0.f, 0.f, 0.f);
@ -125,7 +135,19 @@ int main()
case Nz::WindowEventType::KeyPressed:
if (event.key.virtualKey == Nz::Keyboard::VKey::A)
basicMat.EnableAlphaTest(!basicMat.IsAlphaTestEnabled());
phongMat.EnableAlphaTest(!phongMat.IsAlphaTestEnabled());
else if (event.key.virtualKey == Nz::Keyboard::VKey::N)
{
if (phongMat.GetNormalMap())
phongMat.SetNormalMap({});
else
phongMat.SetNormalMap(normalMap);
}
else if (event.key.virtualKey == Nz::Keyboard::VKey::Space)
{
modelInstance->UpdateWorldMatrix(Nz::Matrix4f::Translate(viewerPos));
framePipeline.InvalidateWorldInstance(modelInstance.get());
}
break;
@ -185,15 +207,17 @@ int main()
// Contrôle (Gauche ou droite) pour descendre dans l'espace global, etc...
if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::LControl) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::RControl))
viewerPos += Nz::Vector3f::Down() * cameraSpeed;
light->UpdatePosition(viewerPos);
}
Nz::RenderFrame frame = window.AcquireFrame();
if (!frame)
continue;
Nz::UploadPool& uploadPool = frame.GetUploadPool();
viewerInstance.UpdateViewMatrix(Nz::Matrix4f::ViewMatrix(viewerPos, camAngles));
viewerInstance.UpdateEyePosition(viewerPos);
framePipeline.InvalidateViewer(&camera);
framePipeline.Render(frame);

View File

@ -54,7 +54,7 @@ int main()
Nz::MeshParams meshParams;
meshParams.center = true;
meshParams.matrix = Nz::Matrix4f::Rotate(Nz::EulerAnglesf(0.f, 90.f, 0.f)) * Nz::Matrix4f::Scale(Nz::Vector3f(0.002f));
meshParams.vertexDeclaration = Nz::VertexDeclaration::Get(Nz::VertexLayout::XYZ_UV);
meshParams.vertexDeclaration = Nz::VertexDeclaration::Get(Nz::VertexLayout::XYZ_Normal_UV_Tangent);
std::shared_ptr<Nz::Mesh> spaceshipMesh = Nz::Mesh::LoadFromFile(resourceDir / "Spaceship/spaceship.obj", meshParams);
if (!spaceshipMesh)
@ -71,10 +71,10 @@ int main()
std::shared_ptr<Nz::MaterialPass> depthPass = std::make_shared<Nz::MaterialPass>(Nz::DepthMaterial::GetSettings());
depthPass->EnableDepthBuffer(true);
depthPass->EnableDepthClamp(true);
//depthPass->EnableDepthClamp(true);
depthPass->EnableFaceCulling(true);
std::shared_ptr<Nz::MaterialPass> materialPass = std::make_shared<Nz::MaterialPass>(Nz::BasicMaterial::GetSettings());
std::shared_ptr<Nz::MaterialPass> materialPass = std::make_shared<Nz::MaterialPass>(Nz::PhongLightingMaterial::GetSettings());
materialPass->EnableDepthBuffer(true);
materialPass->EnableDepthClamp(true);
materialPass->EnableFaceCulling(true);
@ -91,7 +91,7 @@ int main()
Nz::BasicMaterial basicMat(*materialPass);
basicMat.EnableAlphaTest(false);
basicMat.SetAlphaMap(Nz::Texture::LoadFromFile(resourceDir / "alphatile.png", texParams));
//basicMat.SetAlphaMap(Nz::Texture::LoadFromFile(resourceDir / "alphatile.png", texParams));
basicMat.SetDiffuseMap(Nz::Texture::LoadFromFile(resourceDir / "Spaceship/Texture/diffuse.png", texParams));
basicMat.SetDiffuseSampler(samplerInfo);
@ -143,37 +143,12 @@ int main()
Nz::Physics3DSystem physSytem(registry);
Nz::RenderSystem renderSystem(registry);
Nz::Canvas canvas2D(registry, window.GetEventHandler(), window.GetCursorController().CreateHandle(), 2);
canvas2D.Resize(Nz::Vector2f(window.GetSize()));
Nz::LabelWidget* labelWidget = canvas2D.Add<Nz::LabelWidget>();
labelWidget->SetPosition(0.f, 300.f, 0.f);
labelWidget->EnableBackground(true);
labelWidget->UpdateText(Nz::SimpleTextDrawer::Draw("Bonjour Paris !", 72));
Nz::ButtonWidget* buttonWidget = canvas2D.Add<Nz::ButtonWidget>();
buttonWidget->SetPosition(200.f, 400.f);
buttonWidget->UpdateText(Nz::SimpleTextDrawer::Draw("Press me senpai", 72));
buttonWidget->Resize(buttonWidget->GetPreferredSize());
buttonWidget->OnButtonTrigger.Connect([](const Nz::ButtonWidget*)
{
std::cout << "Coucou !" << std::endl;
});
entt::entity viewer2D = registry.create();
{
registry.emplace<Nz::NodeComponent>(viewer2D);
auto& cameraComponent = registry.emplace<Nz::CameraComponent>(viewer2D, window.GetRenderTarget(), Nz::ProjectionType::Orthographic);
cameraComponent.UpdateClearColor(Nz::Color(0, 0, 0, 0));
cameraComponent.UpdateRenderOrder(1);
cameraComponent.UpdateRenderMask(2);
}
entt::entity viewer = registry.create();
{
registry.emplace<Nz::NodeComponent>(viewer);
auto& cameraComponent = registry.emplace<Nz::CameraComponent>(viewer, window.GetRenderTarget());
cameraComponent.UpdateRenderMask(1);
//cameraComponent.UpdateClearColor(Nz::Color(127, 127, 127));
}
auto shipCollider = std::make_shared<Nz::ConvexCollider3D>(vertices, vertexMapper.GetVertexCount(), 0.01f);
@ -211,6 +186,9 @@ int main()
entt::entity headingEntity = registry.create();
{
auto& entityLight = registry.emplace<Nz::LightComponent>(playerEntity);
entityLight.AttachLight(std::make_shared<Nz::DirectionalLight>(), 1);
auto& entityGfx = registry.emplace<Nz::GraphicsComponent>(playerEntity);
entityGfx.AttachRenderable(model, 1);
@ -287,6 +265,7 @@ int main()
case Nz::WindowEventType::KeyPressed:
if (event.key.virtualKey == Nz::Keyboard::VKey::A)
{
//canvas2D.Resize({ 1920.f, 1080.f });
basicMat.EnableAlphaTest(!basicMat.IsAlphaTestEnabled());
basicMatDepth.EnableAlphaTest(!basicMatDepth.IsAlphaTestEnabled());
}

View File

@ -17,50 +17,50 @@ option red: bool = false;
[layout(std140)]
struct Data
{
projectionMatrix: mat4<f32>,
worldMatrix: mat4<f32>,
viewMatrix: mat4<f32>
projectionMatrix: mat4[f32],
worldMatrix: mat4[f32],
viewMatrix: mat4[f32]
}
[set(0)]
external
{
[binding(0)] viewerData: uniform<Data>,
[binding(0)] viewerData: uniform[Data],
}
[set(1)]
external
{
[binding(0)] tex: sampler2D<f32>
[binding(0)] tex: sampler2D[f32]
}
struct VertIn
{
[location(0)] position: vec3<f32>,
[location(1)] normal: vec3<f32>,
[location(2)] uv: vec2<f32>
[location(0)] position: vec3[f32],
[location(1)] normal: vec3[f32],
[location(2)] uv: vec2[f32]
}
struct VertOut
{
[builtin(position)] position: vec4<f32>,
[location(0)] normal: vec3<f32>,
[location(1)] uv: vec2<f32>
[builtin(position)] position: vec4[f32],
[location(0)] normal: vec3[f32],
[location(1)] uv: vec2[f32]
}
struct FragOut
{
[location(0)] color: vec4<f32>
[location(0)] color: vec4[f32]
}
[entry(frag)]
fn main(fragIn: VertOut) -> FragOut
{
let lightDir = vec3<f32>(0.0, 0.707, 0.707);
let lightDir = vec3[f32](0.0, 0.707, 0.707);
let lightFactor = dot(fragIn.normal, lightDir);
let fragOut: FragOut;
fragOut.color = lightFactor * tex.Sample(fragIn.uv) * const_select(red, vec4<f32>(1.0, 0.0, 0.0, 1.0), vec4<f32>(1.0, 1.0, 1.0, 1.0));
fragOut.color = lightFactor * tex.Sample(fragIn.uv) * const_select(red, vec4[f32](1.0, 0.0, 0.0, 1.0), vec4[f32](1.0, 1.0, 1.0, 1.0));
return fragOut;
}
@ -69,7 +69,7 @@ fn main(fragIn: VertOut) -> FragOut
fn main(vertIn: VertIn) -> VertOut
{
let vertOut: VertOut;
vertOut.position = viewerData.projectionMatrix * viewerData.viewMatrix * viewerData.worldMatrix * vec4<f32>(vertIn.position, 1.0);
vertOut.position = viewerData.projectionMatrix * viewerData.viewMatrix * viewerData.worldMatrix * vec4[f32](vertIn.position, 1.0);
vertOut.normal = vertIn.normal;
vertOut.uv = vertIn.uv;

View File

@ -0,0 +1,172 @@
#include <Nazara/Core.hpp>
#include <Nazara/Core/ECS.hpp>
#include <Nazara/Platform.hpp>
#include <Nazara/Graphics.hpp>
#include <Nazara/Graphics/TextSprite.hpp>
#include <Nazara/Graphics/Components.hpp>
#include <Nazara/Graphics/Systems.hpp>
#include <Nazara/Math/PidController.hpp>
#include <Nazara/Physics3D.hpp>
#include <Nazara/Physics3D/Components.hpp>
#include <Nazara/Physics3D/Systems.hpp>
#include <Nazara/Renderer.hpp>
#include <Nazara/Shader.hpp>
#include <Nazara/Shader/SpirvConstantCache.hpp>
#include <Nazara/Shader/SpirvPrinter.hpp>
#include <Nazara/Utility.hpp>
#include <Nazara/Utility/Components.hpp>
#include <Nazara/Widgets.hpp>
#include <entt/entt.hpp>
#include <array>
#include <iostream>
#include <limits>
NAZARA_REQUEST_DEDICATED_GPU()
int main()
{
std::filesystem::path resourceDir = "resources";
if (!std::filesystem::is_directory(resourceDir) && std::filesystem::is_directory(".." / resourceDir))
resourceDir = ".." / resourceDir;
Nz::Renderer::Config rendererConfig;
std::cout << "Run using Vulkan? (y/n)" << std::endl;
if (std::getchar() != 'n')
rendererConfig.preferredAPI = Nz::RenderAPI::Vulkan;
else
rendererConfig.preferredAPI = Nz::RenderAPI::OpenGL;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
Nz::Modules<Nz::Graphics, Nz::Physics3D, Nz::ECS, Nz::Widgets> nazara(rendererConfig);
Nz::RenderWindow window;
std::shared_ptr<Nz::RenderDevice> device = Nz::Graphics::Instance()->GetRenderDevice();
std::string windowTitle = "Widget Test";
if (!window.Create(device, Nz::VideoMode(1920, 1080, 32), windowTitle))
{
std::cout << "Failed to create Window" << std::endl;
return __LINE__;
}
entt::registry registry;
Nz::RenderSystem renderSystem(registry);
Nz::Canvas canvas2D(registry, window.GetEventHandler(), window.GetCursorController().CreateHandle(), 0xFFFFFFFF);
canvas2D.Resize(Nz::Vector2f(window.GetSize()));
Nz::LabelWidget* labelWidget = canvas2D.Add<Nz::LabelWidget>();
labelWidget->SetPosition(0.f, 200.f, 0.f);
labelWidget->UpdateText(Nz::SimpleTextDrawer::Draw("Je suis un LabelWidget !", 72));
Nz::ButtonWidget* buttonWidget = canvas2D.Add<Nz::ButtonWidget>();
buttonWidget->SetPosition(200.f, 400.f);
buttonWidget->UpdateText(Nz::SimpleTextDrawer::Draw("Press me senpai", 72));
buttonWidget->Resize(buttonWidget->GetPreferredSize());
buttonWidget->OnButtonTrigger.Connect([=](const Nz::ButtonWidget*)
{
buttonWidget->Destroy();
});
std::shared_ptr<Nz::Material> material = std::make_shared<Nz::Material>();
std::shared_ptr<Nz::MaterialPass> materialPass = std::make_shared<Nz::MaterialPass>(Nz::BasicMaterial::GetSettings());
material->AddPass("ForwardPass", materialPass);
Nz::TextureSamplerInfo samplerInfo;
samplerInfo.anisotropyLevel = 8;
Nz::TextureParams texParams;
texParams.renderDevice = device;
texParams.loadFormat = Nz::PixelFormat::RGBA8_SRGB;
Nz::BasicMaterial basicMat(*materialPass);
basicMat.SetDiffuseMap(Nz::Texture::LoadFromFile(resourceDir / "Spaceship/Texture/diffuse.png", texParams));
basicMat.SetDiffuseSampler(samplerInfo);
Nz::ImageWidget* imageWidget = canvas2D.Add<Nz::ImageWidget>();
imageWidget->SetPosition(1200.f, 200.f);
imageWidget->SetMaterial(material);
imageWidget->Resize(imageWidget->GetPreferredSize() / 4.f);
Nz::TextAreaWidget* textAreaWidget = canvas2D.Add<Nz::TextAreaWidget>();
textAreaWidget->SetPosition(800.f, 500.f);
textAreaWidget->SetText("Je suis un TextAreaWidget !");
textAreaWidget->Resize(Nz::Vector2f(400.f, textAreaWidget->GetPreferredHeight() * 5.f));
textAreaWidget->SetBackgroundColor(Nz::Color::White);
textAreaWidget->SetTextColor(Nz::Color::Black);
textAreaWidget->EnableMultiline(true);
Nz::CheckboxWidget* checkboxWidget = canvas2D.Add<Nz::CheckboxWidget>();
//checkboxWidget->EnableTristate(true);
checkboxWidget->SetPosition(800.f, 800.f);
checkboxWidget->Resize({ 256.f, 256.f });
checkboxWidget->SetState(true);
/*Nz::TextAreaWidget* textAreaWidget2 = canvas2D.Add<Nz::TextAreaWidget>();
textAreaWidget2->SetPosition(800.f, 700.f);
textAreaWidget2->SetText("Je suis un autre TextAreaWidget !");
textAreaWidget2->Resize(Nz::Vector2f(500.f, textAreaWidget2->GetPreferredHeight()));
textAreaWidget2->SetBackgroundColor(Nz::Color::White);
textAreaWidget2->SetTextColor(Nz::Color::Black);*/
entt::entity viewer2D = registry.create();
{
registry.emplace<Nz::NodeComponent>(viewer2D);
auto& cameraComponent = registry.emplace<Nz::CameraComponent>(viewer2D, window.GetRenderTarget(), Nz::ProjectionType::Orthographic);
cameraComponent.UpdateClearColor(Nz::Color(173, 216, 230, 255));
}
window.EnableEventPolling(true);
Nz::Clock updateClock;
Nz::Clock secondClock;
unsigned int fps = 0;
float elapsedTime = 0.f;
Nz::UInt64 time = Nz::GetElapsedMicroseconds();
while (window.IsOpen())
{
Nz::UInt64 now = Nz::GetElapsedMicroseconds();
elapsedTime = (now - time) / 1'000'000.f;
time = now;
Nz::WindowEvent event;
while (window.PollEvent(&event))
{
switch (event.type)
{
case Nz::WindowEventType::Quit:
window.Close();
break;
default:
break;
}
}
Nz::RenderFrame frame = window.AcquireFrame();
if (!frame)
continue;
renderSystem.Render(registry, frame);
frame.Present();
fps++;
if (secondClock.GetMilliseconds() >= 1000)
{
window.SetTitle(windowTitle + " - " + Nz::NumberToString(fps) + " FPS" + " - " + Nz::NumberToString(registry.alive()) + " entities");
fps = 0;
secondClock.Restart();
}
}
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,6 @@
target("WidgetDemo")
set_group("Examples")
set_kind("binary")
add_deps("NazaraGraphics", "NazaraPhysics3D", "NazaraWidgets")
add_packages("entt")
add_files("main.cpp")

View File

@ -19,8 +19,8 @@ namespace Nz
class SparsePtr
{
public:
using BytePtr = typename std::conditional<std::is_const<T>::value, const UInt8*, UInt8*>::type;
using VoidPtr = typename std::conditional<std::is_const<T>::value, const void*, void*>::type;
using BytePtr = std::conditional_t<std::is_const<T>::value, const UInt8*, UInt8*>;
using VoidPtr = std::conditional_t<std::is_const<T>::value, const void*, void*>;
SparsePtr();
SparsePtr(T* ptr);
@ -46,18 +46,16 @@ namespace Nz
explicit operator T*() const;
T& operator*() const;
T* operator->() const;
T& operator[](std::size_t index) const;
template<typename U> T& operator[](U index) const;
SparsePtr& operator=(const SparsePtr& ptr) = default;
SparsePtr operator+(Int64 count) const;
SparsePtr operator+(UInt64 count) const;
SparsePtr operator-(Int64 count) const;
SparsePtr operator-(UInt64 count) const;
template<typename U> SparsePtr operator+(U count) const;
template<typename U> SparsePtr operator-(U count) const;
std::ptrdiff_t operator-(const SparsePtr& ptr) const;
SparsePtr& operator+=(Int64 count);
SparsePtr& operator-=(Int64 count);
template<typename U> SparsePtr& operator+=(U count);
template<typename U> SparsePtr& operator-=(U count);
SparsePtr& operator++();
SparsePtr operator++(int);

View File

@ -247,8 +247,11 @@ namespace Nz
*/
template<typename T>
T& SparsePtr<T>::operator[](std::size_t index) const
template<typename U>
T& SparsePtr<T>::operator[](U index) const
{
static_assert(std::is_integral_v<U>, "index must be an integral type");
return *reinterpret_cast<T*>(m_ptr + index * m_stride);
}
@ -260,8 +263,11 @@ namespace Nz
*/
template<typename T>
SparsePtr<T> SparsePtr<T>::operator+(Int64 count) const
template<typename U>
SparsePtr<T> SparsePtr<T>::operator+(U count) const
{
static_assert(std::is_integral_v<U>, "count must be an integral type");
return SparsePtr(m_ptr + count * m_stride, m_stride);
}
@ -273,34 +279,11 @@ namespace Nz
*/
template<typename T>
SparsePtr<T> SparsePtr<T>::operator+(UInt64 count) const
template<typename U>
SparsePtr<T> SparsePtr<T>::operator-(U count) const
{
return SparsePtr(m_ptr + count * m_stride, m_stride);
}
static_assert(std::is_integral_v<U>, "count must be an integral type");
/*!
* \brief Gets the SparsePtr with an offset
* \return A SparsePtr with the new stride
*
* \param count Number of stride to do
*/
template<typename T>
SparsePtr<T> SparsePtr<T>::operator-(Int64 count) const
{
return SparsePtr(m_ptr - count * m_stride, m_stride);
}
/*!
* \brief Gets the SparsePtr with an offset
* \return A SparsePtr with the new stride
*
* \param count Number of stride to do
*/
template<typename T>
SparsePtr<T> SparsePtr<T>::operator-(UInt64 count) const
{
return SparsePtr(m_ptr - count * m_stride, m_stride);
}
@ -325,25 +308,22 @@ namespace Nz
*/
template<typename T>
SparsePtr<T>& SparsePtr<T>::operator+=(Int64 count)
template<typename U>
SparsePtr<T>& SparsePtr<T>::operator+=(U count)
{
m_ptr += count * m_stride;
static_assert(std::is_integral_v<U>, "count must be an integral type");
m_ptr += count * m_stride;
return *this;
}
/*!
* \brief Gets the SparsePtr with an offset
* \return A reference to this pointer with the new stride
*
* \param count Number of stride to do
*/
template<typename T>
SparsePtr<T>& SparsePtr<T>::operator-=(Int64 count)
template<typename U>
SparsePtr<T>& SparsePtr<T>::operator-=(U count)
{
m_ptr -= count * m_stride;
static_assert(std::is_integral_v<U>, "count must be an integral type");
m_ptr -= count * m_stride;
return *this;
}

View File

@ -36,6 +36,7 @@
#include <Nazara/Graphics/Camera.hpp>
#include <Nazara/Graphics/Config.hpp>
#include <Nazara/Graphics/DepthMaterial.hpp>
#include <Nazara/Graphics/DirectionalLight.hpp>
#include <Nazara/Graphics/ElementRenderer.hpp>
#include <Nazara/Graphics/Enums.hpp>
#include <Nazara/Graphics/ForwardFramePipeline.hpp>
@ -47,6 +48,7 @@
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/GuillotineTextureAtlas.hpp>
#include <Nazara/Graphics/InstancedRenderable.hpp>
#include <Nazara/Graphics/Light.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/MaterialPass.hpp>
#include <Nazara/Graphics/MaterialPassRegistry.hpp>
@ -54,6 +56,7 @@
#include <Nazara/Graphics/MaterialSettings.hpp>
#include <Nazara/Graphics/Model.hpp>
#include <Nazara/Graphics/PhongLightingMaterial.hpp>
#include <Nazara/Graphics/PointLight.hpp>
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
#include <Nazara/Graphics/RenderElement.hpp>
#include <Nazara/Graphics/RenderQueue.hpp>
@ -61,6 +64,7 @@
#include <Nazara/Graphics/RenderSpriteChain.hpp>
#include <Nazara/Graphics/RenderSubmesh.hpp>
#include <Nazara/Graphics/SlicedSprite.hpp>
#include <Nazara/Graphics/SpotLight.hpp>
#include <Nazara/Graphics/Sprite.hpp>
#include <Nazara/Graphics/SpriteChainRenderer.hpp>
#include <Nazara/Graphics/SubmeshRenderer.hpp>

View File

@ -19,7 +19,7 @@ namespace Nz
friend class MaterialPipeline;
public:
struct UniformOffsets;
struct BasicUniformOffsets;
BasicMaterial(MaterialPass& material);
~BasicMaterial() = default;
@ -48,10 +48,10 @@ namespace Nz
inline void SetDiffuseMap(std::shared_ptr<Texture> diffuseMap);
inline void SetDiffuseSampler(TextureSamplerInfo diffuseSampler);
static inline const UniformOffsets& GetOffsets();
static inline const BasicUniformOffsets& GetOffsets();
static inline const std::shared_ptr<MaterialSettings>& GetSettings();
struct UniformOffsets
struct BasicUniformOffsets
{
std::size_t alphaThreshold;
std::size_t diffuseColor;
@ -59,38 +59,59 @@ namespace Nz
};
protected:
struct OptionIndexes
struct NoInit {};
inline BasicMaterial(MaterialPass& material, NoInit);
struct BasicOptionIndexes
{
std::size_t alphaTest;
std::size_t hasAlphaMap;
std::size_t hasDiffuseMap;
};
struct TextureIndexes
struct BasicTextureIndexes
{
std::size_t alpha;
std::size_t diffuse;
};
static MaterialSettings::Builder Build(const UniformOffsets& offsets, std::vector<UInt8> defaultValues, std::vector<std::shared_ptr<UberShader>> uberShaders, std::size_t* uniformBlockIndex = nullptr, OptionIndexes* optionIndexes = nullptr, TextureIndexes* textureIndexes = nullptr);
struct BasicBuildOptions
{
// Common
std::vector<UInt8> defaultValues;
std::size_t* uniformBlockIndex = nullptr;
std::vector<std::shared_ptr<UberShader>> shaders;
// Basic
BasicUniformOffsets basicOffsets;
BasicOptionIndexes* basicOptionIndexes = nullptr;
BasicTextureIndexes* basicTextureIndexes = nullptr;
};
inline MaterialPass& GetMaterial();
inline const MaterialPass& GetMaterial() const;
static MaterialSettings::Builder Build(BasicBuildOptions& options);
static std::vector<std::shared_ptr<UberShader>> BuildShaders();
static std::pair<UniformOffsets, FieldOffsets> BuildUniformOffsets();
static std::pair<BasicUniformOffsets, FieldOffsets> BuildUniformOffsets();
std::size_t m_uniformBlockIndex;
BasicOptionIndexes m_basicOptionIndexes;
BasicTextureIndexes m_basicTextureIndexes;
BasicUniformOffsets m_basicUniformOffsets;
static std::shared_ptr<MaterialSettings> s_basicMaterialSettings;
static std::size_t s_uniformBlockIndex;
static BasicOptionIndexes s_basicOptionIndexes;
static BasicTextureIndexes s_basicTextureIndexes;
static BasicUniformOffsets s_basicUniformOffsets;
private:
static bool Initialize();
static void Uninitialize();
MaterialPass& m_material;
std::size_t m_uniformBlockIndex;
OptionIndexes m_optionIndexes;
TextureIndexes m_textureIndexes;
UniformOffsets m_uniformOffsets;
static std::shared_ptr<MaterialSettings> s_materialSettings;
static std::size_t s_uniformBlockIndex;
static OptionIndexes s_optionIndexes;
static TextureIndexes s_textureIndexes;
static UniformOffsets s_uniformOffsets;
};
}

View File

@ -9,6 +9,11 @@
namespace Nz
{
inline BasicMaterial::BasicMaterial(MaterialPass& material, NoInit) :
m_material(material)
{
}
/*!
* \brief Enable/Disable alpha test for this material
*
@ -26,37 +31,37 @@ namespace Nz
inline void BasicMaterial::EnableAlphaTest(bool alphaTest)
{
NazaraAssert(HasAlphaTest(), "Material has no alpha test option");
m_material.SetOptionValue(m_optionIndexes.alphaTest, alphaTest);
m_material.SetOptionValue(m_basicOptionIndexes.alphaTest, alphaTest);
}
inline const std::shared_ptr<Texture>& BasicMaterial::GetAlphaMap() const
{
NazaraAssert(HasAlphaMap(), "Material has no alpha texture slot");
return m_material.GetTexture(m_textureIndexes.alpha);
return m_material.GetTexture(m_basicTextureIndexes.alpha);
}
inline const TextureSamplerInfo& BasicMaterial::GetAlphaSampler() const
{
NazaraAssert(HasAlphaMap(), "Material has no alpha texture slot");
return m_material.GetTextureSampler(m_textureIndexes.alpha);
return m_material.GetTextureSampler(m_basicTextureIndexes.alpha);
}
inline const std::shared_ptr<Texture>& BasicMaterial::GetDiffuseMap() const
{
NazaraAssert(HasDiffuseMap(), "Material has no alpha texture slot");
return m_material.GetTexture(m_textureIndexes.diffuse);
return m_material.GetTexture(m_basicTextureIndexes.diffuse);
}
inline const TextureSamplerInfo& BasicMaterial::GetDiffuseSampler() const
{
NazaraAssert(HasDiffuseMap(), "Material has no alpha texture slot");
return m_material.GetTextureSampler(m_textureIndexes.diffuse);
return m_material.GetTextureSampler(m_basicTextureIndexes.diffuse);
}
inline bool BasicMaterial::IsAlphaTestEnabled() const
{
NazaraAssert(HasAlphaTest(), "Material has no alpha test option");
const auto& optionOpt = m_material.GetOptionValue(m_optionIndexes.alphaTest);
const auto& optionOpt = m_material.GetOptionValue(m_basicOptionIndexes.alphaTest);
if (std::holds_alternative<ShaderAst::NoValue>(optionOpt))
return false;
@ -65,69 +70,79 @@ namespace Nz
inline bool BasicMaterial::HasAlphaMap() const
{
return m_textureIndexes.alpha != MaterialSettings::InvalidIndex;
return m_basicTextureIndexes.alpha != MaterialSettings::InvalidIndex;
}
inline bool BasicMaterial::HasAlphaTest() const
{
return m_optionIndexes.alphaTest != MaterialSettings::InvalidIndex;
return m_basicOptionIndexes.alphaTest != MaterialSettings::InvalidIndex;
}
inline bool BasicMaterial::HasAlphaTestThreshold() const
{
return m_uniformOffsets.alphaThreshold != MaterialSettings::InvalidIndex;
return m_basicUniformOffsets.alphaThreshold != MaterialSettings::InvalidIndex;
}
inline bool BasicMaterial::HasDiffuseColor() const
{
return m_uniformOffsets.diffuseColor != MaterialSettings::InvalidIndex;
return m_basicUniformOffsets.diffuseColor != MaterialSettings::InvalidIndex;
}
inline bool BasicMaterial::HasDiffuseMap() const
{
return m_textureIndexes.diffuse != MaterialSettings::InvalidIndex;
return m_basicTextureIndexes.diffuse != MaterialSettings::InvalidIndex;
}
inline void BasicMaterial::SetAlphaMap(std::shared_ptr<Texture> alphaMap)
{
NazaraAssert(HasAlphaMap(), "Material has no alpha map slot");
bool hasAlphaMap = (alphaMap != nullptr);
m_material.SetTexture(m_textureIndexes.alpha, std::move(alphaMap));
m_material.SetTexture(m_basicTextureIndexes.alpha, std::move(alphaMap));
if (m_optionIndexes.hasDiffuseMap != MaterialSettings::InvalidIndex)
m_material.SetOptionValue(m_optionIndexes.hasAlphaMap, hasAlphaMap);
if (m_basicOptionIndexes.hasDiffuseMap != MaterialSettings::InvalidIndex)
m_material.SetOptionValue(m_basicOptionIndexes.hasAlphaMap, hasAlphaMap);
}
inline void BasicMaterial::SetAlphaSampler(TextureSamplerInfo alphaSampler)
{
NazaraAssert(HasAlphaMap(), "Material has no alpha map slot");
m_material.SetTextureSampler(m_textureIndexes.alpha, std::move(alphaSampler));
m_material.SetTextureSampler(m_basicTextureIndexes.alpha, std::move(alphaSampler));
}
inline void BasicMaterial::SetDiffuseMap(std::shared_ptr<Texture> diffuseMap)
{
NazaraAssert(HasDiffuseMap(), "Material has no diffuse map slot");
bool hasDiffuseMap = (diffuseMap != nullptr);
m_material.SetTexture(m_textureIndexes.diffuse, std::move(diffuseMap));
m_material.SetTexture(m_basicTextureIndexes.diffuse, std::move(diffuseMap));
if (m_optionIndexes.hasDiffuseMap != MaterialSettings::InvalidIndex)
m_material.SetOptionValue(m_optionIndexes.hasDiffuseMap, hasDiffuseMap);
if (m_basicOptionIndexes.hasDiffuseMap != MaterialSettings::InvalidIndex)
m_material.SetOptionValue(m_basicOptionIndexes.hasDiffuseMap, hasDiffuseMap);
}
inline void BasicMaterial::SetDiffuseSampler(TextureSamplerInfo diffuseSampler)
{
NazaraAssert(HasDiffuseMap(), "Material has no diffuse map slot");
m_material.SetTextureSampler(m_textureIndexes.diffuse, std::move(diffuseSampler));
m_material.SetTextureSampler(m_basicTextureIndexes.diffuse, std::move(diffuseSampler));
}
inline MaterialPass& BasicMaterial::GetMaterial()
{
return m_material;
}
inline const MaterialPass& BasicMaterial::GetMaterial() const
{
return m_material;
}
inline const std::shared_ptr<MaterialSettings>& BasicMaterial::GetSettings()
{
return s_materialSettings;
return s_basicMaterialSettings;
}
inline auto BasicMaterial::GetOffsets() -> const UniformOffsets&
inline auto BasicMaterial::GetOffsets() -> const BasicUniformOffsets&
{
return s_uniformOffsets;
return s_basicUniformOffsets;
}
}

View File

@ -31,5 +31,6 @@
#include <Nazara/Graphics/Components/CameraComponent.hpp>
#include <Nazara/Graphics/Components/GraphicsComponent.hpp>
#include <Nazara/Graphics/Components/LightComponent.hpp>
#endif // NAZARA_GRAPHICS_COMPONENTS_HPP

View File

@ -0,0 +1,64 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_GRAPHICS_COMPONENTS_LIGHTCOMPONENT_HPP
#define NAZARA_GRAPHICS_COMPONENTS_LIGHTCOMPONENT_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/ECS.hpp>
#include <Nazara/Graphics/Light.hpp>
#include <Nazara/Graphics/WorldInstance.hpp>
#include <memory>
#include <vector>
namespace Nz
{
class NAZARA_GRAPHICS_API LightComponent
{
public:
struct LightEntry;
inline LightComponent(bool initialyVisible = true);
LightComponent(const LightComponent&) = default;
LightComponent(LightComponent&&) = default;
~LightComponent() = default;
inline void AttachLight(std::shared_ptr<Light> renderable, UInt32 renderMask);
inline void Clear();
inline void DetachLight(const std::shared_ptr<Light>& renderable);
inline const std::vector<LightEntry>& GetLights() const;
inline void Hide();
inline bool IsVisible() const;
inline void Show(bool show = true);
LightComponent& operator=(const LightComponent&) = default;
LightComponent& operator=(LightComponent&&) = default;
NazaraSignal(OnLightAttached, LightComponent* /*graphicsComponent*/, const LightEntry& /*lightEntry*/);
NazaraSignal(OnLightDetach, LightComponent* /*graphicsComponent*/, const LightEntry& /*lightEntry*/);
NazaraSignal(OnVisibilityUpdate, LightComponent* /*graphicsComponent*/, bool /*newVisibilityState*/);
struct LightEntry
{
std::shared_ptr<Light> light;
UInt32 renderMask;
};
private:
std::vector<LightEntry> m_lightEntries;
bool m_isVisible;
};
}
#include <Nazara/Graphics/Components/LightComponent.inl>
#endif // NAZARA_GRAPHICS_COMPONENTS_LIGHTCOMPONENT_HPP

View File

@ -0,0 +1,68 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/Components/LightComponent.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
inline LightComponent::LightComponent(bool initialyVisible) :
m_isVisible(initialyVisible)
{
}
inline void LightComponent::AttachLight(std::shared_ptr<Light> light, UInt32 renderMask)
{
auto& entry = m_lightEntries.emplace_back();
entry.light = std::move(light);
entry.renderMask = renderMask;
OnLightAttached(this, m_lightEntries.back());
}
inline void LightComponent::Clear()
{
for (const auto& lightEntry : m_lightEntries)
OnLightDetach(this, lightEntry);
m_lightEntries.clear();
}
inline void LightComponent::DetachLight(const std::shared_ptr<Light>& light)
{
auto it = std::find_if(m_lightEntries.begin(), m_lightEntries.end(), [&](const auto& lightEntry) { return lightEntry.light == light; });
if (it != m_lightEntries.end())
{
OnLightDetach(this, *it);
m_lightEntries.erase(it);
}
}
inline auto LightComponent::GetLights() const -> const std::vector<LightEntry>&
{
return m_lightEntries;
}
inline void LightComponent::Hide()
{
return Show(false);
}
inline bool LightComponent::IsVisible() const
{
return m_isVisible;
}
inline void LightComponent::Show(bool show)
{
if (m_isVisible != show)
{
OnVisibilityUpdate(this, show);
m_isVisible = show;
}
}
}
#include <Nazara/Graphics/DebugOff.hpp>

View File

@ -29,7 +29,7 @@ namespace Nz
static bool Initialize();
static void Uninitialize();
static std::shared_ptr<MaterialSettings> s_materialSettings;
static std::shared_ptr<MaterialSettings> s_basicMaterialSettings;
};
}

View File

@ -9,7 +9,7 @@ namespace Nz
{
inline const std::shared_ptr<MaterialSettings>& DepthMaterial::GetSettings()
{
return s_materialSettings;
return s_basicMaterialSettings;
}
}

View File

@ -0,0 +1,61 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_GRAPHICS_DIRECTIONALLIGHT_HPP
#define NAZARA_GRAPHICS_DIRECTIONALLIGHT_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Color.hpp>
#include <Nazara/Graphics/Config.hpp>
#include <Nazara/Graphics/Light.hpp>
#include <Nazara/Math/Angle.hpp>
#include <memory>
namespace Nz
{
class NAZARA_GRAPHICS_API DirectionalLight : public Light
{
public:
DirectionalLight();
DirectionalLight(const DirectionalLight&) = delete;
DirectionalLight(DirectionalLight&&) noexcept = default;
~DirectionalLight() = default;
float ComputeContributionScore(const BoundingVolumef& boundingVolume) const override;
void FillLightData(void* data) override;
inline float GetAmbientFactor() const;
inline float GetDiffuseFactor() const;
inline Color GetColor() const;
inline const Vector3f& GetDirection() const;
inline const Quaternionf& GetRotation() const;
inline void UpdateAmbientFactor(float factor);
inline void UpdateColor(Color color);
inline void UpdateDiffuseFactor(float factor);
inline void UpdateDirection(const Vector3f& direction);
inline void UpdateRotation(const Quaternionf& rotation);
void UpdateTransform(const Vector3f& position, const Quaternionf& rotation, const Vector3f& scale) override;
DirectionalLight& operator=(const DirectionalLight&) = delete;
DirectionalLight& operator=(DirectionalLight&&) noexcept = default;
private:
inline void UpdateBoundingVolume();
Color m_color;
Quaternionf m_rotation;
Vector3f m_direction;
float m_ambientFactor;
float m_diffuseFactor;
};
}
#include <Nazara/Graphics/DirectionalLight.inl>
#endif // NAZARA_GRAPHICS_DIRECTIONALLIGHT_HPP

View File

@ -0,0 +1,85 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/DirectionalLight.hpp>
#include <Nazara/Graphics/DirectionalLight.hpp>
#include <cassert>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
inline DirectionalLight::DirectionalLight() :
m_color(Color::White),
m_ambientFactor(0.2f),
m_diffuseFactor(1.f)
{
UpdateRotation(Quaternionf::Identity());
}
inline float DirectionalLight::GetAmbientFactor() const
{
return m_ambientFactor;
}
inline Color DirectionalLight::GetColor() const
{
return m_color;
}
inline const Vector3f& DirectionalLight::GetDirection() const
{
return m_direction;
}
inline const Quaternionf& DirectionalLight::GetRotation() const
{
return m_rotation;
}
inline float DirectionalLight::GetDiffuseFactor() const
{
return m_diffuseFactor;
}
inline void DirectionalLight::UpdateAmbientFactor(float factor)
{
m_ambientFactor = factor;
OnLightDataInvalided(this);
}
inline void DirectionalLight::UpdateColor(Color color)
{
m_color = color;
OnLightDataInvalided(this);
}
inline void DirectionalLight::UpdateDiffuseFactor(float factor)
{
m_diffuseFactor = factor;
OnLightDataInvalided(this);
}
inline void DirectionalLight::UpdateDirection(const Vector3f& direction)
{
UpdateRotation(Quaternionf::RotationBetween(Vector3f::Forward(), direction));
}
inline void DirectionalLight::UpdateRotation(const Quaternionf& rotation)
{
m_rotation = rotation;
m_direction = rotation * Vector3f::Forward();
UpdateBoundingVolume();
}
inline void DirectionalLight::UpdateBoundingVolume()
{
Light::UpdateBoundingVolume(BoundingVolumef::Infinite()); //< will trigger OnLightDataInvalided
}
}
#include <Nazara/Graphics/DebugOff.hpp>

View File

@ -11,7 +11,9 @@
#include <Nazara/Core/Algorithm.hpp>
#include <Nazara/Graphics/Config.hpp>
#include <Nazara/Graphics/Enums.hpp>
#include <Nazara/Renderer/RenderBufferView.hpp>
#include <memory>
#include <optional>
#include <vector>
namespace Nz
@ -25,13 +27,21 @@ namespace Nz
class NAZARA_GRAPHICS_API ElementRenderer
{
public:
struct RenderStates;
ElementRenderer() = default;
virtual ~ElementRenderer();
virtual std::unique_ptr<ElementRendererData> InstanciateData() = 0;
virtual void Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& currentFrame, const Pointer<const RenderElement>* elements, std::size_t elementCount);
virtual void Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, const Pointer<const RenderElement>* elements, std::size_t elementCount) = 0;
virtual void Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& currentFrame, std::size_t elementCount, const Pointer<const RenderElement>* elements, const RenderStates* renderStates);
virtual void PrepareEnd(RenderFrame& currentFrame, ElementRendererData& rendererData);
virtual void Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, std::size_t elementCount, const Pointer<const RenderElement>* elements) = 0;
virtual void Reset(ElementRendererData& rendererData, RenderFrame& currentFrame);
struct RenderStates
{
RenderBufferView lightData;
};
};
struct NAZARA_GRAPHICS_API ElementRendererData

View File

@ -12,6 +12,15 @@
namespace Nz
{
enum class BasicLightType
{
Directional,
Point,
Spot,
Max = Spot
};
enum class BasicRenderElement
{
SpriteChain = 0,
@ -54,6 +63,7 @@ namespace Nz
enum class PredefinedShaderBinding
{
InstanceDataUbo,
LightDataUbo,
OverlayTexture,
ViewerDataUbo,

View File

@ -13,11 +13,13 @@
#include <Nazara/Graphics/ElementRenderer.hpp>
#include <Nazara/Graphics/FramePipeline.hpp>
#include <Nazara/Graphics/InstancedRenderable.hpp>
#include <Nazara/Graphics/Light.hpp>
#include <Nazara/Graphics/MaterialPass.hpp>
#include <Nazara/Graphics/RenderElement.hpp>
#include <Nazara/Graphics/RenderQueue.hpp>
#include <Nazara/Graphics/RenderQueueRegistry.hpp>
#include <Nazara/Renderer/ShaderBinding.hpp>
#include <memory>
#include <optional>
#include <unordered_map>
#include <unordered_set>
@ -25,6 +27,7 @@
namespace Nz
{
class PointLight;
class RenderFrame;
class RenderTarget;
@ -40,16 +43,20 @@ namespace Nz
void InvalidateWorldInstance(WorldInstance* worldInstance) override;
void RegisterInstancedDrawable(WorldInstancePtr worldInstance, const InstancedRenderable* instancedRenderable, UInt32 renderMask) override;
void RegisterLight(std::shared_ptr<Light> light, UInt32 renderMask) override;
void RegisterViewer(AbstractViewer* viewerInstance, Int32 renderOrder) override;
void Render(RenderFrame& renderFrame) override;
void UnregisterInstancedDrawable(const WorldInstancePtr& worldInstance, const InstancedRenderable* instancedRenderable) override;
void UnregisterLight(Light* light) override;
void UnregisterViewer(AbstractViewer* viewerInstance) override;
ForwardFramePipeline& operator=(const ForwardFramePipeline&) = delete;
ForwardFramePipeline& operator=(ForwardFramePipeline&&) = delete;
static constexpr std::size_t MaxLightCountPerDraw = 3;
private:
BakedFrameGraph BuildFrameGraph();
@ -59,6 +66,33 @@ namespace Nz
struct ViewerData;
struct LightData
{
std::shared_ptr<Light> light;
UInt32 renderMask;
NazaraSlot(Light, OnLightDataInvalided, onLightInvalidated);
};
using LightKey = std::array<const Light*, MaxLightCountPerDraw>;
struct LightKeyHasher
{
inline std::size_t operator()(const LightKey& lightKey) const;
};
struct LightDataUbo
{
std::shared_ptr<RenderBuffer> renderBuffer;
std::size_t offset = 0;
UploadPool::Allocation* allocation = nullptr;
};
struct LightUboPool
{
std::vector<std::shared_ptr<RenderBuffer>> lightUboBuffers;
};
struct MaterialData
{
std::size_t usedCount = 0;
@ -92,6 +126,8 @@ namespace Nz
std::size_t colorAttachment;
std::size_t depthStencilAttachment;
std::size_t visibilityHash = 0;
std::unordered_map<const RenderElement*, RenderBufferView> lightPerRenderElement;
std::unordered_map<LightKey, RenderBufferView, LightKeyHasher> lightBufferPerLights;
std::vector<std::unique_ptr<RenderElement>> depthPrepassRenderElements;
std::vector<std::unique_ptr<RenderElement>> forwardRenderElements;
std::vector<std::unique_ptr<ElementRendererData>> elementRendererData;
@ -108,7 +144,9 @@ namespace Nz
std::size_t m_depthPassIndex;
std::size_t m_forwardPassIndex;
std::shared_ptr<LightUboPool> m_lightUboPool;
std::unordered_map<AbstractViewer*, ViewerData> m_viewers;
std::unordered_map<Light*, LightData> m_lights;
std::unordered_map<MaterialPass*, MaterialData> m_materials;
std::unordered_map<WorldInstancePtr, std::unordered_map<const InstancedRenderable*, RenderableData>> m_renderables;
std::unordered_map<const RenderTarget*, RenderTargetData> m_renderTargets;
@ -117,6 +155,9 @@ namespace Nz
std::unordered_set<WorldInstance*> m_invalidatedWorldInstances;
std::unordered_set<WorldInstancePtr> m_removedWorldInstances;
std::vector<std::unique_ptr<ElementRenderer>> m_elementRenderers;
std::vector<ElementRenderer::RenderStates> m_renderStates;
std::vector<Light*> m_visibleLights;
std::vector<LightDataUbo> m_lightDataBuffers;
std::vector<VisibleRenderable> m_visibleRenderables;
BakedFrameGraph m_bakedFrameGraph;
RenderFrame* m_currentRenderFrame;

View File

@ -3,10 +3,25 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/ForwardFramePipeline.hpp>
#include <Nazara/Core/Algorithm.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
inline std::size_t ForwardFramePipeline::LightKeyHasher::operator()(const LightKey& lightKey) const
{
std::size_t lightHash = 5;
auto CombineHash = [](std::size_t currentHash, std::size_t newHash)
{
return currentHash * 23 + newHash;
};
std::hash<const Light*> lightPtrHasher;
for (std::size_t i = 0; i < lightKey.size(); ++i)
lightHash = CombineHash(lightHash, lightPtrHasher(lightKey[i]));
return lightHash;
}
}
#include <Nazara/Graphics/DebugOff.hpp>

View File

@ -15,6 +15,7 @@ namespace Nz
{
class AbstractViewer;
class InstancedRenderable;
class Light;
class RenderFrame;
class NAZARA_GRAPHICS_API FramePipeline
@ -29,11 +30,13 @@ namespace Nz
virtual void InvalidateWorldInstance(WorldInstance* worldInstance) = 0;
virtual void RegisterInstancedDrawable(WorldInstancePtr worldInstance, const InstancedRenderable* instancedRenderable, UInt32 renderMask) = 0;
virtual void RegisterLight(std::shared_ptr<Light> light, UInt32 renderMask) = 0;
virtual void RegisterViewer(AbstractViewer* viewerInstance, Int32 renderOrder) = 0;
virtual void Render(RenderFrame& renderFrame) = 0;
virtual void UnregisterInstancedDrawable(const WorldInstancePtr& worldInstance, const InstancedRenderable* instancedRenderable) = 0;
virtual void UnregisterLight(Light* light) = 0;
virtual void UnregisterViewer(AbstractViewer* viewerInstance) = 0;
FramePipeline& operator=(const FramePipeline&) = delete;

View File

@ -19,7 +19,7 @@
namespace Nz
{
class AbstractBuffer;
class RenderBuffer;
class NAZARA_GRAPHICS_API Graphics : public ModuleBase<Graphics>
{
@ -57,10 +57,6 @@ namespace Nz
std::array<std::shared_ptr<Texture>, ImageTypeCount> whiteTextures;
};
static void FillDrawDataPipelineLayout(RenderPipelineLayoutInfo& layoutInfo, UInt32 set);
static void FillViewerPipelineLayout(RenderPipelineLayoutInfo& layoutInfo, UInt32 set);
static void FillWorldPipelineLayout(RenderPipelineLayoutInfo& layoutInfo, UInt32 set);
private:
void BuildBlitPipeline();
void BuildDefaultTextures();

View File

@ -0,0 +1,55 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_GRAPHICS_LIGHT_HPP
#define NAZARA_GRAPHICS_LIGHT_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Signal.hpp>
#include <Nazara/Graphics/Config.hpp>
#include <Nazara/Math/BoundingVolume.hpp>
#include <Nazara/Math/Quaternion.hpp>
#include <Nazara/Math/Vector3.hpp>
#include <memory>
namespace Nz
{
class CommandBufferBuilder;
class RenderBuffer;
class RenderFrame;
class NAZARA_GRAPHICS_API Light
{
public:
inline Light();
Light(const Light&) = delete;
Light(Light&&) noexcept = default;
virtual ~Light();
virtual float ComputeContributionScore(const BoundingVolumef& boundingVolume) const = 0;
virtual void FillLightData(void* data) = 0;
inline const BoundingVolumef& GetBoundingVolume() const;
virtual void UpdateTransform(const Vector3f& position, const Quaternionf& rotation, const Vector3f& scale) = 0;
Light& operator=(const Light&) = delete;
Light& operator=(Light&&) noexcept = default;
NazaraSignal(OnLightDataInvalided, Light* /*emitter*/);
protected:
inline void UpdateBoundingVolume(const BoundingVolumef& boundingVolume);
private:
BoundingVolumef m_boundingVolume;
};
}
#include <Nazara/Graphics/Light.inl>
#endif // NAZARA_GRAPHICS_LIGHT_HPP

View File

@ -0,0 +1,29 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/Light.hpp>
#include <cassert>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
inline Light::Light() :
m_boundingVolume(BoundingVolumef::Null())
{
}
inline const BoundingVolumef& Light::GetBoundingVolume() const
{
return m_boundingVolume;
}
inline void Light::UpdateBoundingVolume(const BoundingVolumef& boundingVolume)
{
m_boundingVolume = boundingVolume;
OnLightDataInvalided(this);
}
}
#include <Nazara/Graphics/DebugOff.hpp>

View File

@ -75,7 +75,7 @@ namespace Nz
inline const std::shared_ptr<Texture>& GetTexture(std::size_t textureIndex) const;
inline const TextureSamplerInfo& GetTextureSampler(std::size_t textureIndex) const;
inline const std::shared_ptr<RenderBuffer>& GetUniformBuffer(std::size_t bufferIndex) const;
inline const std::vector<UInt8>& GetUniformBufferConstData(std::size_t bufferIndex);
inline const std::vector<UInt8>& GetUniformBufferConstData(std::size_t bufferIndex) const;
inline std::vector<UInt8>& GetUniformBufferData(std::size_t bufferIndex);
inline bool HasTexture(std::size_t textureIndex) const;

View File

@ -391,7 +391,7 @@ namespace Nz
return m_uniformBuffers[bufferIndex].buffer;
}
inline const std::vector<UInt8>& MaterialPass::GetUniformBufferConstData(std::size_t bufferIndex)
inline const std::vector<UInt8>& MaterialPass::GetUniformBufferConstData(std::size_t bufferIndex) const
{
NazaraAssert(bufferIndex < m_uniformBuffers.size(), "Invalid uniform buffer index");
return m_uniformBuffers[bufferIndex].data;

View File

@ -8,38 +8,31 @@
#define NAZARA_GRAPHICS_PHONGLIGHTINGMATERIAL_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Graphics/BasicMaterial.hpp>
#include <Nazara/Graphics/MaterialPass.hpp>
namespace Nz
{
class NAZARA_GRAPHICS_API PhongLightingMaterial
class NAZARA_GRAPHICS_API PhongLightingMaterial : public BasicMaterial
{
friend class MaterialPipeline;
public:
PhongLightingMaterial(MaterialPass& material);
inline const std::shared_ptr<Texture>& GetAlphaMap() const;
float GetAlphaThreshold() const;
Color GetAmbientColor() const;
Color GetDiffuseColor() const;
inline const std::shared_ptr<Texture>& GetDiffuseMap() const;
inline TextureSampler& GetDiffuseSampler();
inline const TextureSampler& GetDiffuseSampler() const;
inline const std::shared_ptr<Texture>& GetEmissiveMap() const;
inline const TextureSamplerInfo& GetEmissiveSampler() const;
inline const std::shared_ptr<Texture>& GetHeightMap() const;
inline const TextureSamplerInfo& GetHeightSampler() const;
inline const std::shared_ptr<Texture>& GetNormalMap() const;
inline const TextureSamplerInfo& GetNormalSampler() const;
float GetShininess() const;
Color GetSpecularColor() const;
inline const std::shared_ptr<Texture>& GetSpecularMap() const;
inline TextureSampler& GetSpecularSampler();
inline const TextureSampler& GetSpecularSampler() const;
inline const TextureSamplerInfo& GetSpecularSampler() const;
inline bool HasAlphaMap() const;
inline bool HasAlphaThreshold() const;
inline bool HasAmbientColor() const;
inline bool HasDiffuseColor() const;
inline bool HasDiffuseMap() const;
inline bool HasEmissiveMap() const;
inline bool HasHeightMap() const;
inline bool HasNormalMap() const;
@ -47,53 +40,68 @@ namespace Nz
inline bool HasSpecularColor() const;
inline bool HasSpecularMap() const;
inline void SetAlphaMap(std::shared_ptr<Texture> alphaMap);
void SetAlphaThreshold(float alphaThreshold);
void SetAmbientColor(const Color& ambient);
void SetDiffuseColor(const Color& diffuse);
inline void SetDiffuseMap(std::shared_ptr<Texture> diffuseMap);
inline void SetDiffuseSampler(const TextureSampler& sampler);
inline void SetEmissiveMap(std::shared_ptr<Texture> textureName);
inline void SetHeightMap(std::shared_ptr<Texture> textureName);
inline void SetNormalMap(std::shared_ptr<Texture> textureName);
inline void SetEmissiveMap(std::shared_ptr<Texture> emissiveMap);
inline void SetEmissiveSampler(TextureSamplerInfo emissiveSampler);
inline void SetHeightMap(std::shared_ptr<Texture> heightMap);
inline void SetHeightSampler(TextureSamplerInfo heightSampler);
inline void SetNormalMap(std::shared_ptr<Texture> normalMap);
inline void SetNormalSampler(TextureSamplerInfo normalSampler);
void SetShininess(float shininess);
void SetSpecularColor(const Color& specular);
inline void SetSpecularMap(std::shared_ptr<Texture> specularMap);
inline void SetSpecularSampler(const TextureSampler& sampler);
inline void SetSpecularSampler(TextureSamplerInfo specularSampler);
static const std::shared_ptr<MaterialSettings>& GetSettings();
private:
protected:
struct PhongOptionIndexes
{
std::size_t hasEmissiveMap;
std::size_t hasHeightMap;
std::size_t hasNormalMap;
std::size_t hasSpecularMap;
};
struct PhongUniformOffsets
{
std::size_t alphaThreshold;
std::size_t shininess;
std::size_t ambientColor;
std::size_t diffuseColor;
std::size_t shininess;
std::size_t totalSize;
std::size_t specularColor;
};
struct TextureIndexes
struct PhongTextureIndexes
{
std::size_t alpha;
std::size_t diffuse;
std::size_t emissive;
std::size_t height;
std::size_t normal;
std::size_t specular;
};
struct PhongBuildOptions : BasicBuildOptions
{
PhongUniformOffsets phongOffsets;
PhongOptionIndexes* phongOptionIndexes = nullptr;
PhongTextureIndexes* phongTextureIndexes = nullptr;
};
PhongOptionIndexes m_phongOptionIndexes;
PhongTextureIndexes m_phongTextureIndexes;
PhongUniformOffsets m_phongUniformOffsets;
static MaterialSettings::Builder Build(PhongBuildOptions& options);
static std::vector<std::shared_ptr<UberShader>> BuildShaders();
static std::pair<PhongUniformOffsets, FieldOffsets> BuildUniformOffsets();
private:
static bool Initialize();
static void Uninitialize();
MaterialPass& m_material;
std::size_t m_phongUniformIndex;
TextureIndexes m_textureIndexes;
PhongUniformOffsets m_phongUniformOffsets;
static std::shared_ptr<MaterialSettings> s_materialSettings;
static std::shared_ptr<MaterialSettings> s_phongMaterialSettings;
static std::size_t s_phongUniformBlockIndex;
static TextureIndexes s_textureIndexes;
static PhongOptionIndexes s_phongOptionIndexes;
static PhongTextureIndexes s_phongTextureIndexes;
static PhongUniformOffsets s_phongUniformOffsets;
};
}

View File

@ -9,50 +9,52 @@
namespace Nz
{
inline const std::shared_ptr<Texture>& PhongLightingMaterial::GetAlphaMap() const
{
NazaraAssert(HasAlphaMap(), "Material has no alpha map slot");
return m_material.GetTexture(m_textureIndexes.alpha);
}
inline const std::shared_ptr<Texture>& PhongLightingMaterial::GetDiffuseMap() const
{
NazaraAssert(HasDiffuseMap(), "Material has no alpha map slot");
return m_material.GetTexture(m_textureIndexes.diffuse);
}
inline const std::shared_ptr<Texture>& PhongLightingMaterial::GetEmissiveMap() const
{
NazaraAssert(HasEmissiveMap(), "Material has no alpha map slot");
return m_material.GetTexture(m_textureIndexes.emissive);
NazaraAssert(HasEmissiveMap(), "Material has no emissive map slot");
return GetMaterial().GetTexture(m_phongTextureIndexes.emissive);
}
inline const TextureSamplerInfo& PhongLightingMaterial::GetEmissiveSampler() const
{
NazaraAssert(HasSpecularMap(), "Material has no emissive map slot");
return GetMaterial().GetTextureSampler(m_phongTextureIndexes.emissive);
}
inline const std::shared_ptr<Texture>& PhongLightingMaterial::GetHeightMap() const
{
NazaraAssert(HasHeightMap(), "Material has no alpha map slot");
return m_material.GetTexture(m_textureIndexes.height);
NazaraAssert(HasHeightMap(), "Material has no height map slot");
return GetMaterial().GetTexture(m_phongTextureIndexes.height);
}
inline const TextureSamplerInfo& PhongLightingMaterial::GetHeightSampler() const
{
NazaraAssert(HasSpecularMap(), "Material has no height map slot");
return GetMaterial().GetTextureSampler(m_phongTextureIndexes.height);
}
inline const std::shared_ptr<Texture>& PhongLightingMaterial::GetNormalMap() const
{
NazaraAssert(HasNormalMap(), "Material has no alpha map slot");
return m_material.GetTexture(m_textureIndexes.normal);
NazaraAssert(HasNormalMap(), "Material has no normal map slot");
return GetMaterial().GetTexture(m_phongTextureIndexes.normal);
}
inline const TextureSamplerInfo& PhongLightingMaterial::GetNormalSampler() const
{
NazaraAssert(HasSpecularMap(), "Material has no normal map slot");
return GetMaterial().GetTextureSampler(m_phongTextureIndexes.normal);
}
inline const std::shared_ptr<Texture>& PhongLightingMaterial::GetSpecularMap() const
{
NazaraAssert(HasSpecularMap(), "Material has no alpha map slot");
return m_material.GetTexture(m_textureIndexes.specular);
NazaraAssert(HasSpecularMap(), "Material has no specular map slot");
return GetMaterial().GetTexture(m_phongTextureIndexes.specular);
}
inline bool PhongLightingMaterial::HasAlphaMap() const
inline const TextureSamplerInfo& PhongLightingMaterial::GetSpecularSampler() const
{
return m_textureIndexes.alpha != MaterialSettings::InvalidIndex;
}
inline bool PhongLightingMaterial::HasAlphaThreshold() const
{
return m_phongUniformOffsets.alphaThreshold != MaterialSettings::InvalidIndex;
NazaraAssert(HasSpecularMap(), "Material has no specular map slot");
return GetMaterial().GetTextureSampler(m_phongTextureIndexes.specular);
}
inline bool PhongLightingMaterial::HasAmbientColor() const
@ -60,29 +62,19 @@ namespace Nz
return m_phongUniformOffsets.ambientColor != MaterialSettings::InvalidIndex;
}
inline bool PhongLightingMaterial::HasDiffuseColor() const
{
return m_phongUniformOffsets.diffuseColor != MaterialSettings::InvalidIndex;
}
inline bool PhongLightingMaterial::HasDiffuseMap() const
{
return m_textureIndexes.diffuse != MaterialSettings::InvalidIndex;
}
inline bool PhongLightingMaterial::HasEmissiveMap() const
{
return m_textureIndexes.emissive != MaterialSettings::InvalidIndex;
return m_phongTextureIndexes.emissive != MaterialSettings::InvalidIndex;
}
inline bool PhongLightingMaterial::HasHeightMap() const
{
return m_textureIndexes.height != MaterialSettings::InvalidIndex;
return m_phongTextureIndexes.height != MaterialSettings::InvalidIndex;
}
inline bool PhongLightingMaterial::HasNormalMap() const
{
return m_textureIndexes.normal != MaterialSettings::InvalidIndex;
return m_phongTextureIndexes.normal != MaterialSettings::InvalidIndex;
}
inline bool PhongLightingMaterial::HasShininess() const
@ -97,25 +89,71 @@ namespace Nz
inline bool PhongLightingMaterial::HasSpecularMap() const
{
return m_textureIndexes.specular != MaterialSettings::InvalidIndex;
return m_phongTextureIndexes.specular != MaterialSettings::InvalidIndex;
}
inline void PhongLightingMaterial::SetAlphaMap(std::shared_ptr<Texture> alphaMap)
inline void PhongLightingMaterial::SetEmissiveMap(std::shared_ptr<Texture> emissiveMap)
{
NazaraAssert(HasAlphaMap(), "Material has no alpha map slot");
m_material.SetTexture(m_textureIndexes.alpha, std::move(alphaMap));
NazaraAssert(HasEmissiveMap(), "Material has no emissive map slot");
bool hasEmissiveMap = (emissiveMap != nullptr);
GetMaterial().SetTexture(m_phongTextureIndexes.emissive, std::move(emissiveMap));
if (m_phongOptionIndexes.hasEmissiveMap != MaterialSettings::InvalidIndex)
GetMaterial().SetOptionValue(m_phongOptionIndexes.hasEmissiveMap, hasEmissiveMap);
}
inline void PhongLightingMaterial::SetDiffuseMap(std::shared_ptr<Texture> diffuseMap)
inline void PhongLightingMaterial::SetEmissiveSampler(TextureSamplerInfo emissiveSampler)
{
NazaraAssert(HasDiffuseMap(), "Material has no diffuse map slot");
m_material.SetTexture(m_textureIndexes.diffuse, std::move(diffuseMap));
NazaraAssert(HasEmissiveMap(), "Material has no emissive map slot");
GetMaterial().SetTextureSampler(m_phongTextureIndexes.emissive, std::move(emissiveSampler));
}
inline void PhongLightingMaterial::SetHeightMap(std::shared_ptr<Texture> heightMap)
{
NazaraAssert(HasHeightMap(), "Material has no specular map slot");
bool hasHeightMap = (heightMap != nullptr);
GetMaterial().SetTexture(m_phongTextureIndexes.height, std::move(heightMap));
if (m_phongOptionIndexes.hasHeightMap != MaterialSettings::InvalidIndex)
GetMaterial().SetOptionValue(m_phongOptionIndexes.hasHeightMap, hasHeightMap);
}
inline void PhongLightingMaterial::SetHeightSampler(TextureSamplerInfo heightSampler)
{
NazaraAssert(HasHeightMap(), "Material has no height map slot");
GetMaterial().SetTextureSampler(m_phongTextureIndexes.height, std::move(heightSampler));
}
inline void PhongLightingMaterial::SetNormalMap(std::shared_ptr<Texture> normalMap)
{
NazaraAssert(HasNormalMap(), "Material has no normal map slot");
m_material.SetTexture(m_textureIndexes.normal, std::move(normalMap));
bool hasNormalMap = (normalMap != nullptr);
GetMaterial().SetTexture(m_phongTextureIndexes.normal, std::move(normalMap));
if (m_phongOptionIndexes.hasNormalMap != MaterialSettings::InvalidIndex)
GetMaterial().SetOptionValue(m_phongOptionIndexes.hasNormalMap, hasNormalMap);
}
inline void PhongLightingMaterial::SetNormalSampler(TextureSamplerInfo normalSampler)
{
NazaraAssert(HasNormalMap(), "Material has no normal map slot");
GetMaterial().SetTextureSampler(m_phongTextureIndexes.normal, std::move(normalSampler));
}
inline void PhongLightingMaterial::SetSpecularMap(std::shared_ptr<Texture> specularMap)
{
NazaraAssert(HasNormalMap(), "Material has no specular map slot");
bool hasSpecularMap = (specularMap != nullptr);
GetMaterial().SetTexture(m_phongTextureIndexes.specular, std::move(specularMap));
if (m_phongOptionIndexes.hasSpecularMap != MaterialSettings::InvalidIndex)
GetMaterial().SetOptionValue(m_phongOptionIndexes.hasSpecularMap, hasSpecularMap);
}
inline void PhongLightingMaterial::SetSpecularSampler(TextureSamplerInfo specularSampler)
{
NazaraAssert(HasSpecularMap(), "Material has no specular map slot");
GetMaterial().SetTextureSampler(m_phongTextureIndexes.specular, std::move(specularSampler));
}
}

View File

@ -0,0 +1,61 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_GRAPHICS_POINTLIGHT_HPP
#define NAZARA_GRAPHICS_POINTLIGHT_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Color.hpp>
#include <Nazara/Graphics/Config.hpp>
#include <Nazara/Graphics/Light.hpp>
#include <memory>
namespace Nz
{
class NAZARA_GRAPHICS_API PointLight : public Light
{
public:
PointLight();
PointLight(const PointLight&) = delete;
PointLight(PointLight&&) noexcept = default;
~PointLight() = default;
float ComputeContributionScore(const BoundingVolumef& boundingVolume) const override;
void FillLightData(void* data) override;
inline float GetAmbientFactor() const;
inline float GetDiffuseFactor() const;
inline Color GetColor() const;
inline const Vector3f& GetPosition() const;
inline float GetRadius() const;
inline void UpdateAmbientFactor(float factor);
inline void UpdateColor(Color color);
inline void UpdateDiffuseFactor(float factor);
inline void UpdatePosition(const Vector3f& position);
inline void UpdateRadius(float radius);
void UpdateTransform(const Vector3f& position, const Quaternionf& rotation, const Vector3f& scale) override;
PointLight& operator=(const PointLight&) = delete;
PointLight& operator=(PointLight&&) noexcept = default;
private:
inline void UpdateBoundingVolume();
Color m_color;
Vector3f m_position;
float m_ambientFactor;
float m_diffuseFactor;
float m_invRadius;
float m_radius;
};
}
#include <Nazara/Graphics/PointLight.inl>
#endif // NAZARA_GRAPHICS_POINTLIGHT_HPP

View File

@ -0,0 +1,91 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/PointLight.hpp>
#include <cassert>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
inline PointLight::PointLight() :
m_color(Color::White),
m_position(Vector3f::Zero()),
m_ambientFactor(0.2f),
m_diffuseFactor(1.f)
{
UpdateRadius(5.f);
}
inline float PointLight::GetAmbientFactor() const
{
return m_ambientFactor;
}
inline Color PointLight::GetColor() const
{
return m_color;
}
inline const Vector3f& PointLight::GetPosition() const
{
return m_position;
}
inline float PointLight::GetDiffuseFactor() const
{
return m_diffuseFactor;
}
inline float PointLight::GetRadius() const
{
return m_radius;
}
inline void PointLight::UpdateAmbientFactor(float factor)
{
m_ambientFactor = factor;
OnLightDataInvalided(this);
}
inline void PointLight::UpdateColor(Color color)
{
m_color = color;
OnLightDataInvalided(this);
}
inline void PointLight::UpdateDiffuseFactor(float factor)
{
m_diffuseFactor = factor;
OnLightDataInvalided(this);
}
inline void PointLight::UpdatePosition(const Vector3f& position)
{
m_position = position;
UpdateBoundingVolume();
}
inline void PointLight::UpdateRadius(float radius)
{
m_radius = radius;
m_invRadius = 1.f / m_radius;
UpdateBoundingVolume();
}
inline void PointLight::UpdateBoundingVolume()
{
Vector3f extent = Vector3f(m_radius, m_radius, m_radius) * Sqrt3<float>;
BoundingVolumef boundingVolume(Boxf(-extent, extent));
boundingVolume.Update(m_position);
Light::UpdateBoundingVolume(boundingVolume); //< will trigger OnLightDataInvalided
}
}
#include <Nazara/Graphics/DebugOff.hpp>

View File

@ -15,7 +15,7 @@ namespace Nz
{
struct NAZARA_GRAPHICS_API PredefinedLightData
{
struct InnerStruct
struct Light
{
std::size_t type;
std::size_t color;
@ -24,15 +24,18 @@ namespace Nz
std::size_t parameter2;
std::size_t parameter3;
std::size_t shadowMappingFlag;
std::size_t totalSize;
};
InnerStruct innerOffsets;
std::array<std::size_t, 3> lightArray;
std::size_t lightArraySize;
std::size_t lightsOffset;
std::size_t lightCountOffset;
std::size_t lightSize;
std::size_t totalSize;
Light lightMemberOffsets;
static constexpr std::size_t MaxLightCount = 3;
static PredefinedLightData GetOffsets();
static MaterialSettings::SharedUniformBlock GetUniformBlock();
static MaterialSettings::SharedUniformBlock GetUniformBlock(UInt32 bindingIndex, ShaderStageTypeFlags shaderStages);
};
struct NAZARA_GRAPHICS_API PredefinedInstanceData

View File

@ -25,7 +25,7 @@ namespace Nz
inline RenderElement(UInt8 elementType);
virtual ~RenderElement();
virtual UInt64 ComputeSortingScore(const Nz::Frustumf& frustum, const RenderQueueRegistry& registry) const = 0;
virtual UInt64 ComputeSortingScore(const Frustumf& frustum, const RenderQueueRegistry& registry) const = 0;
inline UInt8 GetElementType() const;

View File

@ -13,7 +13,6 @@
namespace Nz
{
class AbstractBuffer;
class MaterialPass;
class RenderPipeline;
class VertexDeclaration;

View File

@ -16,7 +16,6 @@
namespace Nz
{
class AbstractBuffer;
class MaterialPass;
class VertexDeclaration;
class ViewerInstance;

View File

@ -16,7 +16,6 @@
namespace Nz
{
class AbstractBuffer;
class MaterialPass;
class RenderPipeline;
class ShaderBinding;

View File

@ -0,0 +1,77 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_GRAPHICS_SPOTLIGHT_HPP
#define NAZARA_GRAPHICS_SPOTLIGHT_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Color.hpp>
#include <Nazara/Graphics/Config.hpp>
#include <Nazara/Graphics/Light.hpp>
#include <Nazara/Math/Angle.hpp>
#include <memory>
namespace Nz
{
class NAZARA_GRAPHICS_API SpotLight : public Light
{
public:
SpotLight();
SpotLight(const SpotLight&) = delete;
SpotLight(SpotLight&&) noexcept = default;
~SpotLight() = default;
float ComputeContributionScore(const BoundingVolumef& boundingVolume) const override;
void FillLightData(void* data) override;
inline float GetAmbientFactor() const;
inline float GetDiffuseFactor() const;
inline Color GetColor() const;
inline const Vector3f& GetDirection() const;
inline RadianAnglef GetInnerAngle() const;
inline RadianAnglef GetOuterAngle() const;
inline const Vector3f& GetPosition() const;
inline const Quaternionf& GetRotation() const;
inline float GetRadius() const;
inline void UpdateAmbientFactor(float factor);
inline void UpdateColor(Color color);
inline void UpdateDiffuseFactor(float factor);
inline void UpdateDirection(const Vector3f& direction);
inline void UpdateInnerAngle(RadianAnglef innerAngle);
inline void UpdateOuterAngle(RadianAnglef outerAngle);
inline void UpdatePosition(const Vector3f& position);
inline void UpdateRadius(float radius);
inline void UpdateRotation(const Quaternionf& rotation);
void UpdateTransform(const Vector3f& position, const Quaternionf& rotation, const Vector3f& scale) override;
SpotLight& operator=(const SpotLight&) = delete;
SpotLight& operator=(SpotLight&&) noexcept = default;
private:
inline void UpdateBoundingVolume();
Color m_color;
Quaternionf m_rotation;
RadianAnglef m_innerAngle;
RadianAnglef m_outerAngle;
Vector3f m_direction;
Vector3f m_position;
float m_ambientFactor;
float m_diffuseFactor;
float m_invRadius;
float m_radius;
float m_innerAngleCos;
float m_outerAngleCos;
float m_outerAngleTan;
};
}
#include <Nazara/Graphics/SpotLight.inl>
#endif // NAZARA_GRAPHICS_SPOTLIGHT_HPP

View File

@ -0,0 +1,161 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/SpotLight.hpp>
#include <cassert>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
inline SpotLight::SpotLight() :
m_color(Color::White),
m_position(Vector3f::Zero()),
m_ambientFactor(0.2f),
m_diffuseFactor(1.f)
{
UpdateInnerAngle(DegreeAnglef(30.f));
UpdateOuterAngle(DegreeAnglef(45.f));
UpdateRadius(5.f);
UpdateRotation(Quaternionf::Identity());
}
inline float SpotLight::GetAmbientFactor() const
{
return m_ambientFactor;
}
inline Color SpotLight::GetColor() const
{
return m_color;
}
inline const Vector3f& SpotLight::GetDirection() const
{
return m_direction;
}
inline RadianAnglef SpotLight::GetInnerAngle() const
{
return m_innerAngle;
}
inline RadianAnglef SpotLight::GetOuterAngle() const
{
return m_outerAngle;
}
inline const Vector3f& SpotLight::GetPosition() const
{
return m_position;
}
inline const Quaternionf& SpotLight::GetRotation() const
{
return m_rotation;
}
inline float SpotLight::GetDiffuseFactor() const
{
return m_diffuseFactor;
}
inline float SpotLight::GetRadius() const
{
return m_radius;
}
inline void SpotLight::UpdateAmbientFactor(float factor)
{
m_ambientFactor = factor;
OnLightDataInvalided(this);
}
inline void SpotLight::UpdateColor(Color color)
{
m_color = color;
OnLightDataInvalided(this);
}
inline void SpotLight::UpdateDiffuseFactor(float factor)
{
m_diffuseFactor = factor;
OnLightDataInvalided(this);
}
inline void SpotLight::UpdateDirection(const Vector3f& direction)
{
UpdateRotation(Quaternionf::RotationBetween(Vector3f::Forward(), direction));
}
inline void SpotLight::UpdateInnerAngle(RadianAnglef innerAngle)
{
m_innerAngle = innerAngle;
m_innerAngleCos = m_innerAngle.GetCos();
UpdateBoundingVolume();
}
inline void SpotLight::UpdateOuterAngle(RadianAnglef outerAngle)
{
m_outerAngle = outerAngle;
m_outerAngleCos = m_outerAngle.GetCos();
m_outerAngleTan = m_outerAngle.GetTan();
UpdateBoundingVolume();
}
inline void SpotLight::UpdatePosition(const Vector3f& position)
{
m_position = position;
UpdateBoundingVolume();
}
inline void SpotLight::UpdateRadius(float radius)
{
m_radius = radius;
m_invRadius = 1.f / m_radius;
UpdateBoundingVolume();
}
inline void SpotLight::UpdateRotation(const Quaternionf& rotation)
{
m_rotation = rotation;
m_direction = rotation * Vector3f::Forward();
UpdateBoundingVolume();
}
inline void SpotLight::UpdateBoundingVolume()
{
// We make a box center in the origin
Boxf box(Vector3f::Zero());
// We compute the other points
Vector3f base(Vector3f::Forward() * m_radius);
// Now we need the radius of the projected circle depending on the distance
// Tangent = Opposite/Adjacent <=> Opposite = Adjacent * Tangent
float radius = m_radius * m_outerAngleTan;
Vector3f lExtend = Vector3f::Left() * radius;
Vector3f uExtend = Vector3f::Up() * radius;
// And we add the four extremities of our pyramid
box.ExtendTo(base + lExtend + uExtend);
box.ExtendTo(base + lExtend - uExtend);
box.ExtendTo(base - lExtend + uExtend);
box.ExtendTo(base - lExtend - uExtend);
BoundingVolumef boundingVolume(box);
boundingVolume.Update(Matrix4f::Transform(m_position, m_rotation));
Light::UpdateBoundingVolume(boundingVolume); //< will trigger OnLightDataInvalided
}
}
#include <Nazara/Graphics/DebugOff.hpp>

View File

@ -18,45 +18,15 @@
namespace Nz
{
class AbstractBuffer;
class MaterialPass;
class RenderDevice;
class RenderPipeline;
class RenderSpriteChain;
class ShaderBinding;
class NAZARA_GRAPHICS_API SpriteChainRenderer : public ElementRenderer
{
public:
SpriteChainRenderer(RenderDevice& device, std::size_t maxVertexBufferSize = 32 * 1024);
~SpriteChainRenderer() = default;
std::unique_ptr<ElementRendererData> InstanciateData() override;
void Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& currentFrame, const Pointer<const RenderElement>* elements, std::size_t elementCount) override;
void Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, const Pointer<const RenderElement>* elements, std::size_t elementCount) override;
void Reset(ElementRendererData& rendererData, RenderFrame& currentFrame) override;
private:
struct BufferCopy
{
RenderBuffer* targetBuffer;
UploadPool::Allocation* allocation;
std::size_t size;
};
struct VertexBufferPool
{
std::vector<std::shared_ptr<RenderBuffer>> vertexBuffers;
};
std::shared_ptr<RenderBuffer> m_indexBuffer;
std::shared_ptr<VertexBufferPool> m_vertexBufferPool;
std::size_t m_maxVertexBufferSize;
std::size_t m_maxVertexCount;
std::vector<BufferCopy> m_pendingCopies;
std::vector<ShaderBinding::Binding> m_bindingCache;
RenderDevice& m_device;
};
class Texture;
class VertexDeclaration;
class WorldInstance;
struct SpriteChainRendererData : public ElementRendererData
{
struct DrawCall
@ -80,6 +50,62 @@ namespace Nz
std::vector<std::shared_ptr<RenderBuffer>> vertexBuffers;
std::vector<ShaderBindingPtr> shaderBindings;
};
class NAZARA_GRAPHICS_API SpriteChainRenderer final : public ElementRenderer
{
public:
SpriteChainRenderer(RenderDevice& device, std::size_t maxVertexBufferSize = 32 * 1024);
~SpriteChainRenderer() = default;
std::unique_ptr<ElementRendererData> InstanciateData() override;
void Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& currentFrame, std::size_t elementCount, const Pointer<const RenderElement>* elements, const RenderStates* renderStates) override;
void PrepareEnd(RenderFrame& currentFrame, ElementRendererData& rendererData) override;
void Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, std::size_t elementCount, const Pointer<const RenderElement>* elements) override;
void Reset(ElementRendererData& rendererData, RenderFrame& currentFrame) override;
private:
void Flush();
void FlushDrawCall();
void FlushDrawData();
struct BufferCopy
{
RenderBuffer* targetBuffer;
UploadPool::Allocation* allocation;
std::size_t size;
};
struct PendingData
{
std::size_t firstQuadIndex = 0;
SpriteChainRendererData::DrawCall* currentDrawCall = nullptr;
UploadPool::Allocation* currentAllocation = nullptr;
UInt8* currentAllocationMemPtr = nullptr;
const VertexDeclaration* currentVertexDeclaration = nullptr;
RenderBuffer* currentVertexBuffer = nullptr;
const MaterialPass* currentMaterialPass = nullptr;
const RenderPipeline* currentPipeline = nullptr;
const ShaderBinding* currentShaderBinding = nullptr;
const Texture* currentTextureOverlay = nullptr;
const WorldInstance* currentWorldInstance = nullptr;
RenderBufferView currentLightData;
Recti currentScissorBox = Recti(-1, -1, -1, -1);
};
struct VertexBufferPool
{
std::vector<std::shared_ptr<RenderBuffer>> vertexBuffers;
};
std::shared_ptr<RenderBuffer> m_indexBuffer;
std::shared_ptr<VertexBufferPool> m_vertexBufferPool;
std::size_t m_maxVertexBufferSize;
std::size_t m_maxVertexCount;
std::vector<BufferCopy> m_pendingCopies;
std::vector<ShaderBinding::Binding> m_bindingCache;
PendingData m_pendingData;
RenderDevice& m_device;
};
}
#include <Nazara/Graphics/SpriteChainRenderer.inl>

View File

@ -14,20 +14,20 @@
namespace Nz
{
class AbstractBuffer;
class RenderPipeline;
class RenderSubmesh;
class ShaderBinding;
class NAZARA_GRAPHICS_API SubmeshRenderer : public ElementRenderer
{
public:
SubmeshRenderer();
SubmeshRenderer() = default;
~SubmeshRenderer() = default;
std::unique_ptr<ElementRendererData> InstanciateData();
void Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& currentFrame, const Pointer<const RenderElement>* elements, std::size_t elementCount);
void Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, const Pointer<const RenderElement>* elements, std::size_t elementCount) override;
void Reset(ElementRendererData& rendererData, RenderFrame& currentFrame);
std::unique_ptr<ElementRendererData> InstanciateData() override;
void Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& currentFrame, std::size_t elementCount, const Pointer<const RenderElement>* elements, const RenderStates* renderStates) override;
void Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, std::size_t elementCount, const Pointer<const RenderElement>* elements) override;
void Reset(ElementRendererData& rendererData, RenderFrame& currentFrame) override;
private:
std::vector<ShaderBinding::Binding> m_bindingCache;
@ -41,10 +41,18 @@ namespace Nz
const RenderBuffer* vertexBuffer;
const RenderPipeline* renderPipeline;
const ShaderBinding* shaderBinding;
std::size_t firstIndex;
std::size_t indexCount;
Recti scissorBox;
};
struct DrawCallIndices
{
std::size_t start;
std::size_t count;
};
std::unordered_map<const RenderSubmesh*, DrawCallIndices> drawCallPerElement;
std::vector<DrawCall> drawCalls;
std::vector<ShaderBindingPtr> shaderBindings;
};

View File

@ -11,6 +11,7 @@
#include <Nazara/Core/ECS.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/Components/GraphicsComponent.hpp>
#include <Nazara/Graphics/Components/LightComponent.hpp>
#include <Nazara/Utility/Node.hpp>
#include <memory>
#include <set>
@ -39,6 +40,7 @@ namespace Nz
private:
void OnCameraDestroy(entt::registry& registry, entt::entity entity);
void OnGraphicsDestroy(entt::registry& registry, entt::entity entity);
void OnLightDestroy(entt::registry& registry, entt::entity entity);
void OnNodeDestroy(entt::registry& registry, entt::entity entity);
void UpdateInstances(entt::registry& registry);
void UpdateVisibility(entt::registry& registry);
@ -56,18 +58,32 @@ namespace Nz
NazaraSlot(Node, OnNodeInvalidation, onNodeInvalidation);
};
struct LightEntity
{
NazaraSlot(LightComponent, OnLightAttached, onLightAttached);
NazaraSlot(LightComponent, OnLightDetach, onLightDetach);
NazaraSlot(LightComponent, OnVisibilityUpdate, onVisibilityUpdate);
NazaraSlot(Node, OnNodeInvalidation, onNodeInvalidation);
};
entt::connection m_cameraDestroyConnection;
entt::connection m_graphicsDestroyConnection;
entt::connection m_lightDestroyConnection;
entt::connection m_nodeDestroyConnection;
entt::observer m_cameraConstructObserver;
entt::observer m_graphicsConstructObserver;
entt::observer m_lightConstructObserver;
std::set<entt::entity> m_invalidatedCameraNode;
std::set<entt::entity> m_invalidatedWorldNode;
std::set<entt::entity> m_invalidatedGfxWorldNode;
std::set<entt::entity> m_invalidatedLightWorldNode;
std::unique_ptr<FramePipeline> m_pipeline;
std::unordered_map<entt::entity, CameraEntity> m_cameraEntities;
std::unordered_map<entt::entity, GraphicsEntity> m_graphicsEntities;
std::unordered_set<entt::entity> m_newlyHiddenEntities;
std::unordered_set<entt::entity> m_newlyVisibleEntities;
std::unordered_map<entt::entity, LightEntity> m_lightEntities;
std::unordered_set<entt::entity> m_newlyHiddenGfxEntities;
std::unordered_set<entt::entity> m_newlyVisibleGfxEntities;
std::unordered_set<entt::entity> m_newlyHiddenLightEntities;
std::unordered_set<entt::entity> m_newlyVisibleLightEntities;
};
}

View File

@ -15,9 +15,9 @@
namespace Nz
{
class AbstractBuffer;
class CommandBufferBuilder;
class MaterialSettings;
class RenderBuffer;
class UploadPool;
class NAZARA_GRAPHICS_API ViewerInstance
@ -28,6 +28,7 @@ namespace Nz
ViewerInstance(ViewerInstance&&) noexcept = default;
~ViewerInstance() = default;
inline const Vector3f& GetEyePosition() const;
inline const Matrix4f& GetInvProjectionMatrix() const;
inline const Matrix4f& GetInvViewMatrix() const;
inline const Matrix4f& GetInvViewProjMatrix() const;
@ -39,6 +40,7 @@ namespace Nz
inline const std::shared_ptr<RenderBuffer>& GetViewerBuffer() const;
void UpdateBuffers(UploadPool& uploadPool, CommandBufferBuilder& builder);
inline void UpdateEyePosition(const Vector3f& eyePosition);
inline void UpdateProjectionMatrix(const Matrix4f& projectionMatrix);
inline void UpdateProjectionMatrix(const Matrix4f& projectionMatrix, const Matrix4f& invProjectionMatrix);
inline void UpdateProjViewMatrices(const Matrix4f& projectionMatrix, const Matrix4f& viewMatrix);
@ -60,6 +62,7 @@ namespace Nz
Matrix4f m_viewProjMatrix;
Matrix4f m_viewMatrix;
Vector2f m_targetSize;
Vector3f m_eyePosition;
bool m_dataInvalided;
};
}

View File

@ -8,6 +8,11 @@
namespace Nz
{
inline const Vector3f& ViewerInstance::GetEyePosition() const
{
return m_eyePosition;
}
inline const Matrix4f& ViewerInstance::GetInvProjectionMatrix() const
{
return m_invProjectionMatrix;
@ -53,6 +58,12 @@ namespace Nz
return m_viewerDataBuffer;
}
inline void ViewerInstance::UpdateEyePosition(const Vector3f& eyePosition)
{
m_eyePosition = eyePosition;
m_dataInvalided = true;
}
inline void ViewerInstance::UpdateProjectionMatrix(const Matrix4f& projectionMatrix)
{
m_projectionMatrix = projectionMatrix;

View File

@ -15,9 +15,9 @@
namespace Nz
{
class AbstractBuffer;
class CommandBufferBuilder;
class MaterialSettings;
class RenderBuffer;
class UploadPool;
class WorldInstance;

View File

@ -34,6 +34,8 @@ namespace Nz
BoundingVolume& ExtendTo(const BoundingVolume& volume);
bool Intersect(const Box<T>& box) const;
bool IsFinite() const;
bool IsInfinite() const;
bool IsNull() const;

View File

@ -169,11 +169,28 @@ namespace Nz
return *this;
}
template<typename T>
bool BoundingVolume<T>::Intersect(const Box<T>& box) const
{
switch (extend)
{
case Extend::Infinite:
return true;
case Extend::Finite:
return aabb.Intersect(box);
case Extend::Null:
return false;
}
return false;
}
/*!
* \brief Checks whether the volume is finite
* \return true if extend is Extend::Finite
*/
template<typename T>
bool BoundingVolume<T>::IsFinite() const
{

View File

@ -459,17 +459,12 @@ namespace Nz
{
T left = std::max(x, box.x);
T right = std::min(x + width, box.x + box.width);
if (left >= right)
return false;
T top = std::max(y, box.y);
T bottom = std::min(y + height, box.y + box.height);
if (top >= bottom)
return false;
T up = std::max(z, box.z);
T down = std::min(z + depth, box.z + box.depth);
if (up >= down)
if (left >= right || top >= bottom || up >= down)
return false;
if (intersection)

View File

@ -16,6 +16,7 @@ namespace Nz
class RenderBufferView
{
public:
inline RenderBufferView();
inline RenderBufferView(RenderBuffer* buffer);
inline RenderBufferView(RenderBuffer* buffer, UInt64 offset, UInt64 size);
RenderBufferView(const RenderBufferView&) = default;
@ -26,6 +27,11 @@ namespace Nz
inline UInt64 GetOffset() const;
inline UInt64 GetSize() const;
inline explicit operator bool() const;
inline bool operator==(const RenderBufferView& rhs) const;
inline bool operator!=(const RenderBufferView& rhs) const;
RenderBufferView& operator=(const RenderBufferView&) = default;
RenderBufferView& operator=(RenderBufferView&&) = default;

View File

@ -8,6 +8,13 @@
namespace Nz
{
inline RenderBufferView::RenderBufferView() :
m_offset(0),
m_size(0),
m_buffer(nullptr)
{
}
inline RenderBufferView::RenderBufferView(RenderBuffer* buffer) :
RenderBufferView(buffer, 0, buffer->GetSize())
{
@ -34,6 +41,21 @@ namespace Nz
{
return m_size;
}
inline RenderBufferView::operator bool() const
{
return m_buffer != nullptr;
}
inline bool RenderBufferView::operator==(const RenderBufferView& rhs) const
{
return m_buffer == rhs.m_buffer && m_offset == rhs.m_offset && m_size == rhs.m_size;
}
inline bool RenderBufferView::operator!=(const RenderBufferView& rhs) const
{
return !operator==(rhs);
}
}
#include <Nazara/Renderer/DebugOff.hpp>

View File

@ -17,7 +17,6 @@
namespace Nz
{
class AbstractBuffer;
class Buffer;
class NAZARA_RENDERER_API Renderer : public ModuleBase<Renderer>

View File

@ -103,7 +103,9 @@ namespace Nz
Length = 3,
Max = 4,
Min = 5,
Normalize = 9,
Pow = 6,
Reflect = 8,
SampleTexture = 2,
};

View File

@ -41,7 +41,9 @@ namespace Nz::ShaderAst
std::unordered_map<std::size_t, ConstantValue> optionValues;
bool makeVariableNameUnique = false;
bool reduceLoopsToWhile = false;
bool removeConstDeclaration = false;
bool removeCompoundAssignments = false;
bool removeMatrixCast = false;
bool removeOptionDeclaration = false;
bool removeScalarSwizzling = false;
bool splitMultipleBranches = false;

View File

@ -54,6 +54,7 @@ namespace Nz::ShaderBuilder
struct Cast
{
inline std::unique_ptr<ShaderAst::CastExpression> operator()(ShaderAst::ExpressionType targetType, ShaderAst::ExpressionPtr expression) const;
inline std::unique_ptr<ShaderAst::CastExpression> operator()(ShaderAst::ExpressionType targetType, std::array<ShaderAst::ExpressionPtr, 4> expressions) const;
inline std::unique_ptr<ShaderAst::CastExpression> operator()(ShaderAst::ExpressionType targetType, std::vector<ShaderAst::ExpressionPtr> expressions) const;
};
@ -71,6 +72,7 @@ namespace Nz::ShaderBuilder
struct Constant
{
inline std::unique_ptr<ShaderAst::ConstantValueExpression> operator()(ShaderAst::ConstantValue value) const;
template<typename T> std::unique_ptr<ShaderAst::ConstantValueExpression> operator()(ShaderAst::ExpressionType type, T value) const;
};
struct DeclareConst

View File

@ -3,6 +3,7 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Shader/ShaderBuilder.hpp>
#include <stdexcept>
#include <Nazara/Shader/Debug.hpp>
namespace Nz::ShaderBuilder
@ -110,6 +111,15 @@ namespace Nz::ShaderBuilder
return callFunctionExpression;
}
inline std::unique_ptr<ShaderAst::CastExpression> Impl::Cast::operator()(ShaderAst::ExpressionType targetType, ShaderAst::ExpressionPtr expression) const
{
auto castNode = std::make_unique<ShaderAst::CastExpression>();
castNode->targetType = std::move(targetType);
castNode->expressions[0] = std::move(expression);
return castNode;
}
inline std::unique_ptr<ShaderAst::CastExpression> Impl::Cast::operator()(ShaderAst::ExpressionType targetType, std::array<ShaderAst::ExpressionPtr, 4> expressions) const
{
auto castNode = std::make_unique<ShaderAst::CastExpression>();
@ -159,6 +169,22 @@ namespace Nz::ShaderBuilder
return constantNode;
}
template<typename T>
std::unique_ptr<ShaderAst::ConstantValueExpression> Impl::Constant::operator()(ShaderAst::ExpressionType type, T value) const
{
assert(IsPrimitiveType(type));
switch (std::get<ShaderAst::PrimitiveType>(type))
{
case ShaderAst::PrimitiveType::Boolean: return ShaderBuilder::Constant(value != T(0));
case ShaderAst::PrimitiveType::Float32: return ShaderBuilder::Constant(SafeCast<float>(value));
case ShaderAst::PrimitiveType::Int32: return ShaderBuilder::Constant(SafeCast<Int32>(value));
case ShaderAst::PrimitiveType::UInt32: return ShaderBuilder::Constant(SafeCast<UInt32>(value));
}
throw std::runtime_error("unexpected primitive type");
}
inline std::unique_ptr<ShaderAst::DeclareConstStatement> Impl::DeclareConst::operator()(std::string name, ShaderAst::ExpressionPtr initialValue) const
{
auto declareConstNode = std::make_unique<ShaderAst::DeclareConstStatement>();

View File

@ -113,7 +113,6 @@ namespace Nz::ShaderLang
ShaderAst::ExpressionPtr ParsePrimaryExpression();
ShaderAst::ExpressionPtr ParseVariableAssignation();
ShaderAst::ExpressionType ParseArrayType();
ShaderAst::AttributeType ParseIdentifierAsAttributeType();
const std::string& ParseIdentifierAsName();
ShaderAst::PrimitiveType ParsePrimitiveType();

View File

@ -152,7 +152,7 @@ namespace Nz
std::unordered_map<std::size_t, ShaderAst::StructDescription*> m_structs;
std::unordered_map<std::size_t, Variable> m_variables;
std::vector<std::size_t> m_scopeSizes;
std::vector<SpirvBlock> m_functionBlocks;
std::vector<std::unique_ptr<SpirvBlock>> m_functionBlocks;
std::vector<UInt32> m_resultIds;
SpirvBlock* m_currentBlock;
SpirvSection& m_instructions;

View File

@ -20,6 +20,7 @@
namespace Nz
{
class FieldOffsets;
class SpirvSection;
class NAZARA_SHADER_API SpirvConstantCache
@ -108,6 +109,7 @@ namespace Nz
{
std::string name;
TypePtr type;
mutable std::optional<UInt32> offset;
};
std::string name;
@ -171,6 +173,7 @@ namespace Nz
};
ConstantPtr BuildConstant(const ShaderAst::ConstantValue& value) const;
FieldOffsets BuildFieldOffsets(const Structure& structData) const;
TypePtr BuildFunctionType(const ShaderAst::ExpressionType& retType, const std::vector<ShaderAst::ExpressionType>& parameters) const;
TypePtr BuildPointerType(const ShaderAst::PrimitiveType& type, SpirvStorageClass storageClass) const;
TypePtr BuildPointerType(const ShaderAst::ExpressionType& type, SpirvStorageClass storageClass) const;
@ -195,6 +198,20 @@ namespace Nz
UInt32 Register(Type t);
UInt32 Register(Variable v);
std::size_t RegisterArrayField(FieldOffsets& fieldOffsets, const Array& type, std::size_t arrayLength) const;
std::size_t RegisterArrayField(FieldOffsets& fieldOffsets, const Bool& type, std::size_t arrayLength) const;
std::size_t RegisterArrayField(FieldOffsets& fieldOffsets, const Float& type, std::size_t arrayLength) const;
std::size_t RegisterArrayField(FieldOffsets& fieldOffsets, const Function& type, std::size_t arrayLength) const;
std::size_t RegisterArrayField(FieldOffsets& fieldOffsets, const Image& type, std::size_t arrayLength) const;
std::size_t RegisterArrayField(FieldOffsets& fieldOffsets, const Integer& type, std::size_t arrayLength) const;
std::size_t RegisterArrayField(FieldOffsets& fieldOffsets, const Matrix& type, std::size_t arrayLength) const;
std::size_t RegisterArrayField(FieldOffsets& fieldOffsets, const Pointer& type, std::size_t arrayLength) const;
std::size_t RegisterArrayField(FieldOffsets& fieldOffsets, const SampledImage& type, std::size_t arrayLength) const;
std::size_t RegisterArrayField(FieldOffsets& fieldOffsets, const Structure& type, std::size_t arrayLength) const;
std::size_t RegisterArrayField(FieldOffsets& fieldOffsets, const Type& type, std::size_t arrayLength) const;
std::size_t RegisterArrayField(FieldOffsets& fieldOffsets, const Vector& type, std::size_t arrayLength) const;
std::size_t RegisterArrayField(FieldOffsets& fieldOffsets, const Void& type, std::size_t arrayLength) const;
void SetStructCallback(StructCallback callback);
void Write(SpirvSection& annotations, SpirvSection& constants, SpirvSection& debugInfos);

View File

@ -44,7 +44,7 @@ namespace Nz
NAZARA_UTILITY_API Boxf ComputeAABB(SparsePtr<const Vector3f> positionPtr, std::size_t vertexCount);
NAZARA_UTILITY_API void ComputeBoxIndexVertexCount(const Vector3ui& subdivision, std::size_t* indexCount, std::size_t* vertexCount);
NAZARA_UTILITY_API UInt64 ComputeCacheMissCount(IndexIterator indices, std::size_t indexCount);
NAZARA_UTILITY_API UInt64 ComputeCacheMissCount(IndexIterator indices, UInt32 indexCount);
NAZARA_UTILITY_API void ComputeConeIndexVertexCount(unsigned int subdivision, std::size_t* indexCount, std::size_t* vertexCount);
NAZARA_UTILITY_API void ComputeCubicSphereIndexVertexCount(unsigned int subdivision, std::size_t* indexCount, std::size_t* vertexCount);
NAZARA_UTILITY_API void ComputeIcoSphereIndexVertexCount(unsigned int recursionLevel, std::size_t* indexCount, std::size_t* vertexCount);

View File

@ -29,6 +29,7 @@ namespace Nz
inline std::size_t GetAlignedSize() const;
inline std::size_t GetLargestFieldAlignement() const;
inline StructLayout GetLayout() const;
inline std::size_t GetSize() const;
FieldOffsets& operator=(const FieldOffsets&) = default;

View File

@ -23,6 +23,11 @@ namespace Nz
return m_largestFieldAlignment;
}
inline StructLayout FieldOffsets::GetLayout() const
{
return m_layout;
}
inline std::size_t FieldOffsets::GetAlignedSize() const
{
if (m_layout == StructLayout::Std140)

View File

@ -21,7 +21,7 @@ namespace Nz
class NAZARA_VULKANRENDERER_API VulkanBuffer : public RenderBuffer
{
public:
inline VulkanBuffer(VulkanDevice& device, BufferType type, UInt64 size, BufferUsageFlags usage, const void* initialData = nullptr);
VulkanBuffer(VulkanDevice& device, BufferType type, UInt64 size, BufferUsageFlags usage, const void* initialData = nullptr);
VulkanBuffer(const VulkanBuffer&) = delete;
VulkanBuffer(VulkanBuffer&&) = delete; ///TODO
virtual ~VulkanBuffer();

View File

@ -224,7 +224,7 @@ namespace Nz
UInt32 channelCount = 0;
UInt64 frameCount = 0;
UInt64 sampleCount = 0;
UInt64 sampleRate = 0;
UInt32 sampleRate = 0;
ud.metadataCallback = [&](const FLAC__StreamDecoder* /*decoder*/, const FLAC__StreamMetadata* meta)
{

View File

@ -25,30 +25,37 @@ namespace Nz
}
BasicMaterial::BasicMaterial(MaterialPass& material) :
m_material(material)
BasicMaterial(material, NoInit{})
{
// Most common case: don't fetch texture indexes as a little optimization
const std::shared_ptr<const MaterialSettings>& materialSettings = material.GetSettings();
if (materialSettings == s_materialSettings)
if (materialSettings == s_basicMaterialSettings)
{
m_optionIndexes = s_optionIndexes;
m_textureIndexes = s_textureIndexes;
m_basicOptionIndexes = s_basicOptionIndexes;
m_basicTextureIndexes = s_basicTextureIndexes;
m_uniformBlockIndex = s_uniformBlockIndex;
m_uniformOffsets = s_uniformOffsets;
m_basicUniformOffsets = s_basicUniformOffsets;
}
else
{
m_optionIndexes.alphaTest = materialSettings->GetOptionIndex("AlphaTest");
m_optionIndexes.hasAlphaMap = materialSettings->GetOptionIndex("HasAlphaMap");
m_optionIndexes.hasDiffuseMap = materialSettings->GetOptionIndex("HasDiffuseMap");
m_basicOptionIndexes.alphaTest = materialSettings->GetOptionIndex("AlphaTest");
m_basicOptionIndexes.hasAlphaMap = materialSettings->GetOptionIndex("HasAlphaMap");
m_basicOptionIndexes.hasDiffuseMap = materialSettings->GetOptionIndex("HasDiffuseMap");
m_textureIndexes.alpha = materialSettings->GetTextureIndex("Alpha");
m_textureIndexes.diffuse = materialSettings->GetTextureIndex("Diffuse");
m_basicTextureIndexes.alpha = materialSettings->GetTextureIndex("Alpha");
m_basicTextureIndexes.diffuse = materialSettings->GetTextureIndex("Diffuse");
m_uniformBlockIndex = materialSettings->GetUniformBlockIndex("BasicSettings");
m_uniformOffsets.alphaThreshold = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "AlphaThreshold");
m_uniformOffsets.diffuseColor = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "DiffuseColor");
m_uniformBlockIndex = materialSettings->GetUniformBlockIndex("MaterialSettings");
if (m_uniformBlockIndex != MaterialSettings::InvalidIndex)
{
m_basicUniformOffsets.alphaThreshold = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "AlphaThreshold");
m_basicUniformOffsets.diffuseColor = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "DiffuseColor");
}
else
{
m_basicUniformOffsets.alphaThreshold = MaterialSettings::InvalidIndex;
m_basicUniformOffsets.diffuseColor = MaterialSettings::InvalidIndex;
}
}
}
@ -58,7 +65,7 @@ namespace Nz
const std::vector<UInt8>& bufferData = m_material.GetUniformBufferConstData(m_uniformBlockIndex);
return AccessByOffset<const float&>(bufferData.data(), m_uniformOffsets.alphaThreshold);
return AccessByOffset<const float&>(bufferData.data(), m_basicUniformOffsets.alphaThreshold);
}
Color BasicMaterial::GetDiffuseColor() const
@ -67,7 +74,7 @@ namespace Nz
const std::vector<UInt8>& bufferData = m_material.GetUniformBufferConstData(m_uniformBlockIndex);
const float* colorPtr = AccessByOffset<const float*>(bufferData.data(), m_uniformOffsets.diffuseColor);
const float* colorPtr = AccessByOffset<const float*>(bufferData.data(), m_basicUniformOffsets.diffuseColor);
return Color(colorPtr[0] * 255, colorPtr[1] * 255, colorPtr[2] * 255, colorPtr[3] * 255); //< TODO: Make color able to use float
}
@ -76,7 +83,7 @@ namespace Nz
NazaraAssert(HasAlphaTestThreshold(), "Material has no alpha threshold uniform");
std::vector<UInt8>& bufferData = m_material.GetUniformBufferData(m_uniformBlockIndex);
AccessByOffset<float&>(bufferData.data(), m_uniformOffsets.alphaThreshold) = alphaThreshold;
AccessByOffset<float&>(bufferData.data(), m_basicUniformOffsets.alphaThreshold) = alphaThreshold;
}
void BasicMaterial::SetDiffuseColor(const Color& diffuse)
@ -85,44 +92,45 @@ namespace Nz
std::vector<UInt8>& bufferData = m_material.GetUniformBufferData(m_uniformBlockIndex);
float* colorPtr = AccessByOffset<float*>(bufferData.data(), m_uniformOffsets.diffuseColor);
float* colorPtr = AccessByOffset<float*>(bufferData.data(), m_basicUniformOffsets.diffuseColor);
colorPtr[0] = diffuse.r / 255.f;
colorPtr[1] = diffuse.g / 255.f;
colorPtr[2] = diffuse.b / 255.f;
colorPtr[3] = diffuse.a / 255.f;
}
MaterialSettings::Builder BasicMaterial::Build(const UniformOffsets& offsets, std::vector<UInt8> defaultValues, std::vector<std::shared_ptr<UberShader>> uberShaders, std::size_t* uniformBlockIndex, OptionIndexes* optionIndexes, TextureIndexes* textureIndexes)
MaterialSettings::Builder BasicMaterial::Build(BasicBuildOptions& options)
{
MaterialSettings::Builder settings;
std::vector<MaterialSettings::UniformVariable> variables;
if (offsets.alphaThreshold != std::numeric_limits<std::size_t>::max())
if (options.basicOffsets.alphaThreshold != std::numeric_limits<std::size_t>::max())
{
variables.push_back({
"AlphaThreshold",
offsets.alphaThreshold
options.basicOffsets.alphaThreshold
});
}
if (offsets.diffuseColor != std::numeric_limits<std::size_t>::max())
if (options.basicOffsets.diffuseColor != std::numeric_limits<std::size_t>::max())
{
variables.push_back({
"DiffuseColor",
offsets.diffuseColor
options.basicOffsets.diffuseColor
});
}
if (offsets.alphaThreshold != std::numeric_limits<std::size_t>::max())
AccessByOffset<float&>(defaultValues.data(), offsets.alphaThreshold) = 0.2f;
static_assert(sizeof(Vector4f) == 4 * sizeof(float), "Vector4f is expected to be exactly 4 floats wide");
if (offsets.diffuseColor != std::numeric_limits<std::size_t>::max())
AccessByOffset<Vector4f&>(defaultValues.data(), offsets.diffuseColor) = Vector4f(1.f, 1.f, 1.f, 1.f);
if (options.basicOffsets.alphaThreshold != std::numeric_limits<std::size_t>::max())
AccessByOffset<float&>(options.defaultValues.data(), options.basicOffsets.alphaThreshold) = 0.2f;
if (options.basicOffsets.diffuseColor != std::numeric_limits<std::size_t>::max())
AccessByOffset<Vector4f&>(options.defaultValues.data(), options.basicOffsets.diffuseColor) = Vector4f(1.f, 1.f, 1.f, 1.f);
// Textures
if (textureIndexes)
textureIndexes->alpha = settings.textures.size();
if (options.basicTextureIndexes)
options.basicTextureIndexes->alpha = settings.textures.size();
settings.textures.push_back({
2,
@ -130,8 +138,8 @@ namespace Nz
ImageType::E2D
});
if (textureIndexes)
textureIndexes->diffuse = settings.textures.size();
if (options.basicTextureIndexes)
options.basicTextureIndexes->diffuse = settings.textures.size();
settings.textures.push_back({
1,
@ -139,15 +147,15 @@ namespace Nz
ImageType::E2D
});
if (uniformBlockIndex)
*uniformBlockIndex = settings.uniformBlocks.size();
if (options.uniformBlockIndex)
*options.uniformBlockIndex = settings.uniformBlocks.size();
settings.uniformBlocks.push_back({
0,
"BasicSettings",
offsets.totalSize,
"MaterialSettings",
options.basicOffsets.totalSize,
std::move(variables),
std::move(defaultValues)
options.defaultValues
});
// Common data
@ -164,7 +172,7 @@ namespace Nz
settings.predefinedBindings[UnderlyingCast(PredefinedShaderBinding::OverlayTexture)] = 3;
settings.predefinedBindings[UnderlyingCast(PredefinedShaderBinding::ViewerDataUbo)] = 5;
settings.shaders = std::move(uberShaders);
settings.shaders = options.shaders;
for (std::shared_ptr<UberShader> uberShader : settings.shaders)
{
@ -230,20 +238,20 @@ namespace Nz
// Options
// HasDiffuseMap
if (optionIndexes)
optionIndexes->hasDiffuseMap = settings.options.size();
if (options.basicOptionIndexes)
options.basicOptionIndexes->hasDiffuseMap = settings.options.size();
MaterialSettings::BuildOption(settings.options, settings.shaders, "HasDiffuseMap", "HasDiffuseTexture");
// HasAlphaMap
if (optionIndexes)
optionIndexes->hasAlphaMap = settings.options.size();
if (options.basicOptionIndexes)
options.basicOptionIndexes->hasAlphaMap = settings.options.size();
MaterialSettings::BuildOption(settings.options, settings.shaders, "HasAlphaMap", "HasAlphaTexture");
// AlphaTest
if (optionIndexes)
optionIndexes->alphaTest = settings.options.size();
if (options.basicOptionIndexes)
options.basicOptionIndexes->alphaTest = settings.options.size();
MaterialSettings::BuildOption(settings.options, settings.shaders, "AlphaTest", "AlphaTest");
@ -258,36 +266,46 @@ namespace Nz
return { std::move(shader) };
}
auto BasicMaterial::BuildUniformOffsets() -> std::pair<UniformOffsets, FieldOffsets>
auto BasicMaterial::BuildUniformOffsets() -> std::pair<BasicUniformOffsets, FieldOffsets>
{
FieldOffsets fieldOffsets(StructLayout::Std140);
UniformOffsets uniformOffsets;
BasicUniformOffsets uniformOffsets;
uniformOffsets.alphaThreshold = fieldOffsets.AddField(StructFieldType::Float1);
uniformOffsets.diffuseColor = fieldOffsets.AddField(StructFieldType::Float4);
uniformOffsets.totalSize = fieldOffsets.GetSize();
uniformOffsets.totalSize = fieldOffsets.GetAlignedSize();
return std::make_pair(std::move(uniformOffsets), std::move(fieldOffsets));
}
bool BasicMaterial::Initialize()
{
std::tie(s_uniformOffsets, std::ignore) = BuildUniformOffsets();
std::tie(s_basicUniformOffsets, std::ignore) = BuildUniformOffsets();
std::vector<UInt8> defaultValues(s_uniformOffsets.totalSize);
s_materialSettings = std::make_shared<MaterialSettings>(Build(s_uniformOffsets, std::move(defaultValues), BuildShaders(), &s_uniformBlockIndex, &s_optionIndexes, &s_textureIndexes));
std::vector<UInt8> defaultValues(s_basicUniformOffsets.totalSize);
BasicBuildOptions options;
options.defaultValues.resize(s_basicUniformOffsets.totalSize);
options.shaders = BuildShaders();
options.basicOffsets = s_basicUniformOffsets;
options.basicOptionIndexes = &s_basicOptionIndexes;
options.basicTextureIndexes = &s_basicTextureIndexes;
options.uniformBlockIndex = &s_uniformBlockIndex;
s_basicMaterialSettings = std::make_shared<MaterialSettings>(Build(options));
return true;
}
void BasicMaterial::Uninitialize()
{
s_materialSettings.reset();
s_basicMaterialSettings.reset();
}
std::shared_ptr<MaterialSettings> BasicMaterial::s_materialSettings;
std::shared_ptr<MaterialSettings> BasicMaterial::s_basicMaterialSettings;
std::size_t BasicMaterial::s_uniformBlockIndex;
BasicMaterial::OptionIndexes BasicMaterial::s_optionIndexes;
BasicMaterial::TextureIndexes BasicMaterial::s_textureIndexes;
BasicMaterial::UniformOffsets BasicMaterial::s_uniformOffsets;
BasicMaterial::BasicOptionIndexes BasicMaterial::s_basicOptionIndexes;
BasicMaterial::BasicTextureIndexes BasicMaterial::s_basicTextureIndexes;
BasicMaterial::BasicUniformOffsets BasicMaterial::s_basicUniformOffsets;
}

View File

@ -0,0 +1,10 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/Components/LightComponent.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
}

View File

@ -26,19 +26,26 @@ namespace Nz
bool DepthMaterial::Initialize()
{
UniformOffsets offsets;
BasicUniformOffsets offsets;
std::tie(offsets, std::ignore) = BuildUniformOffsets();
std::vector<UInt8> defaultValues(offsets.totalSize);
s_materialSettings = std::make_shared<MaterialSettings>(Build(offsets, std::move(defaultValues), BuildShaders()));
BasicBuildOptions options;
options.defaultValues.resize(offsets.totalSize);
options.shaders = BuildShaders();
options.basicOffsets = s_basicUniformOffsets;
options.basicOptionIndexes = &s_basicOptionIndexes;
options.basicTextureIndexes = &s_basicTextureIndexes;
s_basicMaterialSettings = std::make_shared<MaterialSettings>(Build(options));
return true;
}
void DepthMaterial::Uninitialize()
{
s_materialSettings.reset();
s_basicMaterialSettings.reset();
}
std::shared_ptr<MaterialSettings> DepthMaterial::s_materialSettings;
std::shared_ptr<MaterialSettings> DepthMaterial::s_basicMaterialSettings;
}

View File

@ -0,0 +1,36 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/DirectionalLight.hpp>
#include <Nazara/Graphics/Enums.hpp>
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
#include <Nazara/Math/Vector2.hpp>
#include <Nazara/Math/Vector3.hpp>
#include <Nazara/Math/Vector4.hpp>
#include <limits>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
float DirectionalLight::ComputeContributionScore(const BoundingVolumef& /*boundingVolume*/) const
{
return -std::numeric_limits<float>::infinity();
}
void DirectionalLight::FillLightData(void* data)
{
auto lightOffset = PredefinedLightData::GetOffsets();
AccessByOffset<UInt32&>(data, lightOffset.lightMemberOffsets.type) = UnderlyingCast(BasicLightType::Directional);
AccessByOffset<Vector4f&>(data, lightOffset.lightMemberOffsets.color) = Vector4f(m_color.r / 255.f, m_color.g / 255.f, m_color.b / 255.f, m_color.a / 255.f);
AccessByOffset<Vector2f&>(data, lightOffset.lightMemberOffsets.factor) = Vector2f(m_ambientFactor, m_diffuseFactor);
AccessByOffset<Vector4f&>(data, lightOffset.lightMemberOffsets.parameter1) = Vector4f(m_direction.x, m_direction.y, m_direction.z, 0.f);
AccessByOffset<UInt8&>(data, lightOffset.lightMemberOffsets.shadowMappingFlag) = 0;
}
void DirectionalLight::UpdateTransform(const Vector3f& /*position*/, const Quaternionf& rotation, const Vector3f& /*scale*/)
{
UpdateRotation(rotation);
}
}

View File

@ -9,7 +9,11 @@ namespace Nz
{
ElementRenderer::~ElementRenderer() = default;
void ElementRenderer::Prepare(const ViewerInstance& /*viewerInstance*/, ElementRendererData& /*rendererData*/, RenderFrame& /*currentFrame*/, const Pointer<const RenderElement>* /*elements*/, std::size_t /*elementCount*/)
void ElementRenderer::Prepare(const ViewerInstance& /*viewerInstance*/, ElementRendererData& /*rendererData*/, RenderFrame& /*currentFrame*/, std::size_t /*elementCount*/, const Pointer<const RenderElement>* /*elements*/, const RenderStates* /*renderStates*/)
{
}
void ElementRenderer::PrepareEnd(RenderFrame& /*currentFrame*/, ElementRendererData& /*rendererData*/)
{
}

View File

@ -9,11 +9,14 @@
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/InstancedRenderable.hpp>
#include <Nazara/Graphics/Material.hpp>
#include <Nazara/Graphics/PointLight.hpp>
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
#include <Nazara/Graphics/RenderElement.hpp>
#include <Nazara/Graphics/SpriteChainRenderer.hpp>
#include <Nazara/Graphics/SubmeshRenderer.hpp>
#include <Nazara/Graphics/ViewerInstance.hpp>
#include <Nazara/Graphics/WorldInstance.hpp>
#include <Nazara/Math/Angle.hpp>
#include <Nazara/Math/Frustum.hpp>
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
#include <Nazara/Renderer/Framebuffer.hpp>
@ -35,6 +38,8 @@ namespace Nz
m_elementRenderers.resize(BasicRenderElementCount);
m_elementRenderers[UnderlyingCast(BasicRenderElement::SpriteChain)] = std::make_unique<SpriteChainRenderer>(*Graphics::Instance()->GetRenderDevice());
m_elementRenderers[UnderlyingCast(BasicRenderElement::Submesh)] = std::make_unique<SubmeshRenderer>();
m_lightUboPool = std::make_shared<LightUboPool>();
}
void ForwardFramePipeline::InvalidateViewer(AbstractViewer* viewerInstance)
@ -126,6 +131,21 @@ namespace Nz
}
}
void ForwardFramePipeline::RegisterLight(std::shared_ptr<Light> light, UInt32 renderMask)
{
auto& lightData = m_lights[light.get()];
lightData.light = std::move(light);
lightData.renderMask = renderMask;
lightData.onLightInvalidated.Connect(lightData.light->OnLightDataInvalided, [this](Light*)
{
for (auto&& [viewer, viewerData] : m_viewers)
{
viewerData.rebuildForwardPass = true;
viewerData.prepare = true;
}
});
}
void ForwardFramePipeline::RegisterViewer(AbstractViewer* viewerInstance, Int32 renderOrder)
{
auto& viewerData = m_viewers.emplace(viewerInstance, ViewerData{}).first->second;
@ -193,6 +213,9 @@ namespace Nz
return currentHash * 23 + newHash;
};
PredefinedLightData lightOffsets = PredefinedLightData::GetOffsets();
std::size_t lightUboAlignedSize = Align(lightOffsets.totalSize, graphics->GetRenderDevice()->GetDeviceInfo().limits.minUniformBufferOffsetAlignment);
// Render queues handling
for (auto&& [viewer, data] : m_viewers)
{
@ -274,12 +297,115 @@ namespace Nz
{
renderFrame.PushForRelease(std::move(viewerData.forwardRenderElements));
viewerData.forwardRenderElements.clear();
for (const auto& renderableData : m_visibleRenderables)
renderableData.instancedRenderable->BuildElement(m_forwardPassIndex, *renderableData.worldInstance, viewerData.forwardRenderElements);
viewerData.forwardRegistry.Clear();
viewerData.forwardRenderQueue.Clear();
viewerData.lightBufferPerLights.clear();
viewerData.lightPerRenderElement.clear();
for (auto& lightDataUbo : m_lightDataBuffers)
{
renderFrame.PushReleaseCallback([pool = m_lightUboPool, lightUbo = std::move(lightDataUbo.renderBuffer)]()
{
pool->lightUboBuffers.push_back(std::move(lightUbo));
});
}
m_lightDataBuffers.clear();
for (const auto& renderableData : m_visibleRenderables)
{
BoundingVolumef renderableBoundingVolume(renderableData.instancedRenderable->GetAABB());
renderableBoundingVolume.Update(renderableData.worldInstance->GetWorldMatrix());
// Select lights (TODO: Cull lights in frustum)
m_visibleLights.clear();
for (auto&& [light, lightData] : m_lights)
{
const BoundingVolumef& boundingVolume = light->GetBoundingVolume();
if ((renderMask & lightData.renderMask) && boundingVolume.Intersect(renderableBoundingVolume.aabb))
m_visibleLights.push_back(light);
}
// Sort lights
std::sort(m_visibleLights.begin(), m_visibleLights.end(), [&](Light* lhs, Light* rhs)
{
return lhs->ComputeContributionScore(renderableBoundingVolume) < rhs->ComputeContributionScore(renderableBoundingVolume);
});
std::size_t lightCount = std::min(m_visibleLights.size(), MaxLightCountPerDraw);
LightKey lightKey;
lightKey.fill(nullptr);
for (std::size_t i = 0; i < lightCount; ++i)
lightKey[i] = m_visibleLights[i];
RenderBufferView lightUboView;
auto it = viewerData.lightBufferPerLights.find(lightKey);
if (it == viewerData.lightBufferPerLights.end())
{
// Prepare light ubo upload
// Find light ubo
LightDataUbo* targetLightData = nullptr;
for (auto& lightUboData : m_lightDataBuffers)
{
if (lightUboData.offset + lightUboAlignedSize <= lightUboData.renderBuffer->GetSize())
{
targetLightData = &lightUboData;
break;
}
}
if (!targetLightData)
{
// Make a new light UBO
auto& lightUboData = m_lightDataBuffers.emplace_back();
// Reuse from pool if possible
if (!m_lightUboPool->lightUboBuffers.empty())
{
lightUboData.renderBuffer = m_lightUboPool->lightUboBuffers.back();
m_lightUboPool->lightUboBuffers.pop_back();
}
else
lightUboData.renderBuffer = graphics->GetRenderDevice()->InstantiateBuffer(BufferType::Uniform, 256 * lightUboAlignedSize, BufferUsage::DeviceLocal | BufferUsage::Dynamic | BufferUsage::Write);
targetLightData = &lightUboData;
}
assert(targetLightData);
if (!targetLightData->allocation)
targetLightData->allocation = &uploadPool.Allocate(targetLightData->renderBuffer->GetSize());
void* lightDataPtr = static_cast<UInt8*>(targetLightData->allocation->mappedPtr) + targetLightData->offset;
AccessByOffset<UInt32&>(lightDataPtr, lightOffsets.lightCountOffset) = SafeCast<UInt32>(lightCount);
UInt8* lightPtr = static_cast<UInt8*>(lightDataPtr) + lightOffsets.lightsOffset;
for (std::size_t i = 0; i < lightCount; ++i)
{
m_visibleLights[i]->FillLightData(lightPtr);
lightPtr += lightOffsets.lightSize;
}
// Associate render element with light ubo
lightUboView = RenderBufferView(targetLightData->renderBuffer.get(), targetLightData->offset, lightUboAlignedSize);
targetLightData->offset += lightUboAlignedSize;
viewerData.lightBufferPerLights.emplace(lightKey, lightUboView);
}
else
lightUboView = it->second;
std::size_t previousCount = viewerData.forwardRenderElements.size();
renderableData.instancedRenderable->BuildElement(m_forwardPassIndex, *renderableData.worldInstance, viewerData.forwardRenderElements);
for (std::size_t i = previousCount; i < viewerData.forwardRenderElements.size(); ++i)
{
const RenderElement* element = viewerData.forwardRenderElements[i].get();
viewerData.lightPerRenderElement.emplace(element, lightUboView);
}
}
for (const auto& renderElement : viewerData.forwardRenderElements)
{
renderElement->Register(viewerData.forwardRegistry);
@ -287,6 +413,23 @@ namespace Nz
}
viewerData.forwardRegistry.Finalize();
renderFrame.Execute([&](CommandBufferBuilder& builder)
{
builder.BeginDebugRegion("Light UBO Update", Color::Yellow);
{
for (auto& lightUboData : m_lightDataBuffers)
{
if (!lightUboData.allocation)
continue;
builder.CopyBuffer(*lightUboData.allocation, RenderBufferView(lightUboData.renderBuffer.get(), 0, lightUboData.offset));
}
builder.PostTransferBarrier();
}
builder.EndDebugRegion();
}, QueueType::Transfer);
}
viewerData.forwardRenderQueue.Sort([&](const RenderElement* element)
@ -323,14 +466,38 @@ namespace Nz
ProcessRenderQueue(viewerData.depthPrepassRenderQueue, [&](std::size_t elementType, const Pointer<const RenderElement>* elements, std::size_t elementCount)
{
ElementRenderer& elementRenderer = *m_elementRenderers[elementType];
elementRenderer.Prepare(viewerInstance, *rendererData[elementType], renderFrame, elements, elementCount);
m_renderStates.clear();
m_renderStates.resize(elementCount);
elementRenderer.Prepare(viewerInstance, *rendererData[elementType], renderFrame, elementCount, elements, m_renderStates.data());
});
for (std::size_t i = 0; i < m_elementRenderers.size(); ++i)
m_elementRenderers[i]->PrepareEnd(renderFrame, *rendererData[i]);
auto& lightPerRenderElement = viewerData.lightPerRenderElement;
ProcessRenderQueue(viewerData.forwardRenderQueue, [&](std::size_t elementType, const Pointer<const RenderElement>* elements, std::size_t elementCount)
{
ElementRenderer& elementRenderer = *m_elementRenderers[elementType];
elementRenderer.Prepare(viewerInstance, *rendererData[elementType], renderFrame, elements, elementCount);
m_renderStates.clear();
m_renderStates.reserve(elementCount);
for (std::size_t i = 0; i < elementCount; ++i)
{
auto it = lightPerRenderElement.find(elements[i]);
assert(it != lightPerRenderElement.end());
auto& renderStates = m_renderStates.emplace_back();
renderStates.lightData = it->second;
}
elementRenderer.Prepare(viewerInstance, *rendererData[elementType], renderFrame, elementCount, elements, m_renderStates.data());
});
for (std::size_t i = 0; i < m_elementRenderers.size(); ++i)
m_elementRenderers[i]->PrepareEnd(renderFrame, *rendererData[i]);
}
if (m_bakedFrameGraph.Resize(renderFrame))
@ -457,6 +624,17 @@ namespace Nz
}
}
void ForwardFramePipeline::UnregisterLight(Light* light)
{
m_lights.erase(light);
for (auto&& [viewer, viewerData] : m_viewers)
{
viewerData.rebuildForwardPass = true;
viewerData.prepare = true;
}
}
void ForwardFramePipeline::UnregisterViewer(AbstractViewer* viewerInstance)
{
m_viewers.erase(viewerInstance);
@ -508,7 +686,7 @@ namespace Nz
ProcessRenderQueue(viewerData.depthPrepassRenderQueue, [&](std::size_t elementType, const Pointer<const RenderElement>* elements, std::size_t elementCount)
{
ElementRenderer& elementRenderer = *m_elementRenderers[elementType];
elementRenderer.Render(viewerInstance, *viewerData.elementRendererData[elementType], builder, elements, elementCount);
elementRenderer.Render(viewerInstance, *viewerData.elementRendererData[elementType], builder, elementCount, elements);
});
});
@ -540,7 +718,7 @@ namespace Nz
ProcessRenderQueue(viewerData.forwardRenderQueue, [&](std::size_t elementType, const Pointer<const RenderElement>* elements, std::size_t elementCount)
{
ElementRenderer& elementRenderer = *m_elementRenderers[elementType];
elementRenderer.Render(viewerInstance , *viewerData.elementRendererData[elementType], builder, elements, elementCount);
elementRenderer.Render(viewerInstance, *viewerData.elementRendererData[elementType], builder, elementCount, elements);
});
});
}

View File

@ -113,36 +113,6 @@ namespace Nz
m_defaultTextures.whiteTextures.fill(nullptr);
}
void Graphics::FillDrawDataPipelineLayout(RenderPipelineLayoutInfo& layoutInfo, UInt32 set)
{
// TextureOverlay
layoutInfo.bindings.push_back({
set, 0,
ShaderBindingType::Texture,
ShaderStageType_All
});
}
void Graphics::FillViewerPipelineLayout(RenderPipelineLayoutInfo& layoutInfo, UInt32 set)
{
// ViewerData
layoutInfo.bindings.push_back({
set, 0,
ShaderBindingType::UniformBuffer,
ShaderStageType_All
});
}
void Graphics::FillWorldPipelineLayout(RenderPipelineLayoutInfo& layoutInfo, UInt32 set)
{
// InstanceData
layoutInfo.bindings.push_back({
set, 0,
ShaderBindingType::UniformBuffer,
ShaderStageType_All
});
}
void Graphics::BuildBlitPipeline()
{
RenderPipelineLayoutInfo layoutInfo;

View File

@ -0,0 +1,11 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/Light.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
Light::~Light() = default;
}

View File

@ -7,77 +7,94 @@
#include <Nazara/Core/ErrorFlags.hpp>
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Shader/ShaderLangParser.hpp>
#include <Nazara/Utility/BufferMapper.hpp>
#include <Nazara/Utility/FieldOffsets.hpp>
#include <Nazara/Utility/MaterialData.hpp>
#include <cassert>
#include <filesystem>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
namespace
{
const UInt8 r_shader[] = {
#include <Nazara/Graphics/Resources/Shaders/phong_material.nzsl.h>
};
}
PhongLightingMaterial::PhongLightingMaterial(MaterialPass& material) :
m_material(material)
BasicMaterial(material, NoInit{})
{
// Most common case: don't fetch texture indexes as a little optimization
const std::shared_ptr<const MaterialSettings>& materialSettings = m_material.GetSettings();
if (materialSettings == s_materialSettings)
const std::shared_ptr<const MaterialSettings>& materialSettings = GetMaterial().GetSettings();
if (materialSettings == s_phongMaterialSettings)
{
m_textureIndexes = s_textureIndexes;
m_phongUniformIndex = s_phongUniformBlockIndex;
m_basicUniformOffsets = s_basicUniformOffsets;
m_basicOptionIndexes = s_basicOptionIndexes;
m_basicTextureIndexes = s_basicTextureIndexes;
m_phongOptionIndexes = s_phongOptionIndexes;
m_phongTextureIndexes = s_phongTextureIndexes;
m_phongUniformOffsets = s_phongUniformOffsets;
}
else
{
m_textureIndexes.alpha = materialSettings->GetTextureIndex("Alpha");
m_textureIndexes.diffuse = materialSettings->GetTextureIndex("Diffuse");
m_textureIndexes.emissive = materialSettings->GetTextureIndex("Emissive");
m_textureIndexes.height = materialSettings->GetTextureIndex("Height");
m_textureIndexes.normal = materialSettings->GetTextureIndex("Normal");
m_textureIndexes.specular = materialSettings->GetTextureIndex("Specular");
m_basicOptionIndexes.alphaTest = materialSettings->GetOptionIndex("AlphaTest");
m_basicOptionIndexes.hasAlphaMap = materialSettings->GetOptionIndex("HasAlphaMap");
m_basicOptionIndexes.hasDiffuseMap = materialSettings->GetOptionIndex("HasDiffuseMap");
m_phongUniformIndex = materialSettings->GetUniformBlockIndex("PhongSettings");
m_phongOptionIndexes.hasEmissiveMap = materialSettings->GetOptionIndex("HasEmissiveMap");
m_phongOptionIndexes.hasHeightMap = materialSettings->GetOptionIndex("HasHeightMap");
m_phongOptionIndexes.hasNormalMap = materialSettings->GetOptionIndex("HasNormalMap");
m_phongOptionIndexes.hasSpecularMap = materialSettings->GetOptionIndex("HasSpecularMap");
m_phongUniformOffsets.alphaThreshold = materialSettings->GetUniformBlockVariableOffset(m_phongUniformIndex, "AlphaThreshold");
m_phongUniformOffsets.ambientColor = materialSettings->GetUniformBlockVariableOffset(m_phongUniformIndex, "AmbientColor");
m_phongUniformOffsets.diffuseColor = materialSettings->GetUniformBlockVariableOffset(m_phongUniformIndex, "DiffuseColor");
m_phongUniformOffsets.shininess = materialSettings->GetUniformBlockVariableOffset(m_phongUniformIndex, "Shininess");
m_phongUniformOffsets.specularColor = materialSettings->GetUniformBlockVariableOffset(m_phongUniformIndex, "SpecularColor");
m_basicTextureIndexes.alpha = materialSettings->GetTextureIndex("Alpha");
m_basicTextureIndexes.diffuse = materialSettings->GetTextureIndex("Diffuse");
m_phongTextureIndexes.emissive = materialSettings->GetTextureIndex("Emissive");
m_phongTextureIndexes.height = materialSettings->GetTextureIndex("Height");
m_phongTextureIndexes.normal = materialSettings->GetTextureIndex("Normal");
m_phongTextureIndexes.specular = materialSettings->GetTextureIndex("Specular");
m_uniformBlockIndex = materialSettings->GetUniformBlockIndex("MaterialSettings");
if (m_uniformBlockIndex != MaterialSettings::InvalidIndex)
{
m_basicUniformOffsets.alphaThreshold = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "AlphaThreshold");
m_basicUniformOffsets.diffuseColor = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "DiffuseColor");
m_phongUniformOffsets.ambientColor = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "AmbientColor");
m_phongUniformOffsets.shininess = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "Shininess");
m_phongUniformOffsets.specularColor = materialSettings->GetUniformBlockVariableOffset(m_uniformBlockIndex, "SpecularColor");
}
else
{
m_basicUniformOffsets.alphaThreshold = MaterialSettings::InvalidIndex;
m_basicUniformOffsets.diffuseColor = MaterialSettings::InvalidIndex;
m_phongUniformOffsets.ambientColor = MaterialSettings::InvalidIndex;
m_phongUniformOffsets.shininess = MaterialSettings::InvalidIndex;
m_phongUniformOffsets.specularColor = MaterialSettings::InvalidIndex;
}
}
}
float PhongLightingMaterial::GetAlphaThreshold() const
{
NazaraAssert(HasAlphaThreshold(), "Material has no alpha threshold uniform");
const std::vector<UInt8>& bufferData = m_material.GetUniformBufferConstData(m_phongUniformIndex);
return AccessByOffset<const float&>(bufferData.data(), m_phongUniformOffsets.alphaThreshold);
}
Color PhongLightingMaterial::GetAmbientColor() const
{
NazaraAssert(HasAmbientColor(), "Material has no ambient color uniform");
const std::vector<UInt8>& bufferData = m_material.GetUniformBufferConstData(m_phongUniformIndex);
const std::vector<UInt8>& bufferData = GetMaterial().GetUniformBufferConstData(m_uniformBlockIndex);
const float* colorPtr = AccessByOffset<const float*>(bufferData.data(), m_phongUniformOffsets.ambientColor);
return Color(colorPtr[0] * 255, colorPtr[1] * 255, colorPtr[2] * 255, colorPtr[3] * 255); //< TODO: Make color able to use float
}
Color PhongLightingMaterial::GetDiffuseColor() const
{
NazaraAssert(HasDiffuseColor(), "Material has no diffuse color uniform");
const std::vector<UInt8>& bufferData = m_material.GetUniformBufferConstData(m_phongUniformIndex);
const float* colorPtr = AccessByOffset<const float*>(bufferData.data(), m_phongUniformOffsets.diffuseColor);
return Color(colorPtr[0] * 255, colorPtr[1] * 255, colorPtr[2] * 255, colorPtr[3] * 255); //< TODO: Make color able to use float
}
float Nz::PhongLightingMaterial::GetShininess() const
{
NazaraAssert(HasShininess(), "Material has no shininess uniform");
const std::vector<UInt8>& bufferData = m_material.GetUniformBufferConstData(m_phongUniformIndex);
const std::vector<UInt8>& bufferData = GetMaterial().GetUniformBufferConstData(m_uniformBlockIndex);
return AccessByOffset<const float&>(bufferData.data(), m_phongUniformOffsets.shininess);
}
@ -85,25 +102,17 @@ namespace Nz
{
NazaraAssert(HasSpecularColor(), "Material has no specular color uniform");
const std::vector<UInt8>& bufferData = m_material.GetUniformBufferConstData(m_phongUniformIndex);
const std::vector<UInt8>& bufferData = GetMaterial().GetUniformBufferConstData(m_uniformBlockIndex);
const float* colorPtr = AccessByOffset<const float*>(bufferData.data(), m_phongUniformOffsets.specularColor);
return Color(colorPtr[0] * 255, colorPtr[1] * 255, colorPtr[2] * 255, colorPtr[3] * 255); //< TODO: Make color able to use float
}
void PhongLightingMaterial::SetAlphaThreshold(float alphaThreshold)
{
NazaraAssert(HasAlphaThreshold(), "Material has no alpha threshold uniform");
std::vector<UInt8>& bufferData = m_material.GetUniformBufferData(m_phongUniformIndex);
AccessByOffset<float&>(bufferData.data(), m_phongUniformOffsets.alphaThreshold) = alphaThreshold;
}
void PhongLightingMaterial::SetAmbientColor(const Color& ambient)
{
NazaraAssert(HasAmbientColor(), "Material has no ambient color uniform");
std::vector<UInt8>& bufferData = m_material.GetUniformBufferData(m_phongUniformIndex);
std::vector<UInt8>& bufferData = GetMaterial().GetUniformBufferData(m_uniformBlockIndex);
float* colorPtr = AccessByOffset<float*>(bufferData.data(), m_phongUniformOffsets.ambientColor);
colorPtr[0] = ambient.r / 255.f;
colorPtr[1] = ambient.g / 255.f;
@ -111,23 +120,19 @@ namespace Nz
colorPtr[3] = ambient.a / 255.f;
}
void PhongLightingMaterial::SetDiffuseColor(const Color& diffuse)
void PhongLightingMaterial::SetShininess(float shininess)
{
NazaraAssert(HasDiffuseColor(), "Material has no diffuse color uniform");
NazaraAssert(HasShininess(), "Material has no shininess uniform");
std::vector<UInt8>& bufferData = m_material.GetUniformBufferData(m_phongUniformIndex);
float* colorPtr = AccessByOffset<float*>(bufferData.data(), m_phongUniformOffsets.diffuseColor);
colorPtr[0] = diffuse.r / 255.f;
colorPtr[1] = diffuse.g / 255.f;
colorPtr[2] = diffuse.b / 255.f;
colorPtr[3] = diffuse.a / 255.f;
std::vector<UInt8>& bufferData = GetMaterial().GetUniformBufferData(m_uniformBlockIndex);
AccessByOffset<float&>(bufferData.data(), m_phongUniformOffsets.shininess) = shininess;
}
void PhongLightingMaterial::SetSpecularColor(const Color& diffuse)
{
NazaraAssert(HasSpecularColor(), "Material has no specular color uniform");
std::vector<UInt8>& bufferData = m_material.GetUniformBufferData(m_phongUniformIndex);
std::vector<UInt8>& bufferData = GetMaterial().GetUniformBufferData(m_uniformBlockIndex);
float* colorPtr = AccessByOffset<float*>(bufferData.data(), m_phongUniformOffsets.specularColor);
colorPtr[0] = diffuse.r / 255.f;
colorPtr[1] = diffuse.g / 255.f;
@ -137,118 +142,282 @@ namespace Nz
const std::shared_ptr<MaterialSettings>& PhongLightingMaterial::GetSettings()
{
return s_materialSettings;
return s_phongMaterialSettings;
}
bool PhongLightingMaterial::Initialize()
MaterialSettings::Builder PhongLightingMaterial::Build(PhongBuildOptions& options)
{
// MaterialPhongSettings
FieldOffsets phongUniformStruct(StructLayout::Std140);
MaterialSettings::Builder settings = BasicMaterial::Build(options);
s_phongUniformOffsets.alphaThreshold = phongUniformStruct.AddField(StructFieldType::Float1);
s_phongUniformOffsets.shininess = phongUniformStruct.AddField(StructFieldType::Float1);
s_phongUniformOffsets.ambientColor = phongUniformStruct.AddField(StructFieldType::Float4);
s_phongUniformOffsets.diffuseColor = phongUniformStruct.AddField(StructFieldType::Float4);
s_phongUniformOffsets.specularColor = phongUniformStruct.AddField(StructFieldType::Float4);
assert(settings.uniformBlocks.size() == 1);
std::vector<MaterialSettings::UniformVariable> variables = std::move(settings.uniformBlocks.front().uniforms);
settings.uniformBlocks.clear();
MaterialSettings::Builder settings;
std::vector<MaterialSettings::UniformVariable> phongVariables;
phongVariables.assign({
{
"AlphaThreshold",
s_phongUniformOffsets.alphaThreshold
},
{
"Shininess",
s_phongUniformOffsets.shininess
},
{
if (options.phongOffsets.ambientColor != std::numeric_limits<std::size_t>::max())
{
variables.push_back({
"AmbientColor",
s_phongUniformOffsets.ambientColor
},
{
"DiffuseColor",
s_phongUniformOffsets.diffuseColor
},
{
options.phongOffsets.ambientColor
});
}
if (options.phongOffsets.shininess != std::numeric_limits<std::size_t>::max())
{
variables.push_back({
"Shininess",
options.phongOffsets.shininess
});
}
if (options.phongOffsets.shininess != std::numeric_limits<std::size_t>::max())
{
variables.push_back({
"SpecularColor",
s_phongUniformOffsets.specularColor
}
});
options.phongOffsets.specularColor
});
}
static_assert(sizeof(Vector4f) == 4 * sizeof(float), "Vector4f is expected to be exactly 4 floats wide");
std::vector<UInt8> defaultValues(phongUniformStruct.GetSize());
AccessByOffset<Vector4f&>(defaultValues.data(), s_phongUniformOffsets.ambientColor) = Vector4f(0.5f, 0.5f, 0.5f, 1.f);
AccessByOffset<Vector4f&>(defaultValues.data(), s_phongUniformOffsets.diffuseColor) = Vector4f(1.f, 1.f, 1.f, 1.f);
AccessByOffset<Vector4f&>(defaultValues.data(), s_phongUniformOffsets.specularColor) = Vector4f(1.f, 1.f, 1.f, 1.f);
AccessByOffset<float&>(defaultValues.data(), s_phongUniformOffsets.alphaThreshold) = 0.2f;
AccessByOffset<float&>(defaultValues.data(), s_phongUniformOffsets.shininess) = 50.f;
if (options.phongOffsets.ambientColor != std::numeric_limits<std::size_t>::max())
AccessByOffset<Vector4f&>(options.defaultValues.data(), options.phongOffsets.ambientColor) = Vector4f(0.f, 0.f, 0.f, 1.f);
s_phongUniformBlockIndex = settings.uniformBlocks.size();
settings.uniformBlocks.push_back({
0,
"PhongSettings",
phongUniformStruct.GetSize(),
std::move(phongVariables),
std::move(defaultValues)
});
if (options.phongOffsets.specularColor != std::numeric_limits<std::size_t>::max())
AccessByOffset<Vector4f&>(options.defaultValues.data(), options.phongOffsets.specularColor) = Vector4f(1.f, 1.f, 1.f, 1.f);
s_textureIndexes.alpha = settings.textures.size();
settings.textures.push_back({
2,
"Alpha",
ImageType::E2D
});
s_textureIndexes.diffuse = settings.textures.size();
settings.textures.push_back({
1,
"Diffuse",
ImageType::E2D
});
if (options.phongOffsets.shininess != std::numeric_limits<std::size_t>::max())
AccessByOffset<float&>(options.defaultValues.data(), options.phongOffsets.shininess) = 2.f;
// Textures
if (options.phongTextureIndexes)
options.phongTextureIndexes->emissive = settings.textures.size();
s_textureIndexes.emissive = settings.textures.size();
settings.textures.push_back({
3,
7,
"Emissive",
ImageType::E2D
});
s_textureIndexes.height = settings.textures.size();
if (options.phongTextureIndexes)
options.phongTextureIndexes->height = settings.textures.size();
settings.textures.push_back({
4,
8,
"Height",
ImageType::E2D
});
s_textureIndexes.normal = settings.textures.size();
if (options.phongTextureIndexes)
options.phongTextureIndexes->normal = settings.textures.size();
settings.textures.push_back({
5,
9,
"Normal",
ImageType::E2D
});
s_textureIndexes.specular = settings.textures.size();
if (options.phongTextureIndexes)
options.phongTextureIndexes->specular = settings.textures.size();
settings.textures.push_back({
6,
10,
"Specular",
ImageType::E2D
});
s_materialSettings = std::make_shared<MaterialSettings>(std::move(settings));
if (options.uniformBlockIndex)
*options.uniformBlockIndex = settings.uniformBlocks.size();
settings.uniformBlocks.push_back({
0,
"MaterialSettings",
options.phongOffsets.totalSize,
std::move(variables),
options.defaultValues
});
settings.sharedUniformBlocks.push_back(PredefinedLightData::GetUniformBlock(6, ShaderStageType::Fragment));
settings.predefinedBindings[UnderlyingCast(PredefinedShaderBinding::LightDataUbo)] = 6;
settings.shaders = options.shaders;
for (std::shared_ptr<UberShader> uberShader : settings.shaders)
{
constexpr std::size_t InvalidOption = std::numeric_limits<std::size_t>::max();
auto FetchLocationOption = [&](const std::string& optionName)
{
const UberShader::Option* optionPtr;
if (!uberShader->HasOption(optionName, &optionPtr))
return InvalidOption;
if (optionPtr->type != ShaderAst::ExpressionType{ ShaderAst::PrimitiveType::Int32 })
throw std::runtime_error("Location options must be of type i32");
return optionPtr->index;
};
std::size_t positionLocationIndex = FetchLocationOption("PosLocation");
std::size_t colorLocationIndex = FetchLocationOption("ColorLocation");
std::size_t normalLocationIndex = FetchLocationOption("NormalLocation");
std::size_t tangentLocationIndex = FetchLocationOption("TangentLocation");
std::size_t uvLocationIndex = FetchLocationOption("UvLocation");
uberShader->UpdateConfigCallback([=](UberShader::Config& config, const std::vector<RenderPipelineInfo::VertexBufferData>& vertexBuffers)
{
if (vertexBuffers.empty())
return;
const VertexDeclaration& vertexDeclaration = *vertexBuffers.front().declaration;
const auto& components = vertexDeclaration.GetComponents();
std::size_t locationIndex = 0;
for (const auto& component : components)
{
switch (component.component)
{
case VertexComponent::Position:
if (positionLocationIndex != InvalidOption)
config.optionValues[positionLocationIndex] = static_cast<Int32>(locationIndex);
break;
case VertexComponent::Color:
if (colorLocationIndex != InvalidOption)
config.optionValues[colorLocationIndex] = static_cast<Int32>(locationIndex);
break;
case VertexComponent::Normal:
if (normalLocationIndex != InvalidOption)
config.optionValues[normalLocationIndex] = static_cast<Int32>(locationIndex);
break;
case VertexComponent::Tangent:
if (tangentLocationIndex != InvalidOption)
config.optionValues[tangentLocationIndex] = static_cast<Int32>(locationIndex);
break;
case VertexComponent::TexCoord:
if (uvLocationIndex != InvalidOption)
config.optionValues[uvLocationIndex] = static_cast<Int32>(locationIndex);
break;
case VertexComponent::Unused:
default:
break;
}
++locationIndex;
}
});
}
// Options
// HasEmissiveMap
if (options.phongOptionIndexes)
options.phongOptionIndexes->hasEmissiveMap = settings.options.size();
MaterialSettings::BuildOption(settings.options, settings.shaders, "HasEmissiveMap", "HasEmissiveTexture");
// HasHeightMap
if (options.phongOptionIndexes)
options.phongOptionIndexes->hasHeightMap = settings.options.size();
MaterialSettings::BuildOption(settings.options, settings.shaders, "HasHeightMap", "HasHeightTexture");
// HasNormalMap
if (options.phongOptionIndexes)
options.phongOptionIndexes->hasNormalMap = settings.options.size();
MaterialSettings::BuildOption(settings.options, settings.shaders, "HasNormalMap", "HasNormalTexture");
// HasSpecularMap
if (options.phongOptionIndexes)
options.phongOptionIndexes->hasSpecularMap = settings.options.size();
MaterialSettings::BuildOption(settings.options, settings.shaders, "HasSpecularMap", "HasSpecularTexture");
return settings;
}
std::vector<std::shared_ptr<UberShader>> PhongLightingMaterial::BuildShaders()
{
ShaderAst::StatementPtr shaderAst;
#ifdef NAZARA_DEBUG
std::filesystem::path shaderPath = "../../src/Nazara/Graphics/Resources/Shaders/phong_material.nzsl";
if (std::filesystem::exists(shaderPath))
{
try
{
shaderAst = ShaderLang::ParseFromFile(shaderPath);
}
catch (const std::exception& e)
{
NazaraError(std::string("failed to load shader from engine folder: ") + e.what());
}
}
#endif
if (!shaderAst)
shaderAst = ShaderLang::Parse(std::string_view(reinterpret_cast<const char*>(r_shader), sizeof(r_shader)));
auto shader = std::make_shared<UberShader>(ShaderStageType::Fragment | ShaderStageType::Vertex, shaderAst);
return { std::move(shader) };
}
auto PhongLightingMaterial::BuildUniformOffsets() -> std::pair<PhongUniformOffsets, FieldOffsets>
{
auto basicOffsets = BasicMaterial::BuildUniformOffsets();
FieldOffsets fieldOffsets = basicOffsets.second;
PhongUniformOffsets uniformOffsets;
uniformOffsets.ambientColor = fieldOffsets.AddField(StructFieldType::Float3);
uniformOffsets.specularColor = fieldOffsets.AddField(StructFieldType::Float3);
uniformOffsets.shininess = fieldOffsets.AddField(StructFieldType::Float1);
uniformOffsets.totalSize = fieldOffsets.GetAlignedSize();
return std::make_pair(std::move(uniformOffsets), std::move(fieldOffsets));
}
bool PhongLightingMaterial::Initialize()
{
std::tie(s_phongUniformOffsets, std::ignore) = BuildUniformOffsets();
std::vector<UInt8> defaultValues(s_phongUniformOffsets.totalSize);
PhongBuildOptions options;
options.defaultValues = std::move(defaultValues);
options.shaders = BuildShaders();
// Basic material
options.basicOffsets = s_basicUniformOffsets;
// Phong Material
options.phongOffsets = s_phongUniformOffsets;
options.phongOptionIndexes = &s_phongOptionIndexes;
options.phongTextureIndexes = &s_phongTextureIndexes;
s_phongMaterialSettings = std::make_shared<MaterialSettings>(Build(options));
return true;
}
void PhongLightingMaterial::Uninitialize()
{
s_materialSettings.reset();
s_phongMaterialSettings.reset();
}
std::shared_ptr<MaterialSettings> PhongLightingMaterial::s_materialSettings;
std::shared_ptr<MaterialSettings> PhongLightingMaterial::s_phongMaterialSettings;
std::size_t PhongLightingMaterial::s_phongUniformBlockIndex;
PhongLightingMaterial::TextureIndexes PhongLightingMaterial::s_textureIndexes;
PhongLightingMaterial::PhongOptionIndexes PhongLightingMaterial::s_phongOptionIndexes;
PhongLightingMaterial::PhongTextureIndexes PhongLightingMaterial::s_phongTextureIndexes;
PhongLightingMaterial::PhongUniformOffsets PhongLightingMaterial::s_phongUniformOffsets;
}

View File

@ -0,0 +1,36 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/PointLight.hpp>
#include <Nazara/Graphics/Enums.hpp>
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
#include <Nazara/Math/Vector2.hpp>
#include <Nazara/Math/Vector3.hpp>
#include <Nazara/Math/Vector4.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
float PointLight::ComputeContributionScore(const BoundingVolumef& boundingVolume) const
{
// TODO: take luminosity/radius into account
return Vector3f::SquaredDistance(m_position, boundingVolume.aabb.GetCenter());
}
void PointLight::FillLightData(void* data)
{
auto lightOffset = PredefinedLightData::GetOffsets();
AccessByOffset<UInt32&>(data, lightOffset.lightMemberOffsets.type) = UnderlyingCast(BasicLightType::Point);
AccessByOffset<Vector4f&>(data, lightOffset.lightMemberOffsets.color) = Vector4f(m_color.r / 255.f, m_color.g / 255.f, m_color.b / 255.f, m_color.a / 255.f);
AccessByOffset<Vector2f&>(data, lightOffset.lightMemberOffsets.factor) = Vector2f(m_ambientFactor, m_diffuseFactor);
AccessByOffset<Vector4f&>(data, lightOffset.lightMemberOffsets.parameter1) = Vector4f(m_position.x, m_position.y, m_position.z, m_invRadius);
AccessByOffset<UInt8&>(data, lightOffset.lightMemberOffsets.shadowMappingFlag) = 0;
}
void PointLight::UpdateTransform(const Vector3f& position, const Quaternionf& /*rotation*/, const Vector3f& /*scale*/)
{
UpdatePosition(position);
}
}

View File

@ -13,42 +13,40 @@ namespace Nz
PredefinedLightData lightData;
FieldOffsets lightStruct(StructLayout::Std140);
lightData.innerOffsets.type = lightStruct.AddField(StructFieldType::Int1);
lightData.innerOffsets.color = lightStruct.AddField(StructFieldType::Float4);
lightData.innerOffsets.factor = lightStruct.AddField(StructFieldType::Float2);
lightData.innerOffsets.parameter1 = lightStruct.AddField(StructFieldType::Float4);
lightData.innerOffsets.parameter2 = lightStruct.AddField(StructFieldType::Float4);
lightData.innerOffsets.parameter3 = lightStruct.AddField(StructFieldType::Float2);
lightData.innerOffsets.shadowMappingFlag = lightStruct.AddField(StructFieldType::Bool1);
lightData.lightMemberOffsets.type = lightStruct.AddField(StructFieldType::Int1);
lightData.lightMemberOffsets.color = lightStruct.AddField(StructFieldType::Float4);
lightData.lightMemberOffsets.factor = lightStruct.AddField(StructFieldType::Float2);
lightData.lightMemberOffsets.parameter1 = lightStruct.AddField(StructFieldType::Float4);
lightData.lightMemberOffsets.parameter2 = lightStruct.AddField(StructFieldType::Float4);
lightData.lightMemberOffsets.parameter3 = lightStruct.AddField(StructFieldType::Float4);
lightData.lightMemberOffsets.shadowMappingFlag = lightStruct.AddField(StructFieldType::Bool1);
lightData.innerOffsets.totalSize = lightStruct.GetAlignedSize();
lightData.lightSize = lightStruct.GetAlignedSize();
FieldOffsets lightDataStruct(StructLayout::Std140);
for (std::size_t& lightOffset : lightData.lightArray)
lightOffset = lightDataStruct.AddStruct(lightStruct);
lightData.lightsOffset = lightDataStruct.AddStructArray(lightStruct, MaxLightCount);
lightData.lightCountOffset = lightDataStruct.AddField(StructFieldType::UInt1);
lightData.lightArraySize = lightDataStruct.GetAlignedSize();
lightData.totalSize = lightDataStruct.GetAlignedSize();
return lightData;
}
MaterialSettings::SharedUniformBlock PredefinedLightData::GetUniformBlock()
MaterialSettings::SharedUniformBlock PredefinedLightData::GetUniformBlock(UInt32 bindingIndex, ShaderStageTypeFlags shaderStages)
{
PredefinedLightData lightData = GetOffsets();
std::vector<MaterialSettings::UniformVariable> lightDataVariables;
for (std::size_t i = 0; i < lightData.lightArray.size(); ++i)
{
lightDataVariables.push_back({
"LightData[" + std::to_string(i) + "]",
lightData.lightArray[i]
});
}
std::vector<MaterialSettings::UniformVariable> variables = {
{
{ "Lights", lightData.lightsOffset }
}
};
MaterialSettings::SharedUniformBlock uniformBlock = {
0, //< FIXME
"Light",
std::move(lightDataVariables)
bindingIndex,
"LightData",
std::move(variables),
shaderStages
};
return uniformBlock;

View File

@ -2,62 +2,69 @@ option HasDiffuseTexture: bool = false;
option HasAlphaTexture: bool = false;
option AlphaTest: bool = false;
// Billboard related options
option Billboard: bool = false;
option BillboardCenterLocation: i32 = -1;
option BillboardColorLocation: i32 = -1;
option BillboardSizeRotLocation: i32 = -1;
// Vertex declaration related options
option PosLocation: i32 = -1;
option ColorLocation: i32 = -1;
option PosLocation: i32 = -1;
option UvLocation: i32 = -1;
const HasVertexColor = (ColorLocation >= 0);
const HasColor = (HasVertexColor || Billboard);
const HasUV = (UvLocation >= 0);
[layout(std140)]
struct BasicSettings
struct MaterialSettings
{
AlphaThreshold: f32,
DiffuseColor: vec4<f32>
DiffuseColor: vec4[f32]
}
[layout(std140)]
struct InstanceData
{
worldMatrix: mat4<f32>,
invWorldMatrix: mat4<f32>
worldMatrix: mat4[f32],
invWorldMatrix: mat4[f32]
}
[layout(std140)]
struct ViewerData
{
projectionMatrix: mat4<f32>,
invProjectionMatrix: mat4<f32>,
viewMatrix: mat4<f32>,
invViewMatrix: mat4<f32>,
viewProjMatrix: mat4<f32>,
invViewProjMatrix: mat4<f32>,
renderTargetSize: vec2<f32>,
invRenderTargetSize: vec2<f32>,
eyePosition: vec3<f32>
projectionMatrix: mat4[f32],
invProjectionMatrix: mat4[f32],
viewMatrix: mat4[f32],
invViewMatrix: mat4[f32],
viewProjMatrix: mat4[f32],
invViewProjMatrix: mat4[f32],
renderTargetSize: vec2[f32],
invRenderTargetSize: vec2[f32],
eyePosition: vec3[f32]
}
external
{
[binding(0)] settings: uniform<BasicSettings>,
[binding(1)] MaterialDiffuseMap: sampler2D<f32>,
[binding(2)] MaterialAlphaMap: sampler2D<f32>,
[binding(3)] TextureOverlay: sampler2D<f32>,
[binding(4)] instanceData: uniform<InstanceData>,
[binding(5)] viewerData: uniform<ViewerData>,
[binding(0)] settings: uniform[MaterialSettings],
[binding(1)] MaterialDiffuseMap: sampler2D[f32],
[binding(2)] MaterialAlphaMap: sampler2D[f32],
[binding(3)] TextureOverlay: sampler2D[f32],
[binding(4)] instanceData: uniform[InstanceData],
[binding(5)] viewerData: uniform[ViewerData],
}
// Fragment stage
struct FragIn
{
[location(0), cond(HasUV)] uv: vec2<f32>,
[location(1), cond(HasVertexColor)] color: vec4<f32>
[location(0), cond(HasUV)] uv: vec2[f32],
[location(1), cond(HasColor)] color: vec4[f32]
}
struct FragOut
{
[location(0)] RenderTarget0: vec4<f32>
[location(0)] RenderTarget0: vec4[f32]
}
[entry(frag)]
@ -68,7 +75,7 @@ fn main(input: FragIn) -> FragOut
const if (HasUV)
diffuseColor *= TextureOverlay.Sample(input.uv);
const if (HasVertexColor)
const if (HasColor)
diffuseColor *= input.color;
const if (HasDiffuseTexture)
@ -91,25 +98,70 @@ fn main(input: FragIn) -> FragOut
// Vertex stage
struct VertIn
{
[location(PosLocation)] pos: vec3<f32>,
[location(ColorLocation), cond(HasVertexColor)] color: vec4<f32>,
[location(UvLocation), cond(HasUV)] uv: vec2<f32>
[location(PosLocation)]
pos: vec3[f32],
[cond(HasVertexColor), location(ColorLocation)]
color: vec4[f32],
[cond(HasUV), location(UvLocation)]
uv: vec2[f32],
[cond(Billboard), location(BillboardCenterLocation)]
billboardCenter: vec3[f32],
[cond(Billboard), location(BillboardSizeRotLocation)]
billboardSizeRot: vec4[f32], //< width,height,sin,cos
[cond(Billboard), location(BillboardColorLocation)]
billboardColor: vec4[f32]
}
struct VertOut
{
[location(0), cond(HasUV)] uv: vec2<f32>,
[location(1), cond(HasVertexColor)] color: vec4<f32>,
[builtin(position)] position: vec4<f32>
[location(0), cond(HasUV)] uv: vec2[f32],
[location(1), cond(HasColor)] color: vec4[f32],
[builtin(position)] position: vec4[f32]
}
[entry(vert)]
[entry(vert), cond(Billboard)]
fn billboardMain(input: VertIn) -> VertOut
{
let size = input.billboardSizeRot.xy;
let sinCos = input.billboardSizeRot.zw;
let rotatedPosition = vec2[f32](
input.pos.x * sinCos.y - input.pos.y * sinCos.x,
input.pos.y * sinCos.y + input.pos.x * sinCos.x
);
rotatedPosition *= size;
let cameraRight = vec3[f32](viewerData.viewMatrix[0][0], viewerData.viewMatrix[1][0], viewerData.viewMatrix[2][0]);
let cameraUp = vec3[f32](viewerData.viewMatrix[0][1], viewerData.viewMatrix[1][1], viewerData.viewMatrix[2][1]);
let vertexPos = input.billboardCenter;
vertexPos += cameraRight * rotatedPosition.x;
vertexPos += cameraUp * rotatedPosition.y;
let output: VertOut;
output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4[f32](vertexPos, 1.0);
const if (HasColor)
output.color = input.billboardColor;
const if (HasUV)
output.uv = input.pos.xy + vec2[f32](0.5, 0.5);
return output;
}
[entry(vert), cond(!Billboard)]
fn main(input: VertIn) -> VertOut
{
let output: VertOut;
output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4<f32>(input.pos, 1.0);
output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4[f32](input.pos, 1.0);
const if (HasVertexColor)
const if (HasColor)
output.color = input.color;
const if (HasUV)

View File

@ -1,25 +1,25 @@
external
{
[binding(0)] texture: sampler2D<f32>
[binding(0)] texture: sampler2D[f32]
}
struct VertIn
{
[location(0)] position: vec2<f32>,
[location(1)] uv: vec2<f32>
[location(0)] position: vec2[f32],
[location(1)] uv: vec2[f32]
}
struct VertOut
{
[builtin(position)] position: vec4<f32>,
[location(0)] uv: vec2<f32>
[builtin(position)] position: vec4[f32],
[location(0)] uv: vec2[f32]
}
[entry(vert)]
fn main(vertIn: VertIn) -> VertOut
{
let output: VertOut;
output.position = vec4<f32>(vertIn.position, 0.0, 1.0);
output.position = vec4[f32](vertIn.position, 0.0, 1.0);
output.uv = vertIn.uv;
return output;
@ -27,7 +27,7 @@ fn main(vertIn: VertIn) -> VertOut
struct FragOut
{
[location(0)] color: vec4<f32>
[location(0)] color: vec4[f32]
}
[entry(frag)]

View File

@ -8,44 +8,44 @@ const HasUV = AlphaTest && (HasDiffuseTexture || HasAlphaTexture);
struct BasicSettings
{
AlphaThreshold: f32,
DiffuseColor: vec4<f32>
DiffuseColor: vec4[f32]
}
[layout(std140)]
struct InstanceData
{
worldMatrix: mat4<f32>,
invWorldMatrix: mat4<f32>
worldMatrix: mat4[f32],
invWorldMatrix: mat4[f32]
}
[layout(std140)]
struct ViewerData
{
projectionMatrix: mat4<f32>,
invProjectionMatrix: mat4<f32>,
viewMatrix: mat4<f32>,
invViewMatrix: mat4<f32>,
viewProjMatrix: mat4<f32>,
invViewProjMatrix: mat4<f32>,
renderTargetSize: vec2<f32>,
invRenderTargetSize: vec2<f32>,
eyePosition: vec3<f32>
projectionMatrix: mat4[f32],
invProjectionMatrix: mat4[f32],
viewMatrix: mat4[f32],
invViewMatrix: mat4[f32],
viewProjMatrix: mat4[f32],
invViewProjMatrix: mat4[f32],
renderTargetSize: vec2[f32],
invRenderTargetSize: vec2[f32],
eyePosition: vec3[f32]
}
external
{
[binding(0)] settings: uniform<BasicSettings>,
[binding(1)] MaterialDiffuseMap: sampler2D<f32>,
[binding(2)] MaterialAlphaMap: sampler2D<f32>,
[binding(3)] TextureOverlay: sampler2D<f32>,
[binding(4)] instanceData: uniform<InstanceData>,
[binding(5)] viewerData: uniform<ViewerData>,
[binding(0)] settings: uniform[BasicSettings],
[binding(1)] MaterialDiffuseMap: sampler2D[f32],
[binding(2)] MaterialAlphaMap: sampler2D[f32],
[binding(3)] TextureOverlay: sampler2D[f32],
[binding(4)] instanceData: uniform[InstanceData],
[binding(5)] viewerData: uniform[ViewerData],
}
// Fragment stage
struct FragIn
{
[location(0), cond(HasUV)] uv: vec2<f32>
[location(0), cond(HasUV)] uv: vec2[f32]
}
[entry(frag), cond(AlphaTest)]
@ -73,21 +73,21 @@ fn main() {}
// Vertex stage
struct VertIn
{
[location(0)] pos: vec3<f32>,
[location(1), cond(HasUV)] uv: vec2<f32>
[location(0)] pos: vec3[f32],
[location(1), cond(HasUV)] uv: vec2[f32]
}
struct VertOut
{
[location(0), cond(HasUV)] uv: vec2<f32>,
[builtin(position)] position: vec4<f32>
[location(0), cond(HasUV)] uv: vec2[f32],
[builtin(position)] position: vec4[f32]
}
[entry(vert)]
fn main(input: VertIn) -> VertOut
{
let output: VertOut;
output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4<f32>(input.pos, 1.0);
output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4[f32](input.pos, 1.0);
const if (HasUV)
output.uv = input.uv;

View File

@ -0,0 +1,346 @@
// Basic material options
option HasDiffuseTexture: bool = false;
option HasAlphaTexture: bool = false;
option AlphaTest: bool = false;
// Phong material options
option HasEmissiveTexture: bool = false;
option HasHeightTexture: bool = false;
option HasNormalTexture: bool = false;
option HasSpecularTexture: bool = false;
option MaxLightCount: u32 = u32(3); //< FIXME: Fix integral value types
// Billboard related options
option Billboard: bool = false;
option BillboardCenterLocation: i32 = -1;
option BillboardColorLocation: i32 = -1;
option BillboardSizeRotLocation: i32 = -1;
// Vertex declaration related options
option ColorLocation: i32 = -1;
option NormalLocation: i32 = -1;
option PosLocation: i32 = -1;
option TangentLocation: i32 = -1;
option UvLocation: i32 = -1;
const HasNormal = (NormalLocation >= 0);
const HasVertexColor = (ColorLocation >= 0);
const HasColor = (HasVertexColor || Billboard);
const HasTangent = (TangentLocation >= 0);
const HasUV = (UvLocation >= 0);
const HasNormalMapping = HasNormalTexture && HasNormal && HasTangent;
[layout(std140)]
struct MaterialSettings
{
// BasicSettings
AlphaThreshold: f32,
DiffuseColor: vec4[f32],
// PhongSettings
AmbientColor: vec3[f32],
SpecularColor: vec3[f32],
Shininess: f32,
}
[layout(std140)]
struct InstanceData
{
worldMatrix: mat4[f32],
invWorldMatrix: mat4[f32]
}
// TODO: Add enums
const DirectionalLight = 0;
const PointLight = 1;
const SpotLight = 2;
[layout(std140)]
struct Light
{
type: i32,
color: vec4[f32],
factor: vec2[f32],
parameter1: vec4[f32],
parameter2: vec4[f32],
parameter3: vec4[f32],
hasShadowMapping: u32
}
[layout(std140)]
struct LightData
{
lights: array[Light, MaxLightCount],
lightCount: u32,
}
[layout(std140)]
struct ViewerData
{
projectionMatrix: mat4[f32],
invProjectionMatrix: mat4[f32],
viewMatrix: mat4[f32],
invViewMatrix: mat4[f32],
viewProjMatrix: mat4[f32],
invViewProjMatrix: mat4[f32],
renderTargetSize: vec2[f32],
invRenderTargetSize: vec2[f32],
eyePosition: vec3[f32]
}
external
{
[binding(0)] settings: uniform[MaterialSettings],
[binding(1)] MaterialDiffuseMap: sampler2D[f32],
[binding(2)] MaterialAlphaMap: sampler2D[f32],
[binding(3)] TextureOverlay: sampler2D[f32],
[binding(4)] instanceData: uniform[InstanceData],
[binding(5)] viewerData: uniform[ViewerData],
[binding(6)] lightData: uniform[LightData],
[binding(7)] MaterialEmissiveMap: sampler2D[f32],
[binding(8)] MaterialHeightMap: sampler2D[f32],
[binding(9)] MaterialNormalMap: sampler2D[f32],
[binding(10)] MaterialSpecularMap: sampler2D[f32],
}
struct VertToFrag
{
[location(0)] worldPos: vec3[f32],
[location(1), cond(HasUV)] uv: vec2[f32],
[location(2), cond(HasColor)] color: vec4[f32],
[location(3), cond(HasNormal)] normal: vec3[f32],
[location(4), cond(HasNormalMapping)] tbnMatrix: mat3[f32],
[builtin(position)] position: vec4[f32],
}
// Fragment stage
struct FragOut
{
[location(0)] RenderTarget0: vec4[f32]
}
[entry(frag)]
fn main(input: VertToFrag) -> FragOut
{
let diffuseColor = settings.DiffuseColor;
const if (HasUV)
diffuseColor *= TextureOverlay.Sample(input.uv);
const if (HasColor)
diffuseColor *= input.color;
const if (HasDiffuseTexture)
diffuseColor *= MaterialDiffuseMap.Sample(input.uv);
const if (HasAlphaTexture)
diffuseColor.w *= MaterialAlphaMap.Sample(input.uv).x;
const if (AlphaTest)
{
if (diffuseColor.w < settings.AlphaThreshold)
discard;
}
const if (HasNormal)
{
let lightAmbient = vec3[f32](0.0, 0.0, 0.0);
let lightDiffuse = vec3[f32](0.0, 0.0, 0.0);
let lightSpecular = vec3[f32](0.0, 0.0, 0.0);
let eyeVec = normalize(viewerData.eyePosition - input.worldPos);
let normal: vec3[f32];
const if (HasNormalMapping)
normal = normalize(input.tbnMatrix * (MaterialNormalMap.Sample(input.uv).xyz * 2.0 - vec3[f32](1.0, 1.0, 1.0)));
else
normal = normalize(input.normal);
for i in 0 -> lightData.lightCount
{
let light = lightData.lights[i];
let lightAmbientFactor = light.factor.x;
let lightDiffuseFactor = light.factor.y;
// TODO: Add switch instruction
if (light.type == DirectionalLight)
{
let lightDir = light.parameter1.xyz;
lightAmbient += light.color.rgb * lightAmbientFactor * settings.AmbientColor;
let lambert = max(dot(normal, -lightDir), 0.0);
lightDiffuse += lambert * light.color.rgb * lightDiffuseFactor;
let reflection = reflect(lightDir, normal);
let specFactor = max(dot(reflection, eyeVec), 0.0);
specFactor = pow(specFactor, settings.Shininess);
lightSpecular += specFactor * light.color.rgb;
}
else if (light.type == PointLight)
{
let lightPos = light.parameter1.xyz;
let lightInvRadius = light.parameter1.w;
let lightToPos = input.worldPos - lightPos;
let dist = length(lightToPos);
let lightToPosNorm = lightToPos / max(dist, 0.0001);
let attenuationFactor = max(1.0 - dist * lightInvRadius, 0.0);
lightAmbient += attenuationFactor * light.color.rgb * lightAmbientFactor * settings.AmbientColor;
let lambert = max(dot(normal, -lightToPosNorm), 0.0);
lightDiffuse += attenuationFactor * lambert * light.color.rgb * lightDiffuseFactor;
let reflection = reflect(lightToPosNorm, normal);
let specFactor = max(dot(reflection, eyeVec), 0.0);
specFactor = pow(specFactor, settings.Shininess);
lightSpecular += attenuationFactor * specFactor * light.color.rgb;
}
else if (light.type == SpotLight)
{
let lightPos = light.parameter1.xyz;
let lightDir = light.parameter2.xyz;
let lightInvRadius = light.parameter1.w;
let lightInnerAngle = light.parameter3.x;
let lightOuterAngle = light.parameter3.y;
let lightToPos = input.worldPos - lightPos;
let dist = length(lightToPos);
let lightToPosNorm = lightToPos / max(dist, 0.0001);
let curAngle = dot(lightDir, lightToPosNorm);
let innerMinusOuterAngle = lightInnerAngle - lightOuterAngle;
let attenuationFactor = max(1.0 - dist * lightInvRadius, 0.0);
attenuationFactor *= max((curAngle - lightOuterAngle) / innerMinusOuterAngle, 0.0);
lightAmbient += attenuationFactor * light.color.rgb * lightAmbientFactor * settings.AmbientColor;
let lambert = max(dot(normal, -lightToPosNorm), 0.0);
lightDiffuse += attenuationFactor * lambert * light.color.rgb * lightDiffuseFactor;
let reflection = reflect(lightToPosNorm, normal);
let specFactor = max(dot(reflection, eyeVec), 0.0);
specFactor = pow(specFactor, settings.Shininess);
lightSpecular += attenuationFactor * specFactor * light.color.rgb;
}
}
lightSpecular *= settings.SpecularColor;
const if (HasSpecularTexture)
lightSpecular *= MaterialSpecularMap.Sample(input.uv).rgb;
let lightColor = lightAmbient + lightDiffuse + lightSpecular;
let output: FragOut;
output.RenderTarget0 = vec4[f32](lightColor, 1.0) * diffuseColor;
return output;
}
else
{
let output: FragOut;
output.RenderTarget0 = diffuseColor;
return output;
}
}
// Vertex stage
struct VertIn
{
[location(PosLocation)]
pos: vec3[f32],
[cond(HasVertexColor), location(ColorLocation)]
color: vec4[f32],
[cond(HasUV), location(UvLocation)]
uv: vec2[f32],
[cond(HasNormal), location(NormalLocation)]
normal: vec3[f32],
[cond(HasTangent), location(TangentLocation)]
tangent: vec3[f32],
[cond(Billboard), location(BillboardCenterLocation)]
billboardCenter: vec3[f32],
[cond(Billboard), location(BillboardSizeRotLocation)]
billboardSizeRot: vec4[f32], //< width,height,sin,cos
[cond(Billboard), location(BillboardColorLocation)]
billboardColor: vec4[f32]
}
[entry(vert), cond(Billboard)]
fn billboardMain(input: VertIn) -> VertOut
{
let size = input.billboardSizeRot.xy;
let sinCos = input.billboardSizeRot.zw;
let rotatedPosition = vec2[f32](
input.pos.x * sinCos.y - input.pos.y * sinCos.x,
input.pos.y * sinCos.y + input.pos.x * sinCos.x
);
rotatedPosition *= size;
let cameraRight = vec3[f32](viewerData.viewMatrix[0][0], viewerData.viewMatrix[1][0], viewerData.viewMatrix[2][0]);
let cameraUp = vec3[f32](viewerData.viewMatrix[0][1], viewerData.viewMatrix[1][1], viewerData.viewMatrix[2][1]);
let vertexPos = input.billboardCenter;
vertexPos += cameraRight * rotatedPosition.x;
vertexPos += cameraUp * rotatedPosition.y;
let output: VertToFrag;
output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4[f32](vertexPos, 1.0);
const if (HasColor)
output.color = input.billboardColor;
const if (HasUV)
output.uv = input.pos.xy + vec2[f32](0.5, 0.5);
return output;
}
[entry(vert), cond(!Billboard)]
fn main(input: VertIn) -> VertToFrag
{
let worldPosition = instanceData.worldMatrix * vec4[f32](input.pos, 1.0);
let output: VertToFrag;
output.worldPos = worldPosition.xyz;
output.position = viewerData.viewProjMatrix * worldPosition;
let rotationMatrix = mat3[f32](instanceData.worldMatrix);
const if (HasColor)
output.color = input.color;
const if (HasNormal)
output.normal = rotationMatrix * input.normal;
const if (HasUV)
output.uv = input.uv;
const if (HasNormalMapping)
{
let binormal = cross(input.normal, input.tangent);
output.tbnMatrix[0] = normalize(rotationMatrix * input.tangent);
output.tbnMatrix[1] = normalize(rotationMatrix * binormal);
output.tbnMatrix[2] = normalize(rotationMatrix * input.normal);
}
return output;
}

View File

@ -0,0 +1,39 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Graphics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Graphics/SpotLight.hpp>
#include <Nazara/Graphics/Enums.hpp>
#include <Nazara/Graphics/PredefinedShaderStructs.hpp>
#include <Nazara/Math/Vector2.hpp>
#include <Nazara/Math/Vector3.hpp>
#include <Nazara/Math/Vector4.hpp>
#include <Nazara/Graphics/Debug.hpp>
namespace Nz
{
float SpotLight::ComputeContributionScore(const BoundingVolumef& boundingVolume) const
{
// TODO: take luminosity/radius/direction into account
return Vector3f::SquaredDistance(m_position, boundingVolume.aabb.GetCenter());
}
void SpotLight::FillLightData(void* data)
{
auto lightOffset = PredefinedLightData::GetOffsets();
AccessByOffset<UInt32&>(data, lightOffset.lightMemberOffsets.type) = UnderlyingCast(BasicLightType::Spot);
AccessByOffset<Vector4f&>(data, lightOffset.lightMemberOffsets.color) = Vector4f(m_color.r / 255.f, m_color.g / 255.f, m_color.b / 255.f, m_color.a / 255.f);
AccessByOffset<Vector2f&>(data, lightOffset.lightMemberOffsets.factor) = Vector2f(m_ambientFactor, m_diffuseFactor);
AccessByOffset<Vector4f&>(data, lightOffset.lightMemberOffsets.parameter1) = Vector4f(m_position.x, m_position.y, m_position.z, m_invRadius);
AccessByOffset<Vector4f&>(data, lightOffset.lightMemberOffsets.parameter2) = Vector4f(m_direction.x, m_direction.y, m_direction.z, 0.f);
AccessByOffset<Vector4f&>(data, lightOffset.lightMemberOffsets.parameter3) = Vector4f(m_innerAngleCos, m_outerAngleCos, 0.f, 0.f);
AccessByOffset<UInt8&>(data, lightOffset.lightMemberOffsets.shadowMappingFlag) = 0;
}
void SpotLight::UpdateTransform(const Vector3f& position, const Quaternionf& rotation, const Vector3f& /*scale*/)
{
UpdatePosition(position);
UpdateRotation(rotation);
}
}

View File

@ -9,6 +9,7 @@
#include <Nazara/Renderer/CommandBufferBuilder.hpp>
#include <Nazara/Renderer/RenderFrame.hpp>
#include <Nazara/Renderer/UploadPool.hpp>
#include <iostream>
#include <utility>
#include <Nazara/Graphics/Debug.hpp>
@ -49,7 +50,7 @@ namespace Nz
return std::make_unique<SpriteChainRendererData>();
}
void SpriteChainRenderer::Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& currentFrame, const Pointer<const RenderElement>* elements, std::size_t elementCount)
void SpriteChainRenderer::Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& currentFrame, std::size_t elementCount, const Pointer<const RenderElement>* elements, const RenderStates* renderStates)
{
Graphics* graphics = Graphics::Instance();
@ -57,103 +58,65 @@ namespace Nz
Recti invalidScissorBox(-1, -1, -1, -1);
std::size_t firstQuadIndex = 0;
SpriteChainRendererData::DrawCall* currentDrawCall = nullptr;
UploadPool::Allocation* currentAllocation = nullptr;
UInt8* currentAllocationMemPtr = nullptr;
const VertexDeclaration* currentVertexDeclaration = nullptr;
RenderBuffer* currentVertexBuffer = nullptr;
const MaterialPass* currentMaterialPass = nullptr;
const RenderPipeline* currentPipeline = nullptr;
const ShaderBinding* currentShaderBinding = nullptr;
const Texture* currentTextureOverlay = nullptr;
const WorldInstance* currentWorldInstance = nullptr;
Recti currentScissorBox = invalidScissorBox;
auto FlushDrawCall = [&]()
{
currentDrawCall = nullptr;
};
auto FlushDrawData = [&]()
{
FlushDrawCall();
currentShaderBinding = nullptr;
};
auto Flush = [&]()
{
// changing vertex buffer always mean we have to switch draw calls
FlushDrawCall();
if (currentAllocation)
{
std::size_t size = currentAllocationMemPtr - static_cast<UInt8*>(currentAllocation->mappedPtr);
m_pendingCopies.emplace_back(BufferCopy{
currentVertexBuffer,
currentAllocation,
size
});
firstQuadIndex = 0;
currentAllocation = nullptr;
currentVertexBuffer = nullptr;
}
};
const auto& defaultSampler = graphics->GetSamplerCache().Get({});
std::size_t oldDrawCallCount = data.drawCalls.size();
const auto& defaultSampler = graphics->GetSamplerCache().Get({});
for (std::size_t i = 0; i < elementCount; ++i)
{
assert(elements[i]->GetElementType() == UnderlyingCast(BasicRenderElement::SpriteChain));
const RenderSpriteChain& spriteChain = static_cast<const RenderSpriteChain&>(*elements[i]);
const RenderStates& renderState = renderStates[i];
const VertexDeclaration* vertexDeclaration = spriteChain.GetVertexDeclaration();
std::size_t stride = vertexDeclaration->GetStride();
if (currentVertexDeclaration != vertexDeclaration)
if (m_pendingData.currentVertexDeclaration != vertexDeclaration)
{
// TODO: It's be possible to use another vertex declaration with the same vertex buffer but currently very complicated
// Wait until buffer rewrite
Flush();
currentVertexDeclaration = vertexDeclaration;
m_pendingData.currentVertexDeclaration = vertexDeclaration;
}
if (const RenderPipeline* pipeline = &spriteChain.GetRenderPipeline(); currentPipeline != pipeline)
if (const RenderPipeline* pipeline = &spriteChain.GetRenderPipeline(); m_pendingData.currentPipeline != pipeline)
{
FlushDrawCall();
currentPipeline = pipeline;
m_pendingData.currentPipeline = pipeline;
}
if (const MaterialPass* materialPass = &spriteChain.GetMaterialPass(); currentMaterialPass != materialPass)
if (const MaterialPass* materialPass = &spriteChain.GetMaterialPass(); m_pendingData.currentMaterialPass != materialPass)
{
FlushDrawData();
currentMaterialPass = materialPass;
m_pendingData.currentMaterialPass = materialPass;
}
if (const WorldInstance* worldInstance = &spriteChain.GetWorldInstance(); currentWorldInstance != worldInstance)
if (const WorldInstance* worldInstance = &spriteChain.GetWorldInstance(); m_pendingData.currentWorldInstance != worldInstance)
{
// TODO: Flushing draw calls on instance binding means we can have e.g. 1000 sprites rendered using a draw call for each one
// which is far from being efficient, using some bindless could help (or at least instancing?)
FlushDrawData();
currentWorldInstance = worldInstance;
m_pendingData.currentWorldInstance = worldInstance;
}
if (const Texture* textureOverlay = spriteChain.GetTextureOverlay(); currentTextureOverlay != textureOverlay)
if (const Texture* textureOverlay = spriteChain.GetTextureOverlay(); m_pendingData.currentTextureOverlay != textureOverlay)
{
FlushDrawData();
currentTextureOverlay = textureOverlay;
m_pendingData.currentTextureOverlay = textureOverlay;
}
if (m_pendingData.currentLightData != renderState.lightData)
{
FlushDrawData();
m_pendingData.currentLightData = renderState.lightData;
}
const Recti& scissorBox = spriteChain.GetScissorBox();
const Recti& targetScissorBox = (scissorBox.width >= 0) ? scissorBox : invalidScissorBox;
if (currentScissorBox != targetScissorBox)
if (m_pendingData.currentScissorBox != targetScissorBox)
{
FlushDrawData();
currentScissorBox = targetScissorBox;
FlushDrawCall();
m_pendingData.currentScissorBox = targetScissorBox;
}
std::size_t remainingQuads = spriteChain.GetSpriteCount();
@ -161,10 +124,10 @@ namespace Nz
while (remainingQuads > 0)
{
if (!currentAllocation)
if (!m_pendingData.currentAllocation)
{
currentAllocation = &currentFrame.GetUploadPool().Allocate(m_maxVertexBufferSize);
currentAllocationMemPtr = static_cast<UInt8*>(currentAllocation->mappedPtr);
m_pendingData.currentAllocation = &currentFrame.GetUploadPool().Allocate(m_maxVertexBufferSize);
m_pendingData.currentAllocationMemPtr = static_cast<UInt8*>(m_pendingData.currentAllocation->mappedPtr);
std::shared_ptr<RenderBuffer> vertexBuffer;
@ -177,12 +140,12 @@ namespace Nz
else
vertexBuffer = m_device.InstantiateBuffer(BufferType::Vertex, m_maxVertexBufferSize, BufferUsage::DeviceLocal | BufferUsage::Dynamic | BufferUsage::Write);
currentVertexBuffer = vertexBuffer.get();
m_pendingData.currentVertexBuffer = vertexBuffer.get();
data.vertexBuffers.emplace_back(std::move(vertexBuffer));
}
if (!currentShaderBinding)
if (!m_pendingData.currentShaderBinding)
{
m_bindingCache.clear();
@ -193,7 +156,7 @@ namespace Nz
const auto& matSettings = materialPass.GetSettings();
if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::InstanceDataUbo); bindingIndex != MaterialSettings::InvalidIndex)
{
const auto& instanceBuffer = currentWorldInstance->GetInstanceBuffer();
const auto& instanceBuffer = m_pendingData.currentWorldInstance->GetInstanceBuffer();
auto& bindingEntry = m_bindingCache.emplace_back();
bindingEntry.bindingIndex = bindingIndex;
@ -203,6 +166,16 @@ namespace Nz
};
}
if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::LightDataUbo); bindingIndex != MaterialSettings::InvalidIndex && m_pendingData.currentLightData)
{
auto& bindingEntry = m_bindingCache.emplace_back();
bindingEntry.bindingIndex = bindingIndex;
bindingEntry.content = ShaderBinding::UniformBufferBinding{
m_pendingData.currentLightData.GetBuffer(),
m_pendingData.currentLightData.GetOffset(), m_pendingData.currentLightData.GetSize()
};
}
if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::ViewerDataUbo); bindingIndex != MaterialSettings::InvalidIndex)
{
const auto& viewerBuffer = viewerInstance.GetViewerBuffer();
@ -220,33 +193,33 @@ namespace Nz
auto& bindingEntry = m_bindingCache.emplace_back();
bindingEntry.bindingIndex = bindingIndex;
bindingEntry.content = ShaderBinding::TextureBinding{
currentTextureOverlay, defaultSampler.get()
m_pendingData.currentTextureOverlay, defaultSampler.get()
};
}
ShaderBindingPtr drawDataBinding = currentPipeline->GetPipelineInfo().pipelineLayout->AllocateShaderBinding(0);
ShaderBindingPtr drawDataBinding = m_pendingData.currentPipeline->GetPipelineInfo().pipelineLayout->AllocateShaderBinding(0);
drawDataBinding->Update(m_bindingCache.data(), m_bindingCache.size());
currentShaderBinding = drawDataBinding.get();
m_pendingData.currentShaderBinding = drawDataBinding.get();
data.shaderBindings.emplace_back(std::move(drawDataBinding));
}
if (!currentDrawCall)
if (!m_pendingData.currentDrawCall)
{
data.drawCalls.push_back(SpriteChainRendererData::DrawCall{
currentVertexBuffer,
currentPipeline,
currentShaderBinding,
6 * firstQuadIndex,
m_pendingData.currentVertexBuffer,
m_pendingData.currentPipeline,
m_pendingData.currentShaderBinding,
6 * m_pendingData.firstQuadIndex,
0,
currentScissorBox
m_pendingData.currentScissorBox
});
currentDrawCall = &data.drawCalls.back();
m_pendingData.currentDrawCall = &data.drawCalls.back();
}
std::size_t remainingSpace = m_maxVertexBufferSize - (currentAllocationMemPtr - static_cast<UInt8*>(currentAllocation->mappedPtr));
std::size_t remainingSpace = m_maxVertexBufferSize - (m_pendingData.currentAllocationMemPtr - static_cast<UInt8*>(m_pendingData.currentAllocation->mappedPtr));
std::size_t maxQuads = remainingSpace / (4 * stride);
if (maxQuads == 0)
{
@ -257,12 +230,12 @@ namespace Nz
std::size_t copiedQuadCount = std::min(maxQuads, remainingQuads);
std::size_t copiedSize = 4 * copiedQuadCount * stride;
std::memcpy(currentAllocationMemPtr, spriteData, copiedSize);
currentAllocationMemPtr += copiedSize;
std::memcpy(m_pendingData.currentAllocationMemPtr, spriteData, copiedSize);
m_pendingData.currentAllocationMemPtr += copiedSize;
spriteData += copiedSize;
firstQuadIndex += copiedQuadCount;
currentDrawCall->quadCount += copiedQuadCount;
m_pendingData.firstQuadIndex += copiedQuadCount;
m_pendingData.currentDrawCall->quadCount += copiedQuadCount;
remainingQuads -= copiedQuadCount;
// If there's still data to copy, it means buffer is full, flush it
@ -271,12 +244,16 @@ namespace Nz
}
}
//TODO: Add Finish()/PrepareEnd() call to allow to reuse buffers/draw calls for multiple Prepare calls
Flush();
FlushDrawCall();
const RenderSpriteChain* firstSpriteChain = static_cast<const RenderSpriteChain*>(elements[0]);
std::size_t drawCallCount = data.drawCalls.size() - oldDrawCallCount;
data.drawCallPerElement[firstSpriteChain] = SpriteChainRendererData::DrawCallIndices{ oldDrawCallCount, drawCallCount };
}
void SpriteChainRenderer::PrepareEnd(RenderFrame& currentFrame, ElementRendererData& /*rendererData*/)
{
Flush();
if (!m_pendingCopies.empty())
{
@ -290,9 +267,11 @@ namespace Nz
m_pendingCopies.clear();
}
m_pendingData = PendingData{};
}
void SpriteChainRenderer::Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, const Pointer<const RenderElement>* elements, std::size_t /*elementCount*/)
void SpriteChainRenderer::Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, std::size_t /*elementCount*/, const Pointer<const RenderElement>* elements)
{
auto& data = static_cast<SpriteChainRendererData&>(rendererData);
@ -364,4 +343,37 @@ namespace Nz
data.drawCalls.clear();
}
void SpriteChainRenderer::Flush()
{
// changing vertex buffer always mean we have to switch draw calls
FlushDrawCall();
if (m_pendingData.currentAllocation)
{
std::size_t size = m_pendingData.currentAllocationMemPtr - static_cast<UInt8*>(m_pendingData.currentAllocation->mappedPtr);
m_pendingCopies.emplace_back(BufferCopy{
m_pendingData.currentVertexBuffer,
m_pendingData.currentAllocation,
size
});
m_pendingData.firstQuadIndex = 0;
m_pendingData.currentAllocation = nullptr;
m_pendingData.currentVertexBuffer = nullptr;
}
}
void SpriteChainRenderer::FlushDrawCall()
{
m_pendingData.currentDrawCall = nullptr;
}
void SpriteChainRenderer::FlushDrawData()
{
FlushDrawCall();
m_pendingData.currentShaderBinding = nullptr;
}
}

View File

@ -12,16 +12,12 @@
namespace Nz
{
SubmeshRenderer::SubmeshRenderer()
{
}
std::unique_ptr<ElementRendererData> SubmeshRenderer::InstanciateData()
{
return std::make_unique<SubmeshRendererData>();
}
void SubmeshRenderer::Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& /*currentFrame*/, const Pointer<const RenderElement>* elements, std::size_t elementCount)
void SubmeshRenderer::Prepare(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, RenderFrame& /*currentFrame*/, std::size_t elementCount, const Pointer<const RenderElement>* elements, const RenderStates* renderStates)
{
Graphics* graphics = Graphics::Instance();
@ -36,6 +32,7 @@ namespace Nz
const ShaderBinding* currentShaderBinding = nullptr;
const WorldInstance* currentWorldInstance = nullptr;
Recti currentScissorBox = invalidScissorBox;
RenderBufferView currentLightData;
auto FlushDrawCall = [&]()
{
@ -52,10 +49,13 @@ namespace Nz
const auto& whiteTexture = Graphics::Instance()->GetDefaultTextures().whiteTextures[UnderlyingCast(ImageType::E2D)];
const auto& defaultSampler = graphics->GetSamplerCache().Get({});
std::size_t oldDrawCallCount = data.drawCalls.size();
for (std::size_t i = 0; i < elementCount; ++i)
{
assert(elements[i]->GetElementType() == UnderlyingCast(BasicRenderElement::Submesh));
const RenderSubmesh& submesh = static_cast<const RenderSubmesh&>(*elements[i]);
const RenderStates& renderState = renderStates[i];
if (const RenderPipeline* pipeline = submesh.GetRenderPipeline(); currentPipeline != pipeline)
{
@ -89,6 +89,12 @@ namespace Nz
currentWorldInstance = worldInstance;
}
if (currentLightData != renderState.lightData)
{
FlushDrawData();
currentLightData = renderState.lightData;
}
const Recti& scissorBox = submesh.GetScissorBox();
const Recti& targetScissorBox = (scissorBox.width >= 0) ? scissorBox : invalidScissorBox;
if (currentScissorBox != targetScissorBox)
@ -118,6 +124,16 @@ namespace Nz
};
}
if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::LightDataUbo); bindingIndex != MaterialSettings::InvalidIndex && currentLightData)
{
auto& bindingEntry = m_bindingCache.emplace_back();
bindingEntry.bindingIndex = bindingIndex;
bindingEntry.content = ShaderBinding::UniformBufferBinding{
currentLightData.GetBuffer(),
currentLightData.GetOffset(), currentLightData.GetSize()
};
}
if (std::size_t bindingIndex = matSettings->GetPredefinedBinding(PredefinedShaderBinding::ViewerDataUbo); bindingIndex != MaterialSettings::InvalidIndex)
{
const auto& viewerBuffer = viewerInstance.GetViewerBuffer();
@ -148,6 +164,7 @@ namespace Nz
}
auto& drawCall = data.drawCalls.emplace_back();
drawCall.firstIndex = 0;
drawCall.indexBuffer = currentIndexBuffer;
drawCall.indexCount = submesh.GetIndexCount();
drawCall.renderPipeline = currentPipeline;
@ -155,9 +172,13 @@ namespace Nz
drawCall.shaderBinding = currentShaderBinding;
drawCall.vertexBuffer = currentVertexBuffer;
}
const RenderSubmesh* firstSubmesh = static_cast<const RenderSubmesh*>(elements[0]);
std::size_t drawCallCount = data.drawCalls.size() - oldDrawCallCount;
data.drawCallPerElement[firstSubmesh] = SubmeshRendererData::DrawCallIndices{ oldDrawCallCount, drawCallCount };
}
void SubmeshRenderer::Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, const Pointer<const RenderElement>* /*elements*/, std::size_t /*elementCount*/)
void SubmeshRenderer::Render(const ViewerInstance& viewerInstance, ElementRendererData& rendererData, CommandBufferBuilder& commandBuffer, std::size_t /*elementCount*/, const Pointer<const RenderElement>* elements)
{
auto& data = static_cast<SubmeshRendererData&>(rendererData);
@ -170,8 +191,16 @@ namespace Nz
const ShaderBinding* currentShaderBinding = nullptr;
Recti currentScissorBox(-1, -1, -1, -1);
for (const auto& drawData : data.drawCalls)
const RenderSubmesh* firstSubmesh = static_cast<const RenderSubmesh*>(elements[0]);
auto it = data.drawCallPerElement.find(firstSubmesh);
assert(it != data.drawCallPerElement.end());
const auto& indices = it->second;
for (std::size_t i = 0; i < indices.count; ++i)
{
const auto& drawData = data.drawCalls[indices.start + i];
if (currentPipeline != drawData.renderPipeline)
{
commandBuffer.BindPipeline(*drawData.renderPipeline);
@ -204,9 +233,9 @@ namespace Nz
}
if (currentIndexBuffer)
commandBuffer.DrawIndexed(SafeCast<UInt32>(drawData.indexCount));
commandBuffer.DrawIndexed(SafeCast<UInt32>(drawData.indexCount), 1U, SafeCast<UInt32>(drawData.firstIndex));
else
commandBuffer.Draw(SafeCast<UInt32>(drawData.indexCount));
commandBuffer.Draw(SafeCast<UInt32>(drawData.indexCount), 1U, SafeCast<UInt32>(drawData.firstIndex));
}
}

View File

@ -18,10 +18,12 @@ namespace Nz
{
RenderSystem::RenderSystem(entt::registry& registry) :
m_cameraConstructObserver(registry, entt::collector.group<CameraComponent, NodeComponent>()),
m_graphicsConstructObserver(registry, entt::collector.group<GraphicsComponent, NodeComponent>())
m_graphicsConstructObserver(registry, entt::collector.group<GraphicsComponent, NodeComponent>()),
m_lightConstructObserver(registry, entt::collector.group<LightComponent, NodeComponent>())
{
m_cameraDestroyConnection = registry.on_destroy<CameraComponent>().connect<&RenderSystem::OnCameraDestroy>(this);
m_graphicsDestroyConnection = registry.on_destroy<GraphicsComponent>().connect<&RenderSystem::OnGraphicsDestroy>(this);
m_lightDestroyConnection = registry.on_destroy<LightComponent>().connect<&RenderSystem::OnLightDestroy>(this);
m_nodeDestroyConnection = registry.on_destroy<NodeComponent>().connect<&RenderSystem::OnNodeDestroy>(this);
m_pipeline = std::make_unique<ForwardFramePipeline>();
@ -31,8 +33,10 @@ namespace Nz
{
m_cameraConstructObserver.disconnect();
m_graphicsConstructObserver.disconnect();
m_lightConstructObserver.disconnect();
m_cameraDestroyConnection.release();
m_graphicsDestroyConnection.release();
m_lightDestroyConnection.release();
m_nodeDestroyConnection.release();
}
@ -67,13 +71,13 @@ namespace Nz
m_pipeline->RegisterInstancedDrawable(worldInstance, renderableEntry.renderable.get(), renderableEntry.renderMask);
}
m_invalidatedWorldNode.insert(entity);
m_invalidatedGfxWorldNode.insert(entity);
assert(m_graphicsEntities.find(entity) == m_graphicsEntities.end());
auto& graphicsEntity = m_graphicsEntities[entity];
graphicsEntity.onNodeInvalidation.Connect(entityNode.OnNodeInvalidation, [this, entity](const Node* /*node*/)
{
m_invalidatedWorldNode.insert(entity);
m_invalidatedGfxWorldNode.insert(entity);
});
graphicsEntity.onRenderableAttached.Connect(entityGfx.OnRenderableAttached, [this](GraphicsComponent* gfx, const GraphicsComponent::Renderable& renderableEntry)
@ -98,13 +102,64 @@ namespace Nz
{
if (isVisible)
{
m_newlyHiddenEntities.erase(entity);
m_newlyVisibleEntities.insert(entity);
m_newlyHiddenGfxEntities.erase(entity);
m_newlyVisibleGfxEntities.insert(entity);
}
else
{
m_newlyHiddenEntities.insert(entity);
m_newlyVisibleEntities.erase(entity);
m_newlyHiddenGfxEntities.insert(entity);
m_newlyVisibleGfxEntities.erase(entity);
}
});
});
m_lightConstructObserver.each([&](entt::entity entity)
{
LightComponent& entityLight = registry.get<LightComponent>(entity);
NodeComponent& entityNode = registry.get<NodeComponent>(entity);
if (entityLight.IsVisible())
{
for (const auto& lightEntry : entityLight.GetLights())
m_pipeline->RegisterLight(lightEntry.light, lightEntry.renderMask);
}
m_invalidatedLightWorldNode.insert(entity);
assert(m_lightEntities.find(entity) == m_lightEntities.end());
auto& lightEntity = m_lightEntities[entity];
lightEntity.onNodeInvalidation.Connect(entityNode.OnNodeInvalidation, [this, entity](const Node* /*node*/)
{
m_invalidatedLightWorldNode.insert(entity);
});
lightEntity.onLightAttached.Connect(entityLight.OnLightAttached, [this](LightComponent* light, const LightComponent::LightEntry& lightEntry)
{
if (!light->IsVisible())
return;
m_pipeline->RegisterLight(lightEntry.light, lightEntry.renderMask);
});
lightEntity.onLightDetach.Connect(entityLight.OnLightDetach, [this](LightComponent* light, const LightComponent::LightEntry& lightEntry)
{
if (!light->IsVisible())
return;
m_pipeline->UnregisterLight(lightEntry.light.get());
});
lightEntity.onVisibilityUpdate.Connect(entityLight.OnVisibilityUpdate, [this, entity](LightComponent* /*light*/, bool isVisible)
{
if (isVisible)
{
m_newlyHiddenLightEntities.erase(entity);
m_newlyVisibleLightEntities.insert(entity);
}
else
{
m_newlyHiddenLightEntities.insert(entity);
m_newlyVisibleLightEntities.erase(entity);
}
});
});
@ -127,9 +182,22 @@ namespace Nz
void RenderSystem::OnGraphicsDestroy(entt::registry& registry, entt::entity entity)
{
m_graphicsEntities.erase(entity);
m_invalidatedWorldNode.erase(entity);
m_newlyHiddenEntities.erase(entity);
m_newlyVisibleEntities.erase(entity);
m_invalidatedGfxWorldNode.erase(entity);
m_newlyHiddenGfxEntities.erase(entity);
m_newlyVisibleGfxEntities.erase(entity);
GraphicsComponent& entityGfx = registry.get<GraphicsComponent>(entity);
const WorldInstancePtr& worldInstance = entityGfx.GetWorldInstance();
for (const auto& renderableEntry : entityGfx.GetRenderables())
m_pipeline->UnregisterInstancedDrawable(worldInstance, renderableEntry.renderable.get());
}
void RenderSystem::OnLightDestroy(entt::registry& registry, entt::entity entity)
{
m_lightEntities.erase(entity);
m_invalidatedLightWorldNode.erase(entity);
m_newlyHiddenLightEntities.erase(entity);
m_newlyVisibleLightEntities.erase(entity);
GraphicsComponent& entityGfx = registry.get<GraphicsComponent>(entity);
const WorldInstancePtr& worldInstance = entityGfx.GetWorldInstance();
@ -139,14 +207,19 @@ namespace Nz
void RenderSystem::OnNodeDestroy(entt::registry& registry, entt::entity entity)
{
m_newlyHiddenEntities.erase(entity);
m_newlyVisibleEntities.erase(entity);
m_newlyHiddenGfxEntities.erase(entity);
m_newlyVisibleGfxEntities.erase(entity);
m_newlyHiddenLightEntities.erase(entity);
m_newlyVisibleLightEntities.erase(entity);
if (registry.try_get<CameraComponent>(entity))
OnCameraDestroy(registry, entity);
if (registry.try_get<GraphicsComponent>(entity))
OnGraphicsDestroy(registry, entity);
if (registry.try_get<LightComponent>(entity))
OnLightDestroy(registry, entity);
}
void RenderSystem::UpdateInstances(entt::registry& registry)
@ -156,14 +229,17 @@ namespace Nz
const NodeComponent& entityNode = registry.get<const NodeComponent>(entity);
CameraComponent& entityCamera = registry.get<CameraComponent>(entity);
Vector3f cameraPosition = entityNode.GetPosition(CoordSys::Global);
ViewerInstance& viewerInstance = entityCamera.GetViewerInstance();
viewerInstance.UpdateViewMatrix(Nz::Matrix4f::ViewMatrix(entityNode.GetPosition(CoordSys::Global), entityNode.GetRotation(CoordSys::Global)));
viewerInstance.UpdateEyePosition(cameraPosition);
viewerInstance.UpdateViewMatrix(Nz::Matrix4f::ViewMatrix(cameraPosition, entityNode.GetRotation(CoordSys::Global)));
m_pipeline->InvalidateViewer(&entityCamera);
}
m_invalidatedCameraNode.clear();
for (entt::entity entity : m_invalidatedWorldNode)
for (entt::entity entity : m_invalidatedGfxWorldNode)
{
const NodeComponent& entityNode = registry.get<const NodeComponent>(entity);
GraphicsComponent& entityGraphics = registry.get<GraphicsComponent>(entity);
@ -173,13 +249,27 @@ namespace Nz
m_pipeline->InvalidateWorldInstance(worldInstance.get());
}
m_invalidatedWorldNode.clear();
m_invalidatedGfxWorldNode.clear();
for (entt::entity entity : m_invalidatedLightWorldNode)
{
const NodeComponent& entityNode = registry.get<const NodeComponent>(entity);
LightComponent& entityLight = registry.get<LightComponent>(entity);
const Vector3f& position = entityNode.GetPosition(CoordSys::Global);
const Quaternionf& rotation = entityNode.GetRotation(CoordSys::Global);
const Vector3f& scale = entityNode.GetScale(CoordSys::Global);
for (const auto& lightEntry : entityLight.GetLights())
lightEntry.light->UpdateTransform(position, rotation, scale);
}
m_invalidatedLightWorldNode.clear();
}
void RenderSystem::UpdateVisibility(entt::registry& registry)
{
// Unregister drawables for hidden entities
for (entt::entity entity : m_newlyHiddenEntities)
// Unregister drawable for hidden entities
for (entt::entity entity : m_newlyHiddenGfxEntities)
{
GraphicsComponent& entityGfx = registry.get<GraphicsComponent>(entity);
@ -187,10 +277,10 @@ namespace Nz
for (const auto& renderableEntry : entityGfx.GetRenderables())
m_pipeline->UnregisterInstancedDrawable(worldInstance, renderableEntry.renderable.get());
}
m_newlyHiddenEntities.clear();
m_newlyHiddenGfxEntities.clear();
// Register drawables for newly visible entities
for (entt::entity entity : m_newlyVisibleEntities)
// Register drawable for newly visible entities
for (entt::entity entity : m_newlyVisibleGfxEntities)
{
GraphicsComponent& entityGfx = registry.get<GraphicsComponent>(entity);
@ -198,6 +288,6 @@ namespace Nz
for (const auto& renderableEntry : entityGfx.GetRenderables())
m_pipeline->RegisterInstancedDrawable(worldInstance, renderableEntry.renderable.get(), renderableEntry.renderMask);
}
m_newlyVisibleEntities.clear();
m_newlyVisibleGfxEntities.clear();
}
}

View File

@ -20,7 +20,8 @@ namespace Nz
m_projectionMatrix(Matrix4f::Identity()),
m_viewProjMatrix(Matrix4f::Identity()),
m_viewMatrix(Matrix4f::Identity()),
m_targetSize(Vector2f(0.f, 0.f)),
m_targetSize(Vector2f::Zero()),
m_eyePosition(Vector3f::Zero()),
m_dataInvalided(true)
{
PredefinedViewerData viewerUboOffsets = PredefinedViewerData::GetOffsets();
@ -35,7 +36,7 @@ namespace Nz
PredefinedViewerData viewerDataOffsets = PredefinedViewerData::GetOffsets();
auto& allocation = uploadPool.Allocate(viewerDataOffsets.totalSize);
AccessByOffset<Vector3f&>(allocation.mappedPtr, viewerDataOffsets.eyePositionOffset) = m_viewMatrix.GetTranslation();
AccessByOffset<Vector3f&>(allocation.mappedPtr, viewerDataOffsets.eyePositionOffset) = m_eyePosition;
AccessByOffset<Vector2f&>(allocation.mappedPtr, viewerDataOffsets.invTargetSizeOffset) = 1.f / m_targetSize;
AccessByOffset<Vector2f&>(allocation.mappedPtr, viewerDataOffsets.targetSizeOffset) = m_targetSize;

View File

@ -42,7 +42,7 @@ namespace Nz
NazaraAssert(handle != InvalidHandle, "Invalid handle");
IpAddressImpl::SockAddrBuffer nameBuffer;
std::fill(nameBuffer.begin(), nameBuffer.end(), 0);
nameBuffer.fill(0);
int bufferLength = static_cast<int>(nameBuffer.size());

View File

@ -10,6 +10,7 @@
#include <Nazara/Shader/Ast/AstOptimizer.hpp>
#include <Nazara/Shader/Ast/AstRecursiveVisitor.hpp>
#include <Nazara/Shader/Ast/AstUtils.hpp>
#include <numeric>
#include <stdexcept>
#include <unordered_set>
#include <Nazara/Shader/Debug.hpp>
@ -74,7 +75,9 @@ namespace Nz::ShaderAst
RegisterIntrinsic("length", IntrinsicType::Length);
RegisterIntrinsic("max", IntrinsicType::Max);
RegisterIntrinsic("min", IntrinsicType::Min);
RegisterIntrinsic("normalize", IntrinsicType::Normalize);
RegisterIntrinsic("pow", IntrinsicType::Pow);
RegisterIntrinsic("reflect", IntrinsicType::Reflect);
// Collect function name and their types
if (statement.GetType() == NodeType::MultiStatement)
@ -152,7 +155,7 @@ namespace Nz::ShaderAst
ExpressionPtr SanitizeVisitor::Clone(AccessIdentifierExpression& node)
{
if (node.identifiers.empty())
throw AstError{ "accessIdentifierExpression must have at least one identifier" };
throw AstError{ "AccessIdentifierExpression must have at least one identifier" };
ExpressionPtr indexedExpr = CloneExpression(MandatoryExpr(node.expr));
for (const std::string& identifier : node.identifiers)
@ -384,6 +387,88 @@ namespace Nz::ShaderAst
auto clone = static_unique_pointer_cast<CastExpression>(AstCloner::Clone(node));
Validate(*clone);
if (m_context->options.removeMatrixCast && IsMatrixType(clone->targetType))
{
const MatrixType& targetMatrixType = std::get<MatrixType>(clone->targetType);
const ShaderAst::ExpressionType& frontExprType = GetExpressionType(*clone->expressions.front());
bool isMatrixCast = IsMatrixType(frontExprType);
if (isMatrixCast && std::get<MatrixType>(frontExprType) == targetMatrixType)
{
// Nothing to do
return std::move(clone->expressions.front());
}
auto variableDeclaration = ShaderBuilder::DeclareVariable("temp", clone->targetType); //< Validation will prevent name-clash if required
Validate(*variableDeclaration);
std::size_t variableIndex = *variableDeclaration->varIndex;
m_context->currentStatementList->emplace_back(std::move(variableDeclaration));
for (std::size_t i = 0; i < targetMatrixType.columnCount; ++i)
{
// temp[i]
auto columnExpr = ShaderBuilder::AccessIndex(ShaderBuilder::Variable(variableIndex, clone->targetType), ShaderBuilder::Constant(UInt32(i)));
Validate(*columnExpr);
// vector expression
ExpressionPtr vectorExpr;
std::size_t vectorComponentCount;
if (isMatrixCast)
{
// fromMatrix[i]
auto matrixColumnExpr = ShaderBuilder::AccessIndex(CloneExpression(clone->expressions.front()), ShaderBuilder::Constant(UInt32(i)));
Validate(*matrixColumnExpr);
vectorExpr = std::move(matrixColumnExpr);
vectorComponentCount = std::get<MatrixType>(frontExprType).rowCount;
}
else
{
// parameter #i
vectorExpr = std::move(clone->expressions[i]);
vectorComponentCount = std::get<VectorType>(GetExpressionType(*vectorExpr)).componentCount;
}
// cast expression (turn fromMatrix[i] to vec3[f32](fromMatrix[i]))
ExpressionPtr castExpr;
if (vectorComponentCount != targetMatrixType.rowCount)
{
CastExpressionPtr vecCast;
if (vectorComponentCount < targetMatrixType.rowCount)
{
std::array<ExpressionPtr, 4> expressions;
expressions[0] = std::move(vectorExpr);
for (std::size_t j = 0; j < targetMatrixType.rowCount - vectorComponentCount; ++j)
expressions[j + 1] = ShaderBuilder::Constant(targetMatrixType.type, (i == j + vectorComponentCount) ? 1 : 0); //< set 1 to diagonal
vecCast = ShaderBuilder::Cast(VectorType{ targetMatrixType.rowCount, targetMatrixType.type }, std::move(expressions));
Validate(*vecCast);
castExpr = std::move(vecCast);
}
else
{
std::array<UInt32, 4> swizzleComponents;
std::iota(swizzleComponents.begin(), swizzleComponents.begin() + targetMatrixType.rowCount, 0);
auto swizzleExpr = ShaderBuilder::Swizzle(std::move(vectorExpr), swizzleComponents, targetMatrixType.rowCount);
Validate(*swizzleExpr);
castExpr = std::move(swizzleExpr);
}
}
else
castExpr = std::move(vectorExpr);
// temp[i] = castExpr
m_context->currentStatementList->emplace_back(ShaderBuilder::ExpressionStatement(ShaderBuilder::Assign(AssignType::Simple, std::move(columnExpr), std::move(castExpr))));
}
return ShaderBuilder::Variable(variableIndex, clone->targetType);
}
return clone;
}
@ -602,6 +687,9 @@ namespace Nz::ShaderAst
clone->constIndex = RegisterConstant(clone->name, value);
if (m_context->options.removeConstDeclaration)
return ShaderBuilder::NoOp();
return clone;
}
@ -648,7 +736,7 @@ namespace Nz::ShaderAst
else if (IsSamplerType(extVar.type))
varType = extVar.type;
else
throw AstError{ "External variable " + extVar.name + " is of wrong type: only uniform and sampler are allowed in external blocks" };
throw AstError{ "external variable " + extVar.name + " is of wrong type: only uniform and sampler are allowed in external blocks" };
std::size_t varIndex = RegisterVariable(extVar.name, std::move(varType));
if (!clone->varIndex)
@ -815,6 +903,18 @@ namespace Nz::ShaderAst
declaredMembers.insert(member.name);
member.type = ResolveType(member.type);
if (clone->description.layout.HasValue() && clone->description.layout.GetResultingValue() == StructLayout::Std140)
{
if (IsPrimitiveType(member.type) && std::get<PrimitiveType>(member.type) == PrimitiveType::Boolean)
throw AstError{ "boolean type is not allowed in std140 layout" };
else if (IsStructType(member.type))
{
std::size_t structIndex = std::get<StructType>(member.type).structIndex;
const StructDescription* desc = m_context->structs[structIndex];
if (!desc->layout.HasValue() || desc->layout.GetResultingValue() != clone->description.layout.GetResultingValue())
throw AstError{ "inner struct layout mismatch" };
}
}
}
clone->structIndex = RegisterStruct(clone->description.name, &clone->description);
@ -1690,18 +1790,44 @@ namespace Nz::ShaderAst
void SanitizeVisitor::Validate(CastExpression& node)
{
node.cachedExpressionType = node.targetType;
node.targetType = ResolveType(node.targetType);
node.cachedExpressionType = node.targetType;
// Allow casting a matrix to itself (wtf?)
// FIXME: Make proper rules
if (IsMatrixType(node.targetType) && node.expressions.front())
const auto& firstExprPtr = node.expressions.front();
if (!firstExprPtr)
throw AstError{ "expected at least one expression" };
if (IsMatrixType(node.targetType))
{
const ExpressionType& exprType = GetExpressionType(*node.expressions.front());
if (IsMatrixType(exprType) && !node.expressions[1])
const MatrixType& targetMatrixType = std::get<MatrixType>(node.targetType);
const ExpressionType& firstExprType = GetExpressionType(*firstExprPtr);
if (IsMatrixType(firstExprType))
{
if (node.expressions[1])
throw AstError{ "too many expressions" };
// Matrix to matrix cast: always valid
return;
}
else
{
assert(targetMatrixType.columnCount <= 4);
for (std::size_t i = 0; i < targetMatrixType.columnCount; ++i)
{
const auto& exprPtr = node.expressions[i];
if (!exprPtr)
throw AstError{ "component count doesn't match required component count" };
const ExpressionType& exprType = GetExpressionType(*exprPtr);
if (!IsVectorType(exprType))
throw AstError{ "expected vector type" };
const VectorType& vecType = std::get<VectorType>(exprType);
if (vecType.componentCount != targetMatrixType.rowCount)
throw AstError{ "vector component count must match target matrix row count" };
}
}
}
auto GetComponentCount = [](const ExpressionType& exprType) -> std::size_t
@ -1775,6 +1901,7 @@ namespace Nz::ShaderAst
case IntrinsicType::Max:
case IntrinsicType::Min:
case IntrinsicType::Pow:
case IntrinsicType::Reflect:
{
if (node.parameters.size() != 2)
throw AstError { "Expected two parameters" };
@ -1803,6 +1930,7 @@ namespace Nz::ShaderAst
}
case IntrinsicType::Length:
case IntrinsicType::Normalize:
{
if (node.parameters.size() != 1)
throw AstError{ "Expected only one parameters" };
@ -1839,7 +1967,7 @@ namespace Nz::ShaderAst
{
const ExpressionType& type = GetExpressionType(*node.parameters.front());
if (type != ExpressionType{ VectorType{ 3, PrimitiveType::Float32 } })
throw AstError{ "CrossProduct only works with vec3<f32> expressions" };
throw AstError{ "CrossProduct only works with vec3[f32] expressions" };
node.cachedExpressionType = type;
break;
@ -1850,12 +1978,23 @@ namespace Nz::ShaderAst
{
const ExpressionType& type = GetExpressionType(*node.parameters.front());
if (!IsVectorType(type))
throw AstError{ "DotProduct expects vector types" };
throw AstError{ "DotProduct expects vector types" }; //< FIXME
node.cachedExpressionType = std::get<VectorType>(type).type;
break;
}
case IntrinsicType::Normalize:
case IntrinsicType::Reflect:
{
const ExpressionType& type = GetExpressionType(*node.parameters.front());
if (!IsVectorType(type))
throw AstError{ "DotProduct expects vector types" }; //< FIXME
node.cachedExpressionType = type;
break;
}
case IntrinsicType::Max:
case IntrinsicType::Min:
{
@ -1918,9 +2057,9 @@ namespace Nz::ShaderAst
if (node.componentCount > 4)
throw AstError{ "cannot swizzle more than four elements" };
for (UInt32 swizzleIndex : node.components)
for (std::size_t i = 0; i < node.componentCount; ++i)
{
if (swizzleIndex >= componentCount)
if (node.components[i] >= componentCount)
throw AstError{ "invalid swizzle" };
}
@ -1998,17 +2137,18 @@ namespace Nz::ShaderAst
case BinaryType::CompGt:
case BinaryType::CompLe:
case BinaryType::CompLt:
{
if (leftType == PrimitiveType::Boolean)
throw AstError{ "this operation is not supported for booleans" };
[[fallthrough]];
case BinaryType::CompEq:
case BinaryType::CompNe:
{
TypeMustMatch(leftExpr, rightExpr);
return PrimitiveType::Boolean;
}
case BinaryType::Add:
case BinaryType::CompEq:
case BinaryType::CompNe:
case BinaryType::Subtract:
TypeMustMatch(leftExpr, rightExpr);
return leftExprType;

View File

@ -209,6 +209,7 @@ namespace Nz
options.makeVariableNameUnique = true;
options.reduceLoopsToWhile = true;
options.removeCompoundAssignments = false;
options.removeConstDeclaration = true;
options.removeOptionDeclaration = true;
options.removeScalarSwizzling = true;
options.reservedIdentifiers = {
@ -489,7 +490,10 @@ namespace Nz
bool first = true;
for (const ShaderAst::StatementPtr& statement : statements)
{
if (!first && statement->GetType() != ShaderAst::NodeType::NoOpStatement)
if (statement->GetType() == ShaderAst::NodeType::NoOpStatement)
continue;
if (!first)
AppendLine();
statement->Visit(*this);
@ -863,10 +867,18 @@ namespace Nz
Append("min");
break;
case ShaderAst::IntrinsicType::Normalize:
Append("normalize");
break;
case ShaderAst::IntrinsicType::Pow:
Append("pow");
break;
case ShaderAst::IntrinsicType::Reflect:
Append("reflect");
break;
case ShaderAst::IntrinsicType::SampleTexture:
Append("texture");
break;

View File

@ -126,7 +126,7 @@ namespace Nz
void LangWriter::Append(const ShaderAst::ArrayType& type)
{
Append("[", type.containedType->type, "; ");
Append("array[", type.containedType->type, ", ");
if (type.length.IsResultingValue())
Append(type.length.GetResultingValue());
@ -164,7 +164,7 @@ namespace Nz
Append(matrixType.rowCount);
}
Append("<", matrixType.type, ">");
Append("[", matrixType.type, "]");
}
void LangWriter::Append(ShaderAst::PrimitiveType type)
@ -192,7 +192,7 @@ namespace Nz
case ImageType::Cubemap: Append("Cube"); break;
}
Append("<", samplerType.sampledType, ">");
Append("[", samplerType.sampledType, "]");
}
void LangWriter::Append(const ShaderAst::StructType& structType)
@ -203,17 +203,17 @@ namespace Nz
void LangWriter::Append(const ShaderAst::UniformType& uniformType)
{
Append("uniform<");
Append("uniform[");
std::visit([&](auto&& arg)
{
Append(arg);
}, uniformType.containedType);
Append(">");
Append("]");
}
void LangWriter::Append(const ShaderAst::VectorType& vecType)
{
Append("vec", vecType.componentCount, "<", vecType.type, ">");
Append("vec", vecType.componentCount, "[", vecType.type, "]");
}
void LangWriter::Append(ShaderAst::NoType)
@ -732,15 +732,15 @@ namespace Nz
else if constexpr (std::is_same_v<T, float> || std::is_same_v<T, Int32> || std::is_same_v<T, UInt32>)
Append(std::to_string(arg));
else if constexpr (std::is_same_v<T, Vector2f>)
Append("vec2<f32>(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ")");
Append("vec2[f32](" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ")");
else if constexpr (std::is_same_v<T, Vector2i32>)
Append("vec2<i32>(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ")");
else if constexpr (std::is_same_v<T, Vector3f>)
Append("vec3<f32>(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ", " + std::to_string(arg.z) + ")");
Append("vec3[f32](" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ", " + std::to_string(arg.z) + ")");
else if constexpr (std::is_same_v<T, Vector3i32>)
Append("vec3<i32>(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ", " + std::to_string(arg.z) + ")");
else if constexpr (std::is_same_v<T, Vector4f>)
Append("vec4<f32>(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ", " + std::to_string(arg.z) + ", " + std::to_string(arg.w) + ")");
Append("vec4[f32](" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ", " + std::to_string(arg.z) + ", " + std::to_string(arg.w) + ")");
else if constexpr (std::is_same_v<T, Vector4i32>)
Append("vec4<i32>(" + std::to_string(arg.x) + ", " + std::to_string(arg.y) + ", " + std::to_string(arg.z) + ", " + std::to_string(arg.w) + ")");
else
@ -945,10 +945,18 @@ namespace Nz
Append("min");
break;
case ShaderAst::IntrinsicType::Normalize:
Append("normalize");
break;
case ShaderAst::IntrinsicType::Pow:
Append("pow");
break;
case ShaderAst::IntrinsicType::Reflect:
Append("reflect");
break;
case ShaderAst::IntrinsicType::SampleTexture:
assert(!node.parameters.empty());
Visit(node.parameters.front(), true);

View File

@ -207,7 +207,25 @@ namespace Nz::ShaderLang
}
//FIXME: Handle this better
if (identifier == "mat4")
if (identifier == "array")
{
Consume();
Expect(Advance(), TokenType::OpenSquareBracket); //< [
ShaderAst::ArrayType arrayType;
arrayType.containedType = std::make_unique<ShaderAst::ContainedType>();
arrayType.containedType->type = ParseType();
Expect(Advance(), TokenType::Comma); //< ,
arrayType.length = ParseExpression();
Expect(Advance(), TokenType::ClosingSquareBracket); //< ]
return arrayType;
}
else if (identifier == "mat4")
{
Consume();
@ -215,9 +233,9 @@ namespace Nz::ShaderLang
matrixType.columnCount = 4;
matrixType.rowCount = 4;
Expect(Advance(), TokenType::LessThan); //< '<'
Expect(Advance(), TokenType::OpenSquareBracket); //< [
matrixType.type = ParsePrimitiveType();
Expect(Advance(), TokenType::GreaterThan); //< '>'
Expect(Advance(), TokenType::ClosingSquareBracket); //< ]
return matrixType;
}
@ -229,9 +247,23 @@ namespace Nz::ShaderLang
matrixType.columnCount = 3;
matrixType.rowCount = 3;
Expect(Advance(), TokenType::LessThan); //< '<'
Expect(Advance(), TokenType::OpenSquareBracket); //< [
matrixType.type = ParsePrimitiveType();
Expect(Advance(), TokenType::GreaterThan); //< '>'
Expect(Advance(), TokenType::ClosingSquareBracket); //< ]
return matrixType;
}
else if (identifier == "mat2")
{
Consume();
ShaderAst::MatrixType matrixType;
matrixType.columnCount = 2;
matrixType.rowCount = 2;
Expect(Advance(), TokenType::OpenSquareBracket); //< [
matrixType.type = ParsePrimitiveType();
Expect(Advance(), TokenType::ClosingSquareBracket); //< ]
return matrixType;
}
@ -242,9 +274,9 @@ namespace Nz::ShaderLang
ShaderAst::SamplerType samplerType;
samplerType.dim = ImageType::E2D;
Expect(Advance(), TokenType::LessThan); //< '<'
Expect(Advance(), TokenType::OpenSquareBracket); //< [
samplerType.sampledType = ParsePrimitiveType();
Expect(Advance(), TokenType::GreaterThan); //< '>'
Expect(Advance(), TokenType::ClosingSquareBracket); //< ]
return samplerType;
}
@ -255,9 +287,9 @@ namespace Nz::ShaderLang
ShaderAst::SamplerType samplerType;
samplerType.dim = ImageType::Cubemap;
Expect(Advance(), TokenType::LessThan); //< '<'
Expect(Advance(), TokenType::OpenSquareBracket); //< [
samplerType.sampledType = ParsePrimitiveType();
Expect(Advance(), TokenType::GreaterThan); //< '>'
Expect(Advance(), TokenType::ClosingSquareBracket); //< ]
return samplerType;
}
@ -267,9 +299,9 @@ namespace Nz::ShaderLang
ShaderAst::UniformType uniformType;
Expect(Advance(), TokenType::LessThan); //< '<'
Expect(Advance(), TokenType::OpenSquareBracket); //< [
uniformType.containedType = ShaderAst::IdentifierType{ ParseIdentifierAsName() };
Expect(Advance(), TokenType::GreaterThan); //< '>'
Expect(Advance(), TokenType::ClosingSquareBracket); //< ]
return uniformType;
}
@ -280,9 +312,9 @@ namespace Nz::ShaderLang
ShaderAst::VectorType vectorType;
vectorType.componentCount = 2;
Expect(Advance(), TokenType::LessThan); //< '<'
Expect(Advance(), TokenType::OpenSquareBracket); //< [
vectorType.type = ParsePrimitiveType();
Expect(Advance(), TokenType::GreaterThan); //< '>'
Expect(Advance(), TokenType::ClosingSquareBracket); //< ]
return vectorType;
}
@ -293,9 +325,9 @@ namespace Nz::ShaderLang
ShaderAst::VectorType vectorType;
vectorType.componentCount = 3;
Expect(Advance(), TokenType::LessThan); //< '<'
Expect(Advance(), TokenType::OpenSquareBracket); //< [
vectorType.type = ParsePrimitiveType();
Expect(Advance(), TokenType::GreaterThan); //< '>'
Expect(Advance(), TokenType::ClosingSquareBracket); //< ]
return vectorType;
}
@ -306,9 +338,9 @@ namespace Nz::ShaderLang
ShaderAst::VectorType vectorType;
vectorType.componentCount = 4;
Expect(Advance(), TokenType::LessThan); //< '<'
Expect(Advance(), TokenType::OpenSquareBracket); //< [
vectorType.type = ParsePrimitiveType();
Expect(Advance(), TokenType::GreaterThan); //< '>'
Expect(Advance(), TokenType::ClosingSquareBracket); //< ]
return vectorType;
}
@ -1323,24 +1355,6 @@ namespace Nz::ShaderLang
}
}
ShaderAst::ExpressionType Parser::ParseArrayType()
{
ShaderAst::ArrayType arrayType;
Expect(Advance(), TokenType::OpenSquareBracket);
arrayType.containedType = std::make_unique<ShaderAst::ContainedType>();
arrayType.containedType->type = ParseType();
Expect(Advance(), TokenType::Semicolon);
arrayType.length = ParseExpression();
Expect(Advance(), TokenType::ClosingSquareBracket);
return arrayType;
}
ShaderAst::AttributeType Parser::ParseIdentifierAsAttributeType()
{
const Token& identifierToken = Expect(Advance(), TokenType::Identifier);
@ -1388,9 +1402,6 @@ namespace Nz::ShaderLang
return ShaderAst::NoType{};
}
if (Peek().type == TokenType::OpenSquareBracket)
return ParseArrayType();
const Token& identifierToken = Expect(Peek(), TokenType::Identifier);
const std::string& identifier = std::get<std::string>(identifierToken.data);

View File

@ -368,34 +368,34 @@ namespace Nz
assert(node.condStatements.size() == 1); //< sanitization splits multiple branches
auto& condStatement = node.condStatements.front();
SpirvBlock mergeBlock(m_writer);
SpirvBlock contentBlock(m_writer);
SpirvBlock elseBlock(m_writer);
auto mergeBlock = std::make_unique<SpirvBlock>(m_writer);
auto contentBlock = std::make_unique<SpirvBlock>(m_writer);
auto elseBlock = std::make_unique<SpirvBlock>(m_writer);
UInt32 conditionId = EvaluateExpression(condStatement.condition);
m_currentBlock->Append(SpirvOp::OpSelectionMerge, mergeBlock.GetLabelId(), SpirvSelectionControl::None);
m_currentBlock->Append(SpirvOp::OpSelectionMerge, mergeBlock->GetLabelId(), SpirvSelectionControl::None);
// FIXME: Can we use merge block directly in OpBranchConditional if no else statement?
m_currentBlock->Append(SpirvOp::OpBranchConditional, conditionId, contentBlock.GetLabelId(), elseBlock.GetLabelId());
m_currentBlock->Append(SpirvOp::OpBranchConditional, conditionId, contentBlock->GetLabelId(), elseBlock->GetLabelId());
m_functionBlocks.emplace_back(std::move(contentBlock));
m_currentBlock = &m_functionBlocks.back();
m_currentBlock = m_functionBlocks.back().get();
condStatement.statement->Visit(*this);
if (!m_currentBlock->IsTerminated())
m_currentBlock->Append(SpirvOp::OpBranch, mergeBlock.GetLabelId());
m_currentBlock->Append(SpirvOp::OpBranch, mergeBlock->GetLabelId());
m_functionBlocks.emplace_back(std::move(elseBlock));
m_currentBlock = &m_functionBlocks.back();
m_currentBlock = m_functionBlocks.back().get();
if (node.elseStatement)
node.elseStatement->Visit(*this);
if (!m_currentBlock->IsTerminated())
m_currentBlock->Append(SpirvOp::OpBranch, mergeBlock.GetLabelId());
m_currentBlock->Append(SpirvOp::OpBranch, mergeBlock->GetLabelId());
m_functionBlocks.emplace_back(std::move(mergeBlock));
m_currentBlock = &m_functionBlocks.back();
m_currentBlock = m_functionBlocks.back().get();
}
void SpirvAstVisitor::Visit(ShaderAst::CallFunctionExpression& node)
@ -609,9 +609,12 @@ namespace Nz
}
}
m_functionBlocks.clear();
auto contentBlock = std::make_unique<SpirvBlock>(m_writer);
m_currentBlock = contentBlock.get();
m_functionBlocks.clear();
m_functionBlocks.emplace_back(std::move(contentBlock));
m_currentBlock = &m_functionBlocks.emplace_back(m_writer);
CallOnExit resetCurrentBlock([&] { m_currentBlock = nullptr; });
for (auto& var : func.variables)
@ -647,11 +650,11 @@ namespace Nz
statementPtr->Visit(*this);
// Add implicit return
if (!m_functionBlocks.back().IsTerminated())
m_functionBlocks.back().Append(SpirvOp::OpReturn);
if (!m_functionBlocks.back()->IsTerminated())
m_functionBlocks.back()->Append(SpirvOp::OpReturn);
for (SpirvBlock& block : m_functionBlocks)
m_instructions.AppendSection(block);
for (std::unique_ptr<SpirvBlock>& block : m_functionBlocks)
m_instructions.AppendSection(*block);
m_instructions.Append(SpirvOp::OpFunctionEnd);
}
@ -702,6 +705,23 @@ namespace Nz
{
switch (node.intrinsic)
{
case ShaderAst::IntrinsicType::CrossProduct:
{
UInt32 glslInstructionSet = m_writer.GetExtendedInstructionSet("GLSL.std.450");
const ShaderAst::ExpressionType& parameterType = GetExpressionType(*node.parameters[0]);
assert(IsVectorType(parameterType));
UInt32 typeId = m_writer.GetTypeId(parameterType);
UInt32 firstParam = EvaluateExpression(node.parameters[0]);
UInt32 secondParam = EvaluateExpression(node.parameters[1]);
UInt32 resultId = m_writer.AllocateResultId();
m_currentBlock->Append(SpirvOp::OpExtInst, typeId, resultId, glslInstructionSet, GLSLstd450Cross, firstParam, secondParam);
PushResultId(resultId);
break;
}
case ShaderAst::IntrinsicType::DotProduct:
{
const ShaderAst::ExpressionType& vecExprType = GetExpressionType(*node.parameters[0]);
@ -801,6 +821,25 @@ namespace Nz
break;
}
case ShaderAst::IntrinsicType::Normalize:
{
UInt32 glslInstructionSet = m_writer.GetExtendedInstructionSet("GLSL.std.450");
const ShaderAst::ExpressionType& vecExprType = GetExpressionType(*node.parameters[0]);
assert(IsVectorType(vecExprType));
const ShaderAst::VectorType& vecType = std::get<ShaderAst::VectorType>(vecExprType);
UInt32 typeId = m_writer.GetTypeId(vecType);
UInt32 vec = EvaluateExpression(node.parameters[0]);
UInt32 resultId = m_writer.AllocateResultId();
m_currentBlock->Append(SpirvOp::OpExtInst, typeId, resultId, glslInstructionSet, GLSLstd450Normalize, vec);
PushResultId(resultId);
break;
}
case ShaderAst::IntrinsicType::Pow:
{
UInt32 glslInstructionSet = m_writer.GetExtendedInstructionSet("GLSL.std.450");
@ -818,6 +857,23 @@ namespace Nz
break;
}
case ShaderAst::IntrinsicType::Reflect:
{
UInt32 glslInstructionSet = m_writer.GetExtendedInstructionSet("GLSL.std.450");
const ShaderAst::ExpressionType& parameterType = GetExpressionType(*node.parameters[0]);
assert(IsVectorType(parameterType));
UInt32 typeId = m_writer.GetTypeId(parameterType);
UInt32 firstParam = EvaluateExpression(node.parameters[0]);
UInt32 secondParam = EvaluateExpression(node.parameters[1]);
UInt32 resultId = m_writer.AllocateResultId();
m_currentBlock->Append(SpirvOp::OpExtInst, typeId, resultId, glslInstructionSet, GLSLstd450Reflect, firstParam, secondParam);
PushResultId(resultId);
break;
}
case ShaderAst::IntrinsicType::SampleTexture:
{
UInt32 typeId = m_writer.GetTypeId(ShaderAst::VectorType{4, ShaderAst::PrimitiveType::Float32});
@ -831,7 +887,6 @@ namespace Nz
break;
}
case ShaderAst::IntrinsicType::CrossProduct:
default:
throw std::runtime_error("not yet implemented");
}
@ -1021,12 +1076,12 @@ namespace Nz
assert(node.condition);
assert(node.body);
SpirvBlock headerBlock(m_writer);
SpirvBlock bodyBlock(m_writer);
SpirvBlock mergeBlock(m_writer);
auto headerBlock = std::make_unique<SpirvBlock>(m_writer);
auto bodyBlock = std::make_unique<SpirvBlock>(m_writer);
auto mergeBlock = std::make_unique<SpirvBlock>(m_writer);
m_currentBlock->Append(SpirvOp::OpBranch, headerBlock.GetLabelId());
m_currentBlock = &headerBlock;
m_currentBlock->Append(SpirvOp::OpBranch, headerBlock->GetLabelId());
m_currentBlock = headerBlock.get();
UInt32 expressionId = EvaluateExpression(node.condition);
@ -1051,18 +1106,22 @@ namespace Nz
else
loopControl = SpirvLoopControl::None;
m_currentBlock->Append(SpirvOp::OpLoopMerge, mergeBlock.GetLabelId(), bodyBlock.GetLabelId(), loopControl);
m_currentBlock->Append(SpirvOp::OpBranchConditional, expressionId, bodyBlock.GetLabelId(), mergeBlock.GetLabelId());
m_currentBlock->Append(SpirvOp::OpLoopMerge, mergeBlock->GetLabelId(), bodyBlock->GetLabelId(), loopControl);
m_currentBlock->Append(SpirvOp::OpBranchConditional, expressionId, bodyBlock->GetLabelId(), mergeBlock->GetLabelId());
m_currentBlock = &bodyBlock;
node.body->Visit(*this);
m_currentBlock->Append(SpirvOp::OpBranch, headerBlock.GetLabelId());
UInt32 headerLabelId = headerBlock->GetLabelId();
m_currentBlock = bodyBlock.get();
m_functionBlocks.emplace_back(std::move(headerBlock));
m_functionBlocks.emplace_back(std::move(bodyBlock));
node.body->Visit(*this);
// Jump back to header block to test condition
m_currentBlock->Append(SpirvOp::OpBranch, headerLabelId);
m_functionBlocks.emplace_back(std::move(mergeBlock));
m_currentBlock = &m_functionBlocks.back();
m_currentBlock = m_functionBlocks.back().get();
}
void SpirvAstVisitor::PushResultId(UInt32 value)

View File

@ -7,6 +7,7 @@
#include <Nazara/Shader/Ast/Nodes.hpp>
#include <Nazara/Utility/FieldOffsets.hpp>
#include <tsl/ordered_map.h>
#include <cassert>
#include <stdexcept>
#include <Nazara/Shader/Debug.hpp>
@ -16,7 +17,27 @@ namespace Nz
{
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...)->overloaded<Ts...>;
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
StructFieldType TypeToStructFieldType(const SpirvConstantCache::AnyType& type)
{
if (std::holds_alternative<SpirvConstantCache::Bool>(type))
return StructFieldType::Bool1;
else if (std::holds_alternative<SpirvConstantCache::Float>(type))
{
const auto& floatType = std::get<SpirvConstantCache::Float>(type);
assert(floatType.width == 32 || floatType.width == 64);
return (floatType.width == 32) ? StructFieldType::Float1 : StructFieldType::Double1;
}
else if (std::holds_alternative<SpirvConstantCache::Integer>(type))
{
const auto& intType = std::get<SpirvConstantCache::Integer>(type);
assert(intType.width == 32);
return (intType.signedness) ? StructFieldType::Int1 : StructFieldType::UInt1;
}
throw std::runtime_error("unexpected type");
}
}
struct SpirvConstantCache::Eq
@ -278,6 +299,7 @@ namespace Nz
void Register(const Structure& s)
{
Register(s.members);
cache.BuildFieldOffsets(s);
}
void Register(const SpirvConstantCache::Structure::Member& m)
@ -408,6 +430,12 @@ namespace Nz
struct SpirvConstantCache::Internal
{
struct StructOffsets
{
FieldOffsets fieldOffsets;
std::vector<UInt32> offsets;
};
Internal(UInt32& resultId) :
nextResultId(resultId)
{
@ -415,7 +443,6 @@ namespace Nz
tsl::ordered_map<std::variant<AnyConstant, AnyType>, UInt32 /*id*/, AnyHasher, Eq> ids;
tsl::ordered_map<Variable, UInt32 /*id*/, AnyHasher, Eq> variableIds;
tsl::ordered_map<Structure, FieldOffsets /*fieldOffsets*/, AnyHasher, Eq> structureSizes;
StructCallback structCallback;
UInt32& nextResultId;
bool isInBlockStruct = false;
@ -480,6 +507,106 @@ namespace Nz
}, value));
}
FieldOffsets SpirvConstantCache::BuildFieldOffsets(const Structure& structData) const
{
FieldOffsets structOffsets(StructLayout::Std140);
for (const Structure::Member& member : structData.members)
{
member.offset = std::visit([&](auto&& arg) -> std::size_t
{
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, Array>)
{
assert(std::holds_alternative<ConstantScalar>(arg.length->constant));
const auto& scalar = std::get<ConstantScalar>(arg.length->constant);
assert(std::holds_alternative<UInt32>(scalar.value));
std::size_t length = std::get<UInt32>(scalar.value);
return RegisterArrayField(structOffsets, arg.elementType->type, length);
}
else if constexpr (std::is_same_v<T, Bool>)
return structOffsets.AddField(StructFieldType::Bool1);
else if constexpr (std::is_same_v<T, Float>)
{
switch (arg.width)
{
case 32: return structOffsets.AddField(StructFieldType::Float1);
case 64: return structOffsets.AddField(StructFieldType::Double1);
default: throw std::runtime_error("unexpected float width " + std::to_string(arg.width));
}
}
else if constexpr (std::is_same_v<T, Integer>)
return structOffsets.AddField((arg.signedness) ? StructFieldType::Int1 : StructFieldType::UInt1);
else if constexpr (std::is_same_v<T, Matrix>)
{
assert(std::holds_alternative<Vector>(arg.columnType->type));
Vector& columnVec = std::get<Vector>(arg.columnType->type);
if (!std::holds_alternative<Float>(columnVec.componentType->type))
throw std::runtime_error("unexpected vector type");
Float& vecType = std::get<Float>(columnVec.componentType->type);
StructFieldType columnType;
switch (vecType.width)
{
case 32: columnType = StructFieldType::Float1; break;
case 64: columnType = StructFieldType::Double1; break;
default: throw std::runtime_error("unexpected float width " + std::to_string(vecType.width));
}
return structOffsets.AddMatrix(columnType, arg.columnCount, columnVec.componentCount, true);
}
else if constexpr (std::is_same_v<T, Pointer>)
throw std::runtime_error("unhandled pointer in struct");
else if constexpr (std::is_same_v<T, Structure>)
return structOffsets.AddStruct(BuildFieldOffsets(arg));
else if constexpr (std::is_same_v<T, Vector>)
{
if (std::holds_alternative<Bool>(arg.componentType->type))
return structOffsets.AddField(static_cast<StructFieldType>(UnderlyingCast(StructFieldType::Bool1) + arg.componentCount - 1));
else if (std::holds_alternative<Float>(arg.componentType->type))
{
Float& floatData = std::get<Float>(arg.componentType->type);
switch (floatData.width)
{
case 32: return structOffsets.AddField(static_cast<StructFieldType>(UnderlyingCast(StructFieldType::Float1) + arg.componentCount - 1));
case 64: return structOffsets.AddField(static_cast<StructFieldType>(UnderlyingCast(StructFieldType::Double1) + arg.componentCount - 1));
default: throw std::runtime_error("unexpected float width " + std::to_string(floatData.width));
}
}
else if (std::holds_alternative<Integer>(arg.componentType->type))
{
Integer& intData = std::get<Integer>(arg.componentType->type);
if (intData.width != 32)
throw std::runtime_error("unexpected integer width " + std::to_string(intData.width));
if (intData.signedness)
return structOffsets.AddField(static_cast<StructFieldType>(UnderlyingCast(StructFieldType::Int1) + arg.componentCount - 1));
else
return structOffsets.AddField(static_cast<StructFieldType>(UnderlyingCast(StructFieldType::UInt1) + arg.componentCount - 1));
}
else
throw std::runtime_error("unexpected type for vector");
}
else if constexpr (std::is_same_v<T, Function>)
throw std::runtime_error("unexpected function as struct member");
else if constexpr (std::is_same_v<T, Identifier>)
throw std::runtime_error("unexpected identifier");
else if constexpr (std::is_same_v<T, Image> || std::is_same_v<T, SampledImage>)
throw std::runtime_error("unexpected opaque type as struct member");
else if constexpr (std::is_same_v<T, Void>)
throw std::runtime_error("unexpected void as struct member");
else
static_assert(AlwaysFalse<T>::value, "non-exhaustive visitor");
}, member.type->type);
}
return structOffsets;
}
auto SpirvConstantCache::BuildFunctionType(const ShaderAst::ExpressionType& retType, const std::vector<ShaderAst::ExpressionType>& parameters) const -> TypePtr
{
std::vector<SpirvConstantCache::TypePtr> parameterTypes;
@ -528,10 +655,24 @@ namespace Nz
auto SpirvConstantCache::BuildType(const ShaderAst::ArrayType& type) const -> TypePtr
{
const auto& containedType = type.containedType->type;
TypePtr builtContainedType = BuildType(containedType);
// ArrayStride
std::optional<UInt32> arrayStride;
if (m_internal->isInBlockStruct)
{
FieldOffsets fieldOffset(StructLayout::Std140);
RegisterArrayField(fieldOffset, builtContainedType->type, 1);
arrayStride = SafeCast<UInt32>(fieldOffset.GetAlignedSize());
}
return std::make_shared<Type>(Array{
BuildType(type.containedType->type),
builtContainedType,
BuildConstant(type.length.GetResultingValue()),
(m_internal->isInBlockStruct) ? std::make_optional<UInt32>(16) : std::nullopt
arrayStride
});
}
@ -759,6 +900,83 @@ namespace Nz
return it.value();
}
std::size_t SpirvConstantCache::RegisterArrayField(FieldOffsets& fieldOffsets, const Array& type, std::size_t arrayLength) const
{
FieldOffsets dummyStruct(fieldOffsets.GetLayout());
RegisterArrayField(dummyStruct, type.elementType->type, std::get<UInt32>(std::get<ConstantScalar>(type.length->constant).value));
return fieldOffsets.AddStructArray(dummyStruct, arrayLength);
}
std::size_t SpirvConstantCache::RegisterArrayField(FieldOffsets& fieldOffsets, const Bool& type, std::size_t arrayLength) const
{
return fieldOffsets.AddFieldArray(TypeToStructFieldType(type), arrayLength);
}
std::size_t SpirvConstantCache::RegisterArrayField(FieldOffsets& fieldOffsets, const Float& type, std::size_t arrayLength) const
{
return fieldOffsets.AddFieldArray(TypeToStructFieldType(type), arrayLength);
}
std::size_t SpirvConstantCache::RegisterArrayField(FieldOffsets& fieldOffsets, const Function& type, std::size_t arrayLength) const
{
throw std::runtime_error("unexpected Function");
}
std::size_t SpirvConstantCache::RegisterArrayField(FieldOffsets& fieldOffsets, const Image& type, std::size_t arrayLength) const
{
throw std::runtime_error("unexpected Image");
}
std::size_t SpirvConstantCache::RegisterArrayField(FieldOffsets& fieldOffsets, const Integer& type, std::size_t arrayLength) const
{
return fieldOffsets.AddFieldArray(TypeToStructFieldType(type), arrayLength);
}
std::size_t SpirvConstantCache::RegisterArrayField(FieldOffsets& fieldOffsets, const Matrix& type, std::size_t arrayLength) const
{
if (!std::holds_alternative<Vector>(type.columnType->type))
throw std::runtime_error("unexpected column type");
const Vector& vecType = std::get<Vector>(type.columnType->type);
return fieldOffsets.AddMatrixArray(TypeToStructFieldType(vecType.componentType->type), type.columnCount, vecType.componentCount, true, arrayLength);
}
std::size_t SpirvConstantCache::RegisterArrayField(FieldOffsets& /*fieldOffsets*/, const Pointer& /*type*/, std::size_t /*arrayLength*/) const
{
throw std::runtime_error("unexpected Pointer (not implemented)");
}
std::size_t SpirvConstantCache::RegisterArrayField(FieldOffsets& /*fieldOffsets*/, const SampledImage& /*type*/, std::size_t /*arrayLength*/) const
{
throw std::runtime_error("unexpected SampledImage");
}
std::size_t SpirvConstantCache::RegisterArrayField(FieldOffsets& fieldOffsets, const Structure& type, std::size_t arrayLength) const
{
auto innerFieldOffset = BuildFieldOffsets(type);
return fieldOffsets.AddStructArray(innerFieldOffset, arrayLength);
}
std::size_t SpirvConstantCache::RegisterArrayField(FieldOffsets& fieldOffsets, const Type& type, std::size_t arrayLength) const
{
return std::visit([&](auto&& arg) -> std::size_t
{
return RegisterArrayField(fieldOffsets, arg, arrayLength);
}, type.type);
}
std::size_t SpirvConstantCache::RegisterArrayField(FieldOffsets& fieldOffsets, const Vector& type, std::size_t arrayLength) const
{
assert(type.componentCount > 0 && type.componentCount <= 4);
return fieldOffsets.AddFieldArray(static_cast<StructFieldType>(UnderlyingCast(TypeToStructFieldType(type.componentType->type)) + type.componentCount), arrayLength);
}
std::size_t SpirvConstantCache::RegisterArrayField(FieldOffsets& fieldOffsets, const Void& type, std::size_t arrayLength) const
{
throw std::runtime_error("unexpected Void");
}
void SpirvConstantCache::SetStructCallback(StructCallback callback)
{
m_internal->structCallback = std::move(callback);
@ -941,125 +1159,25 @@ namespace Nz
for (SpirvDecoration decoration : structData.decorations)
annotations.Append(SpirvOp::OpDecorate, resultId, decoration);
FieldOffsets structOffsets(StructLayout::Std140);
for (std::size_t memberIndex = 0; memberIndex < structData.members.size(); ++memberIndex)
{
const auto& member = structData.members[memberIndex];
debugInfos.Append(SpirvOp::OpMemberName, resultId, memberIndex, member.name);
std::size_t offset = std::visit([&](auto&& arg) -> std::size_t
UInt32 offset = member.offset.value();
std::visit([&](auto&& arg)
{
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, Array>)
if constexpr (std::is_same_v<T, Matrix>)
{
assert(std::holds_alternative<ConstantScalar>(arg.length->constant));
const auto& scalar = std::get<ConstantScalar>(arg.length->constant);
assert(std::holds_alternative<UInt32>(scalar.value));
std::size_t length = std::get<UInt32>(scalar.value);
if (!std::holds_alternative<Float>(arg.elementType->type))
throw std::runtime_error("todo");
// FIXME: Virer cette implémentation du ghetto
const Float& fData = std::get<Float>(arg.elementType->type);
switch (fData.width)
{
case 32: return structOffsets.AddFieldArray(StructFieldType::Float1, length);
case 64: return structOffsets.AddFieldArray(StructFieldType::Double1, length);
default: throw std::runtime_error("unexpected float width " + std::to_string(fData.width));
}
}
else if constexpr (std::is_same_v<T, Bool>)
return structOffsets.AddField(StructFieldType::Bool1);
else if constexpr (std::is_same_v<T, Float>)
{
switch (arg.width)
{
case 32: return structOffsets.AddField(StructFieldType::Float1);
case 64: return structOffsets.AddField(StructFieldType::Double1);
default: throw std::runtime_error("unexpected float width " + std::to_string(arg.width));
}
}
else if constexpr (std::is_same_v<T, Integer>)
return structOffsets.AddField((arg.signedness) ? StructFieldType::Int1 : StructFieldType::UInt1);
else if constexpr (std::is_same_v<T, Matrix>)
{
assert(std::holds_alternative<Vector>(arg.columnType->type));
Vector& columnVec = std::get<Vector>(arg.columnType->type);
if (!std::holds_alternative<Float>(columnVec.componentType->type))
throw std::runtime_error("unexpected vector type");
Float& vecType = std::get<Float>(columnVec.componentType->type);
StructFieldType columnType;
switch (vecType.width)
{
case 32: columnType = StructFieldType::Float1; break;
case 64: columnType = StructFieldType::Double1; break;
default: throw std::runtime_error("unexpected float width " + std::to_string(vecType.width));
}
annotations.Append(SpirvOp::OpMemberDecorate, resultId, memberIndex, SpirvDecoration::ColMajor);
annotations.Append(SpirvOp::OpMemberDecorate, resultId, memberIndex, SpirvDecoration::MatrixStride, 16);
return structOffsets.AddMatrix(columnType, arg.columnCount, columnVec.componentCount, true);
}
else if constexpr (std::is_same_v<T, Pointer>)
throw std::runtime_error("unhandled pointer in struct");
else if constexpr (std::is_same_v<T, Structure>)
{
auto it = m_internal->structureSizes.find(arg);
assert(it != m_internal->structureSizes.end());
return structOffsets.AddStruct(it->second);
}
else if constexpr (std::is_same_v<T, Vector>)
{
if (std::holds_alternative<Bool>(arg.componentType->type))
return structOffsets.AddField(static_cast<StructFieldType>(UnderlyingCast(StructFieldType::Bool1) + arg.componentCount - 1));
else if (std::holds_alternative<Float>(arg.componentType->type))
{
Float& floatData = std::get<Float>(arg.componentType->type);
switch (floatData.width)
{
case 32: return structOffsets.AddField(static_cast<StructFieldType>(UnderlyingCast(StructFieldType::Float1) + arg.componentCount - 1));
case 64: return structOffsets.AddField(static_cast<StructFieldType>(UnderlyingCast(StructFieldType::Double1) + arg.componentCount - 1));
default: throw std::runtime_error("unexpected float width " + std::to_string(floatData.width));
}
}
else if (std::holds_alternative<Integer>(arg.componentType->type))
{
Integer& intData = std::get<Integer>(arg.componentType->type);
if (intData.width != 32)
throw std::runtime_error("unexpected integer width " + std::to_string(intData.width));
if (intData.signedness)
return structOffsets.AddField(static_cast<StructFieldType>(UnderlyingCast(StructFieldType::Int1) + arg.componentCount - 1));
else
return structOffsets.AddField(static_cast<StructFieldType>(UnderlyingCast(StructFieldType::UInt1) + arg.componentCount - 1));
}
else
throw std::runtime_error("unexpected type for vector");
}
else if constexpr (std::is_same_v<T, Function>)
throw std::runtime_error("unexpected function as struct member");
else if constexpr (std::is_same_v<T, Identifier>)
throw std::runtime_error("unexpected identifier");
else if constexpr (std::is_same_v<T, Image> || std::is_same_v<T, SampledImage>)
throw std::runtime_error("unexpected opaque type as struct member");
else if constexpr (std::is_same_v<T, Void>)
throw std::runtime_error("unexpected void as struct member");
else
static_assert(AlwaysFalse<T>::value, "non-exhaustive visitor");
}, member.type->type);
annotations.Append(SpirvOp::OpMemberDecorate, resultId, memberIndex, SpirvDecoration::Offset, offset);
}
m_internal->structureSizes.emplace(structData, std::move(structOffsets));
}
}

Some files were not shown because too many files have changed in this diff Show More