diff --git a/Data/Shaders/Vulkan/triangle.frag b/Data/Shaders/Vulkan/triangle.frag index bd774a41..82eac7da 100644 --- a/Data/Shaders/Vulkan/triangle.frag +++ b/Data/Shaders/Vulkan/triangle.frag @@ -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 diff --git a/Data/Shaders/Vulkan/triangle.vert b/Data/Shaders/Vulkan/triangle.vert index 64ed8bfd..8596f6e1 100644 --- a/Data/Shaders/Vulkan/triangle.vert +++ b/Data/Shaders/Vulkan/triangle.vert @@ -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; } \ No newline at end of file diff --git a/Data/Shaders/volumetric.shader b/Data/Shaders/volumetric.shader index c4e5db64..c90602a3 100644 --- a/Data/Shaders/volumetric.shader +++ b/Data/Shaders/volumetric.shader @@ -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 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 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; + +// 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 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 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; } \ No newline at end of file diff --git a/Editor/Source/Editor/ComponentsPanel/MaterialEditor.cpp b/Editor/Source/Editor/ComponentsPanel/MaterialEditor.cpp index 322b0df3..c9884b58 100644 --- a/Editor/Source/Editor/ComponentsPanel/MaterialEditor.cpp +++ b/Editor/Source/Editor/ComponentsPanel/MaterialEditor.cpp @@ -6,12 +6,268 @@ #include #include +#include +#include "Nuake/Rendering/Vulkan/SceneViewport.h" +#include "Nuake/Scene/Entities/Entity.h" +#include +#include +#include "Nuake/Rendering/Vulkan/DebugCmd.h" +#include "Nuake/Resource/Project.h" +#include +Ref sphereModel; +Ref quadModel; +Ref cubeModel; + +enum class Shapes +{ + Sphere, Cube, Quad +}; + +Shapes currentShape = Shapes::Sphere; + +MaterialEditor::MaterialEditor() +{ + using namespace Nuake; + + PreviewScene = CreateRef(); + PreviewScene->GetEnvironment()->mVolumetric->SetFogAmount(1.0f); + + auto camera = PreviewScene->CreateEntity("Camera"); + camera.GetComponent().Translation = Nuake::Vector3(-2, 0, -2); + auto& camComponent = camera.AddComponent(); + camComponent.CameraInstance->Fov = 44.0f; + //auto light = PreviewScene->CreateEntity("Light"); + //auto& lightC = light.AddComponent(); + //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(); + //lightT.GlobalRotation = glm::quat_cast(rotationMatrix); + + auto sphere = PreviewScene->CreateEntity("Sphere"); + auto& modelComponent = sphere.AddComponent(); + auto& sphereT = sphere.GetComponent(); + sphereT.Translation = { 1, 0, 0 }; + const std::vector 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 quadIndices + { + 5, 4, 3, 2, 1, 0 + }; + + auto meshQuad = CreateRef(); + meshQuad->AddSurface(quadVertices, quadIndices); + + quadModel = CreateRef(); + quadModel->AddMesh(meshQuad); + ResourceManager::RegisterResource(quadModel); + + // Sphere + const int sectorCount = 32; + const int stackCount = 16; + const float radius = 0.5f; + + std::vector sphereVertices; + std::vector sphereIndices; + + for (int i = 0; i <= stackCount; ++i) + { + float stackAngle = glm::pi() / 2 - i * glm::pi() / 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() / 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->AddSurface(sphereVertices, sphereIndices); + + sphereModel = CreateRef(); + sphereModel->AddMesh(mesh); + ResourceManager::RegisterResource(sphereModel); + modelComponent.ModelResource = sphereModel->ID; + + const float boxSize = 0.33f; + const std::vector 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 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(); + meshBox->AddSurface(boxVertices, boxIndices); + + cubeModel = CreateRef(); + 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(); + 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 material) { using namespace Nuake; + auto& t = PreviewScene->GetEntity("Camera").GetComponent(); + 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()->GetMeshes()[0]->SetMaterial(material); + + ent.GetComponent().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 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() + 0.01f, glm::half_pi() - 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 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 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 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))) diff --git a/Editor/Source/Editor/ComponentsPanel/MaterialEditor.h b/Editor/Source/Editor/ComponentsPanel/MaterialEditor.h index 4ac78fec..bc1d283f 100644 --- a/Editor/Source/Editor/ComponentsPanel/MaterialEditor.h +++ b/Editor/Source/Editor/ComponentsPanel/MaterialEditor.h @@ -1,11 +1,16 @@ #pragma once #include #include +#include +#include "Nuake/Rendering/Vulkan/SceneViewport.h" class MaterialEditor { +private: + Ref PreviewScene; + Ref SceneViewport; public: - MaterialEditor() = default; + MaterialEditor(); ~MaterialEditor() = default; void Draw(Ref material); diff --git a/Editor/Source/Editor/ComponentsPanel/ModelResourceInspector.cpp b/Editor/Source/Editor/ComponentsPanel/ModelResourceInspector.cpp index 993fdb27..811574f5 100644 --- a/Editor/Source/Editor/ComponentsPanel/ModelResourceInspector.cpp +++ b/Editor/Source/Editor/ComponentsPanel/ModelResourceInspector.cpp @@ -5,6 +5,7 @@ ModelResourceInspector::ModelResourceInspector(Ref 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(); diff --git a/Editor/Source/Editor/Windows/SceneEditor/Widgets/FileBrowserWidget.cpp b/Editor/Source/Editor/Windows/SceneEditor/Widgets/FileBrowserWidget.cpp index 86c38888..10973c61 100644 --- a/Editor/Source/Editor/Windows/SceneEditor/Widgets/FileBrowserWidget.cpp +++ b/Editor/Source/Editor/Windows/SceneEditor/Widgets/FileBrowserWidget.cpp @@ -10,6 +10,7 @@ #include #include "../../../Misc/InterfaceFonts.h" +#include 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 file, uint32_t drawId) shouldOpenScene = true; } } + + if (AssetBakerManager::Get().IsBakable(file)) + { + if (ImGui::MenuItem("Rebake")) + { + AssetBakerManager::Get().OnNewAssetDetected(file); + } + } ImGui::Separator(); diff --git a/Editor/Source/Editor/Windows/SceneEditor/Widgets/SelectionPropertyWidget.cpp b/Editor/Source/Editor/Windows/SceneEditor/Widgets/SelectionPropertyWidget.cpp index c710a43c..6676277c 100644 --- a/Editor/Source/Editor/Windows/SceneEditor/Widgets/SelectionPropertyWidget.cpp +++ b/Editor/Source/Editor/Windows/SceneEditor/Widgets/SelectionPropertyWidget.cpp @@ -3,7 +3,6 @@ #include "Nuake/Scene/Components.h" #include "Nuake/UI/ImUI.h" -#include "../../../ComponentsPanel/MaterialEditor.h" #include #include @@ -238,7 +237,6 @@ void SelectionPropertyWidget::DrawFile(Ref file) { case FileType::Material: { - MaterialEditor matEditor; matEditor.Draw(std::static_pointer_cast(selectedResource)); break; } @@ -1665,14 +1663,14 @@ void SelectionPropertyWidget::DrawMaterialPanel(Ref 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))) diff --git a/Editor/Source/Editor/Windows/SceneEditor/Widgets/SelectionPropertyWidget.h b/Editor/Source/Editor/Windows/SceneEditor/Widgets/SelectionPropertyWidget.h index 03d63c1a..12f39d7d 100644 --- a/Editor/Source/Editor/Windows/SceneEditor/Widgets/SelectionPropertyWidget.h +++ b/Editor/Source/Editor/Windows/SceneEditor/Widgets/SelectionPropertyWidget.h @@ -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 GLTFBaker::Bake(const Ref& 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 GLTFBaker::Bake(const Ref& 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); diff --git a/Nuake/Source/Nuake/Rendering/Textures/Material.cpp b/Nuake/Source/Nuake/Rendering/Textures/Material.cpp index e43bb8cf..196ee471 100644 --- a/Nuake/Source/Nuake/Rendering/Textures/Material.cpp +++ b/Nuake/Source/Nuake/Rendering/Textures/Material.cpp @@ -161,22 +161,72 @@ namespace Nuake void Material::SetAO(const std::string ao) { + if (FileSystem::FileExists(ao)) + { + GPUResources& resources = GPUResources::Get(); + Ref image = CreateRef(FileSystem::RelativeToAbsolute(ao)); + if (resources.AddTexture(image)) + { + AOImage = image->GetID(); + } + + Ref aoTexture = TextureManager::Get()->GetTexture(FileSystem::RelativeToAbsolute(ao)); + SetAO(aoTexture); + } + m_AO = CreateRef(ao); } void Material::SetMetalness(const std::string metalness) { + if (FileSystem::FileExists(metalness)) + { + GPUResources& resources = GPUResources::Get(); + Ref image = CreateRef(FileSystem::RelativeToAbsolute(metalness)); + if (resources.AddTexture(image)) + { + MetalnessImage = image->GetID(); + } + + Ref aoTexture = TextureManager::Get()->GetTexture(FileSystem::RelativeToAbsolute(metalness)); + SetMetalness(aoTexture); + } + m_Metalness = CreateRef(metalness); } void Material::SetRoughness(const std::string roughness) { + if (FileSystem::FileExists(roughness)) + { + GPUResources& resources = GPUResources::Get(); + Ref image = CreateRef(FileSystem::RelativeToAbsolute(roughness)); + if (resources.AddTexture(image)) + { + RoughnessImage = image->GetID(); + } + + Ref aoTexture = TextureManager::Get()->GetTexture(FileSystem::RelativeToAbsolute(roughness)); + SetRoughness(aoTexture); + } + m_Roughness = CreateRef(roughness); } void Material::SetNormal(const std::string normal) { - m_Normal = CreateRef(normal); + if (FileSystem::FileExists(normal)) + { + GPUResources& resources = GPUResources::Get(); + Ref image = CreateRef(FileSystem::RelativeToAbsolute(normal)); + if (resources.AddTexture(image)) + { + NormalImage = image->GetID(); + } + + Ref aoTexture = TextureManager::Get()->GetTexture(FileSystem::RelativeToAbsolute(normal)); + SetNormal(aoTexture); + } } void Material::SetDisplacement(const std::string displacement) diff --git a/Nuake/Source/Nuake/Rendering/Textures/Material.h b/Nuake/Source/Nuake/Rendering/Textures/Material.h index d2ce9efd..4f887e8a 100644 --- a/Nuake/Source/Nuake/Rendering/Textures/Material.h +++ b/Nuake/Source/Nuake/Rendering/Textures/Material.h @@ -117,19 +117,19 @@ namespace Nuake } void SetAlbedo(Ref 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) { 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) { 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) { 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) { 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 aoTexture = TextureManager::Get()->GetTexture(absolutePath); - SetAO(aoTexture); + Ref normalTexture = TextureManager::Get()->GetTexture(absolutePath); + SetAO(normalTexture); + } + else + { + GPUResources& resources = GPUResources::Get(); + Ref 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 image = CreateRef(absolutePath); if (resources.AddTexture(image)) { - MetalnessImage = image->GetID(); + AOImage = image->GetID(); } - } - Ref metalTexture = TextureManager::Get()->GetTexture(absolutePath); - SetMetalness(metalTexture); + Ref normalTexture = TextureManager::Get()->GetTexture(absolutePath); + SetMetalness(normalTexture); + } + else + { + GPUResources& resources = GPUResources::Get(); + Ref 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 image = CreateRef(absolutePath); if (resources.AddTexture(image)) { - RoughnessImage = image->GetID(); + AOImage = image->GetID(); } - } - Ref metalTexture = TextureManager::Get()->GetTexture(absolutePath); - SetRoughness(metalTexture); + Ref normalTexture = TextureManager::Get()->GetTexture(absolutePath); + SetRoughness(normalTexture); + } + else + { + GPUResources& resources = GPUResources::Get(); + Ref missingTexture = TextureManager::Get()->GetTexture2("missing_texture"); + RoughnessImage = missingTexture->GetID(); + } } if (j.contains("Displacement")) diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.cpp b/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.cpp index e37453f8..9855ab79 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.cpp +++ b/Nuake/Source/Nuake/Rendering/Vulkan/SceneRenderPipeline.cpp @@ -17,6 +17,7 @@ #include #include "DebugCmd.h" #include +#include using namespace Nuake; @@ -405,6 +406,31 @@ void SceneRenderPipeline::RecreatePipeline() cmd.DrawIndexed(vkMesh->GetIndexBuffer()->GetSize() / sizeof(uint32_t)); } } + + auto particleView = scene->m_Registry.view(); + for (auto e : particleView) + { + auto [transform, particle, visibility] = particleView.get(e); + + if (!visibility.Visible) + continue; + + if (particle.resFile.dirty) + { + particle.resFile.dirty = false; + + if (particle.resFile.Exist()) + { + Ref 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 SceneRenderPipeline::ResizeImage(PassRenderContext& ctx, Ref; - using CleanUpStack = std::stack; - - 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); diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/ShaderCompiler.cpp b/Nuake/Source/Nuake/Rendering/Vulkan/ShaderCompiler.cpp index 0f64a155..4a64523e 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/ShaderCompiler.cpp +++ b/Nuake/Source/Nuake/Rendering/Vulkan/ShaderCompiler.cpp @@ -127,7 +127,7 @@ Ref 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 { diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanImage/VulkanImage.cpp b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanImage/VulkanImage.cpp index 90426c26..796b6e7e 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanImage/VulkanImage.cpp +++ b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanImage/VulkanImage.cpp @@ -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 diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanRenderer.h b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanRenderer.h index 02255657..f5aee91e 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanRenderer.h +++ b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanRenderer.h @@ -236,6 +236,11 @@ namespace Nuake return Device; } + VkPhysicalDevice GetPhysicalDevice() const + { + return GPU; + } + FrameData& GetCurrentFrame() { return Frames[FrameNumber % FRAME_OVERLAP]; diff --git a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanResources.cpp b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanResources.cpp index 52e791c4..d54dd752 100644 --- a/Nuake/Source/Nuake/Rendering/Vulkan/VulkanResources.cpp +++ b/Nuake/Source/Nuake/Rendering/Vulkan/VulkanResources.cpp @@ -170,7 +170,7 @@ Ref 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 = {}; diff --git a/Nuake/Source/Nuake/Resource/Bakers/AssetBakerManager.h b/Nuake/Source/Nuake/Resource/Bakers/AssetBakerManager.h index 7d060d1b..4b6796ef 100644 --- a/Nuake/Source/Nuake/Resource/Bakers/AssetBakerManager.h +++ b/Nuake/Source/Nuake/Resource/Bakers/AssetBakerManager.h @@ -34,6 +34,11 @@ namespace Nuake } } + bool IsBakable(const Ref& file) + { + return Bakers.find(file->GetExtension()) != Bakers.end(); + } + void OnAssetReimport(const Ref& file) { const std::string extension = file->GetExtension();