2 Commits

Author SHA1 Message Date
antopilo
6d7a3a09b1 Better far volumetric handling with sky color 2025-04-25 21:20:36 -04:00
antopilo
67916d0307 Added normal maapping + material preview widget 2025-04-25 20:22:41 -04:00
19 changed files with 1029 additions and 233 deletions

View File

@@ -13,8 +13,8 @@ struct Vertex
float uv_x;
float3 normal;
float uv_y;
float3 tangent;
float3 bitangent;
float4 tangent;
float4 bitangent;
};
[[vk::binding(0, 1)]]
@@ -86,7 +86,8 @@ struct PSInput
float3 Color : TEXCOORD0;
float2 UV : TEXCOORD1;
float3 Normal : TEXCOORD2;
//float3x3 TBN : TEXCOORD3;
float3 Tangent : TEXCOORD3;
float3 Bitangent : TEXCOORD4;
};
struct PSOutput {
@@ -107,6 +108,8 @@ struct ModelPushConstant
[[vk::push_constant]]
ModelPushConstant pushConstants;
PSOutput main(PSInput input)
{
PSOutput output;
@@ -114,13 +117,26 @@ PSOutput main(PSInput input)
Material inMaterial = material[pushConstants.materialIndex];
// NORMAL
// TODO use TBN matrix
float3 normal = float3(0.5, 0.5, 1.0);
float3 T = input.Tangent.xyz;
float3 B = input.Bitangent.xyz;
float3 N = input.Normal.xyz;
float3x3 TBN = float3x3(T, B, N);
float3 normal = float3(0.0, 0.0, 1.0);
if(inMaterial.hasNormal == 1)
{
// Sample from texture.
normal = textures[inMaterial.normalTextureId].Sample(mySampler, input.UV).rgb;
normal.xyz = normal.zxy;
normal = normal * 2.0f - 1.0f;
}
//normal = mul(input.TBN, normal);
normal = input.Normal / 2.0f + 0.5f;
else
{
normal = normal;
}
//normal = input.Normal;
normal = mul(transpose(TBN), normal);
normal = normal / 2.0f + 0.5f;
output.oNormal = float4(normal, 1.0f);
// MATERIAL

View File

@@ -13,8 +13,8 @@ struct Vertex
float uv_x;
float3 normal;
float uv_y;
float3 tangent;
float3 bitangent;
float4 tangent;
float4 bitangent;
};
[[vk::binding(0, 1)]]
@@ -98,9 +98,35 @@ struct VSOutput
float3 Color : TEXCOORD0;
float2 UV : TEXCOORD1;
float3 Normal : TEXCOORD2;
//float3x3 TBN : TEXCOORD3;
float3 Tangent : TEXCOORD3;
float3 Bitangent : TEXCOORD4;
};
float3x3 invert(float3x3 m)
{
float3 a = m[0];
float3 b = m[1];
float3 c = m[2];
float3 r0 = cross(b, c);
float3 r1 = cross(c, a);
float3 r2 = cross(a, b);
float det = dot(r2, c);
// Return identity if not invertible (optional fallback)
if (abs(det) < 1e-6)
return float3x3(1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0);
float invDet = 1.0 / det;
return float3x3(r0 * invDet,
r1 * invDet,
r2 * invDet);
}
// Main vertex shader
VSOutput main(uint vertexIndex : SV_VertexID)
{
@@ -116,11 +142,13 @@ VSOutput main(uint vertexIndex : SV_VertexID)
output.Position = mul(camView.Projection, mul(camView.View, mul(modelData.model, float4(v.position, 1.0f))));
output.Color = normalize(float3(v.position.xyz));
output.UV = float2(v.uv_x, v.uv_y);
output.Normal = normalize(v.normal);
float3x3 upper3x3 = (float3x3)modelData.model;
float3x3 normalMatrix = transpose(invert(upper3x3));
output.Bitangent = mul(normalMatrix, normalize(v.bitangent.xyz));
output.Normal = mul(normalMatrix, normalize(v.normal.xyz));
output.Tangent = mul(normalMatrix, normalize(v.tangent.xyz));
//float3 T = normalize(mul((float3x3)modelData.model, normalize(v.tangent.xyz)));
//float3 B = normalize(mul((float3x3)modelData.model, normalize(v.bitangent.xyz)));
//float3 N = normalize(mul((float3x3)modelData.model, normalize(v.normal)).xyz);
//output.TBN = transpose(float3x3(T, B, N));
//output.Normal = v.normal.xyz;
return output;
}

View File

@@ -227,7 +227,7 @@ int GetCSMSplit(float depth)
}
}
return 0;
return -1;
}
PSOutput main(PSInput input)
@@ -253,7 +253,7 @@ PSOutput main(PSInput input)
if(rayLength > 1000.0)
{
output.oColor0 = float4(0.0f, 0.0f, 0, 0.0f);
return output;
//return output;
}
float stepLength = rayLength / pushConstants.StepCount;
@@ -272,24 +272,33 @@ PSOutput main(PSInput input)
float lightDepth = length(worldPos - camView.Position);
int splitIndex = GetCSMSplit(lightDepth);
CameraView lightView = cameras[light.transformId[splitIndex]];
float4 fragPosLightSpace = mul(lightView.Projection, mul(lightView.View, float4(currentPosition, 1.0)));
float3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
projCoords.xy = projCoords.xy * 0.5 + 0.5;
float currentDepth = projCoords.z;
float closestDepth = textures[light.shadowMapTextureId[splitIndex]].Sample(mySampler, projCoords.xy).r;
float3 noiseOffset = float3(pushConstants.NoiseSpeed * pushConstants.Time, pushConstants.NoiseSpeed * pushConstants.Time, pushConstants.NoiseSpeed * pushConstants.Time);
float3 noiseSamplePos = (currentPosition + noiseOffset) * pushConstants.NoiseScale;
if(closestDepth < currentDepth)
if(splitIndex == -1)
{
accumFog += (ComputeScattering(dot(rayDirection, light.direction)).rrr * light.color.xyz) * pushConstants.Exponant * ((snoise(noiseSamplePos.xyz) + 1.0) / 2.0);
accumFog += (ComputeScattering(dot(rayDirection, light.direction)).rrr * light.color.xyz) * pushConstants.Exponant;
}
else
{
accumFog += (ComputeScattering(dot(rayDirection, light.direction)).rrr * light.color.xyz) * pushConstants.Ambient * ((snoise(noiseSamplePos.xyz) + 1.0) / 2.0);
CameraView lightView = cameras[light.transformId[splitIndex]];
float4 fragPosLightSpace = mul(lightView.Projection, mul(lightView.View, float4(currentPosition, 1.0)));
float3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
projCoords.xy = projCoords.xy * 0.5 + 0.5;
float currentDepth = projCoords.z;
float closestDepth = textures[light.shadowMapTextureId[splitIndex]].Sample(mySampler, projCoords.xy).r;
float3 noiseOffset = float3(pushConstants.NoiseSpeed * pushConstants.Time, pushConstants.NoiseSpeed * pushConstants.Time, pushConstants.NoiseSpeed * pushConstants.Time);
float3 noiseSamplePos = (currentPosition + noiseOffset) * pushConstants.NoiseScale;
if(closestDepth < currentDepth)
{
accumFog += (ComputeScattering(dot(rayDirection, light.direction)).rrr * light.color.xyz) * pushConstants.Exponant * ((snoise(noiseSamplePos.xyz) + 1.0) / 2.0);
}
else
{
accumFog += (ComputeScattering(dot(rayDirection, light.direction)).rrr * light.color.xyz) * pushConstants.Ambient * ((snoise(noiseSamplePos.xyz) + 1.0) / 2.0);
}
}
}
else if(light.type == 1)
{

View File

@@ -1,141 +1,321 @@
#shader vertex
#version 440 core
layout(location = 0) in vec3 VertexPosition;
layout(location = 1) in vec2 UVPosition;
out flat vec2 UV;
out mat4 InvView;
out mat4 InvProjection;
uniform mat4 u_View;
uniform mat4 u_Projection;
void main()
// Transforms
struct ModelData
{
UV = UVPosition;
InvView = inverse(u_View);
InvProjection = inverse(u_Projection);
gl_Position = vec4(VertexPosition, 1.0f);
}
float4x4 model;
};
[[vk::binding(0, 0)]]
StructuredBuffer<ModelData> model : register(t1);
#shader fragment
#version 440 core
float ditherPattern[4][4] = { { 0.0f, 0.5f, 0.125f, 0.625f},
{ 0.75f, 0.22f, 0.875f, 0.375f},
{ 0.1875f, 0.6875f, 0.0625f, 0.5625},
{ 0.9375f, 0.4375f, 0.8125f, 0.3125} };
in mat4 InvView;
in mat4 InvProjection;
uniform sampler2D u_Depth;
uniform vec3 u_CamPosition;
uniform int u_StepCount;
uniform float u_FogAmount;
uniform float u_Exponant;
const int MAX_LIGHT = 20;
uniform int u_LightCount;
struct Light {
mat4 transform;
vec3 color;
vec3 direction;
sampler2D shadowmap;
float strength;
// Vertex
struct Vertex
{
float3 position;
float uv_x;
float3 normal;
float uv_y;
float3 tangent;
float3 bitangent;
};
uniform Light u_Lights[MAX_LIGHT];
[[vk::binding(0, 1)]]
StructuredBuffer<Vertex> vertexBuffer : register(t2);
uniform sampler2D lightShadowmap;
in vec2 UV;
// Samplers
[[vk::binding(0, 2)]]
SamplerState mySampler : register(s0);
out vec4 FragColor;
const float PI = 3.141592653589793f;
// Materials
struct Material
{
bool hasAlbedo;
float3 albedo;
bool hasNormal;
bool hasMetalness;
bool hasRoughness;
bool hasAO;
float metalnessValue;
float roughnessValue;
float aoValue;
int albedoTextureId;
int normalTextureId;
int metalnessTextureId;
int roughnessTextureId;
int aoTextureId;
};
[[vk::binding(0, 3)]]
StructuredBuffer<Material> material;
// Textures
[[vk::binding(0, 4)]]
Texture2D textures[];
// Lights
struct Light
{
float3 position;
int type;
float4 color;
float3 direction;
float outerConeAngle;
float innerConeAngle;
bool castShadow;
int shadowMapTextureId[4];
int transformId[4];
};
[[vk::binding(0, 5)]]
StructuredBuffer<Light> lights;
// Cameras
struct CameraView {
float4x4 View;
float4x4 Projection;
float4x4 ViewProjection;
float4x4 InverseView;
float4x4 InverseProjection;
float3 Position;
float Near;
float Far;
};
[[vk::binding(0, 6)]]
StructuredBuffer<CameraView> cameras;
struct PSInput
{
float4 Position : SV_Position;
float2 UV : TEXCOORD0;
};
struct PSOutput {
float4 oColor0 : SV_TARGET;
};
struct VolumetricConstant
{
int DepthTextureID;
int StepCount;
float FogAmount;
float Exponant;
int CamViewID;
int LightCount;
float Ambient;
float Time;
float NoiseSpeed;
float NoiseScale;
float NoiseStrength;
};
[[vk::push_constant]]
VolumetricConstant pushConstants;
float2 GetTexelSize(Texture2D tex)
{
uint width, height;
tex.GetDimensions(width, height);
return 1.0 / float2(width, height);
}
float LinearizeDepth(float depth, float nearPlane, float farPlane)
{
return (2.0 * nearPlane) / (farPlane + nearPlane - (1.0 - depth) * (farPlane - nearPlane));
}
// Mie scaterring approximated with Henyey-Greenstein phase function.
float ComputeScattering(float lightDotView)
{
float result = 1.0f - u_FogAmount ;
result /= (4.0f * PI * pow(1.0f + u_FogAmount * u_FogAmount - (1.0f * u_FogAmount) * lightDotView, 1.5f));
float PI = 3.141592653589793f;
float result = 1.0f - pushConstants.FogAmount;
result /= (4.0f * PI * pow(1.0f + pushConstants.FogAmount * pushConstants.FogAmount - (1.0f * pushConstants.FogAmount) * lightDotView, 1.5f));
return result;
}
vec3 ComputeVolumetric(vec3 FragPos, Light light)
float3 WorldPosFromDepth(float depth, float2 uv, float4x4 invProj, float4x4 invView)
{
vec3 startPosition = u_CamPosition; // Camera Position
vec3 rayVector = FragPos - startPosition; // Ray Direction
float rayLength = length(rayVector); // Length of the raymarched
if(rayLength > 1000.0)
return vec3(0.0);
float stepLength = rayLength / u_StepCount; // Step length
vec3 rayDirection = rayVector / rayLength;
vec3 step = rayDirection * stepLength; // Normalized to step length direction
vec3 accumFog = vec3(0.0f, 0.0f, 0.0f); // accumulative color
// Raymarching
vec3 currentPosition = startPosition;
for (int i = 0; i < u_StepCount; i++)
{
vec4 fragPosLightSpace = light.transform * vec4(currentPosition, 1.0f);
// perform perspective divide
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
// transform to [0,1] range
projCoords = projCoords * 0.5 + 0.5;
float currentDepth = projCoords.z;
float closestDepth = texture(light.shadowmap, projCoords.xy).r;
if (closestDepth > currentDepth && closestDepth < 999)
{
//accumFog = vec3(light.color);
accumFog += (ComputeScattering(dot(rayDirection, light.direction)).xxx * light.color);
//accumFog = vec3(projCoords.x, projCoords.y, 1.0);
}
currentPosition += step * ditherPattern[int(gl_FragCoord.x) % 4][int(gl_FragCoord.y) % 4];
//accumFog = vec3(projCoords);
}
accumFog /= u_StepCount;
return accumFog;
}
// Converts depth to World space coords.
vec3 WorldPosFromDepth(float depth) {
float z = depth * 2.0 - 1.0;
vec4 clipSpacePosition = vec4(UV * 2.0 - 1.0, z, 1.0);
vec4 viewSpacePosition = InvProjection * clipSpacePosition;
// Perspective division
float z = depth;
float4 clipSpacePosition = float4(uv.x * 2.0 - 1.0, (uv.y * 2.0 - 1.0), z, 1.0f);
float4 viewSpacePosition = mul(invProj, clipSpacePosition);
viewSpacePosition /= viewSpacePosition.w;
vec4 worldSpacePosition = InvView * viewSpacePosition;
float4 worldSpacePosition = mul(invView, viewSpacePosition);
return worldSpacePosition.xyz;
}
void main()
{
float depth = texture(u_Depth, UV).r;
vec3 globalFragmentPosition = WorldPosFromDepth(depth);
// Simplex 3D Noise
float mod289(float x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
float3 mod289(float3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
float4 mod289(float4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
vec3 fog = vec3(0, 0, 0);
for (int i = 0; i < u_LightCount; i++)
float4 permute(float4 x) { return mod289(((x*34.0)+1.0)*x); }
float4 taylorInvSqrt(float4 r) { return 1.79284291400159 - 0.85373472095314 * r; }
float snoise(float3 v)
{
const float2 C = float2(1.0/6.0, 1.0/3.0) ;
const float4 D = float4(0.0, 0.5, 1.0, 2.0);
// First corner
float3 i = floor(v + dot(v, C.yyy));
float3 x0 = v - i + dot(i, C.xxx);
// Other corners
float3 g = step(x0.yzx, x0.xyz);
float3 l = 1.0 - g;
float3 i1 = min(g.xyz, l.zxy);
float3 i2 = max(g.xyz, l.zxy);
// x0 = x0 - 0.0 + 0.0 * C.xxx;
float3 x1 = x0 - i1 + C.xxx;
float3 x2 = x0 - i2 + C.yyy;
float3 x3 = x0 - 1.0 + 3.0 * C.xxx;
// Permutations
i = mod289(i);
float4 p = permute(permute(permute(
i.z + float4(0.0, i1.z, i2.z, 1.0))
+ i.y + float4(0.0, i1.y, i2.y, 1.0))
+ i.x + float4(0.0, i1.x, i2.x, 1.0));
// Gradients: 7x7 points over a cube, mapped onto a unit sphere
float4 j = p - 49.0 * floor(p * (1.0 / 49.0)); // mod(p,7*7)
float4 x_ = floor(j * (1.0 / 7.0));
float4 y_ = floor(j - 7.0 * x_); // mod(j,7)
float4 x = (x_ * 2.0 + 0.5) / 7.0 - 1.0;
float4 y = (y_ * 2.0 + 0.5) / 7.0 - 1.0;
float4 h = 1.0 - abs(x) - abs(y);
float4 b0 = float4(x.xy, y.xy);
float4 b1 = float4(x.zw, y.zw);
float4 s0 = floor(b0) * 2.0 + 1.0;
float4 s1 = floor(b1) * 2.0 + 1.0;
float4 sh = -step(h, 0.0);
float4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;
float4 a1 = b1.xzyw + s1.xzyw * sh.zzww;
float3 g0 = float3(a0.xy, h.x);
float3 g1 = float3(a0.zw, h.y);
float3 g2 = float3(a1.xy, h.z);
float3 g3 = float3(a1.zw, h.w);
// Normalize gradients
float4 norm = taylorInvSqrt(float4(dot(g0,g0), dot(g1,g1), dot(g2,g2), dot(g3,g3)));
g0 *= norm.x;
g1 *= norm.y;
g2 *= norm.z;
g3 *= norm.w;
// Mix final noise value
float4 m = max(0.6 - float4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
m = m * m;
return 42.0 * dot(m*m, float4(dot(g0,x0), dot(g1,x1), dot(g2,x2), dot(g3,x3)));
}
PSOutput main(PSInput input)
{
float ditherPattern[4][4] = { { 0.0f, 0.5f, 0.125f, 0.625f},
{ 0.75f, 0.22f, 0.875f, 0.375f},
{ 0.1875f, 0.6875f, 0.0625f, 0.5625},
{ 0.9375f, 0.4375f, 0.8125f, 0.3125} };
CameraView camView = cameras[pushConstants.CamViewID];
float3 startPosition = camView.Position;
int depthTexture = pushConstants.DepthTextureID;
float depth = textures[depthTexture].Sample(mySampler, input.UV).r;
float3 worldPos = WorldPosFromDepth(depth, input.UV, camView.InverseProjection, camView.InverseView);
float3 rayVector = worldPos - startPosition;
float rayLength = length(rayVector);
PSOutput output;
if(rayLength > 1000.0)
{
fog += ComputeVolumetric(globalFragmentPosition, u_Lights[i]) * u_Exponant;
output.oColor0 = float4(0.0f, 0.0f, 0, 0.0f);
return output;
}
FragColor = vec4(fog, 1.0);
//FragColor = vec4(mix(fog, ComputeVolumetric(globalFragmentPosition, u_Lights[0]), 0.9f), 0.01);
//FragColor = vec4(globalFragmentPosition * 10.0, 1.0f);
//FragColor = vec4(globalFragmentPosition.xyz * 100.0, 1.0f);
//FragColor = vec4(worldSpacePosition.x, worldSpacePosition.y, worldSpacePosition.z, 1);
//FragColor = vec4(ComputeVolumetric(globalFragmentPosition, u_Lights[0]), 1.0);
float stepLength = rayLength / pushConstants.StepCount;
float3 rayDirection = rayVector / rayLength;
float3 step = rayDirection * stepLength;
float3 accumFog = float3(0, 0, 0);
float3 currentPosition = startPosition;
for(int i = 0; i < pushConstants.StepCount; i++)
{
for(int l = 0; l < pushConstants.LightCount; l++)
{
Light light = lights[l];
if(light.type == 0)
{
CameraView lightView = cameras[light.transformId[0]];
float4 fragPosLightSpace = mul(lightView.Projection, mul(lightView.View, float4(currentPosition, 1.0)));
float3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
projCoords.xy = projCoords.xy * 0.5 + 0.5;
float currentDepth = projCoords.z;
float closestDepth = textures[light.shadowMapTextureId[0]].Sample(mySampler, projCoords.xy).r;
float3 noiseOffset = float3(pushConstants.NoiseSpeed * pushConstants.Time, pushConstants.NoiseSpeed * pushConstants.Time, pushConstants.NoiseSpeed * pushConstants.Time);
float3 noiseSamplePos = (currentPosition + noiseOffset) * pushConstants.NoiseScale;
if(closestDepth < currentDepth)
{
accumFog += (ComputeScattering(dot(rayDirection, light.direction)).rrr * light.color.xyz) * pushConstants.Exponant * ((snoise(noiseSamplePos.xyz) + 1.0) / 2.0);
}
else
{
accumFog += (ComputeScattering(dot(rayDirection, light.direction)).rrr * light.color.xyz) * pushConstants.Ambient * ((snoise(noiseSamplePos.xyz) + 1.0) / 2.0);
}
}
else if(light.type == 1)
{
float3 lightToFrag = currentPosition - light.position;
float distance = length(lightToFrag);
float3 lightDir = normalize(-lightToFrag);
float attenuation = 1.0 / (distance * distance);
attenuation = 1.0 - smoothstep(0.0, 3.0f, distance);
float3 noiseOffset = float3(pushConstants.NoiseSpeed * pushConstants.Time, pushConstants.NoiseSpeed * pushConstants.Time, pushConstants.NoiseSpeed * pushConstants.Time);
float3 noiseSamplePos = (currentPosition + noiseOffset) * pushConstants.NoiseScale;
float lightScatter = (snoise(noiseSamplePos.xyz) + 1.0) * 0.5;
float3 scatterTerm = ComputeScattering(dot(rayDirection, lightDir)).rrr * light.color.xyz;
accumFog += scatterTerm * lightScatter * pushConstants.Exponant * attenuation;
}
else if(light.type == 2)
{
float3 lightToFrag = currentPosition - light.position;
float distance = length(lightToFrag);
float3 lightDir = normalize(-lightToFrag);
float attenuation = 1.0 / (distance * distance);
attenuation = 1.0 - smoothstep(0.0, 6.0f, distance);
float3 noiseOffset = float3(pushConstants.NoiseSpeed * pushConstants.Time, pushConstants.NoiseSpeed * pushConstants.Time, pushConstants.NoiseSpeed * pushConstants.Time);
float3 noiseSamplePos = (currentPosition + noiseOffset) * pushConstants.NoiseScale;
float lightScatter = (snoise(noiseSamplePos.xyz) + 1.0) * 0.5;
float theta = dot(lightDir, normalize(-light.direction));
float epsilon = light.innerConeAngle - light.outerConeAngle;
float intensity = clamp((theta - light.outerConeAngle) / epsilon, 0.0, 1.0);
float3 scatterTerm = ComputeScattering(dot(rayDirection, lightDir)).rrr * light.color.xyz;
accumFog += scatterTerm * lightScatter * pushConstants.Exponant * attenuation * intensity;
}
}
currentPosition += step ;
}
accumFog /= pushConstants.StepCount;
output.oColor0 = float4(accumFog.x, accumFog.y, accumFog.z, 1.0f);
return output;
}

View File

@@ -6,12 +6,268 @@
#include <imgui/imgui.h>
#include <imgui/imgui_internal.h>
#include <Nuake/Scene/Components/CameraComponent.h>
#include "Nuake/Rendering/Vulkan/SceneViewport.h"
#include "Nuake/Scene/Entities/Entity.h"
#include <Nuake/Scene/Components/ModelComponent.h>
#include <Engine.h>
#include "Nuake/Rendering/Vulkan/DebugCmd.h"
#include "Nuake/Resource/Project.h"
#include <Nuake/UI/ImUI.h>
Ref<Nuake::Model> sphereModel;
Ref<Nuake::Model> quadModel;
Ref<Nuake::Model> cubeModel;
enum class Shapes
{
Sphere, Cube, Quad
};
Shapes currentShape = Shapes::Sphere;
MaterialEditor::MaterialEditor()
{
using namespace Nuake;
PreviewScene = CreateRef<Nuake::Scene>();
PreviewScene->GetEnvironment()->mVolumetric->SetFogAmount(1.0f);
auto camera = PreviewScene->CreateEntity("Camera");
camera.GetComponent<Nuake::TransformComponent>().Translation = Nuake::Vector3(-2, 0, -2);
auto& camComponent = camera.AddComponent<Nuake::CameraComponent>();
camComponent.CameraInstance->Fov = 44.0f;
//auto light = PreviewScene->CreateEntity("Light");
//auto& lightC = light.AddComponent<LightComponent>();
//lightC.CastShadows = false;
//lightC.Type = LightType::Directional;
glm::vec3 forward = glm::normalize(Vector3(0, 1, 0));
glm::vec3 up = glm::vec3(0, 1, 0);
// Prevent up being colinear with forward
if (glm::abs(glm::dot(forward, up)) > 0.999f)
up = glm::vec3(1, 0, 0);
glm::vec3 right = glm::normalize(glm::cross(up, forward));
up = glm::cross(forward, right);
glm::mat3 rotationMatrix(right, up, forward);
//auto& lightT = light.GetComponent<TransformComponent>();
//lightT.GlobalRotation = glm::quat_cast(rotationMatrix);
auto sphere = PreviewScene->CreateEntity("Sphere");
auto& modelComponent = sphere.AddComponent<Nuake::ModelComponent>();
auto& sphereT = sphere.GetComponent<TransformComponent>();
sphereT.Translation = { 1, 0, 0 };
const std::vector<Nuake::Vertex> quadVertices
{
{ Vector3(-0.5f, 0.5f, 0.0f), 0.0f, Vector3(0, 0, 1), 1.0f, Vector4(1, 0, 0, 0), Vector4(0, 1, 0, 0) },
{ Vector3(0.5f, 0.5f, 0.0f), 1.0f, Vector3(0, 0, 1), 1.0f, Vector4(1, 0, 0, 0), Vector4(0, 1, 0, 0) },
{ Vector3(-0.5f, -0.5f, 0.0f), 0.0f, Vector3(0, 0, 1), 0.0f, Vector4(1, 0, 0, 0), Vector4(0, 1, 0, 0) },
{ Vector3(0.5f, -0.5f, 0.0f), 1.0f, Vector3(0, 0, 1), 0.0f, Vector4(1, 0, 0, 0), Vector4(0, 1, 0, 0) },
{ Vector3(-0.5f, -0.5f, 0.0f), 0.0f, Vector3(0, 0, 1), 0.0f, Vector4(1, 0, 0, 0), Vector4(0, 1, 0, 0) },
{ Vector3(0.5f, 0.5f, 0.0f), 1.0f, Vector3(0, 0, 1), 1.0f, Vector4(1, 0, 0, 0), Vector4(0, 1, 0, 0) }
};
const std::vector<uint32_t> quadIndices
{
5, 4, 3, 2, 1, 0
};
auto meshQuad = CreateRef<Mesh>();
meshQuad->AddSurface(quadVertices, quadIndices);
quadModel = CreateRef<Model>();
quadModel->AddMesh(meshQuad);
ResourceManager::RegisterResource(quadModel);
// Sphere
const int sectorCount = 32;
const int stackCount = 16;
const float radius = 0.5f;
std::vector<Nuake::Vertex> sphereVertices;
std::vector<uint32_t> sphereIndices;
for (int i = 0; i <= stackCount; ++i)
{
float stackAngle = glm::pi<float>() / 2 - i * glm::pi<float>() / stackCount;
float xy = radius * cosf(stackAngle);
float z = radius * sinf(stackAngle);
for (int j = 0; j <= sectorCount; ++j)
{
float sectorAngle = j * 2.0f * glm::pi<float>() / sectorCount;
float x = xy * cosf(sectorAngle);
float y = xy * sinf(sectorAngle);
Vector3 position = Vector3(x, y, z);
Vector3 normal = glm::normalize(position);
// Collapse seam at the poles
float u = (i == 0 || i == stackCount) ? 0.5f : (float)j / sectorCount;
float v = 1.0f - (float)i / stackCount;
Vector4 tangent = Vector4(1, 0, 0, 0);
Vector4 bitangent = Vector4(0, 1, 0, 0);
sphereVertices.push_back({ position, u, normal, v, tangent, bitangent });
}
}
for (int i = 0; i < stackCount; ++i)
{
int k1 = i * (sectorCount + 1);
int k2 = k1 + sectorCount + 1;
for (int j = 0; j < sectorCount; ++j, ++k1, ++k2)
{
if (i != 0)
{
sphereIndices.push_back(k1);
sphereIndices.push_back(k2);
sphereIndices.push_back(k1 + 1);
}
if (i != (stackCount - 1))
{
sphereIndices.push_back(k1 + 1);
sphereIndices.push_back(k2);
sphereIndices.push_back(k2 + 1);
}
}
}
auto mesh = CreateRef<Mesh>();
mesh->AddSurface(sphereVertices, sphereIndices);
sphereModel = CreateRef<Model>();
sphereModel->AddMesh(mesh);
ResourceManager::RegisterResource(sphereModel);
modelComponent.ModelResource = sphereModel->ID;
const float boxSize = 0.33f;
const std::vector<Nuake::Vertex> boxVertices =
{
// Front face
{ Vector3(-boxSize, -boxSize, boxSize), 0.0f, Vector3(0, 0, 1), 0.0f, Vector4(1, 0, 0, 0), Vector4(0, 1, 0, 0) },
{ Vector3(boxSize, -boxSize, boxSize), 1.0f, Vector3(0, 0, 1), 0.0f, Vector4(1, 0, 0, 0), Vector4(0, 1, 0, 0) },
{ Vector3(boxSize, boxSize, boxSize), 1.0f, Vector3(0, 0, 1), 1.0f, Vector4(1, 0, 0, 0), Vector4(0, 1, 0, 0) },
{ Vector3(-boxSize, boxSize, boxSize), 0.0f, Vector3(0, 0, 1), 1.0f, Vector4(1, 0, 0, 0), Vector4(0, 1, 0, 0) },
// Back face
{ Vector3(-boxSize, -boxSize, -boxSize), 1.0f, Vector3(0, 0, -1), 0.0f, Vector4(-1, 0, 0, 0), Vector4(0, 1, 0, 0) },
{ Vector3(-boxSize, boxSize, -boxSize), 1.0f, Vector3(0, 0, -1), 1.0f, Vector4(-1, 0, 0, 0), Vector4(0, 1, 0, 0) },
{ Vector3(boxSize, boxSize, -boxSize), 0.0f, Vector3(0, 0, -1), 1.0f, Vector4(-1, 0, 0, 0), Vector4(0, 1, 0, 0) },
{ Vector3(boxSize, -boxSize, -boxSize), 0.0f, Vector3(0, 0, -1), 0.0f, Vector4(-1, 0, 0, 0), Vector4(0, 1, 0, 0) },
// Left face
{ Vector3(-boxSize, -boxSize, -boxSize), 0.0f, Vector3(-1, 0, 0), 0.0f, Vector4(0, 0, 1, 0), Vector4(0, 1, 0, 0) },
{ Vector3(-boxSize, -boxSize, boxSize), 1.0f, Vector3(-1, 0, 0), 0.0f, Vector4(0, 0, 1, 0), Vector4(0, 1, 0, 0) },
{ Vector3(-boxSize, boxSize, boxSize), 1.0f, Vector3(-1, 0, 0), 1.0f, Vector4(0, 0, 1, 0), Vector4(0, 1, 0, 0) },
{ Vector3(-boxSize, boxSize, -boxSize), 0.0f, Vector3(-1, 0, 0), 1.0f, Vector4(0, 0, 1, 0), Vector4(0, 1, 0, 0) },
// Right face
{ Vector3(boxSize, -boxSize, -boxSize), 1.0f, Vector3(1, 0, 0), 0.0f, Vector4(0, 0, -1, 0), Vector4(0, 1, 0, 0) },
{ Vector3(boxSize, boxSize, -boxSize), 1.0f, Vector3(1, 0, 0), 1.0f, Vector4(0, 0, -1, 0), Vector4(0, 1, 0, 0) },
{ Vector3(boxSize, boxSize, boxSize), 0.0f, Vector3(1, 0, 0), 1.0f, Vector4(0, 0, -1, 0), Vector4(0, 1, 0, 0) },
{ Vector3(boxSize, -boxSize, boxSize), 0.0f, Vector3(1, 0, 0), 0.0f, Vector4(0, 0, -1, 0), Vector4(0, 1, 0, 0) },
// Top face
{ Vector3(-boxSize, boxSize, -boxSize), 0.0f, Vector3(0, 1, 0), 0.0f, Vector4(1, 0, 0, 0), Vector4(0, 0, -1, 0) },
{ Vector3(-boxSize, boxSize, boxSize), 0.0f, Vector3(0, 1, 0), 1.0f, Vector4(1, 0, 0, 0), Vector4(0, 0, -1, 0) },
{ Vector3(boxSize, boxSize, boxSize), 1.0f, Vector3(0, 1, 0), 1.0f, Vector4(1, 0, 0, 0), Vector4(0, 0, -1, 0) },
{ Vector3(boxSize, boxSize, -boxSize), 1.0f, Vector3(0, 1, 0), 0.0f, Vector4(1, 0, 0, 0), Vector4(0, 0, -1, 0) },
// Bottom face
{ Vector3(-boxSize, -boxSize, -boxSize), 1.0f, Vector3(0, -1, 0), 0.0f, Vector4(1, 0, 0, 0), Vector4(0, 0, 1, 0) },
{ Vector3(boxSize, -boxSize, -boxSize), 0.0f, Vector3(0, -1, 0), 0.0f, Vector4(1, 0, 0, 0), Vector4(0, 0, 1, 0) },
{ Vector3(boxSize, -boxSize, boxSize), 0.0f, Vector3(0, -1, 0), 1.0f, Vector4(1, 0, 0, 0), Vector4(0, 0, 1, 0) },
{ Vector3(-boxSize, -boxSize, boxSize), 1.0f, Vector3(0, -1, 0), 1.0f, Vector4(1, 0, 0, 0), Vector4(0, 0, 1, 0) },
};
const std::vector<uint32_t> boxIndices =
{
// Front
0, 1, 2, 2, 3, 0,
// Back
4, 5, 6, 6, 7, 4,
// Left
8, 9,10,10,11, 8,
// Right
12,13,14,14,15,12,
// Top
16,17,18,18,19,16,
// Bottom
20,21,22,22,23,20
};
auto meshBox = CreateRef<Mesh>();
meshBox->AddSurface(boxVertices, boxIndices);
cubeModel = CreateRef<Model>();
cubeModel->AddMesh(meshBox);
ResourceManager::RegisterResource(cubeModel);
modelComponent.ModelResource = cubeModel->ID;
auto& vkRenderer = Nuake::VkRenderer::Get();
const UUID viewId = camComponent.CameraInstance->ID;
SceneViewport = vkRenderer.CreateViewport(viewId, {200, 200});
SceneViewport->GetOnDebugDraw().AddStatic([](DebugCmd& cmd) {
Matrix4 transform = Matrix4(1.0f);
//cmd.DrawQuad(transform);
});
SceneViewport->GetOnLineDraw().AddStatic([](DebugLineCmd& cmd) {
Matrix4 transform = Matrix4(1.0f);
auto cam = cmd.GetScene()->GetEntity("Camera");
auto& camc = cam.GetComponent<CameraComponent>();
auto& cami = camc.CameraInstance;
auto proj = cami->GetPerspective();
auto view = cami->GetTransform();
//cmd.DrawSphere(proj * view * transform, { 1, 0, 0, 1 }, 2.0f, false);
});
//PreviewScene->GetEnvironment()->AmbientColor = { 0, 0, 0, 0 };
vkRenderer.RegisterSceneViewport(PreviewScene, SceneViewport->GetID());
}
void MaterialEditor::Draw(Ref<Nuake::Material> material)
{
using namespace Nuake;
auto& t = PreviewScene->GetEntity("Camera").GetComponent<CameraComponent>();
auto ent = PreviewScene->GetEntity("Sphere");
RID shape;
switch (currentShape)
{
case Shapes::Quad:
{
shape = quadModel->ID;
break;
}
case Shapes::Sphere:
{
shape = sphereModel->ID;
break;
}
case Shapes::Cube:
{
shape = cubeModel->ID;
break;
}
}
shape.Get<Model>()->GetMeshes()[0]->SetMaterial(material);
ent.GetComponent<ModelComponent>().ModelResource = shape;
auto& cam = Engine::GetCurrentScene()->m_EditorCamera;
std::string materialTitle = material->Path;
{
UIFont boldfont = UIFont(Fonts::SubTitle);
@@ -36,6 +292,130 @@ void MaterialEditor::Draw(Ref<Nuake::Material> material)
}
}
ImVec2 previewSize = {ImGui::GetContentRegionAvail().x, 200 };
Vector2 viewportPanelSize = glm::vec2(previewSize.x, previewSize.y);
static float yaw = 0.0f; // Horizontal angle in radians
static float pitch = 0.0f; // Vertical angle in radians
static float actualYaw = 0.0f;
static float actualPitch = 0.0f;
static Vector3 actualPos = { 0, 0, 0 };
static float distance = 1.5f; // Distance from origin
const float yawSpeed = 0.01f;
const float pitchSpeed = 0.01f;
static Vector3 camPosition = Vector3(1.5, 0, 0);
t.CameraInstance->OnWindowResize(previewSize.x, previewSize.y);
SceneViewport->QueueResize({ previewSize.x, previewSize.y });
ImGui::BeginChild("MaterialPreview", previewSize);
{
auto cursorPos = ImGui::GetCursorPos();
if (ImGui::BeginPopup("shapes_popup"))
{
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 2));
ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(0, 0, 0, 0));
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 100);
bool isActive = currentShape == Shapes::Sphere;
if (isActive)
{
Color color = Engine::GetProject()->Settings.PrimaryColor;
ImGui::PushStyleColor(ImGuiCol_Button, { color.r, color.g, color.b, 1.0f });
}
if (ImGui::Button((std::string(ICON_FA_CIRCLE) + " Sphere").c_str()))
{
currentShape = Shapes::Sphere;
}
Nuake::UI::Tooltip("Sphere");
if (isActive)
{
ImGui::PopStyleColor();
}
isActive = currentShape == Shapes::Cube;
if (isActive)
{
Color color = Engine::GetProject()->Settings.PrimaryColor;
ImGui::PushStyleColor(ImGuiCol_Button, { color.r, color.g, color.b, 1.0f });
}
if (ImGui::Button((std::string(ICON_FA_CUBE) + " Cube").c_str()))
{
currentShape = Shapes::Cube;
}
UI::Tooltip("Cube");
if (isActive)
{
ImGui::PopStyleColor();
}
isActive = currentShape == Shapes::Quad;
if (isActive)
{
Color color = Engine::GetProject()->Settings.PrimaryColor;
ImGui::PushStyleColor(ImGuiCol_Button, { color.r, color.g, color.b, 1.0f });
}
if (ImGui::Button((std::string(ICON_FA_SQUARE) + " Plane").c_str()))
{
currentShape = Shapes::Quad;
}
UI::Tooltip("Plane");
if (isActive)
{
ImGui::PopStyleColor();
}
ImGui::PopStyleColor();
ImGui::PopStyleVar(2);
ImGui::EndPopup();
}
if (ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) && ImGui::IsMouseDragging(ImGuiMouseButton_Left))
{
ImVec2 delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Left);
yaw -= delta.x * yawSpeed;
pitch += delta.y * pitchSpeed;
// Clamp pitch to prevent flipping
pitch = std::clamp(pitch, -glm::half_pi<float>() + 0.01f, glm::half_pi<float>() - 0.01f);
ImGui::ResetMouseDragDelta(ImGuiMouseButton_Left); // Prevents accumulating deltas
}
VkDescriptorSet textureDesc = SceneViewport->GetRenderTarget()->GetImGuiDescriptorSet();
ImGui::Image(textureDesc, ImGui::GetContentRegionAvail(), {0, 1}, {1, 0});
ImGui::SetCursorPos(cursorPos);
if (ImGui::Button(ICON_FA_SHAPES, ImVec2(30, 28)))
{
ImGui::OpenPopup("shapes_popup");
}
UI::Tooltip("Preview Shape");
}
ImGui::EndChild();
actualYaw = glm::mix(actualYaw, yaw, 20.0f * Engine::GetTimestep());
actualPitch = glm::mix(actualPitch, pitch, 20.0f * Engine::GetTimestep());
camPosition.x = distance * cosf(actualPitch) * sinf(actualYaw);
camPosition.y = distance * sinf(actualPitch);
camPosition.z = distance * cosf(actualPitch) * cosf(actualYaw);
actualPos = glm::mix(actualPos, camPosition, 20.0f * Engine::GetTimestep());
Vector3 target = Vector3(0, 0, 0);
Vector3 direction = glm::normalize(target - camPosition);
t.CameraInstance->Translation = { camPosition };
t.CameraInstance->SetDirection(direction);
bool flagsHeaderOpened;
{
UIFont boldfont = UIFont(Fonts::Bold);
@@ -87,79 +467,141 @@ void MaterialEditor::Draw(Ref<Nuake::Material> material)
if (AlbedoOpened)
{
ImGui::BeginChild("##albedo", TexturePanelSize, true);
ImGui::BeginTable("##Flags", 3, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingStretchProp);
{
ImTextureID textureID = 0;
if (material->HasAlbedo())
ImGui::TableSetupColumn("name", 0, 0.3f);
ImGui::TableSetupColumn("set", 0, 0.6f);
ImGui::TableSetupColumn("reset", 0, 0.1f);
ImGui::TableNextColumn();
{
auto vkTexture = GPUResources::Get().GetTexture(material->AlbedoImage);
textureID = (ImTextureID)vkTexture->GetImGuiDescriptorSet();
ImGui::Text("Color");
ImGui::TableNextColumn();
Vector3 materialColor = material->data.m_AlbedoColor;
ImVec4 color = { materialColor.r, materialColor.g, materialColor.b, 1.0 };
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
ImGui::ColorEdit3("##materialAlbedoColor", &material->data.m_AlbedoColor.r, ImGuiColorEditFlags_NoInputs);
ImGui::PopItemWidth();
ImGui::TableNextColumn();
// Reset
ImGui::TableNextColumn();
}
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image1"), (ImTextureID)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, 1)))
{
std::string texture = FileDialog::OpenFile("*.png | *.jpg");
if (texture != "")
ImGui::Text("Texture");
ImGui::TableNextColumn();
ImTextureID textureID = 0;
if (material->HasAlbedo())
{
material->SetAlbedo(TextureManager::Get()->GetTexture(texture));
}
}
auto vkTexture = GPUResources::Get().GetTexture(material->AlbedoImage);
if (ImGui::BeginPopupContextWindow())
{
if (ImGui::MenuItem("Clear Texture"))
textureID = (ImTextureID)vkTexture->GetImGuiDescriptorSet();
}
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image1"), (ImTextureID)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, 1)))
{
material->m_Albedo = nullptr;
std::string texture = FileDialog::OpenFile("*.png | *.jpg");
if (texture != "")
{
material->SetAlbedo(TextureManager::Get()->GetTexture(texture));
}
}
ImGui::EndPopup();
}
ImGui::SameLine();
ImGui::ColorEdit3("Color", &material->data.m_AlbedoColor.r);
if (ImGui::BeginPopupContextWindow())
{
if (ImGui::MenuItem("Clear Texture"))
{
material->m_Albedo = nullptr;
}
ImGui::EndPopup();
}
ImGui::TableNextColumn();
// Reset
}
}
ImGui::EndChild();
ImGui::EndTable();
}
if (ImGui::CollapsingHeader("Normal", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::BeginChild("##normal", TexturePanelSize, true);
ImGui::BeginTable("##Flags", 3, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingStretchProp);
{
uint32_t textureID = 0;
if (material->HasNormal())
ImGui::TableSetupColumn("name", 0, 0.3f);
ImGui::TableSetupColumn("set", 0, 0.6f);
ImGui::TableSetupColumn("reset", 0, 0.1f);
ImGui::TableNextColumn();
static bool normalEnabled = true;
{
textureID = material->m_Normal->GetID();
ImGui::Text("Enabled");
ImGui::TableNextColumn();
ImGui::Checkbox("##normalEnabled", &normalEnabled);
ImGui::TableNextColumn();
// Reset
ImGui::TableNextColumn();
}
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image3"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(0, 0, 0, 1), ImVec4(1, 1, 1, 1)))
if (!normalEnabled)
{
std::string texture = FileDialog::OpenFile("*.png | *.jpg");
if (texture != "")
ImGui::BeginDisabled();
}
{
ImGui::Text("Texture");
ImGui::TableNextColumn();
ImTextureID textureID = 0;
if (material->HasNormal())
{
material->SetNormal(TextureManager::Get()->GetTexture(texture));
auto vkTexture = GPUResources::Get().GetTexture(material->NormalImage);
textureID = (ImTextureID)vkTexture->GetImGuiDescriptorSet();
}
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image3"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(0, 0, 0, 1), ImVec4(1, 1, 1, 1)))
{
std::string texture = FileDialog::OpenFile("*.png | *.jpg");
if (texture != "")
{
material->SetNormal(TextureManager::Get()->GetTexture(texture));
}
}
if (ImGui::BeginPopupContextWindow())
{
if (ImGui::MenuItem("Clear Texture"))
{
material->m_Normal = nullptr;
}
ImGui::EndPopup();
}
}
if (ImGui::BeginPopupContextWindow())
if (!normalEnabled)
{
if (ImGui::MenuItem("Clear Texture"))
{
material->m_Normal = nullptr;
}
ImGui::EndPopup();
ImGui::EndDisabled();
}
}
ImGui::EndChild();
ImGui::EndTable();
}
if (ImGui::CollapsingHeader("AO", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::BeginChild("##ao", TexturePanelSize, true);
{
uint32_t textureID = 0;
ImTextureID textureID = 0;
if (material->HasAO())
{
textureID = material->m_AO->GetID();
auto vkTexture = GPUResources::Get().GetTexture(material->AOImage);
textureID = (ImTextureID)vkTexture->GetImGuiDescriptorSet();
}
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image2"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(1, 1, 1, 1), ImVec4(1, 1, 1, 1)))
@@ -190,10 +632,11 @@ void MaterialEditor::Draw(Ref<Nuake::Material> material)
{
ImGui::BeginChild("##metalness", TexturePanelSize, true);
{
uint32_t textureID = 0;
ImTextureID textureID = 0;
if (material->HasMetalness())
{
textureID = material->m_Metalness->GetID();
auto vkTexture = GPUResources::Get().GetTexture(material->MetalnessImage);
textureID = (ImTextureID)vkTexture->GetImGuiDescriptorSet();
}
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image4"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(0, 0, 0, 1), ImVec4(1, 1, 1, 1)))
@@ -224,10 +667,11 @@ void MaterialEditor::Draw(Ref<Nuake::Material> material)
{
ImGui::BeginChild("##roughness", TexturePanelSize, true);
{
uint32_t textureID = 0;
ImTextureID textureID = 0;
if (material->HasRoughness())
{
textureID = material->m_Roughness->GetID();
auto vkTexture = GPUResources::Get().GetTexture(material->RoughnessImage);
textureID = (ImTextureID)vkTexture->GetImGuiDescriptorSet();
}
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image5"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, 1)))

View File

@@ -1,11 +1,16 @@
#pragma once
#include <Nuake/Core/Core.h>
#include <Nuake/Rendering/Textures/Material.h>
#include <Nuake/Scene/Scene.h>
#include "Nuake/Rendering/Vulkan/SceneViewport.h"
class MaterialEditor
{
private:
Ref<Nuake::Scene> PreviewScene;
Ref<Nuake::Viewport> SceneViewport;
public:
MaterialEditor() = default;
MaterialEditor();
~MaterialEditor() = default;
void Draw(Ref<Nuake::Material> material);

View File

@@ -5,6 +5,7 @@
ModelResourceInspector::ModelResourceInspector(Ref<Nuake::Model> model)
{
_model = model;
}
void ModelResourceInspector::Draw()
@@ -19,7 +20,7 @@ void ModelResourceInspector::Draw()
std::string childId = "materialEditor" + std::to_string(i);
ImGui::BeginChild(childId.c_str(), ImVec2(0, 0), false);
{
MaterialEditor editor;
static MaterialEditor editor;
editor.Draw(_model->GetMeshes().at(i)->GetMaterial());
}
ImGui::EndChild();

View File

@@ -10,6 +10,7 @@
#include <Nuake/UI/ImUI.h>
#include "../../../Misc/InterfaceFonts.h"
#include <Nuake/Resource/Bakers/AssetBakerManager.h>
using namespace Nuake;
@@ -269,7 +270,7 @@ void FileBrowserWidget::Draw()
{
if (searchQuery.empty() || f->GetName().find(String::Sanitize(searchQuery)) != std::string::npos)
{
if (f->GetFileType() == FileType::Unknown || f->GetFileType() == FileType::Assembly)
if ((f->GetFileType() == FileType::Unknown && !AssetBakerManager::Get().IsBakable(f)) || f->GetFileType() == FileType::Assembly)
{
continue;
}
@@ -781,6 +782,14 @@ void FileBrowserWidget::DrawFile(Ref<Nuake::File> file, uint32_t drawId)
shouldOpenScene = true;
}
}
if (AssetBakerManager::Get().IsBakable(file))
{
if (ImGui::MenuItem("Rebake"))
{
AssetBakerManager::Get().OnNewAssetDetected(file);
}
}
ImGui::Separator();

View File

@@ -3,7 +3,6 @@
#include "Nuake/Scene/Components.h"
#include "Nuake/UI/ImUI.h"
#include "../../../ComponentsPanel/MaterialEditor.h"
#include <Nuake/Resource/SkyResource.h>
#include <Nuake/FileSystem/FileDialog.h>
@@ -238,7 +237,6 @@ void SelectionPropertyWidget::DrawFile(Ref<Nuake::File> file)
{
case FileType::Material:
{
MaterialEditor matEditor;
matEditor.Draw(std::static_pointer_cast<Material>(selectedResource));
break;
}
@@ -1665,14 +1663,14 @@ void SelectionPropertyWidget::DrawMaterialPanel(Ref<Nuake::Material> material)
ImGui::EndChild();
}
if (ImGui::CollapsingHeader("Normal", ImGuiTreeNodeFlags_DefaultOpen))
if (ImGui::CollapsingHeader("Normal", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::BeginChild("##normal", TexturePanelSize, true);
{
uint32_t textureID = 0;
if (material->HasNormal())
{
textureID = material->m_Normal->GetID();
textureID = material->m_Normal->GetID();
}
if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image3"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(0, 0, 0, 1), ImVec4(1, 1, 1, 1)))

View File

@@ -3,6 +3,7 @@
#include "../../EditorSelectionPanel.h"
#include "../../../misc/AnimatedValue.h"
#include "../../../ComponentsPanel/MaterialEditor.h"
class EditorContext;
@@ -12,6 +13,7 @@ using DrawFieldTypeFn = std::function<void(entt::meta_data& fieldMeta, entt::met
class SelectionPropertyWidget : public IEditorWidget
{
private:
MaterialEditor matEditor;
TransformPanel transformPanel;
MeshPanel meshPanel;
SkinnedMeshPanel skinnedMeshPanel;

View File

@@ -35,10 +35,7 @@ Ref<File> GLTFBaker::Bake(const Ref<File>& file)
const std::string absolutePath = file->GetAbsolutePath();
auto importFlags =
aiProcess_Triangulate |
aiProcess_GenSmoothNormals |
aiProcess_FixInfacingNormals |
aiProcess_CalcTangentSpace;
aiProcessPreset_TargetRealtime_Fast;
const aiScene* scene = importer.ReadFile(absolutePath, importFlags);
if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) // Assimp failed
@@ -88,22 +85,22 @@ Ref<File> GLTFBaker::Bake(const Ref<File>& file)
if (!materialData.normal.empty())
{
material->SetNormal(absolutePath + "/../" + materialData.normal);
material->SetNormal(FileSystem::AbsoluteToRelative(absolutePath + "/../" + materialData.normal));
}
if (!materialData.ao.empty())
{
material->SetAO(absolutePath + "/../" + materialData.ao);
material->SetAO(FileSystem::AbsoluteToRelative(absolutePath + "/../" + materialData.ao));
}
if (!materialData.metallic.empty())
{
material->SetMetalness(absolutePath + "/../" + materialData.metallic);
material->SetMetalness(FileSystem::AbsoluteToRelative(absolutePath + "/../" + materialData.metallic));
}
if (!materialData.roughness.empty())
{
material->SetRoughness(absolutePath + "/../" + materialData.roughness);
material->SetRoughness(FileSystem::AbsoluteToRelative(absolutePath + "/../" + materialData.roughness));
}
ResourceManager::RegisterResource(material);

View File

@@ -161,22 +161,72 @@ namespace Nuake
void Material::SetAO(const std::string ao)
{
if (FileSystem::FileExists(ao))
{
GPUResources& resources = GPUResources::Get();
Ref<VulkanImage> image = CreateRef<VulkanImage>(FileSystem::RelativeToAbsolute(ao));
if (resources.AddTexture(image))
{
AOImage = image->GetID();
}
Ref<Texture> aoTexture = TextureManager::Get()->GetTexture(FileSystem::RelativeToAbsolute(ao));
SetAO(aoTexture);
}
m_AO = CreateRef<Texture>(ao);
}
void Material::SetMetalness(const std::string metalness)
{
if (FileSystem::FileExists(metalness))
{
GPUResources& resources = GPUResources::Get();
Ref<VulkanImage> image = CreateRef<VulkanImage>(FileSystem::RelativeToAbsolute(metalness));
if (resources.AddTexture(image))
{
MetalnessImage = image->GetID();
}
Ref<Texture> aoTexture = TextureManager::Get()->GetTexture(FileSystem::RelativeToAbsolute(metalness));
SetMetalness(aoTexture);
}
m_Metalness = CreateRef<Texture>(metalness);
}
void Material::SetRoughness(const std::string roughness)
{
if (FileSystem::FileExists(roughness))
{
GPUResources& resources = GPUResources::Get();
Ref<VulkanImage> image = CreateRef<VulkanImage>(FileSystem::RelativeToAbsolute(roughness));
if (resources.AddTexture(image))
{
RoughnessImage = image->GetID();
}
Ref<Texture> aoTexture = TextureManager::Get()->GetTexture(FileSystem::RelativeToAbsolute(roughness));
SetRoughness(aoTexture);
}
m_Roughness = CreateRef<Texture>(roughness);
}
void Material::SetNormal(const std::string normal)
{
m_Normal = CreateRef<Texture>(normal);
if (FileSystem::FileExists(normal))
{
GPUResources& resources = GPUResources::Get();
Ref<VulkanImage> image = CreateRef<VulkanImage>(FileSystem::RelativeToAbsolute(normal));
if (resources.AddTexture(image))
{
NormalImage = image->GetID();
}
Ref<Texture> aoTexture = TextureManager::Get()->GetTexture(FileSystem::RelativeToAbsolute(normal));
SetNormal(aoTexture);
}
}
void Material::SetDisplacement(const std::string displacement)

View File

@@ -117,19 +117,19 @@ namespace Nuake
}
void SetAlbedo(Ref<Texture> texture) { m_Albedo = texture; }
bool HasAO() { return m_AO != nullptr; }
bool HasAO() { return (m_AO != nullptr || AOImage != UUID(0)); }
void SetAO(const std::string albedo);
void SetAO(Ref<Texture> texture) { m_AO = texture; }
bool HasMetalness() { return m_Metalness != nullptr; }
bool HasMetalness() { return (m_Metalness != nullptr || MetalnessImage != UUID(0)); }
void SetMetalness(const std::string albedo);
void SetMetalness(Ref<Texture> texture) { m_Metalness = texture; }
bool HasRoughness() { return m_Roughness != nullptr; }
bool HasRoughness() { return (m_Roughness != nullptr || RoughnessImage != UUID(0)); }
void SetRoughness(const std::string albedo);
void SetRoughness(Ref<Texture> texture) { m_Roughness = texture; }
bool HasNormal() { return m_Normal != nullptr; }
bool HasNormal() { return (m_Normal != nullptr || NormalImage != UUID(0)); }
void SetNormal(const std::string albedo);
void SetNormal(Ref<Texture> texture) { m_Normal = texture; }
@@ -176,6 +176,7 @@ namespace Nuake
{
j["Albedo"] = this->m_Albedo->Serialize();
}
Vector3 AlbedoColor = data.m_AlbedoColor;
SERIALIZE_VEC3(AlbedoColor);
@@ -328,6 +329,7 @@ namespace Nuake
{
const auto& texturePath = j["AO"]["Path"];
const std::string absolutePath = FileSystem::RelativeToAbsolute(texturePath);
if (FileSystem::FileExists(texturePath))
{
GPUResources& resources = GPUResources::Get();
@@ -336,46 +338,66 @@ namespace Nuake
{
AOImage = image->GetID();
}
}
Ref<Texture> aoTexture = TextureManager::Get()->GetTexture(absolutePath);
SetAO(aoTexture);
Ref<Texture> normalTexture = TextureManager::Get()->GetTexture(absolutePath);
SetAO(normalTexture);
}
else
{
GPUResources& resources = GPUResources::Get();
Ref<VulkanImage> missingTexture = TextureManager::Get()->GetTexture2("missing_texture");
AOImage = missingTexture->GetID();
}
}
if (j.contains("Metalness"))
{
const auto& texturePath = j["Metalness"]["Path"];
const std::string absolutePath = FileSystem::RelativeToAbsolute(texturePath);
if (FileSystem::FileExists(texturePath))
{
GPUResources& resources = GPUResources::Get();
Ref<VulkanImage> image = CreateRef<VulkanImage>(absolutePath);
if (resources.AddTexture(image))
{
MetalnessImage = image->GetID();
AOImage = image->GetID();
}
}
Ref<Texture> metalTexture = TextureManager::Get()->GetTexture(absolutePath);
SetMetalness(metalTexture);
Ref<Texture> normalTexture = TextureManager::Get()->GetTexture(absolutePath);
SetMetalness(normalTexture);
}
else
{
GPUResources& resources = GPUResources::Get();
Ref<VulkanImage> missingTexture = TextureManager::Get()->GetTexture2("missing_texture");
MetalnessImage = missingTexture->GetID();
}
}
if (j.contains("Roughness"))
{
const auto& texturePath = j["Roughness"]["Path"];
const std::string absolutePath = FileSystem::RelativeToAbsolute(texturePath);
if (FileSystem::FileExists(texturePath))
{
GPUResources& resources = GPUResources::Get();
Ref<VulkanImage> image = CreateRef<VulkanImage>(absolutePath);
if (resources.AddTexture(image))
{
RoughnessImage = image->GetID();
AOImage = image->GetID();
}
}
Ref<Texture> metalTexture = TextureManager::Get()->GetTexture(absolutePath);
SetRoughness(metalTexture);
Ref<Texture> normalTexture = TextureManager::Get()->GetTexture(absolutePath);
SetRoughness(normalTexture);
}
else
{
GPUResources& resources = GPUResources::Get();
Ref<VulkanImage> missingTexture = TextureManager::Get()->GetTexture2("missing_texture");
RoughnessImage = missingTexture->GetID();
}
}
if (j.contains("Displacement"))

View File

@@ -17,6 +17,7 @@
#include <Tracy.hpp>
#include "DebugCmd.h"
#include <random>
#include <Nuake/Scene/Components/ParticleEmitterComponent.h>
using namespace Nuake;
@@ -405,6 +406,31 @@ void SceneRenderPipeline::RecreatePipeline()
cmd.DrawIndexed(vkMesh->GetIndexBuffer()->GetSize() / sizeof(uint32_t));
}
}
auto particleView = scene->m_Registry.view<TransformComponent, ParticleEmitterComponent, VisibilityComponent>();
for (auto e : particleView)
{
auto [transform, particle, visibility] = particleView.get<TransformComponent, ParticleEmitterComponent, VisibilityComponent>(e);
if (!visibility.Visible)
continue;
if (particle.resFile.dirty)
{
particle.resFile.dirty = false;
if (particle.resFile.Exist())
{
Ref<Nuake::Material> material = Nuake::ResourceLoader::LoadMaterial(particle.resFile.GetRelativePath());
particle.ParticleMaterial = material;
}
}
if (particle.ParticleMaterial == nullptr)
{
continue;
}
}
});
auto& ssaoPass = GBufferPipeline.AddPass("SSAOPass");
@@ -927,16 +953,7 @@ Ref<VulkanImage> SceneRenderPipeline::ResizeImage(PassRenderContext& ctx, Ref<Vu
// Register to resource manager
GPUResources& gpuResources = GPUResources::Get();
gpuResources.AddTexture(newAttachment);
using CleanUpFunc = std::function<void()>;
using CleanUpStack = std::stack<CleanUpFunc>;
CleanUpStack stack;
stack.push([image]() {
GPUResources& gpuResources = GPUResources::Get();
//gpuResources.RemoveTexture(image);
});
//gpuResources.QueueDeletion(std::move(stack));
gpuResources.RemoveTexture(image);
// We might need to do this?
ctx.commandBuffer.TransitionImageLayout(newAttachment, VK_IMAGE_LAYOUT_GENERAL);

View File

@@ -127,7 +127,7 @@ Ref<VulkanShader> ShaderCompiler::CompileShader(const std::string& path)
Logger::Log("Shader compilation failed: " + errorMsgStr, "DXC", CRITICAL);
throw std::runtime_error("Shader compilation failed: " + errorMsgStr);
throw std::runtime_error("Shader compilation failed: " + errorMsgStr);
}
else
{

View File

@@ -388,6 +388,7 @@ VkDescriptorSet& VulkanImage::GetImGuiDescriptorSet()
sampler_info.minLod = -1000;
sampler_info.maxLod = 1000;
sampler_info.maxAnisotropy = 1.0f;
VK_CALL(vkCreateSampler(VkRenderer::Get().GetDevice(), &sampler_info, nullptr, &Sampler));
// Create Descriptor Set using ImGUI's implementation

View File

@@ -236,6 +236,11 @@ namespace Nuake
return Device;
}
VkPhysicalDevice GetPhysicalDevice() const
{
return GPU;
}
FrameData& GetCurrentFrame()
{
return Frames[FrameNumber % FRAME_OVERLAP];

View File

@@ -170,7 +170,7 @@ Ref<VulkanImage> GPUResources::GetTexture(const UUID& id)
return Images[id];
}
Logger::Log("Mesh with ID does not exist", "vulkan", CRITICAL);
Logger::Log("Texture with ID does not exist", "vulkan", CRITICAL);
return TextureManager::Get()->GetTexture2("missing_texture");
}
@@ -285,13 +285,20 @@ void GPUResources::CreateBindlessLayout()
SSAOKernelDescriptor = allocator.Allocate(device, SSAOKernelDescriptorLayout);
// Samplers
VkPhysicalDeviceProperties properties{};
vkGetPhysicalDeviceProperties(VkRenderer::Get().GetPhysicalDevice(), &properties);
VkSamplerCreateInfo sampler = { .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
sampler.magFilter = VK_FILTER_NEAREST;
sampler.minFilter = VK_FILTER_NEAREST;
sampler.anisotropyEnable = VK_TRUE;
sampler.maxAnisotropy = properties.limits.maxSamplerAnisotropy;
vkCreateSampler(device, &sampler, nullptr, &SamplerNearest);
sampler.magFilter = VK_FILTER_LINEAR;
sampler.minFilter = VK_FILTER_LINEAR;
sampler.anisotropyEnable = VK_TRUE;
sampler.maxAnisotropy = properties.limits.maxSamplerAnisotropy;
vkCreateSampler(device, &sampler, nullptr, &SamplerLinear);
VkDescriptorImageInfo textureInfo = {};

View File

@@ -34,6 +34,11 @@ namespace Nuake
}
}
bool IsBakable(const Ref<File>& file)
{
return Bakers.find(file->GetExtension()) != Bakers.end();
}
void OnAssetReimport(const Ref<File>& file)
{
const std::string extension = file->GetExtension();