particle overhaul. emitters!
Some checks reported errors
studiorailgun/Renderer/pipeline/head Something is wrong with the build of this commit

This commit is contained in:
austin 2024-09-19 21:38:42 -04:00
parent 63a302444f
commit 2ef4b13786
27 changed files with 1128 additions and 237 deletions

View File

@ -7,6 +7,29 @@
"tokens": [
"SPAWNPOINT"
]
},
{
"id" : "particleEmitterTest",
"particleEmitter": {
"maxLife": 40,
"lifeCurrent": 0,
"particleVelocity": {
"x": 0.0,
"y": 0.1,
"z": 0.0
},
"acceleration": -0.01,
"texture": "",
"size": 0.3,
"color": {
"x": 0.5,
"y": 0.5,
"z": 0.5
},
"frequency": 1
},
"tokens": [
]
}
],

View File

@ -4,7 +4,11 @@
"name" : "blood",
"maxLife" : 7,
"lifeCurrent" : 0,
"velocity" : 0.3,
"velocity" : {
"x": 0.3,
"y": 0.3,
"z": 0.3
},
"acceleration" : -0.1,
"size": 0.15,
"texture" : "Textures/bloodsplat1.png"

View File

@ -0,0 +1,297 @@
#version 450 core
//foliage.fs
/**
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(std430, binding = CLUSTER_SSBO_BIND_POINT) restrict buffer clusterGridSSBO {
Cluster clusters[];
};
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 {
sampler2D diffuse;
sampler2D specular;
float shininess;
};
in vec3 FragPos;
in vec3 ViewFragPos;
in vec3 Normal;
in vec2 TexCoord;
in vec4 FragPosLightSpace;
in vec4 color;
uniform vec3 viewPos;
// uniform DirLight dirLight;
// uniform PointLight pointLights[NR_POINT_LIGHTS];
// uniform SpotLight spotLight;
uniform Material material;
//texture stuff
// uniform sampler2D ourTexture;
uniform int hasTransparency;
// uniform sampler2D specularTexture;
//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
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);
float easeIn(float interpolator);
float easeOut(float interpolator);
void main(){
vec3 viewDir = normalize(viewPos - FragPos);
//grab light intensity
vec3 lightIntensity = vec3(calcLightIntensityTotal(Normal));
//get color of base texture
// vec3 textureColor = vec3((norm.x + 1) / 2.0, norm.y, 1.0 - (norm.x + 1) / 2.0);
vec3 textureColor = color.rgb;
// vec3 textureColor = vec3(0.17647,0.4,0.09411);//texture(material.diffuse, TexCoord).rgb;
//shadow
float shadow = ShadowCalculation(FragPosLightSpace, normalize(-directLight.direction), Normal);
//
//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, Normal, 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 lightAmount = CalcDirLight(norm, viewDir);
// for(int i = 0; i < NR_POINT_LIGHTS; i++){
// lightAmount += CalcPointLight(i, norm, FragPos, viewDir);
// }
//this final calculation is for transparency
FragColor = vec4(finalColor, 1.0);//texture(ourTexture, TexCoord);//vec4(result, 1.0);
}
// calculates the color when using a directional light.
// vec3 CalcDirLight(vec3 normal, vec3 viewDir){
// vec3 lightDir = normalize(-dLDirection);
// // 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);
// // combine results
// vec3 texColor = texture(material.diffuse, TexCoord).rgb;
// vec3 diffuse = dLDiffuse * diff;
// //vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoord).rgb);
// float shadow = ShadowCalculation(FragPosLightSpace, lightDir, normal);
// return ( dLAmbient + (1.0-shadow) * diffuse ) * texColor;// + specular);
// }
//
float calcLightIntensityAmbient(){
//calculate average of ambient light
float avg = (directLight.color.x + directLight.color.y + directLight.color.z)/3.0;
return avg;
}
//
float calcLightIntensityDir(vec3 normal){
vec3 lightDir = normalize(-directLight.direction);
// diffuse shading
float diff = max(dot(normal, lightDir), 0.0);
return diff;
}
//
float calcLightIntensityTotal(vec3 normal){
//ambient intensity
float ambientLightIntensity = calcLightIntensityAmbient();
//get direct intensity
float directLightIntensity = calcLightIntensityDir(normal);
//sum
float total = ambientLightIntensity + directLightIntensity;
return total;
}
//
vec3 getTotalLightColor(vec3 normal){
//get the direct light color adjusted for intensity
vec3 diffuseLightColor = directLight.color * calcLightIntensityDir(normal);
//sum light colors
vec3 totalLightColor = diffuseLightColor;
return totalLightColor;
}
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(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 = 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 = ambient * attenuation;
diffuse = diffuse * attenuation;
// specular *= attenuation;
vec3 specular = vec3(0,0,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;
}
/**
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){
// perform perspective divide
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
//transform to NDC
projCoords = projCoords * 0.5 + 0.5;
//get closest depth from light's POV
float closestDepth = texture(shadowMap, projCoords.xy).r;
//get depth of current fragment
float currentDepth = projCoords.z;
//calculate bias
float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005);
//calculate shadow value
float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0;
if(projCoords.z > 1.0){
shadow = 0.0;
}
//calculate dot product, if it is >0 we know they're parallel-ish therefore should disregard the shadow mapping
//ie the fragment is already facing away from the light source
float dotprod = dot(normalize(lightDir),normalize(normal));
if(dotprod > 0.0){
shadow = 0.0;
}
// shadow = currentDepth;
return shadow;
}
float easeIn(float interpolator){
return interpolator * interpolator;
}
float easeOut(float interpolator){
return 1 - easeIn(1 - interpolator);
}

View File

@ -0,0 +1,76 @@
//Vertex Shader
#version 450 core
/**
Bind points for different SSBOs
*/
#define PARTICLE_SSBO_BIND_POINT 4
/**
A point light
*/
struct ParticleData {
mat4 model;
vec4 color;
};
//input buffers
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 4) in vec2 aTex;
layout(std430, binding = PARTICLE_SSBO_BIND_POINT) restrict buffer particleSSBO {
ParticleData particleData[];
};
//coordinate space transformation matrices
uniform mat4 transform;
uniform mat4 view;
uniform mat4 projection;
uniform mat4 lightSpaceMatrix;
//output buffers
out vec3 Normal;
out vec3 FragPos;
out vec3 ViewFragPos;
out vec2 TexCoord;
out vec4 FragPosLightSpace;
out vec4 color;
void main() {
ParticleData currentData = particleData[gl_InstanceID];
mat4 model = currentData.model;
color = currentData.color;
//normalize posiiton and normal
vec4 FinalVertex = vec4(aPos, 1.0);
vec4 FinalNormal = vec4(aNormal, 1.0);
//make sure the W component is 1.0
FinalVertex = vec4(FinalVertex.xyz, 1.0);
FinalNormal = vec4(FinalNormal.xyz, 1.0);
//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;
//shadow map stuff
FragPosLightSpace = lightSpaceMatrix * vec4(FragPos, 1.0);
//set final position with opengl space
gl_Position = projection * view * model * FinalVertex;
}

View File

@ -1,3 +1,3 @@
#maven.buildNumber.plugin properties file
#Thu Sep 19 15:35:07 EDT 2024
buildNumber=339
#Thu Sep 19 21:21:28 EDT 2024
buildNumber=351

View File

@ -811,6 +811,7 @@ Fix terrain editing across chunk borders on server
- This is because the ray on the client doesn't intersect at the border (because the physics generation isn't working on chunk-end)
- Also because the client doesn't scan border chunks to see if they should update
Fix shader program bug with no-bone variants
Particle Emitter work (it renders! it has management!)
# TODO

View File

@ -2,6 +2,7 @@ package electrosphere.client.entity.instance;
import java.util.Map;
import electrosphere.renderer.actor.instance.StridedInstanceData;
import electrosphere.renderer.buffer.ShaderAttribute;
import electrosphere.renderer.buffer.HomogenousUniformBuffer.HomogenousBufferTypes;
@ -19,6 +20,16 @@ public class InstanceTemplate {
//The map of all attributes for instanced foliage
protected Map<ShaderAttribute,HomogenousBufferTypes> attributes;
/**
* The strided instance data
*/
protected StridedInstanceData stridedInstanceData;
/**
* The bind point for the data
*/
int dataBindPoint;
//shader paths
protected String vertexPath;
protected String fragmentPath;
@ -42,6 +53,26 @@ public class InstanceTemplate {
return rVal;
}
/**
* Creates a template to create instanced actors off of
* @param capacity The number of actors that can be drawn per frame (going over this limit will result in drawing the closest ${capacity} number of actors)
* @param modelPath The path for the model of the instance
* @param vertexPath The vertex shader path
* @param fragmentPath The fragment shader path
* @param stridedInstanceData The strided instance data to use
* @return The template
*/
public static InstanceTemplate createInstanceTemplate(int capacity, String modelPath, String vertexPath, String fragmentPath, StridedInstanceData stridedInstanceData, int bindPoint){
InstanceTemplate rVal = new InstanceTemplate();
rVal.capacity = capacity;
rVal.modelPath = modelPath;
rVal.vertexPath = vertexPath;
rVal.fragmentPath = fragmentPath;
rVal.stridedInstanceData = stridedInstanceData;
rVal.dataBindPoint = bindPoint;
return rVal;
}
}

View File

@ -23,12 +23,24 @@ public class InstancedEntityUtils {
* @return The instanced actor that is attached to this entity
*/
public static InstancedActor makeEntityInstanced(Entity entity, InstanceTemplate template){
InstancedActor instancedActor = Globals.clientInstanceManager.createInstancedActor(
template.modelPath,
template.vertexPath,
template.fragmentPath,
template.attributes,
template.capacity);
InstancedActor instancedActor = null;
if(template.attributes != null){
instancedActor = Globals.clientInstanceManager.createInstancedActor(
template.modelPath,
template.vertexPath,
template.fragmentPath,
template.attributes,
template.capacity
);
} else if(template.stridedInstanceData != null) {
instancedActor = Globals.clientInstanceManager.createInstancedActor(
template.modelPath,
template.vertexPath,
template.fragmentPath,
template.stridedInstanceData,
template.capacity
);
}
entity.putData(EntityDataStrings.INSTANCED_ACTOR, instancedActor);
entity.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
entity.putData(EntityDataStrings.DATA_STRING_ROTATION, new Quaterniond().identity());
@ -50,12 +62,24 @@ public class InstancedEntityUtils {
* @return The instanced actor that is attached to this entity
*/
public static InstancedActor makeEntityInstancedWithModelTransform(Entity entity, InstanceTemplate template, ShaderAttribute modelTransformAttribute){
InstancedActor instancedActor = Globals.clientInstanceManager.createInstancedActor(
template.modelPath,
template.vertexPath,
template.fragmentPath,
template.attributes,
template.capacity);
InstancedActor instancedActor = null;
if(template.attributes != null){
instancedActor = Globals.clientInstanceManager.createInstancedActor(
template.modelPath,
template.vertexPath,
template.fragmentPath,
template.attributes,
template.capacity
);
} else if(template.stridedInstanceData != null) {
instancedActor = Globals.clientInstanceManager.createInstancedActor(
template.modelPath,
template.vertexPath,
template.fragmentPath,
template.stridedInstanceData,
template.capacity
);
}
entity.putData(EntityDataStrings.INSTANCED_ACTOR, instancedActor);
entity.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
entity.putData(EntityDataStrings.DATA_STRING_ROTATION, new Quaterniond().identity());

View File

@ -3,10 +3,21 @@ package electrosphere.client.entity.particle;
import java.util.Arrays;
import java.util.List;
import org.joml.Vector3d;
import electrosphere.client.entity.instance.InstanceTemplate;
import electrosphere.client.entity.instance.InstancedEntityUtils;
import electrosphere.engine.assetmanager.AssetDataStrings;
import electrosphere.engine.signal.Signal;
import electrosphere.engine.signal.SignalServiceImpl;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityCreationUtils;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.client.particle.ClientParticleTree;
import electrosphere.game.data.particle.ParticleData;
import electrosphere.renderer.actor.instance.StridedInstanceData;
import electrosphere.renderer.buffer.HomogenousUniformBuffer.HomogenousBufferTypes;
import electrosphere.renderer.buffer.ShaderAttribute;
/**
* The particle service
@ -18,16 +29,20 @@ public class ParticleService extends SignalServiceImpl {
*/
static final int MAX_PARTICLES = 1000;
/**
* The bind point for the particle ssbo
*/
static final int PARTICLE_SSBO_BIND_POINT = 4;
/**
* Path to the vertex shader
*/
static final String VERTEX_SHADER_PATH = "";
static final String VERTEX_SHADER_PATH = "Shaders/entities/particle/particle.vs";
/**
* Path to the fragment shader
*/
static final String FRAGMENT_SHADER_PATH = "";
static final String FRAGMENT_SHADER_PATH = "Shaders/entities/particle/particle.fs";
/**
@ -35,6 +50,16 @@ public class ParticleService extends SignalServiceImpl {
*/
StridedInstanceData particleInstanceData;
/**
* The template to use when creating instanced actors
*/
InstanceTemplate instanceTemplate;
ShaderAttribute modelAttrib;
ShaderAttribute colorAttrib;
/**
* Constructor
*/
@ -55,17 +80,14 @@ public class ParticleService extends SignalServiceImpl {
boolean rVal = false;
switch(signal.getType()){
case RENDERING_ENGINE_READY: {
List<HomogenousBufferTypes> types = Arrays.asList(new HomogenousBufferTypes[]{
//position
HomogenousBufferTypes.VEC3D,
//rotation
HomogenousBufferTypes.VEC4D,
//scale
HomogenousBufferTypes.VEC3D,
//texture index
HomogenousBufferTypes.INT,
modelAttrib = new ShaderAttribute("model", HomogenousBufferTypes.MAT4F);
colorAttrib = new ShaderAttribute("color", HomogenousBufferTypes.VEC4F);
List<ShaderAttribute> types = Arrays.asList(new ShaderAttribute[]{
modelAttrib,
colorAttrib,
});
this.particleInstanceData = new StridedInstanceData(MAX_PARTICLES,types,VERTEX_SHADER_PATH,FRAGMENT_SHADER_PATH);
this.particleInstanceData = new StridedInstanceData(MAX_PARTICLES,PARTICLE_SSBO_BIND_POINT,types,VERTEX_SHADER_PATH,FRAGMENT_SHADER_PATH);
this.instanceTemplate = InstanceTemplate.createInstanceTemplate(MAX_PARTICLES, AssetDataStrings.MODEL_PARTICLE, VERTEX_SHADER_PATH, FRAGMENT_SHADER_PATH, particleInstanceData, PARTICLE_SSBO_BIND_POINT);
rVal = true;
} break;
default: {
@ -73,5 +95,35 @@ public class ParticleService extends SignalServiceImpl {
}
return rVal;
}
/**
* Gets the instance data for the particles
* @return The instance data
*/
public StridedInstanceData getInstanceData(){
return this.particleInstanceData;
}
/**
* Spawns a particle
* @param data The particle data for the particle
* @param position The position of the particle
* @return The particle
*/
public Entity spawn(ParticleData data, Vector3d position){
Entity rVal = EntityCreationUtils.createClientSpatialEntity();
InstancedEntityUtils.makeEntityInstanced(rVal, instanceTemplate);
EntityUtils.getPosition(rVal).set(position);
ClientParticleTree.attachTree(rVal, data);
return rVal;
}
public ShaderAttribute getModelAttrib(){
return modelAttrib;
}
public ShaderAttribute getColorAttrib(){
return colorAttrib;
}
}

View File

@ -1,14 +1,14 @@
package electrosphere.client.entity.particle;
import electrosphere.engine.Globals;
import electrosphere.engine.assetmanager.AssetDataStrings;
import electrosphere.entity.DrawableUtils;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityCreationUtils;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityTags;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.ParticleTree;
import electrosphere.entity.state.particle.ClientParticleTree;
import electrosphere.entity.state.client.particle.ClientParticleTree;
import electrosphere.game.data.particle.ParticleData;
import electrosphere.renderer.actor.Actor;
import electrosphere.renderer.actor.ActorTextureMask;
@ -16,7 +16,6 @@ import electrosphere.renderer.actor.ActorTextureMask;
import java.util.Arrays;
import org.joml.Vector3d;
import org.joml.Vector3f;
/**
* Particle utility functions
@ -27,15 +26,15 @@ public class ParticleUtils {
public static Entity clientSpawnStaticBillboardParticle(){
Entity rVal = EntityCreationUtils.createClientSpatialEntity();
EntityCreationUtils.makeEntityDrawable(rVal, Globals.particleBillboardModel);
ParticleTree particleTree = new ParticleTree(rVal, 10, new Vector3f(0,0,0), 0, 0, false);
rVal.putData(EntityDataStrings.TREE_CLIENTPARTICLETREE, particleTree);
rVal.putData(EntityDataStrings.IS_PARTICLE, true);
Globals.clientSceneWrapper.getScene().registerEntityToTag(rVal, EntityTags.PARTICLE);
return rVal;
}
// public static Entity clientSpawnStaticBillboardParticle(){
// Entity rVal = EntityCreationUtils.createClientSpatialEntity();
// EntityCreationUtils.makeEntityDrawable(rVal, Globals.particleBillboardModel);
// ClientParticleTree particleTree = new ClientParticleTree(rVal, 10, new Vector3f(0,0,0), 0, 0, false);
// rVal.putData(EntityDataStrings.TREE_CLIENTPARTICLETREE, particleTree);
// rVal.putData(EntityDataStrings.IS_PARTICLE, true);
// Globals.clientSceneWrapper.getScene().registerEntityToTag(rVal, EntityTags.PARTICLE);
// return rVal;
// }
/**
* Spawns a billboard particle
@ -45,7 +44,7 @@ public class ParticleUtils {
*/
public static Entity clientSpawnBillboardParticle(ParticleData data, Vector3d destination){
Entity rVal = EntityCreationUtils.createClientSpatialEntity();
EntityCreationUtils.makeEntityDrawable(rVal, Globals.particleBillboardModel);
EntityCreationUtils.makeEntityDrawable(rVal, AssetDataStrings.MODEL_PARTICLE);
//actor logic
Actor particleActor = EntityUtils.getActor(rVal);

View File

@ -76,6 +76,7 @@ public class ClientSimulation {
//
//update attached entity positions
AttachUtils.clientUpdateAttachedEntityPositions();
Globals.particleService.handleAllSignals();
//
//Hitbox stuff
Globals.profiler.beginCpuSample("update hitboxes");

View File

@ -292,7 +292,6 @@ public class Globals {
//
// Particle stuff
//
public static String particleBillboardModel;
public static ParticleDefinition particleDefinition;
public static ParticleService particleService;
@ -619,7 +618,7 @@ public class Globals {
fontManager.loadFonts();
assetManager.registerModelToSpecificString(RenderUtils.createBitmapCharacter(), AssetDataStrings.BITMAP_CHARACTER_MODEL);
//particle billboard model
particleBillboardModel = assetManager.registerModel(RenderUtils.createParticleModel());
assetManager.registerModelToSpecificString(RenderUtils.createParticleModel(), AssetDataStrings.MODEL_PARTICLE);
//initialize required windows
WindowUtils.initBaseWindows();
//init default shaderProgram

View File

@ -15,6 +15,7 @@ public class AssetDataStrings {
public static final String UNITSPHERE = "unitSphere";
public static final String UNITCYLINDER = "unitCylinder";
public static final String UNITCUBE = "unitCube";
public static final String MODEL_PARTICLE = "particle";
/**
* UI generic audio

View File

@ -3,6 +3,7 @@ package electrosphere.entity;
import org.joml.Quaterniond;
import org.joml.Vector3d;
import electrosphere.engine.Globals;
import electrosphere.entity.types.collision.CollisionObjUtils;
/**
@ -28,7 +29,8 @@ public class ClientEntityUtils {
*/
public static void destroyEntity(Entity entity){
//check for client-specific stuff
Globals.renderingEngine.getLightManager().destroyPointLight(entity);
//deregister all behavior trees
EntityUtils.cleanUpEntity(entity);
}

View File

@ -260,9 +260,10 @@ public class EntityDataStrings {
public static final String TREE_SERVEREQUIPSTATE = "treeServerEquipState";
/*
Light state
Client-only components
*/
public static final String TREE_CLIENTLIGHTSTATE = "treeClientLightState";
public static final String TREE_CLIENTPARTICLEEMITTERSTATE = "treeClientParticleEmitterState";
/*
Inventory in general

View File

@ -1,68 +0,0 @@
package electrosphere.entity.state;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.btree.BehaviorTree;
import org.joml.Vector3d;
import org.joml.Vector3f;
/**
* Particle b tree
*/
public class ParticleTree implements BehaviorTree {
Entity parent;
boolean hasLife = true;
int maxLife;
int lifeCurrent;
Vector3f destination;
float velocity;
float acceleration;
public ParticleTree(Entity parent, int maxLife, Vector3f destination, float velocity, float acceleration, boolean hasLife){
this.parent = parent;
this.maxLife = maxLife;
this.destination = destination;
this.velocity = velocity;
this.acceleration = acceleration;
this.hasLife = hasLife;
lifeCurrent = maxLife;
}
public int getMaxLife() {
return maxLife;
}
public int getLifeCurrent() {
return lifeCurrent;
}
public Vector3f getDestination() {
return destination;
}
public float getVelocity() {
return velocity;
}
public float getAcceleration() {
return acceleration;
}
public void simulate(float deltaTime){
Vector3d parentPosition = EntityUtils.getPosition(parent);
parentPosition.add(new Vector3f(destination).mul(velocity));
velocity = velocity - acceleration;
if(velocity < 0){
velocity = 0;
acceleration = 0;
}
if(hasLife){
lifeCurrent--;
if(lifeCurrent <= 0){
EntityUtils.cleanUpEntity(parent);
}
}
}
}

View File

@ -0,0 +1,107 @@
package electrosphere.entity.state.client.particle;
import org.joml.Vector3d;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.btree.BehaviorTree;
import electrosphere.entity.state.equip.ClientEquipState;
import electrosphere.game.data.particle.ParticleData;
import electrosphere.game.data.particle.ParticleEmitter;
/**
* A component that causes the entity to emit particles
*/
public class ClientParticleEmitterComponent implements BehaviorTree {
/**
* The parent entity
*/
Entity parent;
/**
* The particle emitter data
*/
ParticleEmitter particleEmitter;
/**
* The last frame this emitter sent out a particle
*/
long lastEmittedFrame = 0;
@Override
public void simulate(float deltaTime) {
Vector3d entityPos = EntityUtils.getPosition(parent);
if((float)(Globals.timekeeper.getNumberOfRenderFramesElapsed() - lastEmittedFrame) > particleEmitter.getFrequency()){
lastEmittedFrame = Globals.timekeeper.getNumberOfRenderFramesElapsed();
//create particle here
Globals.particleService.spawn(this.getData(), new Vector3d(entityPos));
}
}
/**
* Private constructor
* @param parent
* @param params
*/
private ClientParticleEmitterComponent(Entity parent, Object ... params){
this.parent = parent;
particleEmitter = (ParticleEmitter)params[0];
}
/**
* Gets particle data for a new particle
* @return The data
*/
private ParticleData getData(){
ParticleData data = new ParticleData();
data.setAcceleration(this.particleEmitter.getAcceleration());
data.setColor(this.particleEmitter.getColor());
data.setLifeCurrent(this.particleEmitter.getLifeCurrent());
data.setMaxLife(this.particleEmitter.getMaxLife());
data.setSize(this.particleEmitter.getSize());
data.setTexture(this.particleEmitter.getTexture());
data.setVelocity(this.particleEmitter.getParticleVelocity());
return data;
}
/**
* <p>
* Attaches this tree to the entity.
* </p>
* @param entity The entity to attach to
* @param tree The behavior tree to attach
* @param params Optional parameters that will be provided to the constructor
*/
public static ClientParticleEmitterComponent attachTree(Entity parent, Object ... params){
ClientParticleEmitterComponent rVal = new ClientParticleEmitterComponent(parent,params);
//!!WARNING!! from here below should not be touched
//This was generated automatically to properly alert various systems that the btree exists and should be tracked
parent.putData(EntityDataStrings.TREE_CLIENTPARTICLEEMITTERSTATE, rVal);
Globals.clientSceneWrapper.getScene().registerBehaviorTree(rVal);
return rVal;
}
/**
* <p>
* Detatches this tree from the entity.
* </p>
* @param entity The entity to detach to
* @param tree The behavior tree to detach
*/
public static void detachTree(Entity entity, BehaviorTree tree){
}
/**
* <p>
* Gets the ClientEquipState of the entity
* </p>
* @param entity the entity
* @return The ClientEquipState
*/
public static ClientEquipState getClientEquipState(Entity entity){
return (ClientEquipState)entity.getData(EntityDataStrings.TREE_CLIENTPARTICLEEMITTERSTATE);
}
}

View File

@ -1,10 +1,15 @@
package electrosphere.entity.state.particle;
package electrosphere.entity.state.client.particle;
import java.util.Random;
import org.joml.AxisAngle4f;
import org.joml.Matrix4f;
import org.joml.Quaternionf;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector4f;
import electrosphere.client.entity.camera.CameraEntityUtils;
import electrosphere.engine.Globals;
import electrosphere.entity.ClientEntityUtils;
import electrosphere.entity.Entity;
@ -12,6 +17,7 @@ import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.btree.BehaviorTree;
import electrosphere.game.data.particle.ParticleData;
import electrosphere.renderer.actor.instance.InstancedActor;
/**
* Particle component for a client-side particle
@ -28,15 +34,21 @@ public class ClientParticleTree implements BehaviorTree {
//current life
int lifeCurrent;
//The destination of the particle
Vector3d destination;
//the velocity of the particle
float velocity;
Vector3d velocity;
//the acceleration of the particle
float acceleration;
/**
* The data for this particle
*/
ParticleData particleData;
/**
* The color of the particle
*/
Vector3d color;
/**
@ -48,20 +60,16 @@ public class ClientParticleTree implements BehaviorTree {
if(params.length < 1){
throw new IllegalArgumentException("No particle data was provided");
}
if(params.length < 2){
throw new IllegalArgumentException("No destination set for the particle");
}
ParticleData particleData = (ParticleData)params[0];
Vector3d destination = (Vector3d)params[1];
this.particleData = (ParticleData)params[0];
//sets data for the tree
this.parent = parent;
this.maxLife = particleData.getMaxLife();
this.destination = destination;
this.velocity = particleData.getVelocity();
this.acceleration = particleData.getAcceleration();
this.hasLife = particleData.getMaxLife() != null;
this.lifeCurrent = maxLife;
this.color = new Vector3d(new Random().nextFloat(),new Random().nextFloat(),new Random().nextFloat());
}
public int getMaxLife() {
@ -72,11 +80,7 @@ public class ClientParticleTree implements BehaviorTree {
return lifeCurrent;
}
public Vector3d getDestination() {
return destination;
}
public float getVelocity() {
public Vector3d getVelocity() {
return velocity;
}
@ -86,17 +90,25 @@ public class ClientParticleTree implements BehaviorTree {
@Override
public void simulate(float deltaTime){
InstancedActor instancedActor = InstancedActor.getInstancedActor(parent);
Vector3d parentPosition = EntityUtils.getPosition(parent);
parentPosition.add(new Vector3d(destination).mul(velocity));
velocity = velocity + acceleration;
if(velocity < 0){
velocity = 0;
Vector3f cameraPos = CameraEntityUtils.getCameraCenter(Globals.playerCamera);
//update position
parentPosition.set(new Vector3d(parentPosition).add(velocity));
//update velocity
Vector3d accelerationVec = new Vector3d(velocity).normalize().mul(acceleration);
velocity = new Vector3d(velocity).add(accelerationVec);
if(velocity.length() < 0){
velocity = new Vector3d(0,0,0);
acceleration = 0;
}
if(hasLife){
lifeCurrent--;
if(lifeCurrent <= 0){
ClientEntityUtils.destroyEntity(parent);
Globals.clientSceneWrapper.getScene().deregisterBehaviorTree(this);
}
}
@ -104,6 +116,19 @@ public class ClientParticleTree implements BehaviorTree {
Matrix4f rotationMatrix = new Matrix4f(Globals.viewMatrix).invert();
Quaternionf rotation = new Quaternionf(rotationMatrix.getRotation(new AxisAngle4f()));
EntityUtils.getRotation(parent).set(rotation);
Vector3f scale = EntityUtils.getScale(parent);
scale.set(this.particleData.getSize());
//push values to buffer that eventually gets uploaded to gpu
if(instancedActor != null){
instancedActor.setAttribute(Globals.particleService.getModelAttrib(), new Matrix4f().translationRotateScale(
new Vector3f((float)parentPosition.x,(float)parentPosition.y,(float)parentPosition.z).sub(cameraPos),
new Quaternionf(rotation),
scale
));
instancedActor.setAttribute(Globals.particleService.getColorAttrib(), new Vector4f((float)this.color.x,(float)this.color.y,(float)this.color.z,1.0f));
}
}
/**

View File

@ -84,7 +84,7 @@ public class ClientPointLightComponent implements BehaviorTree {
* @return The ClientEquipState
*/
public static ClientEquipState getClientEquipState(Entity entity){
return (ClientEquipState)entity.getData(EntityDataStrings.TREE_CLIENTEQUIPSTATE);
return (ClientEquipState)entity.getData(EntityDataStrings.TREE_CLIENTLIGHTSTATE);
}
}

View File

@ -20,6 +20,7 @@ import electrosphere.entity.state.attack.ServerAttackTree;
import electrosphere.entity.state.attack.ShooterTree;
import electrosphere.entity.state.block.ClientBlockTree;
import electrosphere.entity.state.block.ServerBlockTree;
import electrosphere.entity.state.client.particle.ClientParticleEmitterComponent;
import electrosphere.entity.state.equip.ClientEquipState;
import electrosphere.entity.state.equip.ServerEquipState;
import electrosphere.entity.state.gravity.ClientGravityTree;
@ -257,6 +258,15 @@ public class CommonEntityUtils {
ClientPointLightComponent.attachTree(entity, rawType.getPointLight());
}
//
//
// Particle emitter
//
//
if(rawType.getParticleEmitter() != null){
ClientParticleEmitterComponent.attachTree(entity, rawType.getParticleEmitter());
}
if(rawType.getEquipPoints() != null && rawType.getEquipPoints().size() > 0){
ClientEquipState.attachTree(entity, rawType.getEquipPoints());
entity.putData(EntityDataStrings.EQUIP_INVENTORY, RelationalInventoryState.buildRelationalInventoryStateFromEquipList(rawType.getEquipPoints()));

View File

@ -21,6 +21,7 @@ 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;
/**
* Common data that all entity types use
@ -137,6 +138,11 @@ public class CommonEntityType {
*/
PointLightDescription pointLight;
/**
* The particle emitter assigned to the entity
*/
ParticleEmitter particleEmitter;
/**
* Gets the id for this creature type
* @return The id
@ -321,4 +327,12 @@ public class CommonEntityType {
return pointLight;
}
/**
* Gets the particle emitter data
* @return The particle emitter data
*/
public ParticleEmitter getParticleEmitter(){
return particleEmitter;
}
}

View File

@ -1,5 +1,7 @@
package electrosphere.game.data.particle;
import org.joml.Vector3d;
/**
* Data on how a particle should behave
*/
@ -16,7 +18,6 @@ public class ParticleData {
*/
Integer maxLife;
/**
* The life the particle starts with
*/
@ -26,7 +27,7 @@ public class ParticleData {
/**
* The initial velocity of the particle
*/
Float velocity;
Vector3d velocity;
/**
* The acceleration of the particle
@ -43,6 +44,11 @@ public class ParticleData {
*/
Float size;
/**
* The color of the particle
*/
Vector3d color;
/**
* Gets the max life of the particle
* @return The max life
@ -63,7 +69,7 @@ public class ParticleData {
* Gets the starting velocity of the particle
* @return The starting velocity
*/
public Float getVelocity(){
public Vector3d getVelocity(){
return velocity;
}
@ -99,4 +105,38 @@ public class ParticleData {
return size;
}
public void setName(String name) {
this.name = name;
}
public void setMaxLife(Integer maxLife) {
this.maxLife = maxLife;
}
public void setLifeCurrent(Integer lifeCurrent) {
this.lifeCurrent = lifeCurrent;
}
public void setVelocity(Vector3d velocity) {
this.velocity = velocity;
}
public void setAcceleration(Float acceleration) {
this.acceleration = acceleration;
}
public void setTexture(String texture) {
this.texture = texture;
}
public void setSize(Float size) {
this.size = size;
}
public void setColor(Vector3d color) {
this.color = color;
}
}

View File

@ -0,0 +1,166 @@
package electrosphere.game.data.particle;
import org.joml.Vector3d;
/**
* Describes a particle emitter
*/
public class ParticleEmitter {
/**
* The name of the particle type
*/
String name;
/**
* The maximum life of the particle
*/
Integer maxLife;
/**
* The life the particle starts with
*/
Integer lifeCurrent;
/**
* The initial velocity of the particle
*/
Vector3d particleVelocity;
/**
* The acceleration of the particle
*/
Float acceleration;
/**
* The texture of the particle
*/
String texture;
/**
* The size of the particle
*/
Float size;
/**
* The color of the particle
*/
Vector3d color;
/**
* The number of particles to emit per frame
*/
Float frequency;
/**
* Gets the max life of the particle
* @return The max life
*/
public Integer getMaxLife(){
return maxLife;
}
/**
* Gets the starting life of the particle
* @return The starting life
*/
public Integer getLifeCurrent(){
return lifeCurrent;
}
/**
* Gets the starting velocity of the particle
* @return The starting velocity
*/
public Vector3d getParticleVelocity(){
return particleVelocity;
}
/**
* Gets the acceleration of the particle
* @return The acceleration
*/
public Float getAcceleration(){
return acceleration;
}
/**
* Gets the texture of the particle
* @return The texture
*/
public String getTexture(){
return texture;
}
/**
* Gets the name of the particle type
* @return The name of the particle type
*/
public String getName(){
return name;
}
/**
* Gets the size of the particle
* @return The size of the particle
*/
public Float getSize(){
return size;
}
/**
* Gets the number of particles to emit per frame
* @return The number of particles to emit per frame
*/
public Float getFrequency(){
return frequency;
}
/**
* Gets the color of the particles generated by the emitted
* @return The color
*/
public Vector3d getColor(){
return color;
}
public void setName(String name) {
this.name = name;
}
public void setMaxLife(Integer maxLife) {
this.maxLife = maxLife;
}
public void setLifeCurrent(Integer lifeCurrent) {
this.lifeCurrent = lifeCurrent;
}
public void setParticleVelocity(Vector3d particleVelocity) {
this.particleVelocity = particleVelocity;
}
public void setAcceleration(Float acceleration) {
this.acceleration = acceleration;
}
public void setTexture(String texture) {
this.texture = texture;
}
public void setSize(Float size) {
this.size = size;
}
public void setColor(Vector3d color) {
this.color = color;
}
public void setFrequency(Float frequency){
this.frequency = frequency;
}
}

View File

@ -5,12 +5,11 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import electrosphere.engine.Globals;
import electrosphere.renderer.OpenGLState;
import electrosphere.renderer.RenderPipelineState;
import electrosphere.renderer.buffer.ShaderAttribute;
import electrosphere.renderer.buffer.HomogenousUniformBuffer.HomogenousBufferTypes;
import electrosphere.renderer.buffer.ShaderAttribute;
import electrosphere.renderer.model.Model;
import electrosphere.renderer.shader.ShaderProgram;
@ -67,6 +66,33 @@ public class InstanceManager {
return rVal;
}
/**
* Creates an instanced actor of a model at a given model path
* @param modelPath The path for the model
* @return The instanced actor
*/
public InstancedActor createInstancedActor(
String modelPath,
String vertexShaderPath,
String fragmentShaderPath,
StridedInstanceData instanceData,
int capacity
){
InstancedActor rVal = new InstancedActor(modelPath);
if(!pathToInstanceData.containsKey(modelPath)){
//queue shader
Globals.assetManager.addShaderToQueue(vertexShaderPath, fragmentShaderPath);
//if asset manager doesn't have model, queue model
if(Globals.assetManager.fetchModel(modelPath) == null){
Globals.assetManager.addModelPathToQueue(modelPath);
}
//register to internal-to-manager datastructures
pathToInstanceData.put(modelPath,instanceData);
modelsToDraw.add(modelPath);
}
return rVal;
}
/**
* Draws all models that are queued in this instance manager
*/

View File

@ -6,9 +6,13 @@ import java.util.Map;
import org.joml.Matrix4d;
import org.joml.Matrix4f;
import org.joml.Quaterniond;
import org.joml.Quaternionf;
import org.joml.Sphered;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector4d;
import org.joml.Vector4f;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
@ -116,8 +120,18 @@ public class InstancedActor implements Comparable<InstancedActor> {
attributes.put(attribute, value);
} else if(value instanceof Vector3f){
attributes.put(attribute, value);
} else if(value instanceof Vector3d){
attributes.put(attribute, value);
} else if(value instanceof Vector4d){
attributes.put(attribute, value);
} else if(value instanceof Vector4f){
attributes.put(attribute, value);
} else if(value instanceof Quaterniond){
attributes.put(attribute, value);
} else if(value instanceof Quaternionf){
attributes.put(attribute, value);
} else {
LoggerInterface.loggerRenderer.ERROR("Unsupported operation", new Exception());
LoggerInterface.loggerRenderer.ERROR("Unsupported operation " + value, new Exception());
}
// attributes.put(attribute, value);
}

View File

@ -13,10 +13,10 @@ import org.joml.Vector3f;
import org.joml.Vector4d;
import org.joml.Vector4f;
import electrosphere.renderer.buffer.HomogenousUniformBuffer.HomogenousBufferTypes;
import electrosphere.renderer.buffer.HomogenousUniformBuffer;
import electrosphere.renderer.buffer.ShaderAttribute;
import electrosphere.renderer.buffer.ShaderStorageBuffer;
import electrosphere.logger.LoggerInterface;
import electrosphere.renderer.OpenGLState;
import electrosphere.renderer.RenderPipelineState;
import electrosphere.renderer.buffer.BufferEnums.BufferAccess;
@ -27,7 +27,7 @@ import electrosphere.renderer.buffer.BufferEnums.BufferUsage;
*/
public class StridedInstanceData implements InstanceData {
//the capacity (number of instanced) of this data block. Defaults to 100
//the capacity (number of instances) of this data block. Defaults to 1000
int capacity = 1000;
//shader paths
@ -45,35 +45,60 @@ public class StridedInstanceData implements InstanceData {
Map<Integer,InstancedActor> indexActorMap = new HashMap<Integer,InstancedActor>();
//list of all attribute indices in use by this instance data
List<ShaderAttribute> attributeIndices = new LinkedList<ShaderAttribute>();
List<ShaderAttribute> attributes;
//the SSBO
ShaderStorageBuffer buffer;
/**
* The index to bind to
*/
int bindPoint;
/**
* Constructor
* @param capacity Capacity of the buffer (number of elements) backing this data
*/
public StridedInstanceData(int capacity, List<HomogenousBufferTypes> types, String vertexPath, String fragmentPath){
public StridedInstanceData(int capacity, int bindPoint, List<ShaderAttribute> attributes, String vertexPath, String fragmentPath){
int entrySize = 0;
for(HomogenousBufferTypes type : types){
entrySize = entrySize + HomogenousUniformBuffer.calculateTypeSize(type);
boolean hitMat = false;
boolean hitVec = false;
boolean hitPrimitive = false;
for(ShaderAttribute attribute : attributes){
entrySize = entrySize + HomogenousUniformBuffer.calculateTypeSize(attribute.getType());
switch(attribute.getType()){
case MAT4D:
case MAT4F: {
hitMat = true;
} break;
case VEC3D:
case VEC3F:
case VEC4D:
case VEC4F: {
hitVec = true;
} break;
case INT:
case DOUBLE:
case FLOAT: {
hitPrimitive = true;
} break;
}
}
if(hitPrimitive && (hitMat || hitVec)){
String message = "Warning! You are mixing a larger alignment type (vec, mat) with primitives (int, float)!\n" +
"This can potentially cause alignment bugs. See hhttps://learnopengl.com/Advanced-OpenGL/Advanced-GLSL or \n" +
"https://www.khronos.org/opengl/wiki/Interface_Block_(GLSL)#Memory_layout for details on memory layout!"
;
LoggerInterface.loggerRenderer.WARNING(message);
}
this.attributes = attributes;
this.capacity = capacity;
this.vertexShaderPath = vertexPath;
this.fragmentShaderPath = fragmentPath;
actorQueue = new LinkedList<InstancedActor>();
this.buffer = new ShaderStorageBuffer(capacity * entrySize, BufferUsage.STREAM, BufferAccess.DRAW);
}
/**
* Adds a new type of attribute to this instance data block
* @param shaderAttribute The shader attribute
* @param type The type of the attribute
*/
protected void addDataType(ShaderAttribute shaderAttribute, HomogenousBufferTypes type){
attributeIndices.add(shaderAttribute);
this.bindPoint = bindPoint;
}
@ -108,90 +133,96 @@ public class StridedInstanceData implements InstanceData {
public void fillBuffers(){
int i = 0;
ByteBuffer byteBuff = this.buffer.getBuffer();
byteBuff.limit(byteBuff.capacity());
//buffer data
for(InstancedActor actor : actorQueue){
//push values to attribute buffers
for(ShaderAttribute attribute : attributeIndices){
switch(attribute.getType()){
case VEC3F: {
Vector3f vec = (Vector3f)actor.getAttributeValue(attribute);
byteBuff.putFloat(vec.x);
byteBuff.putFloat(vec.y);
byteBuff.putFloat(vec.z);
} break;
case VEC3D: {
Vector3d vec = (Vector3d)actor.getAttributeValue(attribute);
byteBuff.putDouble(vec.x);
byteBuff.putDouble(vec.y);
byteBuff.putDouble(vec.z);
} break;
case VEC4F: {
Vector4f vec = (Vector4f)actor.getAttributeValue(attribute);
byteBuff.putFloat(vec.w);
byteBuff.putFloat(vec.x);
byteBuff.putFloat(vec.y);
byteBuff.putFloat(vec.z);
} break;
case VEC4D: {
Vector4d vec = (Vector4d)actor.getAttributeValue(attribute);
byteBuff.putDouble(vec.w);
byteBuff.putDouble(vec.x);
byteBuff.putDouble(vec.y);
byteBuff.putDouble(vec.z);
} break;
case MAT4F: {
Matrix4f mat = (Matrix4f)actor.getAttributeValue(attribute);
byteBuff.putFloat(mat.m00());
byteBuff.putFloat(mat.m01());
byteBuff.putFloat(mat.m02());
byteBuff.putFloat(mat.m03());
for(ShaderAttribute attribute : attributes){
if(actor.getAttributeValue(attribute) != null){
switch(attribute.getType()){
case VEC3F: {
Vector3f vec = (Vector3f)actor.getAttributeValue(attribute);
byteBuff.putFloat(vec.x);
byteBuff.putFloat(vec.y);
byteBuff.putFloat(vec.z);
} break;
case VEC3D: {
Vector3d vec = (Vector3d)actor.getAttributeValue(attribute);
byteBuff.putDouble(vec.x);
byteBuff.putDouble(vec.y);
byteBuff.putDouble(vec.z);
} break;
case VEC4F: {
Vector4f vec = (Vector4f)actor.getAttributeValue(attribute);
byteBuff.putFloat(vec.w);
byteBuff.putFloat(vec.x);
byteBuff.putFloat(vec.y);
byteBuff.putFloat(vec.z);
} break;
case VEC4D: {
Vector4d vec = (Vector4d)actor.getAttributeValue(attribute);
byteBuff.putDouble(vec.w);
byteBuff.putDouble(vec.x);
byteBuff.putDouble(vec.y);
byteBuff.putDouble(vec.z);
} break;
case MAT4F: {
Matrix4f mat = (Matrix4f)actor.getAttributeValue(attribute);
byteBuff.putFloat(mat.m00());
byteBuff.putFloat(mat.m01());
byteBuff.putFloat(mat.m02());
byteBuff.putFloat(mat.m03());
byteBuff.putFloat(mat.m10());
byteBuff.putFloat(mat.m11());
byteBuff.putFloat(mat.m12());
byteBuff.putFloat(mat.m13());
byteBuff.putFloat(mat.m20());
byteBuff.putFloat(mat.m21());
byteBuff.putFloat(mat.m22());
byteBuff.putFloat(mat.m23());
byteBuff.putFloat(mat.m10());
byteBuff.putFloat(mat.m11());
byteBuff.putFloat(mat.m12());
byteBuff.putFloat(mat.m13());
byteBuff.putFloat(mat.m20());
byteBuff.putFloat(mat.m21());
byteBuff.putFloat(mat.m22());
byteBuff.putFloat(mat.m23());
byteBuff.putFloat(mat.m30());
byteBuff.putFloat(mat.m31());
byteBuff.putFloat(mat.m32());
byteBuff.putFloat(mat.m33());
} break;
case MAT4D: {
Matrix4d mat = (Matrix4d)actor.getAttributeValue(attribute);
byteBuff.putDouble((float)mat.m00());
byteBuff.putDouble((float)mat.m01());
byteBuff.putDouble((float)mat.m02());
byteBuff.putDouble((float)mat.m03());
byteBuff.putFloat(mat.m30());
byteBuff.putFloat(mat.m31());
byteBuff.putFloat(mat.m32());
byteBuff.putFloat(mat.m33());
} break;
case MAT4D: {
Matrix4d mat = (Matrix4d)actor.getAttributeValue(attribute);
byteBuff.putDouble((float)mat.m00());
byteBuff.putDouble((float)mat.m01());
byteBuff.putDouble((float)mat.m02());
byteBuff.putDouble((float)mat.m03());
byteBuff.putDouble((float)mat.m10());
byteBuff.putDouble((float)mat.m11());
byteBuff.putDouble((float)mat.m12());
byteBuff.putDouble((float)mat.m13());
byteBuff.putDouble((float)mat.m20());
byteBuff.putDouble((float)mat.m21());
byteBuff.putDouble((float)mat.m22());
byteBuff.putDouble((float)mat.m23());
byteBuff.putDouble((float)mat.m10());
byteBuff.putDouble((float)mat.m11());
byteBuff.putDouble((float)mat.m12());
byteBuff.putDouble((float)mat.m13());
byteBuff.putDouble((float)mat.m20());
byteBuff.putDouble((float)mat.m21());
byteBuff.putDouble((float)mat.m22());
byteBuff.putDouble((float)mat.m23());
byteBuff.putDouble((float)mat.m30());
byteBuff.putDouble((float)mat.m31());
byteBuff.putDouble((float)mat.m32());
byteBuff.putDouble((float)mat.m33());
} break;
case DOUBLE: {
byteBuff.putDouble((Double)actor.getAttributeValue(attribute));
} break;
case FLOAT: {
byteBuff.putFloat((Float)actor.getAttributeValue(attribute));
} break;
case INT: {
byteBuff.putInt((Integer)actor.getAttributeValue(attribute));
} break;
byteBuff.putDouble((float)mat.m30());
byteBuff.putDouble((float)mat.m31());
byteBuff.putDouble((float)mat.m32());
byteBuff.putDouble((float)mat.m33());
} break;
case DOUBLE: {
byteBuff.putDouble((Double)actor.getAttributeValue(attribute));
} break;
case FLOAT: {
byteBuff.putFloat((Float)actor.getAttributeValue(attribute));
} break;
case INT: {
byteBuff.putInt((Integer)actor.getAttributeValue(attribute));
} break;
default: {
throw new Error("Unhandled attribute type!");
}
}
}
}
//increment
@ -224,7 +255,8 @@ public class StridedInstanceData implements InstanceData {
@Override
public void upload(OpenGLState openGLState, RenderPipelineState renderPipelineState){
this.buffer.upload(openGLState);
openGLState.glBindBufferBase(0, buffer);
openGLState.glBindBufferBase(this.bindPoint, buffer);
renderPipelineState.setInstanceCount(this.getDrawCount());
}
@Override

View File

@ -15,6 +15,11 @@ public class ShaderAttribute {
//for multi-attribute index types (mat4f, mat4d, etc)
int[] attributeIndices;
/**
* The name of the attribute
*/
String name;
/**
* The type of the attribute
*/
@ -39,10 +44,11 @@ public class ShaderAttribute {
/**
* Constructor for 1-1 attribute
* @param attributeIndex The attribute index
* @param name The name of the attribute
* @param type The type of attribute
*/
public ShaderAttribute(int attributeIndex, HomogenousBufferTypes type){
this.attributeIndex = attributeIndex;
public ShaderAttribute(String name, HomogenousBufferTypes type){
this.name = name;
this.type = type;
}
@ -78,4 +84,12 @@ public class ShaderAttribute {
return type;
}
/**
* Gets the name of the attribute
* @return The name
*/
public String getName(){
return name;
}
}