From 63f0f3338c3ec885dca18abb67407c487af7a1ca Mon Sep 17 00:00:00 2001 From: austin Date: Mon, 23 Sep 2024 00:26:01 -0400 Subject: [PATCH] tree model debug menu --- assets/Data/entity/foliage.json | 91 ++++--- .../instanced/colorshift/colorshift.fs | 188 ++++++++----- .../instanced/colorshift/colorshift.vs | 2 + .../proceduraltree/proceduraltree.fs | 183 ++++++++----- .../proceduraltree/proceduraltree.vs | 2 + docs/src/progress/renderertodo.md | 1 + .../ui/menu/debug/ImGuiPlayerEntity.java | 1 + .../ui/menu/debug/ImGuiWindowMacros.java | 1 + .../debug/entity/ImGuiEntityActorTab.java | 135 ++++++++++ .../entity/ImGuiEntityInstancedActorTab.java | 253 ++++++++++++++++++ .../debug/{ => entity}/ImGuiEntityMacros.java | 124 ++------- .../entity/ClientEntityUtils.java | 13 + .../entity/EntityDataStrings.java | 1 + .../types/common/CommonEntityUtils.java | 20 ++ .../entity/types/foliage/FoliageUtils.java | 7 +- .../entity/types/tree/ProceduralTree.java | 19 +- .../game/data/common/CommonEntityType.java | 14 - .../game/data/foliage/type/TreeModel.java | 128 ++++++++- 18 files changed, 879 insertions(+), 304 deletions(-) create mode 100644 src/main/java/electrosphere/client/ui/menu/debug/entity/ImGuiEntityActorTab.java create mode 100644 src/main/java/electrosphere/client/ui/menu/debug/entity/ImGuiEntityInstancedActorTab.java rename src/main/java/electrosphere/client/ui/menu/debug/{ => entity}/ImGuiEntityMacros.java (85%) diff --git a/assets/Data/entity/foliage.json b/assets/Data/entity/foliage.json index 608aa287..f1717558 100644 --- a/assets/Data/entity/foliage.json +++ b/assets/Data/entity/foliage.json @@ -29,49 +29,6 @@ "growthModel": { "growthRate" : 0.001 }, - "treeModel": { - "limbScalarFalloffFactor": 0.3, - "minimumLimbScalar": 0.25, - "maximumLimbDispersion": 0.5, - "minimumLimbDispersion": 0.3, - "minimumNumberForks": 3, - "maximumNumberForks": 5, - "branchHeight": 3, - "centralTrunk": false, - "maximumTrunkSegments": 4, - "maximumBranchSegments": 3, - "maxBranchSegmentFalloffFactor": 1, - "minimumSegmentToSpawnLeaves": 2, - "minBranchHeightToStartSpawningLeaves": 1.5, - "maxBranchHeightToStartSpawningLeaves": 3.01, - "leafIncrement": 0.5, - "minLeavesToSpawnPerPoint": 3, - "maxLeavesToSpawnPerPoint": 5, - "leafDistanceFromCenter": 1.2, - "peelVariance": 0.2, - "peelMinimum": 0.1, - "swaySigmoidFactor": 2, - "minimumSwayTime": 500, - "swayTimeVariance": 500, - "yawVariance": 0.2, - "yawMinimum": 0.1, - "minimumScalarToGenerateSwayTree": 0.5, - "maximumScalarToGenerateSwayTree": 1.0, - "physicsCutoff": 3, - "physicsBody": { - "type" : "CYLINDER", - "dimension1" : 0.5, - "dimension2" : 3, - "dimension3" : 0.5, - "rotX": 0, - "rotY": 0, - "rotZ": 0, - "rotW": 1, - "offsetX" : 0, - "offsetY" : 1.5, - "offsetZ" : 0 - } - }, "ambientAudio": { "responseWindAudioFilePath": "Audio/ambienceWind1SeamlessMono.ogg", "responseWindLoops": true, @@ -79,7 +36,53 @@ "gainMultiplier": 0.9, "emitterSpatialOffset": [0,3,0] }, - "modelPath" : "Models/foliage/proceduralTree2/proceduralTree2v2.fbx" + "graphicsTemplate": { + "proceduralModel": { + "treeModel": { + "limbScalarFalloffFactor": 0.3, + "minimumLimbScalar": 0.25, + "maximumLimbDispersion": 0.5, + "minimumLimbDispersion": 0.3, + "minimumNumberForks": 3, + "maximumNumberForks": 5, + "branchHeight": 3, + "centralTrunk": false, + "maximumTrunkSegments": 4, + "maximumBranchSegments": 3, + "maxBranchSegmentFalloffFactor": 1, + "minimumSegmentToSpawnLeaves": 2, + "minBranchHeightToStartSpawningLeaves": 1.5, + "maxBranchHeightToStartSpawningLeaves": 3.01, + "leafIncrement": 0.5, + "minLeavesToSpawnPerPoint": 3, + "maxLeavesToSpawnPerPoint": 5, + "leafDistanceFromCenter": 1.2, + "peelVariance": 0.2, + "peelMinimum": 0.1, + "swaySigmoidFactor": 2, + "minimumSwayTime": 500, + "swayTimeVariance": 500, + "yawVariance": 0.2, + "yawMinimum": 0.1, + "minimumScalarToGenerateSwayTree": 0.5, + "maximumScalarToGenerateSwayTree": 1.0, + "physicsCutoff": 3, + "physicsBody": { + "type" : "CYLINDER", + "dimension1" : 0.5, + "dimension2" : 3, + "dimension3" : 0.5, + "rotX": 0, + "rotY": 0, + "rotZ": 0, + "rotW": 1, + "offsetX" : 0, + "offsetY" : 1.5, + "offsetZ" : 0 + } + } + } + } } ] diff --git a/assets/Shaders/instanced/colorshift/colorshift.fs b/assets/Shaders/instanced/colorshift/colorshift.fs index 4c8123fa..e7c72dba 100644 --- a/assets/Shaders/instanced/colorshift/colorshift.fs +++ b/assets/Shaders/instanced/colorshift/colorshift.fs @@ -1,39 +1,73 @@ -#version 330 core +#version 450 core //colorshift.fs -#define NR_POINT_LIGHTS 10 +/** +Bind points for different SSBOs +*/ +#define CLUSTER_SSBO_BIND_POINT 1 +#define POINT_LIGHT_SSBO_BIND_POINT 2 +#define DIRECT_LIGHT_SSBO_BIND_POINT 3 -#define SMALL_EPSILON 0.0001 + +/** +Maximum number of point lights +*/ +#define MAX_POINT_LIGHTS 512 + +/** +Maximum number of lights per cluster +*/ +#define MAX_LIGHTS_PER_CLUSTER 100 + +/** +transparency +*/ +#define SMALL_EPSILON 0.001 + +/** +The direct global light +*/ +struct DirectLight { + vec3 direction; + vec3 color; +}; + +/** +A point light +*/ +struct PointLight { + vec4 position; + vec4 color; + float constant; + float linear; + float quadratic; + float radius; +}; + +/** +A light cluster +*/ +struct Cluster { + vec4 minPoint; + vec4 maxPoint; + uint count; + uint lightIndices[MAX_LIGHTS_PER_CLUSTER]; +}; out vec4 FragColor; -layout (std140) uniform Lights { - // this is how many because we have to align - // bytes it SHOULD in multiples of 16, this - // take it where it ACTUALLY is - // - //refer: https://learnopengl.com/Advanced-OpenGL/Advanced-GLSL - // - // base alignment aligned offset - //direct light - vec3 dLDirection; // 16 0 - vec3 dLAmbient; // 16 16 - vec3 dLDiffuse; // 16 32 - vec3 dLSpecular; // 16 48 +layout(std430, binding = CLUSTER_SSBO_BIND_POINT) restrict buffer clusterGridSSBO { + Cluster clusters[]; +}; - //point light - vec3 pLposition[NR_POINT_LIGHTS]; // 16*10 64 - float pLconstant[NR_POINT_LIGHTS]; // 16*10 224 - float pLlinear[NR_POINT_LIGHTS]; // 16*10 384 - float pLquadratic[NR_POINT_LIGHTS]; // 16*10 544 - vec3 pLambient[NR_POINT_LIGHTS]; // 16*10 704 - vec3 pLdiffuse[NR_POINT_LIGHTS]; // 16*10 864 - vec3 pLspecular[NR_POINT_LIGHTS]; // 16*10 1024 - - //for a total size of 1184 +layout(std430, binding = POINT_LIGHT_SSBO_BIND_POINT) restrict buffer pointLightSSBO { + PointLight pointLight[]; +}; +layout(std430, binding = DIRECT_LIGHT_SSBO_BIND_POINT) restrict buffer dirLightSSBO { + DirectLight directLight; }; struct Material { @@ -43,6 +77,7 @@ struct Material { }; in vec3 FragPos; +in vec3 ViewFragPos; in vec3 Normal; in vec2 TexCoord; in vec4 FragPosLightSpace; @@ -63,11 +98,19 @@ uniform int hasTransparency; //light depth map uniform sampler2D shadowMap; +/** +Used for light cluster calculation +*/ +uniform float zNear; +uniform float zFar; +uniform uvec3 gridSize; +uniform uvec2 screenDimensions; +uniform mat4 view; + // function prototypes -// vec3 CalcDirLight(vec3 normal, vec3 viewDir); -// vec3 CalcPointLight(int i, vec3 normal, vec3 fragPos, vec3 viewDir); -// vec3 CalcSpotLight(vec3 normal, vec3 fragPos, vec3 viewDir); +uint findCluster(vec3 FragPos, float zNear, float zFar); +vec3 CalcPointLight(PointLight pointLight, vec3 normal, vec3 fragPos, vec3 viewDir); float calcLightIntensityTotal(vec3 normal); float ShadowCalculation(vec4 fragPosLightSpace, vec3 lightDir, vec3 normal); @@ -77,7 +120,7 @@ void main(){ vec3 viewDir = normalize(viewPos - FragPos); //grab light intensity - float lightIntensity = calcLightIntensityTotal(norm); + vec3 lightIntensity = vec3(calcLightIntensityTotal(norm)); if(texture(material.diffuse, TexCoord).a < SMALL_EPSILON){ discard; @@ -92,10 +135,25 @@ void main(){ ); //shadow - float shadow = ShadowCalculation(FragPosLightSpace, normalize(-dLDirection), norm); + float shadow = ShadowCalculation(FragPosLightSpace, normalize(-directLight.direction), norm); + + // + //point light calculations + uint clusterIndex = findCluster(ViewFragPos, zNear, zFar); + uint pointLightCount = clusters[clusterIndex].count; + for(int i = 0; i < pointLightCount; i++){ + uint pointLightIndex = clusters[clusterIndex].lightIndices[i]; + PointLight pointLight = pointLight[pointLightIndex]; + lightIntensity = lightIntensity + CalcPointLight(pointLight, norm, FragPos, viewDir); + } + //error checking on light clusters + if(pointLightCount > MAX_LIGHTS_PER_CLUSTER){ + FragColor = vec4(1.0f,0.0f,0.0f,1); + return; + } //calculate final color - vec3 finalColor = textureColor * lightIntensity * max(shadow,0.4); + vec3 finalColor = textureColor * lightIntensity; // vec3 lightAmount = CalcDirLight(norm, viewDir); // for(int i = 0; i < NR_POINT_LIGHTS; i++){ // lightAmount += CalcPointLight(i, norm, FragPos, viewDir); @@ -127,13 +185,13 @@ void main(){ // float calcLightIntensityAmbient(){ //calculate average of ambient light - float avg = (dLAmbient.x + dLAmbient.y + dLAmbient.z)/3.0; + float avg = (directLight.color.x + directLight.color.y + directLight.color.z)/3.0; return avg; } // float calcLightIntensityDir(vec3 normal){ - vec3 lightDir = normalize(-dLDirection); + vec3 lightDir = normalize(-directLight.direction); // diffuse shading float diff = max(dot(normal, lightDir), 0.0); @@ -156,63 +214,53 @@ float calcLightIntensityTotal(vec3 normal){ // vec3 getTotalLightColor(vec3 normal){ //get the direct light color adjusted for intensity - vec3 diffuseLightColor = dLDiffuse * calcLightIntensityDir(normal); + vec3 diffuseLightColor = directLight.color * calcLightIntensityDir(normal); //sum light colors vec3 totalLightColor = diffuseLightColor; return totalLightColor; } -vec3 CalcPointLight(int i, vec3 normal, vec3 fragPos, vec3 viewDir){ - vec3 lightDir = normalize(pLposition[i] - fragPos); +vec3 CalcPointLight(PointLight pointLight, vec3 normal, vec3 fragPos, vec3 viewDir){ + vec3 lightDir = normalize(pointLight.position.xyz - fragPos); // diffuse shading float diff = max(dot(normal, lightDir), 0.0); // specular shading // vec3 reflectDir = reflect(-lightDir, normal); // float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); // attenuation - float distance = length(pLposition[i] - fragPos); - float attenuation = 1.0 / (pLconstant[i] + pLlinear[i] * distance + pLquadratic[i] * (distance * distance)); + float distance = length(pointLight.position.xyz - fragPos); + float attenuation = 1.0 / (pointLight.constant + pointLight.linear * distance + pointLight.quadratic * (distance * distance)); + if(distance > pointLight.radius){ + attenuation = 0; + } // combine results - vec3 ambient = pLambient[i];// * vec4(texture(material.diffuse, TexCoord)).xyz; - vec3 diffuse = pLdiffuse[i] * diff;// * vec4(texture(material.diffuse, TexCoord)).xyz; + vec3 ambient = pointLight.color.xyz;// * vec4(texture(material.diffuse, TexCoord)).xyz; + vec3 diffuse = pointLight.color.xyz * diff;// * vec4(texture(material.diffuse, TexCoord)).xyz; // vec3 specular = pLspecular[i] * spec;// * vec4(texture(material.specular, TexCoord)).xyz; - ambient *= attenuation; - diffuse *= attenuation; + ambient = ambient * attenuation; + diffuse = diffuse * attenuation; // specular *= attenuation; vec3 specular = vec3(0,0,0); - vec3 finalValue = (ambient + diffuse + specular); - finalValue = vec3(max(finalValue.x,0),max(finalValue.y,0),max(finalValue.z,0)); + vec3 finalValue = vec3(0); + if(distance < pointLight.radius){ + finalValue = (ambient + diffuse + specular); + finalValue = vec3(max(finalValue.x,0),max(finalValue.y,0),max(finalValue.z,0)); + } return finalValue; } -// // calculates the color when using a point light. -// vec3 CalcPointLight(int i, vec3 normal, vec3 fragPos, vec3 viewDir){ -// vec3 lightDir = normalize(pLposition[i] - fragPos); -// // diffuse shading -// float diff = max(dot(normal, lightDir), 0.0); -// // specular shading -// // vec3 reflectDir = reflect(-lightDir, normal); -// // float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); -// // attenuation -// float distance = length(pLposition[i] - fragPos); -// float attenuation = 1.0 / (pLconstant[i] + pLlinear[i] * distance + pLquadratic[i] * (distance * distance)); -// // combine results -// vec3 ambient = pLambient[i];// * vec4(texture(material.diffuse, TexCoord)).xyz; -// vec3 diffuse = pLdiffuse[i] * diff;// * vec4(texture(material.diffuse, TexCoord)).xyz; -// // vec3 specular = pLspecular[i] * spec;// * vec4(texture(material.specular, TexCoord)).xyz; -// ambient *= attenuation; -// diffuse *= attenuation; -// // specular *= attenuation; -// vec3 specular = vec3(0,0,0); - -// vec3 finalValue = (ambient + diffuse + specular); -// finalValue = vec3(max(finalValue.x,0),max(finalValue.y,0),max(finalValue.z,0)); - -// return finalValue; -// } +/** +Finds the light cluster this fragment belongs to +*/ +uint findCluster(vec3 viewspaceFragPos, float zNear, float zFar){ + uint zTile = uint((log(abs(viewspaceFragPos.z) / zNear) * gridSize.z) / log(zFar / zNear)); + vec2 tileSize = screenDimensions / gridSize.xy; + uvec3 tile = uvec3(gl_FragCoord.xy / tileSize, zTile); + return tile.x + (tile.y * gridSize.x) + (tile.z * gridSize.x * gridSize.y); +} float ShadowCalculation(vec4 fragPosLightSpace, vec3 lightDir, vec3 normal){ diff --git a/assets/Shaders/instanced/colorshift/colorshift.vs b/assets/Shaders/instanced/colorshift/colorshift.vs index 331e8746..3aa7185e 100644 --- a/assets/Shaders/instanced/colorshift/colorshift.vs +++ b/assets/Shaders/instanced/colorshift/colorshift.vs @@ -26,6 +26,7 @@ uniform mat4 lightSpaceMatrix; //output buffers out vec3 Normal; out vec3 FragPos; +out vec3 ViewFragPos; out vec2 TexCoord; out vec4 FragPosLightSpace; out vec3 colorShiftValue; @@ -49,6 +50,7 @@ void main() { //push frag, normal, and texture positions to fragment shader FragPos = vec3(model * FinalVertex); + ViewFragPos = vec3(view * model * FinalVertex); Normal = mat3(transpose(inverse(model))) * aNormal; TexCoord = aTex; diff --git a/assets/Shaders/instanced/proceduraltree/proceduraltree.fs b/assets/Shaders/instanced/proceduraltree/proceduraltree.fs index 7414ea0a..7d47d90e 100644 --- a/assets/Shaders/instanced/proceduraltree/proceduraltree.fs +++ b/assets/Shaders/instanced/proceduraltree/proceduraltree.fs @@ -1,37 +1,68 @@ -#version 330 core +#version 450 core //proceduraltree.fs -#define NR_POINT_LIGHTS 10 +/** +Bind points for different SSBOs +*/ +#define CLUSTER_SSBO_BIND_POINT 1 +#define POINT_LIGHT_SSBO_BIND_POINT 2 +#define DIRECT_LIGHT_SSBO_BIND_POINT 3 + + +/** +Maximum number of point lights +*/ +#define MAX_POINT_LIGHTS 512 + +/** +Maximum number of lights per cluster +*/ +#define MAX_LIGHTS_PER_CLUSTER 100 + +/** +The direct global light +*/ +struct DirectLight { + vec3 direction; + vec3 color; +}; + +/** +A point light +*/ +struct PointLight { + vec4 position; + vec4 color; + float constant; + float linear; + float quadratic; + float radius; +}; + +/** +A light cluster +*/ +struct Cluster { + vec4 minPoint; + vec4 maxPoint; + uint count; + uint lightIndices[MAX_LIGHTS_PER_CLUSTER]; +}; out vec4 FragColor; -layout (std140) uniform Lights { - // this is how many because we have to align - // bytes it SHOULD in multiples of 16, this - // take it where it ACTUALLY is - // - //refer: https://learnopengl.com/Advanced-OpenGL/Advanced-GLSL - // - // base alignment aligned offset - //direct light - vec3 dLDirection; // 16 0 - vec3 dLAmbient; // 16 16 - vec3 dLDiffuse; // 16 32 - vec3 dLSpecular; // 16 48 +layout(std430, binding = CLUSTER_SSBO_BIND_POINT) restrict buffer clusterGridSSBO { + Cluster clusters[]; +}; - //point light - vec3 pLposition[NR_POINT_LIGHTS]; // 16*10 64 - float pLconstant[NR_POINT_LIGHTS]; // 16*10 224 - float pLlinear[NR_POINT_LIGHTS]; // 16*10 384 - float pLquadratic[NR_POINT_LIGHTS]; // 16*10 544 - vec3 pLambient[NR_POINT_LIGHTS]; // 16*10 704 - vec3 pLdiffuse[NR_POINT_LIGHTS]; // 16*10 864 - vec3 pLspecular[NR_POINT_LIGHTS]; // 16*10 1024 - - //for a total size of 1184 +layout(std430, binding = POINT_LIGHT_SSBO_BIND_POINT) restrict buffer pointLightSSBO { + PointLight pointLight[]; +}; +layout(std430, binding = DIRECT_LIGHT_SSBO_BIND_POINT) restrict buffer dirLightSSBO { + DirectLight directLight; }; struct Material { @@ -41,6 +72,7 @@ struct Material { }; in vec3 FragPos; +in vec3 ViewFragPos; in vec3 Normal; in vec2 TexCoord; in vec4 FragPosLightSpace; @@ -60,11 +92,19 @@ uniform int hasTransparency; //light depth map uniform sampler2D shadowMap; +/** +Used for light cluster calculation +*/ +uniform float zNear; +uniform float zFar; +uniform uvec3 gridSize; +uniform uvec2 screenDimensions; +uniform mat4 view; + // function prototypes -// vec3 CalcDirLight(vec3 normal, vec3 viewDir); -// vec3 CalcPointLight(int i, vec3 normal, vec3 fragPos, vec3 viewDir); -// vec3 CalcSpotLight(vec3 normal, vec3 fragPos, vec3 viewDir); +uint findCluster(vec3 FragPos, float zNear, float zFar); +vec3 CalcPointLight(PointLight pointLight, vec3 normal, vec3 fragPos, vec3 viewDir); float calcLightIntensityTotal(vec3 normal); float ShadowCalculation(vec4 fragPosLightSpace, vec3 lightDir, vec3 normal); @@ -73,16 +113,31 @@ void main(){ vec3 viewDir = normalize(viewPos - FragPos); //grab light intensity - float lightIntensity = calcLightIntensityTotal(norm); + vec3 lightIntensity = vec3(calcLightIntensityTotal(norm)); //get color of base texture vec3 textureColor = texture(material.diffuse, TexCoord).rgb; //shadow - float shadow = ShadowCalculation(FragPosLightSpace, normalize(-dLDirection), norm); + float shadow = ShadowCalculation(FragPosLightSpace, normalize(-directLight.direction), norm); + + // + //point light calculations + uint clusterIndex = findCluster(ViewFragPos, zNear, zFar); + uint pointLightCount = clusters[clusterIndex].count; + for(int i = 0; i < pointLightCount; i++){ + uint pointLightIndex = clusters[clusterIndex].lightIndices[i]; + PointLight pointLight = pointLight[pointLightIndex]; + lightIntensity = lightIntensity + CalcPointLight(pointLight, norm, FragPos, viewDir); + } + //error checking on light clusters + if(pointLightCount > MAX_LIGHTS_PER_CLUSTER){ + FragColor = vec4(1.0f,0.0f,0.0f,1); + return; + } //calculate final color - vec3 finalColor = textureColor * lightIntensity * max(shadow,0.4); + vec3 finalColor = textureColor * lightIntensity; // vec3 lightAmount = CalcDirLight(norm, viewDir); // for(int i = 0; i < NR_POINT_LIGHTS; i++){ // lightAmount += CalcPointLight(i, norm, FragPos, viewDir); @@ -114,13 +169,13 @@ void main(){ // float calcLightIntensityAmbient(){ //calculate average of ambient light - float avg = (dLAmbient.x + dLAmbient.y + dLAmbient.z)/3.0; + float avg = (directLight.color.x + directLight.color.y + directLight.color.z)/3.0; return avg; } // float calcLightIntensityDir(vec3 normal){ - vec3 lightDir = normalize(-dLDirection); + vec3 lightDir = normalize(-directLight.direction); // diffuse shading float diff = max(dot(normal, lightDir), 0.0); @@ -143,63 +198,53 @@ float calcLightIntensityTotal(vec3 normal){ // vec3 getTotalLightColor(vec3 normal){ //get the direct light color adjusted for intensity - vec3 diffuseLightColor = dLDiffuse * calcLightIntensityDir(normal); + vec3 diffuseLightColor = directLight.color * calcLightIntensityDir(normal); //sum light colors vec3 totalLightColor = diffuseLightColor; return totalLightColor; } -vec3 CalcPointLight(int i, vec3 normal, vec3 fragPos, vec3 viewDir){ - vec3 lightDir = normalize(pLposition[i] - fragPos); +vec3 CalcPointLight(PointLight pointLight, vec3 normal, vec3 fragPos, vec3 viewDir){ + vec3 lightDir = normalize(pointLight.position.xyz - fragPos); // diffuse shading float diff = max(dot(normal, lightDir), 0.0); // specular shading // vec3 reflectDir = reflect(-lightDir, normal); // float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); // attenuation - float distance = length(pLposition[i] - fragPos); - float attenuation = 1.0 / (pLconstant[i] + pLlinear[i] * distance + pLquadratic[i] * (distance * distance)); + float distance = length(pointLight.position.xyz - fragPos); + float attenuation = 1.0 / (pointLight.constant + pointLight.linear * distance + pointLight.quadratic * (distance * distance)); + if(distance > pointLight.radius){ + attenuation = 0; + } // combine results - vec3 ambient = pLambient[i];// * vec4(texture(material.diffuse, TexCoord)).xyz; - vec3 diffuse = pLdiffuse[i] * diff;// * vec4(texture(material.diffuse, TexCoord)).xyz; + vec3 ambient = pointLight.color.xyz;// * vec4(texture(material.diffuse, TexCoord)).xyz; + vec3 diffuse = pointLight.color.xyz * diff;// * vec4(texture(material.diffuse, TexCoord)).xyz; // vec3 specular = pLspecular[i] * spec;// * vec4(texture(material.specular, TexCoord)).xyz; - ambient *= attenuation; - diffuse *= attenuation; + ambient = ambient * attenuation; + diffuse = diffuse * attenuation; // specular *= attenuation; vec3 specular = vec3(0,0,0); - vec3 finalValue = (ambient + diffuse + specular); - finalValue = vec3(max(finalValue.x,0),max(finalValue.y,0),max(finalValue.z,0)); + vec3 finalValue = vec3(0); + if(distance < pointLight.radius){ + finalValue = (ambient + diffuse + specular); + finalValue = vec3(max(finalValue.x,0),max(finalValue.y,0),max(finalValue.z,0)); + } return finalValue; } -// // calculates the color when using a point light. -// vec3 CalcPointLight(int i, vec3 normal, vec3 fragPos, vec3 viewDir){ -// vec3 lightDir = normalize(pLposition[i] - fragPos); -// // diffuse shading -// float diff = max(dot(normal, lightDir), 0.0); -// // specular shading -// // vec3 reflectDir = reflect(-lightDir, normal); -// // float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); -// // attenuation -// float distance = length(pLposition[i] - fragPos); -// float attenuation = 1.0 / (pLconstant[i] + pLlinear[i] * distance + pLquadratic[i] * (distance * distance)); -// // combine results -// vec3 ambient = pLambient[i];// * vec4(texture(material.diffuse, TexCoord)).xyz; -// vec3 diffuse = pLdiffuse[i] * diff;// * vec4(texture(material.diffuse, TexCoord)).xyz; -// // vec3 specular = pLspecular[i] * spec;// * vec4(texture(material.specular, TexCoord)).xyz; -// ambient *= attenuation; -// diffuse *= attenuation; -// // specular *= attenuation; -// vec3 specular = vec3(0,0,0); - -// vec3 finalValue = (ambient + diffuse + specular); -// finalValue = vec3(max(finalValue.x,0),max(finalValue.y,0),max(finalValue.z,0)); - -// return finalValue; -// } +/** +Finds the light cluster this fragment belongs to +*/ +uint findCluster(vec3 viewspaceFragPos, float zNear, float zFar){ + uint zTile = uint((log(abs(viewspaceFragPos.z) / zNear) * gridSize.z) / log(zFar / zNear)); + vec2 tileSize = screenDimensions / gridSize.xy; + uvec3 tile = uvec3(gl_FragCoord.xy / tileSize, zTile); + return tile.x + (tile.y * gridSize.x) + (tile.z * gridSize.x * gridSize.y); +} float ShadowCalculation(vec4 fragPosLightSpace, vec3 lightDir, vec3 normal){ diff --git a/assets/Shaders/instanced/proceduraltree/proceduraltree.vs b/assets/Shaders/instanced/proceduraltree/proceduraltree.vs index 03e2cc44..837ec4dc 100644 --- a/assets/Shaders/instanced/proceduraltree/proceduraltree.vs +++ b/assets/Shaders/instanced/proceduraltree/proceduraltree.vs @@ -30,6 +30,7 @@ uniform mat4 lightSpaceMatrix; //output buffers out vec3 Normal; out vec3 FragPos; +out vec3 ViewFragPos; out vec2 TexCoord; out vec4 FragPosLightSpace; @@ -61,6 +62,7 @@ void main() { //push frag, normal, and texture positions to fragment shader FragPos = vec3(model * FinalVertex); + ViewFragPos = vec3(view * model * FinalVertex); Normal = mat3(transpose(inverse(model))) * aNormal; TexCoord = aTex; diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 461e9d3d..82caaf0a 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -837,6 +837,7 @@ Fix static friction coeff causing player to slide on shallow slopes - Turns out it needed auto disabling logic Change timescale for test Refactor graphics entity definitions to be under dedicated object +Tree model debug menu # TODO diff --git a/src/main/java/electrosphere/client/ui/menu/debug/ImGuiPlayerEntity.java b/src/main/java/electrosphere/client/ui/menu/debug/ImGuiPlayerEntity.java index 51291a41..4c912d63 100644 --- a/src/main/java/electrosphere/client/ui/menu/debug/ImGuiPlayerEntity.java +++ b/src/main/java/electrosphere/client/ui/menu/debug/ImGuiPlayerEntity.java @@ -3,6 +3,7 @@ package electrosphere.client.ui.menu.debug; import org.ode4j.ode.DBody; import electrosphere.client.entity.camera.CameraEntityUtils; +import electrosphere.client.ui.menu.debug.entity.ImGuiEntityMacros; import electrosphere.collision.PhysicsEntityUtils; import electrosphere.engine.Globals; import electrosphere.entity.Entity; diff --git a/src/main/java/electrosphere/client/ui/menu/debug/ImGuiWindowMacros.java b/src/main/java/electrosphere/client/ui/menu/debug/ImGuiWindowMacros.java index 31891ef7..b9a27080 100644 --- a/src/main/java/electrosphere/client/ui/menu/debug/ImGuiWindowMacros.java +++ b/src/main/java/electrosphere/client/ui/menu/debug/ImGuiWindowMacros.java @@ -3,6 +3,7 @@ package electrosphere.client.ui.menu.debug; import java.util.HashMap; import java.util.Map; +import electrosphere.client.ui.menu.debug.entity.ImGuiEntityMacros; import electrosphere.controls.ControlHandler.ControlsState; import electrosphere.engine.Globals; import electrosphere.renderer.ui.imgui.ImGuiLinePlot; diff --git a/src/main/java/electrosphere/client/ui/menu/debug/entity/ImGuiEntityActorTab.java b/src/main/java/electrosphere/client/ui/menu/debug/entity/ImGuiEntityActorTab.java new file mode 100644 index 00000000..4d836769 --- /dev/null +++ b/src/main/java/electrosphere/client/ui/menu/debug/entity/ImGuiEntityActorTab.java @@ -0,0 +1,135 @@ +package electrosphere.client.ui.menu.debug.entity; + +import java.util.Set; +import java.util.Random; + +import electrosphere.engine.Globals; +import electrosphere.entity.Entity; +import electrosphere.entity.EntityUtils; +import electrosphere.entity.state.AnimationPriorities; +import electrosphere.entity.types.common.CommonEntityUtils; +import electrosphere.entity.types.tree.ProceduralTree; +import electrosphere.game.data.common.CommonEntityType; +import electrosphere.logger.LoggerInterface; +import electrosphere.renderer.actor.Actor; +import electrosphere.renderer.actor.ActorAnimationMask; +import electrosphere.renderer.actor.ActorMeshMask; +import electrosphere.renderer.anim.AnimChannel; +import electrosphere.renderer.anim.Animation; +import electrosphere.renderer.model.Bone; +import electrosphere.renderer.model.Mesh; +import electrosphere.renderer.model.Model; +import imgui.ImGui; + +/** + * The actor tab on the entity detail view + */ +public class ImGuiEntityActorTab { + + /** + * Client scene entity view + */ + protected static void drawActorView(boolean show, Entity detailViewEntity){ + if(show && ImGui.collapsingHeader("Actor Details")){ + ImGui.indent(); + if(detailViewEntity != null && EntityUtils.getActor(detailViewEntity) != null){ + Actor actor = EntityUtils.getActor(detailViewEntity); + CommonEntityType commonEntityData = CommonEntityUtils.getCommonData(detailViewEntity); + + //procedural model + if(commonEntityData.getGraphicsTemplate().getProceduralModel() != null && ImGui.collapsingHeader("Procedural Model")){ + if(ImGui.button("Regenerate")){ + if(commonEntityData.getGraphicsTemplate().getProceduralModel().getTreeModel() != null){ + ProceduralTree.setProceduralActor( + detailViewEntity, + commonEntityData.getGraphicsTemplate().getProceduralModel().getTreeModel(), + new Random() + ); + } + } + } + + //mesh mask + if(ImGui.collapsingHeader("Mesh Mask")){ + ActorMeshMask meshMask = actor.getMeshMask(); + ImGui.text("To Draw Meshes:"); + for(Mesh mesh : meshMask.getToDrawMeshes()){ + ImGui.text(mesh.getMeshName()); + } + ImGui.text("Blocked Meshes:"); + for(String blocked : meshMask.getBlockedMeshes()){ + ImGui.text(blocked); + } + } + + //animation queue + if(ImGui.collapsingHeader("Animation Queue")){ + Set animationQueue = actor.getAnimationQueue(); + for(ActorAnimationMask mask : animationQueue){ + ImGui.text(mask.getAnimationName() + " - " + mask.getPriority()); + ImGui.text(mask.getDuration() + " " + mask.getTime()); + } + } + + //bone values + if(ImGui.collapsingHeader("Bone Values")){ + for(Bone bone : actor.getBoneValues()){ + ImGui.text(bone.boneID); + ImGui.text("Position: " + actor.getBonePosition(bone.boneID)); + ImGui.text("Rotation: " + actor.getBoneRotation(bone.boneID)); + ImGui.text(bone.getFinalTransform() + ""); + } + } + + //Draws all the bones in the world + if(ImGui.button("Draw Bones")){ + Globals.renderingEngine.getDebugContentPipeline().getDebugBonesPipeline().setEntity(detailViewEntity); + } + + //Browsable list of all animations with their data + if(ImGui.collapsingHeader("Animation Channel Data")){ + Model model = Globals.assetManager.fetchModel(actor.getModelPath()); + ImGui.indent(); + for(Animation animation : model.getAnimations()){ + if(ImGui.collapsingHeader(animation.name)){ + if(ImGui.button("Play")){ + actor.playAnimation(animation.name, AnimationPriorities.getValue(AnimationPriorities.MODIFIER_MAX)); + } + for(AnimChannel channel : animation.channels){ + ImGui.pushID(channel.getNodeID()); + if(ImGui.button("Fully describe")){ + channel.fullDescribeChannel(); + } + ImGui.text("=" + channel.getNodeID() + "="); + ImGui.text("" + channel.getCurrentPosition()); + ImGui.text("" + channel.getCurrentRotation()); + ImGui.text("" + channel.getCurrentScale()); + ImGui.popID(); + } + } + } + ImGui.unindent(); + } + + //print data macros + if(ImGui.collapsingHeader("Print Data")){ + //print bone values + if(ImGui.button("Print current bone values")){ + for(Bone bone : actor.getBoneValues()){ + LoggerInterface.loggerRenderer.DEBUG(bone.boneID); + LoggerInterface.loggerRenderer.DEBUG("" + bone.getFinalTransform()); + } + } + + //print animation keys + if(ImGui.button("Print animation keys")){ + Model model = Globals.assetManager.fetchModel(actor.getModelPath()); + model.describeAllAnimations(); + } + } + } + ImGui.unindent(); + } + } + +} diff --git a/src/main/java/electrosphere/client/ui/menu/debug/entity/ImGuiEntityInstancedActorTab.java b/src/main/java/electrosphere/client/ui/menu/debug/entity/ImGuiEntityInstancedActorTab.java new file mode 100644 index 00000000..2b4a1905 --- /dev/null +++ b/src/main/java/electrosphere/client/ui/menu/debug/entity/ImGuiEntityInstancedActorTab.java @@ -0,0 +1,253 @@ +package electrosphere.client.ui.menu.debug.entity; + +import java.util.Random; + +import electrosphere.entity.ClientEntityUtils; +import electrosphere.entity.Entity; +import electrosphere.entity.state.attach.AttachUtils; +import electrosphere.entity.types.common.CommonEntityUtils; +import electrosphere.entity.types.tree.ProceduralTree; +import electrosphere.game.data.common.CommonEntityType; +import electrosphere.game.data.foliage.type.TreeModel; +import electrosphere.game.data.graphics.ProceduralModel; +import electrosphere.renderer.actor.instance.InstancedActor; +import imgui.ImGui; + +/** + * The actor tab on the entity detail view + */ +public class ImGuiEntityInstancedActorTab { + + /** + * Client scene entity view + */ + protected static void drawInstancedActorView(boolean show, Entity detailViewEntity){ + if(show && ImGui.collapsingHeader("Instanced Actor Details")){ + ImGui.indent(); + float[] limbScalarFalloffFactor = new float[1]; + float[] minimumLimbScalar = new float[1]; + float[] maximumLimbDispersion = new float[1]; + float[] minimumLimbDispersion = new float[1]; + int[] minimumNumberForks = new int[1]; + int[] maximumNumberForks = new int[1]; + int[] maximumTrunkSegments = new int[1]; + int[] maximumBranchSegments = new int[1]; + float[] maxBranchSegmentFalloffFactor = new float[1]; + int[] minimumSegmentToSpawnLeaves = new int[1]; + float[] minBranchHeightToStartSpawningLeaves = new float[1]; + float[] maxBranchHeightToStartSpawningLeaves = new float[1]; + float[] leafIncrement = new float[1]; + int[] minLeavesToSpawnPerPoint = new int[1]; + int[] maxLeavesToSpawnPerPoint = new int[1]; + float[] leafDistanceFromCenter = new float[1]; + float[] peelVariance = new float[1]; + float[] peelMinimum = new float[1]; + float[] swaySigmoidFactor = new float[1]; + int[] minimumSwayTime = new int[1]; + int[] swayTimeVariance = new int[1]; + float[] yawVariance = new float[1]; + float[] yawMinimum = new float[1]; + float[] minimumScalarToGenerateSwayTree = new float[1]; + float[] maximumScalarToGenerateSwayTree = new float[1]; + if(detailViewEntity != null && InstancedActor.getInstancedActor(detailViewEntity) != null){ + // InstancedActor actor = InstancedActor.getInstancedActor(detailViewEntity); + CommonEntityType commonEntityData = CommonEntityUtils.getCommonData(detailViewEntity); + + //procedural model + if(commonEntityData.getGraphicsTemplate().getProceduralModel() != null && ImGui.collapsingHeader("Procedural Model")){ + ProceduralModel proceduralModel = commonEntityData.getGraphicsTemplate().getProceduralModel(); + if(ImGui.button("Regenerate")){ + ImGuiEntityInstancedActorTab.regenerateModel(detailViewEntity,proceduralModel); + } + if(proceduralModel.getTreeModel() != null && ImGui.collapsingHeader("Tree Model")){ + TreeModel treeModel = proceduralModel.getTreeModel(); + + + maximumTrunkSegments[0] = treeModel.getMaximumTrunkSegments(); + if(ImGui.sliderInt("maximumTrunkSegments", maximumTrunkSegments, 1, 8)){ + treeModel.setMaximumTrunkSegments(maximumTrunkSegments[0]); + ImGuiEntityInstancedActorTab.regenerateModel(detailViewEntity,proceduralModel); + } + + + if(ImGui.collapsingHeader("Branches")){ + limbScalarFalloffFactor[0] = treeModel.getLimbScalarFalloffFactor(); + if(ImGui.sliderFloat("limbScalarFalloffFactor", limbScalarFalloffFactor, 0.01f, 1f)){ + treeModel.setLimbScalarFalloffFactor(limbScalarFalloffFactor[0]); + ImGuiEntityInstancedActorTab.regenerateModel(detailViewEntity,proceduralModel); + } + + minimumLimbScalar[0] = treeModel.getMinimumLimbScalar(); + if(ImGui.sliderFloat("minimumLimbScalar", minimumLimbScalar, 0.01f, 1f)){ + treeModel.setLimbScalarFalloffFactor(minimumLimbScalar[0]); + ImGuiEntityInstancedActorTab.regenerateModel(detailViewEntity,proceduralModel); + } + + maximumLimbDispersion[0] = treeModel.getMaximumLimbDispersion(); + if(ImGui.sliderFloat("maximumLimbDispersion", maximumLimbDispersion, 0.01f, 1f)){ + treeModel.setMaximumLimbDispersion(maximumLimbDispersion[0]); + ImGuiEntityInstancedActorTab.regenerateModel(detailViewEntity,proceduralModel); + } + + minimumLimbDispersion[0] = treeModel.getMinimumLimbDispersion(); + if(ImGui.sliderFloat("minimumLimbDispersion", minimumLimbDispersion, 0.01f, 1f)){ + treeModel.setMinimumLimbDispersion(minimumLimbDispersion[0]); + ImGuiEntityInstancedActorTab.regenerateModel(detailViewEntity,proceduralModel); + } + + minimumNumberForks[0] = treeModel.getMinimumNumberForks(); + if(ImGui.sliderInt("minimumNumberForks", minimumNumberForks, 1, 8)){ + treeModel.setMinimumNumberForks(minimumNumberForks[0]); + ImGuiEntityInstancedActorTab.regenerateModel(detailViewEntity,proceduralModel); + } + + maximumNumberForks[0] = treeModel.getMaximumNumberForks(); + if(ImGui.sliderInt("maximumNumberForks", maximumNumberForks, 1, 8)){ + treeModel.setMaximumNumberForks(maximumNumberForks[0]); + ImGuiEntityInstancedActorTab.regenerateModel(detailViewEntity,proceduralModel); + } + + maximumBranchSegments[0] = treeModel.getMaximumBranchSegments(); + if(ImGui.sliderInt("maximumBranchSegments", maximumBranchSegments, 1, 8)){ + treeModel.setMaximumBranchSegments(maximumBranchSegments[0]); + ImGuiEntityInstancedActorTab.regenerateModel(detailViewEntity,proceduralModel); + } + + maxBranchSegmentFalloffFactor[0] = treeModel.getMaxBranchSegmentFalloffFactor(); + if(ImGui.sliderFloat("maxBranchSegmentFalloffFactor", maxBranchSegmentFalloffFactor, 0.01f, 1f)){ + treeModel.setMaxBranchSegmentFalloffFactor(maxBranchSegmentFalloffFactor[0]); + ImGuiEntityInstancedActorTab.regenerateModel(detailViewEntity,proceduralModel); + } + } + + if(ImGui.collapsingHeader("Branch Sway")){ + peelVariance[0] = (float)treeModel.getPeelVariance(); + if(ImGui.sliderFloat("peelVariance", peelVariance, 0.01f, 3f)){ + treeModel.setPeelVariance(peelVariance[0]); + ImGuiEntityInstancedActorTab.regenerateModel(detailViewEntity,proceduralModel); + } + + peelMinimum[0] = (float)treeModel.getPeelMinimum(); + if(ImGui.sliderFloat("peelMinimum", peelMinimum, 0.01f, 3f)){ + treeModel.setPeelMinimum(peelMinimum[0]); + ImGuiEntityInstancedActorTab.regenerateModel(detailViewEntity,proceduralModel); + } + + swaySigmoidFactor[0] = (float)treeModel.getSwaySigmoidFactor(); + if(ImGui.sliderFloat("swaySigmoidFactor", swaySigmoidFactor, 0.01f, 3f)){ + treeModel.setSwaySigmoidFactor(swaySigmoidFactor[0]); + ImGuiEntityInstancedActorTab.regenerateModel(detailViewEntity,proceduralModel); + } + + minimumSwayTime[0] = treeModel.getMinimumSwayTime(); + if(ImGui.sliderInt("minimumSwayTime", minimumSwayTime, 1, 1000)){ + treeModel.setMinimumSwayTime(minimumSwayTime[0]); + ImGuiEntityInstancedActorTab.regenerateModel(detailViewEntity,proceduralModel); + } + + swayTimeVariance[0] = treeModel.getSwayTimeVariance(); + if(ImGui.sliderInt("swayTimeVariance", swayTimeVariance, 1, 1000)){ + treeModel.setSwayTimeVariance(swayTimeVariance[0]); + ImGuiEntityInstancedActorTab.regenerateModel(detailViewEntity,proceduralModel); + } + + yawVariance[0] = (float)treeModel.getYawVariance(); + if(ImGui.sliderFloat("yawVariance", yawVariance, 0.01f, 3f)){ + treeModel.setYawVariance(yawVariance[0]); + ImGuiEntityInstancedActorTab.regenerateModel(detailViewEntity,proceduralModel); + } + + yawMinimum[0] = (float)treeModel.getYawMinimum(); + if(ImGui.sliderFloat("yawMinimum", yawMinimum, 0.01f, 3f)){ + treeModel.setYawMinimum(yawMinimum[0]); + ImGuiEntityInstancedActorTab.regenerateModel(detailViewEntity,proceduralModel); + } + + minimumScalarToGenerateSwayTree[0] = (float)treeModel.getMinimumScalarToGenerateSwayTree(); + if(ImGui.sliderFloat("minimumScalarToGenerateSwayTree", minimumScalarToGenerateSwayTree, 0.01f, 3f)){ + treeModel.setMinimumScalarToGenerateSwayTree(minimumScalarToGenerateSwayTree[0]); + ImGuiEntityInstancedActorTab.regenerateModel(detailViewEntity,proceduralModel); + } + + maximumScalarToGenerateSwayTree[0] = (float)treeModel.getMaximumScalarToGenerateSwayTree(); + if(ImGui.sliderFloat("maximumScalarToGenerateSwayTree", maximumScalarToGenerateSwayTree, 0.01f, 3f)){ + treeModel.setMaximumScalarToGenerateSwayTree(maximumScalarToGenerateSwayTree[0]); + ImGuiEntityInstancedActorTab.regenerateModel(detailViewEntity,proceduralModel); + } + } + + + + if(ImGui.collapsingHeader("Leaves")){ + minimumSegmentToSpawnLeaves[0] = treeModel.getMinimumSegmentToSpawnLeaves(); + if(ImGui.sliderInt("minimumSegmentToSpawnLeaves", minimumSegmentToSpawnLeaves, 1, 8)){ + treeModel.setMinimumSegmentToSpawnLeaves(minimumSegmentToSpawnLeaves[0]); + ImGuiEntityInstancedActorTab.regenerateModel(detailViewEntity,proceduralModel); + } + + + minBranchHeightToStartSpawningLeaves[0] = treeModel.getMinBranchHeightToStartSpawningLeaves(); + if(ImGui.sliderFloat("minBranchHeightToStartSpawningLeaves", minBranchHeightToStartSpawningLeaves, 0.01f, 5f)){ + treeModel.setMinBranchHeightToStartSpawningLeaves(minBranchHeightToStartSpawningLeaves[0]); + ImGuiEntityInstancedActorTab.regenerateModel(detailViewEntity,proceduralModel); + } + + + maxBranchHeightToStartSpawningLeaves[0] = treeModel.getMaxBranchHeightToStartSpawningLeaves(); + if(ImGui.sliderFloat("maxBranchHeightToStartSpawningLeaves", maxBranchHeightToStartSpawningLeaves, 0.01f, 5f)){ + treeModel.setMaxBranchHeightToStartSpawningLeaves(maxBranchHeightToStartSpawningLeaves[0]); + ImGuiEntityInstancedActorTab.regenerateModel(detailViewEntity,proceduralModel); + } + + + leafIncrement[0] = treeModel.getLeafIncrement(); + if(ImGui.sliderFloat("leafIncrement", leafIncrement, 0.01f, 1f)){ + treeModel.setLeafIncrement(leafIncrement[0]); + ImGuiEntityInstancedActorTab.regenerateModel(detailViewEntity,proceduralModel); + } + + minLeavesToSpawnPerPoint[0] = treeModel.getMinLeavesToSpawnPerPoint(); + if(ImGui.sliderInt("minLeavesToSpawnPerPoint", minLeavesToSpawnPerPoint, 1, 8)){ + treeModel.setMinLeavesToSpawnPerPoint(minLeavesToSpawnPerPoint[0]); + ImGuiEntityInstancedActorTab.regenerateModel(detailViewEntity,proceduralModel); + } + + maxLeavesToSpawnPerPoint[0] = treeModel.getMaxLeavesToSpawnPerPoint(); + if(ImGui.sliderInt("maxLeavesToSpawnPerPoint", maxLeavesToSpawnPerPoint, 1, 8)){ + treeModel.setMaxLeavesToSpawnPerPoint(maxLeavesToSpawnPerPoint[0]); + ImGuiEntityInstancedActorTab.regenerateModel(detailViewEntity,proceduralModel); + } + + leafDistanceFromCenter[0] = treeModel.getLeafDistanceFromCenter(); + if(ImGui.sliderFloat("leafDistanceFromCenter", leafDistanceFromCenter, 0.01f, 3f)){ + treeModel.setLeafDistanceFromCenter(leafDistanceFromCenter[0]); + ImGuiEntityInstancedActorTab.regenerateModel(detailViewEntity,proceduralModel); + } + } + } + } + } + ImGui.unindent(); + } + } + + /** + * Regenerates the procedural model for the entity + * @param detailViewEntity The entity + * @param proceduralModel The procedural model + */ + private static void regenerateModel(Entity detailViewEntity, ProceduralModel proceduralModel){ + if(proceduralModel.getTreeModel() != null){ + for(Entity child : AttachUtils.getChildrenList(detailViewEntity)){ + ClientEntityUtils.destroyEntity(child); + } + AttachUtils.getChildrenList(detailViewEntity).clear(); + ProceduralTree.setProceduralActor( + detailViewEntity, + proceduralModel.getTreeModel(), + new Random() + ); + } + } + +} diff --git a/src/main/java/electrosphere/client/ui/menu/debug/ImGuiEntityMacros.java b/src/main/java/electrosphere/client/ui/menu/debug/entity/ImGuiEntityMacros.java similarity index 85% rename from src/main/java/electrosphere/client/ui/menu/debug/ImGuiEntityMacros.java rename to src/main/java/electrosphere/client/ui/menu/debug/entity/ImGuiEntityMacros.java index a36e4b63..6b273d57 100644 --- a/src/main/java/electrosphere/client/ui/menu/debug/ImGuiEntityMacros.java +++ b/src/main/java/electrosphere/client/ui/menu/debug/entity/ImGuiEntityMacros.java @@ -1,4 +1,4 @@ -package electrosphere.client.ui.menu.debug; +package electrosphere.client.ui.menu.debug.entity; import java.util.LinkedList; import java.util.List; @@ -23,13 +23,11 @@ import electrosphere.entity.types.foliage.FoliageUtils; import electrosphere.entity.types.item.ItemUtils; import electrosphere.game.data.creature.type.equip.EquipPoint; import electrosphere.logger.LoggerInterface; -import electrosphere.renderer.actor.Actor; import electrosphere.renderer.actor.ActorAnimationMask; -import electrosphere.renderer.actor.ActorMeshMask; +import electrosphere.renderer.actor.instance.InstancedActor; import electrosphere.renderer.anim.AnimChannel; import electrosphere.renderer.anim.Animation; import electrosphere.renderer.model.Bone; -import electrosphere.renderer.model.Mesh; import electrosphere.renderer.model.Model; import electrosphere.renderer.ui.imgui.ImGuiWindow; import electrosphere.renderer.ui.imgui.ImGuiWindow.ImGuiWindowCallback; @@ -44,8 +42,10 @@ import imgui.ImGui; public class ImGuiEntityMacros { //window for selecting entities to view - protected static ImGuiWindow clientEntityListWindow; - private static boolean filterToCreatures = true; //filters the entity list to just creatures + public static ImGuiWindow clientEntityListWindow; + private static boolean filterBasic = true; //filters out entities we probably wouldn't want to see (particles, terrain meshes, foliage cells, etc) + private static boolean filterToCreatures = false; //filters the entity list to just creatures + private static boolean filterToFoliage = false; //filters the entity list to just foliage //window for viewing details about an entity protected static ImGuiWindow clientEntityDetailWindow; @@ -54,6 +54,7 @@ public class ImGuiEntityMacros { //tree node values private static boolean showDataTab = false; //show all data names stored in the entity private static boolean showActorTab = false; //show the actor tab + private static boolean showInstancedActorTab = false; //show the instanced actor tab private static boolean showPoseActorTab = false; //show the pose actor tab private static boolean showEquipStateTab = false; //actor details private static boolean showFirstPersonTab = false; //first person tab @@ -64,7 +65,7 @@ public class ImGuiEntityMacros { /** * Creates the windows in this file */ - protected static void createClientEntityWindows(){ + public static void createClientEntityWindows(){ createClientEntityDetailWindow(); createClientEntitySelectionWindow(); } @@ -79,14 +80,23 @@ public class ImGuiEntityMacros { public void exec() { //audio engine details ImGui.text("Client Entities"); + if(ImGui.checkbox("Filter Basic", filterBasic)){ + filterBasic = !filterBasic; + } if(ImGui.checkbox("Filter to Creatures", filterToCreatures)){ filterToCreatures = !filterToCreatures; } + if(ImGui.checkbox("Filter to Foliage", filterToFoliage)){ + filterToFoliage = !filterToFoliage; + } for(Entity entity : Globals.clientSceneWrapper.getScene().getEntityList()){ //filters if(filterToCreatures && !CreatureUtils.isCreature(entity)){ continue; } + if(filterToFoliage && !FoliageUtils.isFoliage(entity)){ + continue; + } ImGui.beginGroup(); ImGui.pushID(entity.getId()); ImGui.text("Id: " + entity.getId() + " (" + getEntityName(entity) + ")"); @@ -119,6 +129,9 @@ public class ImGuiEntityMacros { if(EntityUtils.getActor(detailViewEntity) != null && ImGui.checkbox("Actor Details", showActorTab)){ showActorTab = !showActorTab; } + if(InstancedActor.getInstancedActor(detailViewEntity) != null && ImGui.checkbox("Instanced Actor Details", showInstancedActorTab)){ + showInstancedActorTab = !showInstancedActorTab; + } if(EntityUtils.getPoseActor(detailViewEntity) != null && ImGui.checkbox("Pose Actor Details", showPoseActorTab)){ showPoseActorTab = !showPoseActorTab; } @@ -143,7 +156,8 @@ public class ImGuiEntityMacros { ImGui.treePop(); } ImGui.nextColumn(); - drawActorView(); + ImGuiEntityActorTab.drawActorView(showActorTab,detailViewEntity); + ImGuiEntityInstancedActorTab.drawInstancedActorView(showInstancedActorTab, detailViewEntity); drawPoseActor(); drawEquipState(); drawFirstPersonView(); @@ -161,7 +175,7 @@ public class ImGuiEntityMacros { * Shows the entity window for a specific entity * @param entity The entity */ - protected static void showEntity(Entity entity){ + public static void showEntity(Entity entity){ detailViewEntity = entity; clientEntityDetailWindow.setOpen(true); } @@ -179,98 +193,6 @@ public class ImGuiEntityMacros { } } - /** - * Client scene entity view - */ - protected static void drawActorView(){ - if(showActorTab && ImGui.collapsingHeader("Actor Details")){ - ImGui.indent(); - if(detailViewEntity != null && EntityUtils.getActor(detailViewEntity) != null){ - Actor actor = EntityUtils.getActor(detailViewEntity); - - //mesh mask - if(ImGui.collapsingHeader("Mesh Mask")){ - ActorMeshMask meshMask = actor.getMeshMask(); - ImGui.text("To Draw Meshes:"); - for(Mesh mesh : meshMask.getToDrawMeshes()){ - ImGui.text(mesh.getMeshName()); - } - ImGui.text("Blocked Meshes:"); - for(String blocked : meshMask.getBlockedMeshes()){ - ImGui.text(blocked); - } - } - - //animation queue - if(ImGui.collapsingHeader("Animation Queue")){ - Set animationQueue = actor.getAnimationQueue(); - for(ActorAnimationMask mask : animationQueue){ - ImGui.text(mask.getAnimationName() + " - " + mask.getPriority()); - ImGui.text(mask.getDuration() + " " + mask.getTime()); - } - } - - //bone values - if(ImGui.collapsingHeader("Bone Values")){ - for(Bone bone : actor.getBoneValues()){ - ImGui.text(bone.boneID); - ImGui.text("Position: " + actor.getBonePosition(bone.boneID)); - ImGui.text("Rotation: " + actor.getBoneRotation(bone.boneID)); - ImGui.text(bone.getFinalTransform() + ""); - } - } - - //Draws all the bones in the world - if(ImGui.button("Draw Bones")){ - Globals.renderingEngine.getDebugContentPipeline().getDebugBonesPipeline().setEntity(detailViewEntity); - } - - //Browsable list of all animations with their data - if(ImGui.collapsingHeader("Animation Channel Data")){ - Model model = Globals.assetManager.fetchModel(actor.getModelPath()); - ImGui.indent(); - for(Animation animation : model.getAnimations()){ - if(ImGui.collapsingHeader(animation.name)){ - if(ImGui.button("Play")){ - actor.playAnimation(animation.name, AnimationPriorities.getValue(AnimationPriorities.MODIFIER_MAX)); - } - for(AnimChannel channel : animation.channels){ - ImGui.pushID(channel.getNodeID()); - if(ImGui.button("Fully describe")){ - channel.fullDescribeChannel(); - } - ImGui.text("=" + channel.getNodeID() + "="); - ImGui.text("" + channel.getCurrentPosition()); - ImGui.text("" + channel.getCurrentRotation()); - ImGui.text("" + channel.getCurrentScale()); - ImGui.popID(); - } - } - } - ImGui.unindent(); - } - - //print data macros - if(ImGui.collapsingHeader("Print Data")){ - //print bone values - if(ImGui.button("Print current bone values")){ - for(Bone bone : actor.getBoneValues()){ - LoggerInterface.loggerRenderer.DEBUG(bone.boneID); - LoggerInterface.loggerRenderer.DEBUG("" + bone.getFinalTransform()); - } - } - - //print animation keys - if(ImGui.button("Print animation keys")){ - Model model = Globals.assetManager.fetchModel(actor.getModelPath()); - model.describeAllAnimations(); - } - } - } - ImGui.unindent(); - } - } - /** * Draws pose actor */ diff --git a/src/main/java/electrosphere/entity/ClientEntityUtils.java b/src/main/java/electrosphere/entity/ClientEntityUtils.java index 20b67eb8..bf5e5e0a 100644 --- a/src/main/java/electrosphere/entity/ClientEntityUtils.java +++ b/src/main/java/electrosphere/entity/ClientEntityUtils.java @@ -1,9 +1,12 @@ package electrosphere.entity; +import java.util.List; + import org.joml.Quaterniond; import org.joml.Vector3d; import electrosphere.engine.Globals; +import electrosphere.entity.state.attach.AttachUtils; import electrosphere.entity.types.collision.CollisionObjUtils; /** @@ -28,6 +31,16 @@ public class ClientEntityUtils { * @param entity the entity to destroy */ public static void destroyEntity(Entity entity){ + + // + //destroy the child entities, too + if(AttachUtils.hasChildren(entity)){ + List children = AttachUtils.getChildrenList(entity); + for(Entity child : children){ + ClientEntityUtils.destroyEntity(child); + } + } + //check for client-specific stuff Globals.renderingEngine.getLightManager().destroyPointLight(entity); diff --git a/src/main/java/electrosphere/entity/EntityDataStrings.java b/src/main/java/electrosphere/entity/EntityDataStrings.java index 90befa4b..cc721920 100644 --- a/src/main/java/electrosphere/entity/EntityDataStrings.java +++ b/src/main/java/electrosphere/entity/EntityDataStrings.java @@ -42,6 +42,7 @@ public class EntityDataStrings { */ public static final String ENTITY_TYPE = "entityType"; //ie "creature", "foliage", "terrain", etc public static final String ENTITY_SUBTYPE = "entitySubtype"; //ie "human", "woodenCrate", etc + public static final String COMMON_DATA = "commonData"; /* Terrain Entity diff --git a/src/main/java/electrosphere/entity/types/common/CommonEntityUtils.java b/src/main/java/electrosphere/entity/types/common/CommonEntityUtils.java index 446402ea..89eb9b00 100644 --- a/src/main/java/electrosphere/entity/types/common/CommonEntityUtils.java +++ b/src/main/java/electrosphere/entity/types/common/CommonEntityUtils.java @@ -99,6 +99,7 @@ public class CommonEntityUtils { //Set typing stuff // CommonEntityUtils.setTyping(entity,rawType); + CommonEntityUtils.setCommonData(entity,rawType); //tracks whether to generate a drawable or not boolean generateDrawable = true; @@ -392,6 +393,7 @@ public class CommonEntityUtils { // CommonEntityUtils.setTyping(entity,rawType); CommonEntityUtils.serverAttachToTag(entity,rawType); + CommonEntityUtils.setCommonData(entity,rawType); //tracks whether to generate a drawable or not boolean generateDrawable = true; @@ -815,6 +817,24 @@ public class CommonEntityUtils { entity.putData(EntityDataStrings.ENTITY_TYPE, type); } + /** + * Gets the common data on the entity + * @param entity The entity + * @return The common data + */ + public static CommonEntityType getCommonData(Entity entity){ + return (CommonEntityType)entity.getData(EntityDataStrings.COMMON_DATA); + } + + /** + * Sets the common data on the entity + * @param entity The entity + * @param data The common data + */ + public static void setCommonData(Entity entity, CommonEntityType data){ + entity.putData(EntityDataStrings.COMMON_DATA, data); + } + /** * Gets the subtype of this entity * @param entity The entity diff --git a/src/main/java/electrosphere/entity/types/foliage/FoliageUtils.java b/src/main/java/electrosphere/entity/types/foliage/FoliageUtils.java index 39f0565e..0497a8b7 100644 --- a/src/main/java/electrosphere/entity/types/foliage/FoliageUtils.java +++ b/src/main/java/electrosphere/entity/types/foliage/FoliageUtils.java @@ -35,7 +35,7 @@ public class FoliageUtils { public static Entity clientSpawnBasicFoliage(String type, long seed){ FoliageType rawType = Globals.gameConfigCurrent.getFoliageMap().getFoliage(type); Entity rVal; - if(rawType.getTreeModel()!=null){ + if(rawType.getGraphicsTemplate().getProceduralModel().getTreeModel()!=null){ rVal = ProceduralTree.clientGenerateProceduralTree(type, 0); } else { rVal = EntityCreationUtils.createClientSpatialEntity(); @@ -52,6 +52,9 @@ public class FoliageUtils { //Foliage specific transforms // // + rVal.putData(EntityDataStrings.FOLIAGE_TYPE, rawType); + rVal.putData(EntityDataStrings.FOLIAGE_SEED, seed); + rVal.putData(EntityDataStrings.FOLIAGE_IS_SEEDED, true); //audio if(rawType.getAmbientAudio()!=null){ @@ -74,7 +77,7 @@ public class FoliageUtils { public static Entity serverSpawnTreeFoliage(Realm realm, Vector3d position, String type, long seed){ FoliageType rawType = Globals.gameConfigCurrent.getFoliageMap().getFoliage(type); Entity rVal; - if(rawType.getTreeModel()!=null){ + if(rawType.getGraphicsTemplate().getProceduralModel().getTreeModel()!=null){ rVal = ProceduralTree.serverGenerateProceduralTree(realm, position, rawType, seed); } else { rVal = EntityCreationUtils.createServerEntity(realm, position); diff --git a/src/main/java/electrosphere/entity/types/tree/ProceduralTree.java b/src/main/java/electrosphere/entity/types/tree/ProceduralTree.java index 8ad0186c..58526b18 100644 --- a/src/main/java/electrosphere/entity/types/tree/ProceduralTree.java +++ b/src/main/java/electrosphere/entity/types/tree/ProceduralTree.java @@ -22,6 +22,7 @@ import electrosphere.collision.CollisionBodyCreation; import electrosphere.collision.PhysicsEntityUtils; import electrosphere.collision.collidable.Collidable; import electrosphere.engine.Globals; +import electrosphere.entity.ClientEntityUtils; import electrosphere.entity.Entity; import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityDataStrings; @@ -101,10 +102,22 @@ public class ProceduralTree { //call recursive branching routine to generate branches from trunk + leaf blobs FoliageType foliageType = Globals.gameConfigCurrent.getFoliageMap().getFoliage(type); - TreeModel treeModel = foliageType.getTreeModel(); + TreeModel treeModel = foliageType.getGraphicsTemplate().getProceduralModel().getTreeModel(); //generate trunk Entity trunkChild = EntityCreationUtils.createClientSpatialEntity(); + setProceduralActor(trunkChild, treeModel, treeRandom); + + return trunkChild; + } + + /** + * Sets the procedural actor for the tree + * @param trunkChild The entity + * @param treeModel The tree model params + * @param treeRandom The random + */ + public static void setProceduralActor(Entity trunkChild, TreeModel treeModel, Random treeRandom){ InstancedActor instancedActor = InstancedEntityUtils.makeEntityInstancedWithModelTransform(trunkChild, branchInstanceTemplate, modelMatrixAttribute); instancedActor.setAttribute(boneMatrixAttribute, new Matrix4f().identity()); instancedActor.setAttribute(modelMatrixAttribute, new Matrix4f().identity()); @@ -150,7 +163,7 @@ public class ProceduralTree { true ); - return trunkChild; + ClientEntityUtils.initiallyPositionEntity(trunkChild, EntityUtils.getPosition(trunkChild), EntityUtils.getRotation(trunkChild)); } private static List clientGenerateBranchesAlt( @@ -371,7 +384,7 @@ public class ProceduralTree { */ public static Entity serverGenerateProceduralTree(Realm realm, Vector3d position, FoliageType foliageType, long seed){ //call recursive branching routine to generate branches from trunk + leaf blobs - TreeModel treeModel = foliageType.getTreeModel(); + TreeModel treeModel = foliageType.getGraphicsTemplate().getProceduralModel().getTreeModel(); //generate trunk Entity trunkChild = EntityCreationUtils.createServerEntity(realm,position); diff --git a/src/main/java/electrosphere/game/data/common/CommonEntityType.java b/src/main/java/electrosphere/game/data/common/CommonEntityType.java index 8d53567b..4d1d7938 100644 --- a/src/main/java/electrosphere/game/data/common/CommonEntityType.java +++ b/src/main/java/electrosphere/game/data/common/CommonEntityType.java @@ -18,7 +18,6 @@ import electrosphere.game.data.creature.type.movement.MovementSystem; import electrosphere.game.data.creature.type.rotator.RotatorSystem; import electrosphere.game.data.foliage.type.AmbientAudio; import electrosphere.game.data.foliage.type.GrowthModel; -import electrosphere.game.data.foliage.type.TreeModel; import electrosphere.game.data.graphics.GraphicsTemplate; import electrosphere.game.data.particle.ParticleEmitter; @@ -107,11 +106,6 @@ public class CommonEntityType { */ GrowthModel growthModel; - /** - * The model for a tree - */ - TreeModel treeModel; - /** * The ambient audio model */ @@ -276,14 +270,6 @@ public class CommonEntityType { return growthModel; } - /** - * Gets the tree model - * @return The tree model - */ - public TreeModel getTreeModel(){ - return treeModel; - } - /** * Gets the ambient audio model * @return The ambient audio model diff --git a/src/main/java/electrosphere/game/data/foliage/type/TreeModel.java b/src/main/java/electrosphere/game/data/foliage/type/TreeModel.java index 38faf8d2..f104492e 100644 --- a/src/main/java/electrosphere/game/data/foliage/type/TreeModel.java +++ b/src/main/java/electrosphere/game/data/foliage/type/TreeModel.java @@ -96,7 +96,7 @@ public class TreeModel { //The minimum scalar of a branch to generate a sway behavior tree float minimumScalarToGenerateSwayTree; - //The maximum scalar of a branch to generate a sway behavior tree + //The maximum scalar of a branch to generate a sway behavior tree* float maximumScalarToGenerateSwayTree; //The model for the trunk of the tree @@ -354,4 +354,130 @@ public class TreeModel { return leafModelPath; } + public void setLimbScalarFalloffFactor(float limbScalarFalloffFactor) { + this.limbScalarFalloffFactor = limbScalarFalloffFactor; + } + + public void setMinimumLimbScalar(float minimumLimbScalar) { + this.minimumLimbScalar = minimumLimbScalar; + } + + public void setMaximumLimbDispersion(float maximumLimbDispersion) { + this.maximumLimbDispersion = maximumLimbDispersion; + } + + public void setMinimumLimbDispersion(float minimumLimbDispersion) { + this.minimumLimbDispersion = minimumLimbDispersion; + } + + public void setMinimumNumberForks(int minimumNumberForks) { + this.minimumNumberForks = minimumNumberForks; + } + + public void setMaximumNumberForks(int maximumNumberForks) { + this.maximumNumberForks = maximumNumberForks; + } + + public void setBranchHeight(float branchHeight) { + this.branchHeight = branchHeight; + } + + public void setCentralTrunk(boolean centralTrunk) { + this.centralTrunk = centralTrunk; + } + + public void setMaximumTrunkSegments(int maximumTrunkSegments) { + this.maximumTrunkSegments = maximumTrunkSegments; + } + + public void setMaximumBranchSegments(int maximumBranchSegments) { + this.maximumBranchSegments = maximumBranchSegments; + } + + public void setMaxBranchSegmentFalloffFactor(float maxBranchSegmentFalloffFactor) { + this.maxBranchSegmentFalloffFactor = maxBranchSegmentFalloffFactor; + } + + public void setMinimumSegmentToSpawnLeaves(int minimumSegmentToSpawnLeaves) { + this.minimumSegmentToSpawnLeaves = minimumSegmentToSpawnLeaves; + } + + public void setMinBranchHeightToStartSpawningLeaves(float minBranchHeightToStartSpawningLeaves) { + this.minBranchHeightToStartSpawningLeaves = minBranchHeightToStartSpawningLeaves; + } + + public void setMaxBranchHeightToStartSpawningLeaves(float maxBranchHeightToStartSpawningLeaves) { + this.maxBranchHeightToStartSpawningLeaves = maxBranchHeightToStartSpawningLeaves; + } + + public void setLeafIncrement(float leafIncrement) { + this.leafIncrement = leafIncrement; + } + + public void setMinLeavesToSpawnPerPoint(int minLeavesToSpawnPerPoint) { + this.minLeavesToSpawnPerPoint = minLeavesToSpawnPerPoint; + } + + public void setMaxLeavesToSpawnPerPoint(int maxLeavesToSpawnPerPoint) { + this.maxLeavesToSpawnPerPoint = maxLeavesToSpawnPerPoint; + } + + public void setLeafDistanceFromCenter(float leafDistanceFromCenter) { + this.leafDistanceFromCenter = leafDistanceFromCenter; + } + + public void setPhysicsCutoff(int physicsCutoff) { + this.physicsCutoff = physicsCutoff; + } + + public void setPhysicsBody(CollidableTemplate physicsBody) { + this.physicsBody = physicsBody; + } + + public void setPeelVariance(double peelVariance) { + this.peelVariance = peelVariance; + } + + public void setPeelMinimum(double peelMinimum) { + this.peelMinimum = peelMinimum; + } + + public void setSwaySigmoidFactor(double swaySigmoidFactor) { + this.swaySigmoidFactor = swaySigmoidFactor; + } + + public void setMinimumSwayTime(int minimumSwayTime) { + this.minimumSwayTime = minimumSwayTime; + } + + public void setSwayTimeVariance(int swayTimeVariance) { + this.swayTimeVariance = swayTimeVariance; + } + + public void setYawVariance(double yawVariance) { + this.yawVariance = yawVariance; + } + + public void setYawMinimum(double yawMinimum) { + this.yawMinimum = yawMinimum; + } + + public void setMinimumScalarToGenerateSwayTree(float minimumScalarToGenerateSwayTree) { + this.minimumScalarToGenerateSwayTree = minimumScalarToGenerateSwayTree; + } + + public void setMaximumScalarToGenerateSwayTree(float maximumScalarToGenerateSwayTree) { + this.maximumScalarToGenerateSwayTree = maximumScalarToGenerateSwayTree; + } + + public void setTrunkModelPath(String trunkModelPath) { + this.trunkModelPath = trunkModelPath; + } + + public void setLeafModelPath(String leafModelPath) { + this.leafModelPath = leafModelPath; + } + + + }