Merge pull request #358 from DigitalPulseSoftware/phong-lighting
Add phong lighting support
This commit is contained in:
commit
29cd77db55
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
target("WidgetDemo")
|
||||
set_group("Examples")
|
||||
set_kind("binary")
|
||||
add_deps("NazaraGraphics", "NazaraPhysics3D", "NazaraWidgets")
|
||||
add_packages("entt")
|
||||
add_files("main.cpp")
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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>
|
||||
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ namespace Nz
|
|||
{
|
||||
inline const std::shared_ptr<MaterialSettings>& DepthMaterial::GetSettings()
|
||||
{
|
||||
return s_materialSettings;
|
||||
return s_basicMaterialSettings;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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>
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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>
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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>
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
class AbstractBuffer;
|
||||
class MaterialPass;
|
||||
class RenderPipeline;
|
||||
class VertexDeclaration;
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
class AbstractBuffer;
|
||||
class MaterialPass;
|
||||
class VertexDeclaration;
|
||||
class ViewerInstance;
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
class AbstractBuffer;
|
||||
class MaterialPass;
|
||||
class RenderPipeline;
|
||||
class ShaderBinding;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
class AbstractBuffer;
|
||||
class CommandBufferBuilder;
|
||||
class MaterialSettings;
|
||||
class RenderBuffer;
|
||||
class UploadPool;
|
||||
class WorldInstance;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
class AbstractBuffer;
|
||||
class Buffer;
|
||||
|
||||
class NAZARA_RENDERER_API Renderer : public ModuleBase<Renderer>
|
||||
|
|
|
|||
|
|
@ -103,7 +103,9 @@ namespace Nz
|
|||
Length = 3,
|
||||
Max = 4,
|
||||
Min = 5,
|
||||
Normalize = 9,
|
||||
Pow = 6,
|
||||
Reflect = 8,
|
||||
SampleTexture = 2,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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*/)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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 = ¤tFrame.GetUploadPool().Allocate(m_maxVertexBufferSize);
|
||||
currentAllocationMemPtr = static_cast<UInt8*>(currentAllocation->mappedPtr);
|
||||
m_pendingData.currentAllocation = ¤tFrame.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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in New Issue