The grass update
This commit is contained in:
parent
ff285e5fb7
commit
0273bc54c8
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -3,5 +3,6 @@
|
||||
"files.watcherExclude": {
|
||||
"**/.git/objects/**": true,
|
||||
"**/node_modules/**": true
|
||||
}
|
||||
},
|
||||
"java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx2G -Xms100m -Xlog:disable"
|
||||
}
|
||||
Binary file not shown.
238
assets/Shaders/foliage/foliage.fs
Normal file
238
assets/Shaders/foliage/foliage.fs
Normal file
@ -0,0 +1,238 @@
|
||||
#version 330 core
|
||||
|
||||
#define NR_POINT_LIGHTS 10
|
||||
|
||||
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
|
||||
|
||||
//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
|
||||
|
||||
};
|
||||
|
||||
struct Material {
|
||||
sampler2D diffuse;
|
||||
sampler2D specular;
|
||||
float shininess;
|
||||
};
|
||||
|
||||
in vec3 FragPos;
|
||||
in vec3 Normal;
|
||||
in vec2 TexCoord;
|
||||
in vec4 FragPosLightSpace;
|
||||
|
||||
|
||||
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;
|
||||
|
||||
|
||||
// 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);
|
||||
float calcLightIntensityTotal(vec3 normal);
|
||||
float ShadowCalculation(vec4 fragPosLightSpace, vec3 lightDir, vec3 normal);
|
||||
|
||||
void main(){
|
||||
vec3 norm = normalize(Normal);
|
||||
vec3 viewDir = normalize(viewPos - FragPos);
|
||||
|
||||
//grab light intensity
|
||||
float lightIntensity = calcLightIntensityTotal(norm);
|
||||
|
||||
//get color of base texture
|
||||
vec3 textureColor = vec3(0.17647,0.4,0.09411);//texture(material.diffuse, TexCoord).rgb;
|
||||
|
||||
//shadow
|
||||
float shadow = ShadowCalculation(FragPosLightSpace, normalize(-dLDirection), norm);
|
||||
|
||||
//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, texture(material.diffuse, TexCoord).a);//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 = (dLAmbient.x + dLAmbient.y + dLAmbient.z)/3.0;
|
||||
return avg;
|
||||
}
|
||||
|
||||
//
|
||||
float calcLightIntensityDir(vec3 normal){
|
||||
vec3 lightDir = normalize(-dLDirection);
|
||||
// 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 = dLDiffuse * 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);
|
||||
// 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;
|
||||
}
|
||||
|
||||
// // 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;
|
||||
// }
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
53
assets/Shaders/foliage/foliage.vs
Normal file
53
assets/Shaders/foliage/foliage.vs
Normal file
@ -0,0 +1,53 @@
|
||||
//Vertex Shader
|
||||
#version 330 core
|
||||
|
||||
|
||||
|
||||
//input buffers
|
||||
layout (location = 0) in vec3 aPos;
|
||||
layout (location = 1) in vec3 aNormal;
|
||||
layout (location = 4) in vec2 aTex;
|
||||
layout (location = 5) in vec4 modelA;
|
||||
layout (location = 6) in vec4 modelB;
|
||||
layout (location = 7) in vec4 modelC;
|
||||
layout (location = 8) in vec4 modelD;
|
||||
|
||||
|
||||
//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 vec2 TexCoord;
|
||||
out vec4 FragPosLightSpace;
|
||||
|
||||
|
||||
|
||||
|
||||
void main() {
|
||||
//normalize posiiton and normal
|
||||
vec4 FinalVertex = vec4(aPos, 1.0);
|
||||
vec4 FinalNormal = vec4(aNormal, 1.0);
|
||||
|
||||
mat4 model = mat4(modelA,modelB,modelC,modelD);
|
||||
|
||||
|
||||
//push frag, normal, and texture positions to fragment shader
|
||||
FragPos = vec3(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;
|
||||
}
|
||||
162
docs/InstancedActors.txt
Normal file
162
docs/InstancedActors.txt
Normal file
@ -0,0 +1,162 @@
|
||||
|
||||
|
||||
Instanced Actors Documentation
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Terminology
|
||||
|
||||
"Attribute" is a term that is used a lot in this implementation. An attribute is a value that will show up for a given instance in a shader.
|
||||
For instance, aPos is an attribute that shows up in a lot of shaders that represents the position of the vertex in model-space.
|
||||
They have a layout location in the shader and require special logic for making sure there is a 1-1 relation of buffer index to each instance.
|
||||
These are different from "Uniforms" which you should be familiar with.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Goals of the implementation
|
||||
|
||||
The main goal of the implementation was to provide an interface to create a single instanced entity and have it have two main functions:
|
||||
- Update a value that the shader uses to draw this entity
|
||||
- Call a draw function and have it appear on the screen with whatever its current values are
|
||||
|
||||
Behind the scenes there's a lot of complicated logic to handle actually queueing these entities so that buffers aren't overflowing and values end up in the right spots.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Restrictions
|
||||
|
||||
For the moment, the instanced actors only support having values of the HomogenousUniformBuffer type. Eg, you can only have mat4s, vec4s, vec3, etc. No strings.
|
||||
Furthermore, there's a requirement to declare a capacity, or maximum number of instances, of the model you're about to draw.
|
||||
EG you have to declare that there will only be 1000 leaf objects. You can still create more than 1000 and call draw more than 1000 times per frame, but only 1000 will draw.
|
||||
^ This is for buffer-related reasons. GPU and CPU preallocate the buffers for all attributes
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Code layout
|
||||
|
||||
|
||||
There are three main components to working with an instanced actor
|
||||
- InstancedActor.java
|
||||
- InstanceManager.java
|
||||
- InstanceData.java
|
||||
|
||||
InstanceManager.java provides the constructor for creating an instanced actor. It handles registration of the actor behind the scenes and queueing logic for drawing individual instances.
|
||||
|
||||
InstanceActor.java provides most of the publicly facing interface for instanced things that you want to draw. For instance, handles setting values of attributes for the single instance.
|
||||
|
||||
InstanceData.java used primarily behind the scenes to handle queueing and buffering data to the gpu based on what instances have drawn this frame.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Basic flow for the parts you should be concerned with:
|
||||
|
||||
Have a managing class for whatever type of instance you want to draw. For instance, "GrassManager".
|
||||
|
||||
(1) "GrassManager" should loop through each instance and update any attributes by calling setAttribute() on InstancedActor.java for each instance.
|
||||
- This updates the values for that instance prior to draw call.
|
||||
- This does NOT immediately buffer these values to the gpu. That happens in step 3
|
||||
|
||||
(2) Every frame, while iterating through entities to draw, call the draw() method on the InstancedActor.java object.
|
||||
- This adds that instance to the queue to be drawn by the InstanceManager.java
|
||||
|
||||
(3) At the end of looping through normal entities in a RenderingEngine.java render pass, call draw() on InstanceManager.java.
|
||||
- This will draw every model that has instanced queued to be drawn.
|
||||
|
||||
|
||||
@ -0,0 +1,194 @@
|
||||
package electrosphere.client.foliagemanager;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Quaternionf;
|
||||
import org.joml.Vector3d;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.entity.Entity;
|
||||
import electrosphere.entity.EntityCreationUtils;
|
||||
import electrosphere.entity.EntityDataStrings;
|
||||
import electrosphere.entity.EntityTags;
|
||||
import electrosphere.entity.EntityUtils;
|
||||
import electrosphere.entity.types.camera.CameraEntityUtils;
|
||||
import electrosphere.renderer.actor.instance.InstancedActor;
|
||||
import electrosphere.renderer.buffer.ShaderAttribute;
|
||||
import electrosphere.renderer.buffer.HomogenousUniformBuffer.HomogenousBufferTypes;
|
||||
|
||||
/**
|
||||
* Manages foliage (grass, small plants, etc) that should be shown, typically instanced
|
||||
*/
|
||||
public class ClientFoliageManager {
|
||||
|
||||
//threshold for a grass blade to relocate to a new position
|
||||
static final float GRASS_RELOCATION_THRESHOLD = 5f;
|
||||
|
||||
//amount of grass entities to manage
|
||||
static final int grassCapacity = 10000;
|
||||
|
||||
//Random for finding new positions for foliage
|
||||
Random placementRandomizer = new Random();
|
||||
|
||||
//The list of grass entities currently in use
|
||||
Set<Entity> grassEntities = new HashSet<Entity>();
|
||||
|
||||
//Used to prevent concurrent usage of grassEntities set
|
||||
boolean ready = false;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//The map of all attributes for instanced foliage
|
||||
static final Map<ShaderAttribute,HomogenousBufferTypes> attributes = new HashMap<ShaderAttribute,HomogenousBufferTypes>();
|
||||
|
||||
//model matrix shader attribute
|
||||
static ShaderAttribute modelMatrixAttribute;
|
||||
|
||||
//set attributes
|
||||
static {
|
||||
int[] attributeIndices = new int[]{
|
||||
5,6,7,8
|
||||
};
|
||||
modelMatrixAttribute = new ShaderAttribute(attributeIndices);
|
||||
attributes.put(modelMatrixAttribute,HomogenousBufferTypes.MAT4F);
|
||||
}
|
||||
|
||||
//shader paths
|
||||
static final String vertexPath = "shaders/foliage/foliage.vs";
|
||||
static final String fragmentPath = "shaders/foliage/foliage.fs";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Starts up the foliage manager
|
||||
*/
|
||||
public void start(){
|
||||
//queue grass model
|
||||
Globals.assetManager.addModelPathToQueue("models/grass1.fbx");
|
||||
|
||||
Vector3d centerPosition = new Vector3d(0,0,0);
|
||||
//create grass entities
|
||||
Entity grassEntity = EntityCreationUtils.createClientSpatialEntity();
|
||||
makeEntityInstancedFoliage(grassEntity, "models/grass1.fbx", grassCapacity);
|
||||
EntityUtils.getPosition(grassEntity).set(getNewPosition(centerPosition));
|
||||
EntityUtils.getRotation(grassEntity).set(getNewRotation());
|
||||
EntityUtils.getScale(grassEntity).set(new Vector3d(2.0, 2.0, 2.0));
|
||||
grassEntities.add(grassEntity);
|
||||
for(int i = 0; i < grassCapacity - 1; i++){
|
||||
grassEntity = EntityCreationUtils.createClientSpatialEntity();
|
||||
makeEntityInstancedFoliage(grassEntity, "models/grass1.fbx", grassCapacity);
|
||||
EntityUtils.getPosition(grassEntity).set(getNewPosition(centerPosition));
|
||||
EntityUtils.getRotation(grassEntity).set(getNewRotation());
|
||||
EntityUtils.getScale(grassEntity).set(new Vector3d(2.0, 2.0, 2.0));
|
||||
grassEntities.add(grassEntity);
|
||||
}
|
||||
ready = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates all grass entities
|
||||
*/
|
||||
public void update(){
|
||||
if(ready){
|
||||
Matrix4f modelMatrix = new Matrix4f();
|
||||
Vector3f cameraCenter = CameraEntityUtils.getCameraCenter(Globals.playerCamera);
|
||||
for(Entity grassEntity : grassEntities){
|
||||
Vector3d grassPosition = EntityUtils.getPosition(grassEntity);
|
||||
Quaternionf grassRotation = EntityUtils.getRotation(grassEntity);
|
||||
Vector3d playerPosition = EntityUtils.getPosition(Globals.playerEntity);
|
||||
InstancedActor instancedActor = InstancedActor.getInstancedActor(grassEntity);
|
||||
//update position
|
||||
if(playerPosition.distance(grassPosition) > GRASS_RELOCATION_THRESHOLD){
|
||||
grassPosition.set(getNewPosition(playerPosition));
|
||||
grassRotation.set(getNewRotation());
|
||||
}
|
||||
//update uniforms
|
||||
// instancedActor.setUniform("position", grassPosition);
|
||||
// instancedActor.setUniform("rotation", new Vector4d(
|
||||
// grassRotation.x,
|
||||
// grassRotation.y,
|
||||
// grassRotation.z,
|
||||
// grassRotation.w));
|
||||
// instancedActor.setUniform("scale", new Vector3d(EntityUtils.getScale(grassEntity)));
|
||||
|
||||
modelMatrix = modelMatrix.identity();
|
||||
Vector3f cameraModifiedPosition = new Vector3f((float)grassPosition.x,(float)grassPosition.y,(float)grassPosition.z).sub(cameraCenter);
|
||||
modelMatrix.translate(cameraModifiedPosition);
|
||||
modelMatrix.rotate(grassRotation);
|
||||
modelMatrix.scale(EntityUtils.getScale(grassEntity));
|
||||
|
||||
instancedActor.setAttribute(modelMatrixAttribute, modelMatrix);
|
||||
|
||||
//draw
|
||||
instancedActor.draw(Globals.renderingEngine.getRenderPipelineState());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a good position to put a new blade of grass
|
||||
* @param centerPosition The player's position
|
||||
* @return The new position for the blade of grass
|
||||
*/
|
||||
protected Vector3d getNewPosition(Vector3d centerPosition){
|
||||
double angle = placementRandomizer.nextDouble() * Math.PI * 2;
|
||||
double radius = placementRandomizer.nextDouble() * GRASS_RELOCATION_THRESHOLD;
|
||||
return new Vector3d(
|
||||
centerPosition.x + Math.cos(angle) * radius,
|
||||
centerPosition.y,
|
||||
centerPosition.z + Math.sin(angle) * radius
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a new rotation for a blade of grass
|
||||
* @return The rotation
|
||||
*/
|
||||
protected Quaternionf getNewRotation(){
|
||||
return new Quaternionf().rotationX(-(float)Math.PI / 2.0f).rotateLocalY((float)Math.PI * placementRandomizer.nextFloat());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Makes an already created entity a drawable, instanced entity (client only) by backing it with an InstancedActor
|
||||
* @param entity The entity
|
||||
* @param modelPath The model path for the model to back the instanced actor
|
||||
*/
|
||||
public static void makeEntityInstancedFoliage(Entity entity, String modelPath, int capacity){
|
||||
entity.putData(EntityDataStrings.INSTANCED_ACTOR, Globals.clientInstanceManager.createInstancedActor(modelPath, vertexPath, fragmentPath, attributes, capacity));
|
||||
entity.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
|
||||
entity.putData(EntityDataStrings.DATA_STRING_ROTATION, new Quaternionf().identity());
|
||||
entity.putData(EntityDataStrings.DATA_STRING_SCALE, new Vector3f(1,1,1));
|
||||
entity.putData(EntityDataStrings.DRAW_SOLID_PASS, true);
|
||||
Globals.clientScene.registerEntity(entity);
|
||||
Globals.clientScene.registerEntityToTag(entity, EntityTags.DRAW_INSTANCED);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -56,6 +56,10 @@ public class ClientSimulation {
|
||||
HitboxUtils.clientCollideEntities(currentHitbox);
|
||||
}
|
||||
}
|
||||
//update foliage
|
||||
if(Globals.clientFoliageManager != null){
|
||||
Globals.clientFoliageManager.update();
|
||||
}
|
||||
//tally collidables and offset position accordingly
|
||||
// for(Entity currentCollidable : Globals.entityManager.getEntitiesWithTag(EntityTags.COLLIDABLE)){
|
||||
// CollidableTree tree = CollidableTree.getCollidableTree(currentCollidable);
|
||||
|
||||
@ -12,6 +12,7 @@ import org.lwjgl.glfw.GLFWErrorCallback;
|
||||
import electrosphere.audio.AudioEngine;
|
||||
import electrosphere.auth.AuthenticationManager;
|
||||
import electrosphere.client.culling.ClientEntityCullingManager;
|
||||
import electrosphere.client.foliagemanager.ClientFoliageManager;
|
||||
import electrosphere.client.scene.ClientSceneWrapper;
|
||||
import electrosphere.client.sim.ClientSimulation;
|
||||
import electrosphere.collision.dispatch.CollisionObject;
|
||||
@ -47,6 +48,7 @@ import electrosphere.renderer.Material;
|
||||
import electrosphere.renderer.RenderUtils;
|
||||
import electrosphere.renderer.RenderingEngine;
|
||||
import electrosphere.renderer.ShaderProgram;
|
||||
import electrosphere.renderer.actor.instance.InstanceManager;
|
||||
import electrosphere.renderer.light.PointLight;
|
||||
import electrosphere.renderer.light.SpotLight;
|
||||
import electrosphere.renderer.loading.ModelPretransforms;
|
||||
@ -262,6 +264,12 @@ public class Globals {
|
||||
public static ClientEntityCullingManager clientEntityCullingManager;
|
||||
public static ClientSimulation clientSimulation;
|
||||
|
||||
//instanced actor manager
|
||||
public static InstanceManager clientInstanceManager = new InstanceManager();
|
||||
|
||||
//client side foliage manager
|
||||
public static ClientFoliageManager clientFoliageManager;
|
||||
|
||||
//client world data
|
||||
public static ClientWorldData clientWorldData;
|
||||
|
||||
|
||||
@ -7,6 +7,8 @@ import electrosphere.renderer.Mesh;
|
||||
import electrosphere.renderer.Model;
|
||||
import electrosphere.renderer.ShaderProgram;
|
||||
import electrosphere.renderer.actor.ActorShaderMask;
|
||||
import electrosphere.renderer.buffer.HomogenousInstancedArray;
|
||||
import electrosphere.renderer.buffer.HomogenousUniformBuffer;
|
||||
import electrosphere.renderer.loading.ModelLoader;
|
||||
import electrosphere.renderer.texture.Texture;
|
||||
import electrosphere.server.poseactor.PoseModel;
|
||||
@ -44,6 +46,12 @@ public class AssetManager {
|
||||
|
||||
Map<String,PoseModel> poseModelsLoadedIntoMemory = new ConcurrentHashMap<String,PoseModel>();
|
||||
List<String> poseModelsInQueue = new CopyOnWriteArrayList<String>();
|
||||
|
||||
//A queue of homogenous buffers to allocate this render frame
|
||||
List<HomogenousUniformBuffer> homogenousBufferAllocationQueue = new CopyOnWriteArrayList<HomogenousUniformBuffer>();
|
||||
|
||||
//A queue of homogenous buffers to allocate this render frame
|
||||
List<HomogenousInstancedArray> instanceArrayBufferAllocationQueue = new CopyOnWriteArrayList<HomogenousInstancedArray>();
|
||||
|
||||
|
||||
|
||||
@ -52,7 +60,11 @@ public class AssetManager {
|
||||
//General asset manager stuff
|
||||
//
|
||||
|
||||
/**
|
||||
* For each class/type of asset, load all assets in queue
|
||||
*/
|
||||
public void loadAssetsInQueue(){
|
||||
//models
|
||||
for(String currentPath : modelsInQueue){
|
||||
modelsInQueue.remove(currentPath);
|
||||
AIScene scene = ModelLoader.loadAIScene(currentPath);
|
||||
@ -63,14 +75,17 @@ public class AssetManager {
|
||||
physicsMeshesLoadedIntoMemory.put(currentPath,PhysicsUtils.generateRigidBodyFromAIScene(scene));
|
||||
}
|
||||
}
|
||||
//textures from disk to gpu
|
||||
for(String currentPath : texturesInQueue){
|
||||
texturesInQueue.remove(currentPath);
|
||||
texturesLoadedIntoMemory.put(currentPath, new Texture(currentPath));
|
||||
}
|
||||
//audio from disk
|
||||
for(String currentPath : audioInQueue){
|
||||
audioInQueue.remove(currentPath);
|
||||
audioLoadedIntoMemory.put(currentPath, new AudioBuffer(currentPath));
|
||||
}
|
||||
//shaders
|
||||
for(ActorShaderMask currentShader : shadersInQueue){
|
||||
shadersInQueue.remove(currentShader);
|
||||
String key = getShaderKey(currentShader.getVertexShaderPath(),currentShader.getGeometryShaderPath(),currentShader.getFragmentShaderPath());
|
||||
@ -86,11 +101,17 @@ public class AssetManager {
|
||||
);
|
||||
}
|
||||
}
|
||||
//pose models
|
||||
for(String currentPath: poseModelsInQueue){
|
||||
poseModelsInQueue.remove(currentPath);
|
||||
AIScene scene = ModelLoader.loadAIScene(currentPath);
|
||||
poseModelsLoadedIntoMemory.put(currentPath, new PoseModel(currentPath, scene));
|
||||
}
|
||||
//allocate homogenous buffers
|
||||
allocateHomogenousBuffers();
|
||||
//allocate instance array buffers
|
||||
allocateInstanceArrayBuffers();
|
||||
//override meshes
|
||||
performMeshOverrides();
|
||||
}
|
||||
|
||||
@ -334,6 +355,49 @@ public class AssetManager {
|
||||
return physicsMeshesLoadedIntoMemory.get(path);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//HOMOGENOUS UNIFORM BUFFERS
|
||||
//
|
||||
/**
|
||||
* Allocates all uniform buffers in queue
|
||||
*/
|
||||
public void allocateHomogenousBuffers(){
|
||||
for(HomogenousUniformBuffer buffer : homogenousBufferAllocationQueue){
|
||||
buffer.allocate();
|
||||
}
|
||||
homogenousBufferAllocationQueue.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a uniform buffer to the queue to be allocated
|
||||
* @param buffer The buffer
|
||||
*/
|
||||
public void addHomogenousBufferToQueue(HomogenousUniformBuffer buffer){
|
||||
homogenousBufferAllocationQueue.add(buffer);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//INSTANCE ARRAY BUFFERS
|
||||
//
|
||||
/**
|
||||
* Allocates all instance array buffers in queue
|
||||
*/
|
||||
public void allocateInstanceArrayBuffers(){
|
||||
for(HomogenousInstancedArray buffer : instanceArrayBufferAllocationQueue){
|
||||
buffer.allocate();
|
||||
}
|
||||
instanceArrayBufferAllocationQueue.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an instance array buffer to the queue to be allocated
|
||||
* @param buffer The buffer
|
||||
*/
|
||||
public void addInstanceArrayBufferToQueue(HomogenousInstancedArray buffer){
|
||||
instanceArrayBufferAllocationQueue.add(buffer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -22,6 +22,7 @@ import electrosphere.net.NetUtils;
|
||||
import electrosphere.net.client.ClientNetworking;
|
||||
import electrosphere.renderer.ui.Window;
|
||||
import electrosphere.client.culling.ClientEntityCullingManager;
|
||||
import electrosphere.client.foliagemanager.ClientFoliageManager;
|
||||
import electrosphere.client.sim.ClientSimulation;
|
||||
import electrosphere.controls.ControlHandler;
|
||||
|
||||
@ -89,7 +90,9 @@ public class ClientLoading {
|
||||
//sets micro and macro sims to ready if they exist
|
||||
setSimulationsToReady();
|
||||
//init culling manager and other graphics-focused non-simulation items
|
||||
initEntitycullingManager();
|
||||
initEntityCullingManager();
|
||||
//init foliage manager
|
||||
initFoliageManager();
|
||||
//hide cursor
|
||||
Globals.controlHandler.hideMouse();
|
||||
//make loading window disappear
|
||||
@ -243,10 +246,21 @@ public class ClientLoading {
|
||||
// System.out.println("Draw Cell Manager ready");
|
||||
}
|
||||
|
||||
private static void initEntitycullingManager(){
|
||||
/**
|
||||
* Starts up the entity culling manager
|
||||
*/
|
||||
private static void initEntityCullingManager(){
|
||||
Globals.clientEntityCullingManager = new ClientEntityCullingManager(Globals.clientScene);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts up the foliage manager
|
||||
*/
|
||||
private static void initFoliageManager(){
|
||||
Globals.clientFoliageManager = new ClientFoliageManager();
|
||||
Globals.clientFoliageManager.start();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ import org.joml.Vector3f;
|
||||
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.renderer.actor.ActorUtils;
|
||||
import electrosphere.renderer.actor.instance.InstancedActor;
|
||||
import electrosphere.server.datacell.Realm;
|
||||
import electrosphere.server.datacell.ServerDataCell;
|
||||
import electrosphere.server.datacell.utils.EntityLookupUtils;
|
||||
|
||||
@ -21,6 +21,8 @@ public class EntityDataStrings {
|
||||
public static final String DRAW_CAST_SHADOW = "castShadow";
|
||||
public static final String DRAW_VOLUMETRIC = "drawVolumetric";
|
||||
public static final String DRAW_OUTLINE = "drawOutline";
|
||||
public static final String INSTANCED_ACTOR = "instancedActor";
|
||||
public static final String DRAW_INSTANCED = "drawInstanced";
|
||||
|
||||
|
||||
/*
|
||||
|
||||
@ -12,6 +12,7 @@ public class EntityTags {
|
||||
public static final String CREATURE = "creature";
|
||||
public static final String UI = "ui";
|
||||
public static final String DRAWABLE = "drawable";
|
||||
public static final String DRAW_INSTANCED = "drawInstanced";
|
||||
public static final String LIGHT = "light";
|
||||
public static final String ITEM = "item";
|
||||
public static final String GRAVITY = "gravity";
|
||||
|
||||
@ -6,6 +6,11 @@ import electrosphere.entity.types.camera.CameraEntityUtils;
|
||||
import electrosphere.logger.LoggerInterface;
|
||||
import electrosphere.renderer.RenderPipelineState.SelectedShaderEnum;
|
||||
import electrosphere.renderer.actor.ActorTextureMask;
|
||||
import electrosphere.renderer.actor.instance.InstanceData;
|
||||
import electrosphere.renderer.buffer.HomogenousInstancedArray;
|
||||
import electrosphere.renderer.buffer.HomogenousUniformBuffer;
|
||||
import electrosphere.renderer.buffer.ShaderAttribute;
|
||||
import electrosphere.renderer.buffer.HomogenousUniformBuffer.HomogenousBufferTypes;
|
||||
import electrosphere.renderer.light.LightManager;
|
||||
import electrosphere.renderer.loading.ModelPretransforms;
|
||||
import electrosphere.renderer.texture.Texture;
|
||||
@ -15,6 +20,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.joml.Matrix4d;
|
||||
import org.joml.Matrix4f;
|
||||
@ -55,6 +61,9 @@ import static org.lwjgl.opengl.GL20.glVertexAttribPointer;
|
||||
import static org.lwjgl.opengl.GL30.glBindVertexArray;
|
||||
import static org.lwjgl.opengl.GL30.glGenVertexArrays;
|
||||
|
||||
import org.lwjgl.opengl.GL40;
|
||||
import org.lwjgl.opengl.GL45;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author satellite
|
||||
@ -558,19 +567,57 @@ public class Mesh {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a buffer to the gpu
|
||||
* @param uniformTypeMap The type of the buffer
|
||||
* @param buffers The buffer
|
||||
*/
|
||||
void bufferInstanceData(
|
||||
RenderPipelineState renderPipelineState,
|
||||
Map<ShaderAttribute,Object> buffers,
|
||||
Map<ShaderAttribute,HomogenousInstancedArray> uniformGlBufferMap
|
||||
){
|
||||
for(ShaderAttribute attribute : buffers.keySet()){
|
||||
HomogenousInstancedArray buffer = uniformGlBufferMap.get(attribute);
|
||||
buffer.updateBuffer(buffers.get(attribute), 0);
|
||||
buffer.bind(renderPipelineState);
|
||||
// switch(uniformTypeMap.get(uniformName)){
|
||||
// case VEC3F: {
|
||||
// FloatBuffer buffer = (FloatBuffer)buffers.get(key);
|
||||
// int bufferIndex = GL31.glGetUniformBlockIndex(shaderIndex, "Lights");
|
||||
// //bind that position to the slot '2'
|
||||
// GL31.glUniformBlockBinding(shaderIndex, bufferIndex, BIND_POINT);
|
||||
// //bind our buffer to slot '2' as well
|
||||
// GL31.glBindBufferBase(GL_UNIFORM_BUFFER, BIND_POINT, uboIndex);
|
||||
// //alternatively if want to use range, do glBindBufferRange(GL_UNIFORM_BUFFER, 2, uboExampleBlock, 0, 152);
|
||||
// } break;
|
||||
// case VEC3D: {
|
||||
|
||||
// } break;
|
||||
// case VEC4F: {
|
||||
|
||||
// } break;
|
||||
// case VEC4D: {
|
||||
|
||||
// } break;
|
||||
// case DOUBLE: {
|
||||
|
||||
// } break;
|
||||
// case FLOAT: {
|
||||
|
||||
// } break;
|
||||
// case INT: {
|
||||
|
||||
// } break;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
*
|
||||
boolean setShader,
|
||||
boolean bufferStandardUniforms,
|
||||
boolean bufferNonStandardUniforms,
|
||||
boolean useMaterial,
|
||||
boolean useShadowMap,
|
||||
boolean setBones,
|
||||
boolean useLight
|
||||
/**
|
||||
* Draws the mesh
|
||||
* @param renderPipelineState The state of the render pipeline
|
||||
*/
|
||||
public void complexDraw(RenderPipelineState renderPipelineState){
|
||||
|
||||
@ -587,7 +634,7 @@ public class Mesh {
|
||||
if(selectedProgram == null){
|
||||
selectedProgram = shader;
|
||||
}
|
||||
Globals.renderingEngine.setActiveShader(selectedProgram);
|
||||
Globals.renderingEngine.setActiveShader(renderPipelineState, selectedProgram);
|
||||
}
|
||||
|
||||
if(renderPipelineState.getUseLight()){
|
||||
@ -703,10 +750,20 @@ public class Mesh {
|
||||
if(renderPipelineState.getBufferNonStandardUniforms()){
|
||||
bufferAllUniforms();
|
||||
}
|
||||
|
||||
if(renderPipelineState.getInstanced()){
|
||||
InstanceData instanceData = renderPipelineState.getInstanceData();
|
||||
Map<ShaderAttribute,Object> buffers = instanceData.getCpuBufferMap();
|
||||
Map<ShaderAttribute,HomogenousInstancedArray> glBufferMap = instanceData.getGlBufferMap();
|
||||
bufferInstanceData(renderPipelineState, buffers, glBufferMap);
|
||||
}
|
||||
|
||||
|
||||
|
||||
GL11.glDrawElements(GL_TRIANGLES, elementCount, GL_UNSIGNED_INT, 0);
|
||||
if(renderPipelineState.getInstanced()){
|
||||
GL45.glDrawElementsInstanced(GL_TRIANGLES, elementCount, GL_UNSIGNED_INT, 0, renderPipelineState.getInstanceData().getDrawCount());
|
||||
} else {
|
||||
GL11.glDrawElements(GL_TRIANGLES, elementCount, GL_UNSIGNED_INT, 0);
|
||||
}
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -441,7 +441,7 @@ public class Model {
|
||||
|
||||
public void drawUI(){
|
||||
for(Mesh m : meshes){
|
||||
m.complexDraw(RenderingEngine.getRenderPipelineState());
|
||||
m.complexDraw(Globals.renderingEngine.getRenderPipelineState());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,16 @@
|
||||
package electrosphere.renderer;
|
||||
|
||||
import electrosphere.renderer.actor.instance.InstanceData;
|
||||
|
||||
/**
|
||||
* Contains all the currently up to date state of how the render pipeline is configured.
|
||||
* Used in lots of different places to pass information up/down the render pipeline call stack and configure variables for passes.
|
||||
*/
|
||||
public class RenderPipelineState {
|
||||
|
||||
/**
|
||||
* Enum of different phases of the pipeline
|
||||
*/
|
||||
public static enum RenderPipelineStateEnum {
|
||||
SHADOW_MAP,
|
||||
MAIN_OIT,
|
||||
@ -10,21 +19,39 @@ public class RenderPipelineState {
|
||||
COMPOSITE,
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum of different categories of shaders that can be selected
|
||||
*/
|
||||
public static enum SelectedShaderEnum {
|
||||
PRIMARY,
|
||||
OIT,
|
||||
}
|
||||
|
||||
//The current phase of the render pipeline
|
||||
RenderPipelineStateEnum state = RenderPipelineStateEnum.SHADOW_MAP;
|
||||
//The currently selected category of shader for the current render pipeline phase
|
||||
SelectedShaderEnum selectedShader = SelectedShaderEnum.PRIMARY;
|
||||
|
||||
//Whether to use a mesh's default shader
|
||||
boolean useMeshShader = false;
|
||||
//Whether to buffer standard uniforms (model matrix, view matrix, etc)
|
||||
boolean bufferStandardUniforms = false;
|
||||
//Whether to buffer any nonstandard uniforms that may be in the mesh uniform map
|
||||
boolean bufferNonStandardUniforms = false;
|
||||
//Whether to use the material attached to the mesh or not
|
||||
boolean useMaterial = false;
|
||||
//Whether to use the shadow map or not
|
||||
boolean useShadowMap = false;
|
||||
//Whether to update and use bones
|
||||
boolean useBones = false;
|
||||
//Whether to use the light buffer or not
|
||||
boolean useLight = false;
|
||||
//Whether the current rendering call is of an instanced object
|
||||
boolean instanced = false;
|
||||
//The instance data for rendering an instanced object
|
||||
InstanceData instanceData;
|
||||
//The pointer to the current shader program bound
|
||||
int currentShaderPointer;
|
||||
|
||||
public boolean getUseMeshShader(){
|
||||
return this.useMeshShader;
|
||||
@ -90,4 +117,28 @@ public class RenderPipelineState {
|
||||
this.selectedShader = selectedShader;
|
||||
}
|
||||
|
||||
public boolean getInstanced(){
|
||||
return this.instanced;
|
||||
}
|
||||
|
||||
public void setInstanced(boolean instanced){
|
||||
this.instanced = instanced;
|
||||
}
|
||||
|
||||
public InstanceData getInstanceData(){
|
||||
return this.instanceData;
|
||||
}
|
||||
|
||||
public void setInstanceData(InstanceData instanceData){
|
||||
this.instanceData = instanceData;
|
||||
}
|
||||
|
||||
public int getCurrentShaderPointer(){
|
||||
return currentShaderPointer;
|
||||
}
|
||||
|
||||
public void setCurrentShaderPointer(int currentShaderPointer){
|
||||
this.currentShaderPointer = currentShaderPointer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -527,7 +527,7 @@ public class RenderingEngine {
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthFunc(GL_ALWAYS);
|
||||
|
||||
Globals.renderingEngine.setActiveShader(lightDepthShaderProgram);
|
||||
Globals.renderingEngine.setActiveShader(renderPipelineState, lightDepthShaderProgram);
|
||||
|
||||
lightDepthBuffer.bind();
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
@ -668,6 +668,8 @@ public class RenderingEngine {
|
||||
currentActor.draw(renderPipelineState);
|
||||
}
|
||||
}
|
||||
//draw all instanced models
|
||||
Globals.clientInstanceManager.draw(renderPipelineState);
|
||||
|
||||
//
|
||||
// Pass Two: Transparency Accumulator + Revealage
|
||||
@ -1013,7 +1015,7 @@ public class RenderingEngine {
|
||||
|
||||
Matrix4f modelTransformMatrix = new Matrix4f();
|
||||
|
||||
Globals.renderingEngine.setActiveShader(renderNormalsShader);
|
||||
Globals.renderingEngine.setActiveShader(renderPipelineState, renderNormalsShader);
|
||||
|
||||
Vector3f cameraPos = CameraEntityUtils.getCameraCenter(Globals.playerCamera);
|
||||
modelTransformMatrix = new Matrix4f();
|
||||
@ -1049,7 +1051,7 @@ public class RenderingEngine {
|
||||
normalsOutlineFrambuffer.bind();
|
||||
ShaderProgram program = Globals.assetManager.fetchShader("Shaders/anime/outlineNormals.vs", null, "Shaders/anime/outlineNormals.fs");
|
||||
if(program != null){
|
||||
Globals.renderingEngine.setActiveShader(program);
|
||||
Globals.renderingEngine.setActiveShader(renderPipelineState, program);
|
||||
|
||||
glBindVertexArray(screenTextureVAO);
|
||||
|
||||
@ -1086,7 +1088,7 @@ public class RenderingEngine {
|
||||
//
|
||||
//Draw anime outline
|
||||
//
|
||||
Globals.renderingEngine.setActiveShader(compositeAnimeOutline);
|
||||
Globals.renderingEngine.setActiveShader(renderPipelineState, compositeAnimeOutline);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
@ -1104,7 +1106,7 @@ public class RenderingEngine {
|
||||
//
|
||||
//Composite transparency on top of solids
|
||||
//
|
||||
Globals.renderingEngine.setActiveShader(oitCompositeProgram);
|
||||
Globals.renderingEngine.setActiveShader(renderPipelineState, oitCompositeProgram);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
@ -1153,7 +1155,7 @@ public class RenderingEngine {
|
||||
//render full screen quad
|
||||
// glBlitFramebuffer(0, 0, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT, 0, 0, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT,
|
||||
// GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
Globals.renderingEngine.setActiveShader(screenTextureShaders);
|
||||
Globals.renderingEngine.setActiveShader(renderPipelineState, screenTextureShaders);
|
||||
glBindVertexArray(screenTextureVAO);
|
||||
//aaa
|
||||
switch(outputFramebuffer){
|
||||
@ -1179,7 +1181,7 @@ public class RenderingEngine {
|
||||
glBindTexture(GL_TEXTURE_2D, normalsOutlineTexture.getTexturePointer());
|
||||
break;
|
||||
case 7:
|
||||
Globals.renderingEngine.setActiveShader(drawChannel);
|
||||
Globals.renderingEngine.setActiveShader(renderPipelineState, drawChannel);
|
||||
glUniform1f(glGetUniformLocation(Globals.renderingEngine.getActiveShader().shaderProgram, "channel"),4);
|
||||
glBindTexture(GL_TEXTURE_2D, screenTextureDepth.getTexturePointer());
|
||||
break;
|
||||
@ -1235,7 +1237,7 @@ public class RenderingEngine {
|
||||
GL15.glEnable(GL15.GL_CULL_FACE);
|
||||
GL15.glCullFace(GL15.GL_FRONT);
|
||||
|
||||
Globals.renderingEngine.setActiveShader(volumeDepthShaderProgram);
|
||||
Globals.renderingEngine.setActiveShader(renderPipelineState, volumeDepthShaderProgram);
|
||||
|
||||
volumeDepthBackfaceFramebuffer.bind();
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
@ -1338,7 +1340,7 @@ public class RenderingEngine {
|
||||
GL15.glEnable(GL15.GL_CULL_FACE);
|
||||
GL15.glCullFace(GL15.GL_BACK);
|
||||
|
||||
Globals.renderingEngine.setActiveShader(volumeDepthShaderProgram);
|
||||
Globals.renderingEngine.setActiveShader(renderPipelineState, volumeDepthShaderProgram);
|
||||
|
||||
volumeDepthFrontfaceFramebuffer.bind();
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
@ -1424,10 +1426,15 @@ public class RenderingEngine {
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
|
||||
public void setActiveShader(ShaderProgram program){
|
||||
/**
|
||||
* Sets the currently active shader program for the renderer
|
||||
* @param renderPipelineState The render pipeline state object
|
||||
* @param program The shader program to bind
|
||||
*/
|
||||
public void setActiveShader(RenderPipelineState renderPipelineState, ShaderProgram program){
|
||||
glUseProgram(program.shaderProgram);
|
||||
activeProgram = program;
|
||||
renderPipelineState.setCurrentShaderPointer(program.shaderProgram);
|
||||
}
|
||||
|
||||
public ShaderProgram getActiveShader(){
|
||||
@ -1489,7 +1496,7 @@ public class RenderingEngine {
|
||||
Globals.projectionMatrix.setPerspective(radVerticalFOV, RenderingEngine.aspectRatio, nearClip, Globals.userSettings.getGraphicsViewDistance());
|
||||
}
|
||||
|
||||
public static RenderPipelineState getRenderPipelineState(){
|
||||
public RenderPipelineState getRenderPipelineState(){
|
||||
return renderPipelineState;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,327 @@
|
||||
package electrosphere.renderer.actor.instance;
|
||||
|
||||
import java.nio.DoubleBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector3d;
|
||||
import org.joml.Vector3f;
|
||||
import org.joml.Vector4d;
|
||||
import org.joml.Vector4f;
|
||||
import org.lwjgl.BufferUtils;
|
||||
|
||||
import electrosphere.renderer.buffer.HomogenousInstancedArray;
|
||||
import electrosphere.renderer.buffer.ShaderAttribute;
|
||||
import electrosphere.renderer.buffer.HomogenousUniformBuffer.HomogenousBufferTypes;
|
||||
|
||||
/**
|
||||
* Effectively controls the block of data that is passed to the gpu each time this instance is drawn.
|
||||
* Does priority management to draw the instanced of higher priority if there happens to be greater than the capacity number of items to draw.
|
||||
*/
|
||||
public class InstanceData {
|
||||
|
||||
//the capacity (number of instanced) of this data block. Defaults to 100
|
||||
int capacity = 1000;
|
||||
|
||||
//shader paths
|
||||
String vertexShaderPath;
|
||||
String fragmentShaderPath;
|
||||
|
||||
//the number of draw calls since the last clear operation
|
||||
int drawCalls = 0;
|
||||
|
||||
//The priority queue of instanced actors to draw
|
||||
PriorityQueue<InstancedActor> actorQueue = new PriorityQueue<InstancedActor>(1000);
|
||||
//Map of actor to index in the buffers that are emitted
|
||||
Map<InstancedActor,Integer> actorIndexMap = new HashMap<InstancedActor,Integer>();
|
||||
//Map of index -> actor used for buffer evictions
|
||||
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>();
|
||||
//map of attribute -> buffer of attribute data
|
||||
Map<ShaderAttribute,Object> attributeCpuBufferMap = new HashMap<ShaderAttribute,Object>();
|
||||
//map of attribute -> gl HomogenousBuffer
|
||||
Map<ShaderAttribute,HomogenousInstancedArray> attributeGlBufferMap = new HashMap<ShaderAttribute,HomogenousInstancedArray>();
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param capacity Capacity of the buffer (number of elements) backing this data
|
||||
*/
|
||||
protected InstanceData(int capacity, String vertexPath, String fragmentPath){
|
||||
this.capacity = capacity;
|
||||
this.vertexShaderPath = vertexPath;
|
||||
this.fragmentShaderPath = fragmentPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
switch(type){
|
||||
case VEC3F: {
|
||||
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createFloatBuffer(capacity * 3));
|
||||
} break;
|
||||
case VEC3D: {
|
||||
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createDoubleBuffer(capacity * 3));
|
||||
} break;
|
||||
case VEC4F: {
|
||||
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createFloatBuffer(capacity * 4));
|
||||
} break;
|
||||
case VEC4D: {
|
||||
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createDoubleBuffer(capacity * 4));
|
||||
} break;
|
||||
case DOUBLE: {
|
||||
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createDoubleBuffer(capacity));
|
||||
} break;
|
||||
case FLOAT: {
|
||||
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createFloatBuffer(capacity));
|
||||
} break;
|
||||
case INT: {
|
||||
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createIntBuffer(capacity));
|
||||
} break;
|
||||
case MAT4F: {
|
||||
attributeCpuBufferMap.put(shaderAttribute, BufferUtils.createFloatBuffer(capacity * 4 * 4));
|
||||
} break;
|
||||
}
|
||||
if(shaderAttribute.isSingleIndex()){
|
||||
attributeGlBufferMap.put(shaderAttribute,HomogenousInstancedArray.createHomogenousInstancedArray(shaderAttribute.getIndex(), type, capacity));
|
||||
} else {
|
||||
attributeGlBufferMap.put(shaderAttribute,HomogenousInstancedArray.createHomogenousInstancedArray(shaderAttribute.getIndices(), type, capacity));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds an actor to be sorted in the queue
|
||||
* @param actor The actor to be sorted
|
||||
*/
|
||||
protected void addInstance(InstancedActor actor){
|
||||
actorQueue.add(actor);
|
||||
drawCalls++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of entries that are to be drawn
|
||||
* @return The number of entries to be drawn
|
||||
*/
|
||||
public int getDrawCount(){
|
||||
return drawCalls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the queue
|
||||
*/
|
||||
protected void clearDrawQueue(){
|
||||
actorQueue.clear();
|
||||
drawCalls = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the buffers for the upcoming render call. The intention is to make this emberassingly parallel.
|
||||
*/
|
||||
protected void fillBuffers(){
|
||||
int i = 0;
|
||||
//reset all buffers
|
||||
for(ShaderAttribute attribute : attributeIndices){
|
||||
switch(attributeGlBufferMap.get(attribute).getType()){
|
||||
case VEC3F: {
|
||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||
buffer.position(0);
|
||||
} break;
|
||||
case VEC3D: {
|
||||
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
||||
buffer.position(0);
|
||||
} break;
|
||||
case VEC4F: {
|
||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||
buffer.position(0);
|
||||
} break;
|
||||
case VEC4D: {
|
||||
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
||||
buffer.position(0);
|
||||
} break;
|
||||
case MAT4F: {
|
||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||
buffer.position(0);
|
||||
} break;
|
||||
case DOUBLE: {
|
||||
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
||||
buffer.position(0);
|
||||
} break;
|
||||
case FLOAT: {
|
||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||
buffer.position(0);
|
||||
} break;
|
||||
case INT: {
|
||||
IntBuffer buffer = ((IntBuffer)attributeCpuBufferMap.get(attribute));
|
||||
buffer.position(0);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
//buffer data
|
||||
for(InstancedActor actor : actorQueue){
|
||||
//push values to attribute buffers
|
||||
for(ShaderAttribute attribute : attributeIndices){
|
||||
switch(attributeGlBufferMap.get(attribute).getType()){
|
||||
case VEC3F: {
|
||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||
Vector3f vec = (Vector3f)actor.getAttributeValue(attribute);
|
||||
buffer.put(vec.x);
|
||||
buffer.put(vec.y);
|
||||
buffer.put(vec.z);
|
||||
} break;
|
||||
case VEC3D: {
|
||||
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
||||
Vector3d vec = (Vector3d)actor.getAttributeValue(attribute);
|
||||
buffer.put(vec.x);
|
||||
buffer.put(vec.y);
|
||||
buffer.put(vec.z);
|
||||
} break;
|
||||
case VEC4F: {
|
||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||
Vector4f vec = (Vector4f)actor.getAttributeValue(attribute);
|
||||
buffer.put(vec.w);
|
||||
buffer.put(vec.x);
|
||||
buffer.put(vec.y);
|
||||
buffer.put(vec.z);
|
||||
} break;
|
||||
case VEC4D: {
|
||||
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
||||
Vector4d vec = (Vector4d)actor.getAttributeValue(attribute);
|
||||
buffer.put(vec.w);
|
||||
buffer.put(vec.x);
|
||||
buffer.put(vec.y);
|
||||
buffer.put(vec.z);
|
||||
} break;
|
||||
case MAT4F: {
|
||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||
Matrix4f mat = (Matrix4f)actor.getAttributeValue(attribute);
|
||||
buffer.put(mat.m00());
|
||||
buffer.put(mat.m10());
|
||||
buffer.put(mat.m20());
|
||||
buffer.put(mat.m30());
|
||||
|
||||
buffer.put(mat.m10());
|
||||
buffer.put(mat.m11());
|
||||
buffer.put(mat.m12());
|
||||
buffer.put(mat.m13());
|
||||
|
||||
buffer.put(mat.m20());
|
||||
buffer.put(mat.m21());
|
||||
buffer.put(mat.m22());
|
||||
buffer.put(mat.m23());
|
||||
|
||||
buffer.put(mat.m30());
|
||||
buffer.put(mat.m31());
|
||||
buffer.put(mat.m32());
|
||||
buffer.put(mat.m33());
|
||||
/*
|
||||
buffer.put(mat.m00());
|
||||
buffer.put(mat.m10());
|
||||
buffer.put(mat.m20());
|
||||
buffer.put(mat.m30());
|
||||
|
||||
buffer.put(mat.m01());
|
||||
buffer.put(mat.m11());
|
||||
buffer.put(mat.m21());
|
||||
buffer.put(mat.m31());
|
||||
|
||||
buffer.put(mat.m02());
|
||||
buffer.put(mat.m12());
|
||||
buffer.put(mat.m22());
|
||||
buffer.put(mat.m32());
|
||||
|
||||
buffer.put(mat.m03());
|
||||
buffer.put(mat.m13());
|
||||
buffer.put(mat.m23());
|
||||
buffer.put(mat.m33());
|
||||
*/
|
||||
} break;
|
||||
case DOUBLE: {
|
||||
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
||||
buffer.put((Double)actor.getAttributeValue(attribute));
|
||||
} break;
|
||||
case FLOAT: {
|
||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||
buffer.put((Float)actor.getAttributeValue(attribute));
|
||||
} break;
|
||||
case INT: {
|
||||
IntBuffer buffer = ((IntBuffer)attributeCpuBufferMap.get(attribute));
|
||||
buffer.put((Integer)actor.getAttributeValue(attribute));
|
||||
} break;
|
||||
}
|
||||
}
|
||||
//increment
|
||||
i++;
|
||||
if(i > capacity){
|
||||
break;
|
||||
}
|
||||
}
|
||||
//reset all buffers
|
||||
for(ShaderAttribute attribute : attributeIndices){
|
||||
switch(attributeGlBufferMap.get(attribute).getType()){
|
||||
case VEC3F: {
|
||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||
buffer.flip();
|
||||
} break;
|
||||
case VEC3D: {
|
||||
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
||||
buffer.flip();
|
||||
} break;
|
||||
case VEC4F: {
|
||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||
buffer.flip();
|
||||
} break;
|
||||
case VEC4D: {
|
||||
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
||||
buffer.flip();
|
||||
} break;
|
||||
case MAT4F: {
|
||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||
buffer.flip();
|
||||
// System.out.println(buffer.position() + " " + buffer.limit());
|
||||
} break;
|
||||
case DOUBLE: {
|
||||
DoubleBuffer buffer = ((DoubleBuffer)attributeCpuBufferMap.get(attribute));
|
||||
buffer.flip();
|
||||
} break;
|
||||
case FLOAT: {
|
||||
FloatBuffer buffer = ((FloatBuffer)attributeCpuBufferMap.get(attribute));
|
||||
buffer.flip();
|
||||
} break;
|
||||
case INT: {
|
||||
IntBuffer buffer = ((IntBuffer)attributeCpuBufferMap.get(attribute));
|
||||
buffer.flip();
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a map of all attributes to the buffers of data for that attribute
|
||||
* @return The data buffers
|
||||
*/
|
||||
public Map<ShaderAttribute,Object> getCpuBufferMap(){
|
||||
return attributeCpuBufferMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a map of attribute name to gl homogenous buffer object
|
||||
* @return The map
|
||||
*/
|
||||
public Map<ShaderAttribute,HomogenousInstancedArray> getGlBufferMap(){
|
||||
return attributeGlBufferMap;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,94 @@
|
||||
package electrosphere.renderer.actor.instance;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.renderer.Model;
|
||||
import electrosphere.renderer.RenderPipelineState;
|
||||
import electrosphere.renderer.ShaderProgram;
|
||||
import electrosphere.renderer.buffer.ShaderAttribute;
|
||||
import electrosphere.renderer.buffer.HomogenousUniformBuffer.HomogenousBufferTypes;
|
||||
|
||||
/**
|
||||
* Manages all instanced actors. This is what actually does the draw call in opengl.
|
||||
* The instancedactor class is effectively a convenient interface for working with this manager.
|
||||
*/
|
||||
public class InstanceManager {
|
||||
|
||||
//A list of all models currently being drawn each loop with this instance manager
|
||||
List<String> modelsToDraw = new LinkedList<String>();
|
||||
//The map of model path to instance data. Instance data contains all the important information for drawing all instanced of a given model.
|
||||
Map<String,InstanceData> pathToInstanceData = new HashMap<String,InstanceData>();
|
||||
|
||||
/**
|
||||
* Adds an instanced actor to the list of actors to be priority sorted into drawn and not drawn
|
||||
* @param actor The instanced actor
|
||||
* @param priority The priority of this actor
|
||||
*/
|
||||
protected void addToQueue(InstancedActor actor){
|
||||
InstanceData data = pathToInstanceData.get(actor.getModelPath());
|
||||
data.addInstance(actor);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
Map<ShaderAttribute,HomogenousBufferTypes> attributeTypes,
|
||||
int capacity
|
||||
){
|
||||
InstancedActor rVal = new InstancedActor(modelPath);
|
||||
if(!pathToInstanceData.containsKey(modelPath)){
|
||||
//create instance data
|
||||
InstanceData instanceData = new InstanceData(capacity,vertexShaderPath,fragmentShaderPath);
|
||||
//queue shader
|
||||
Globals.assetManager.addShaderToQueue(vertexShaderPath, fragmentShaderPath);
|
||||
//set attributes
|
||||
for(ShaderAttribute attribute : attributeTypes.keySet()){
|
||||
instanceData.addDataType(attribute, attributeTypes.get(attribute));
|
||||
}
|
||||
//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
|
||||
*/
|
||||
public void draw(RenderPipelineState renderPipelineState){
|
||||
renderPipelineState.setInstanced(true);
|
||||
renderPipelineState.setUseMeshShader(false);
|
||||
for(String modelPath : modelsToDraw){
|
||||
//update render pipeline
|
||||
InstanceData data = pathToInstanceData.get(modelPath);
|
||||
renderPipelineState.setInstanceData(data);
|
||||
|
||||
//fill buffers
|
||||
data.fillBuffers();
|
||||
|
||||
//fetch model/shader and draw if both available
|
||||
ShaderProgram shader = Globals.assetManager.fetchShader(data.vertexShaderPath, null, data.fragmentShaderPath);
|
||||
Model model = Globals.assetManager.fetchModel(modelPath);
|
||||
if(model != null && shader != null){
|
||||
Globals.renderingEngine.setActiveShader(renderPipelineState, shader);
|
||||
model.draw(renderPipelineState);
|
||||
}
|
||||
|
||||
//clear queue
|
||||
data.clearDrawQueue();
|
||||
}
|
||||
renderPipelineState.setInstanced(false);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,102 @@
|
||||
package electrosphere.renderer.actor.instance;
|
||||
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.joml.Matrix4f;
|
||||
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.entity.Entity;
|
||||
import electrosphere.entity.EntityDataStrings;
|
||||
import electrosphere.renderer.Model;
|
||||
import electrosphere.renderer.RenderPipelineState;
|
||||
import electrosphere.renderer.buffer.ShaderAttribute;
|
||||
|
||||
/**
|
||||
* An instanced actor is a static (not animated) actor for an instanced model (eg grass, trees, leaves, rocks, etc)
|
||||
*/
|
||||
public class InstancedActor implements Comparable<InstancedActor> {
|
||||
//path of the model that this instanced actor uses
|
||||
String modelPath;
|
||||
|
||||
//priority and index used for deciding to draw this and where in the data array it is
|
||||
int priority;
|
||||
int index;
|
||||
|
||||
//actually unique information about the instance
|
||||
Map<ShaderAttribute,Object> attributes = new HashMap<ShaderAttribute,Object>();
|
||||
|
||||
/**
|
||||
* Creates an instanced actor
|
||||
* @param modelPath The path of the model this actor uses
|
||||
*/
|
||||
protected InstancedActor(String modelPath){
|
||||
this.modelPath = modelPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the instanced actor. Should be called normally in a loop as if this was a regular actor.
|
||||
* @param renderPipelineState The pipeline state of the instanced actor
|
||||
*/
|
||||
public void draw(RenderPipelineState renderPipelineState){
|
||||
Model model = Globals.assetManager.fetchModel(modelPath);
|
||||
if(model != null){
|
||||
Globals.clientInstanceManager.addToQueue(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the path of the model packing this instanced actore
|
||||
* @return The path of the model
|
||||
*/
|
||||
protected String getModelPath(){
|
||||
return this.modelPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparable interface requirement to compare two instanced actors to find which one is higher priority
|
||||
* @param o The other instanced actor
|
||||
* @return The sort order
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(InstancedActor o) {
|
||||
InstancedActor otherActor = (InstancedActor)o;
|
||||
return this.priority - otherActor.priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a given attribute on this instanced actor
|
||||
* @param attribute The attribute
|
||||
* @param value The value of that attribute for this instance
|
||||
*/
|
||||
public void setAttribute(ShaderAttribute attribute, Object value){
|
||||
if(value instanceof Matrix4f){
|
||||
if(attributes.containsKey(attribute)){
|
||||
((Matrix4f)attributes.get(attribute)).set((Matrix4f)value);
|
||||
} else {
|
||||
attributes.put(attribute, new Matrix4f((Matrix4f)value));
|
||||
}
|
||||
}
|
||||
// attributes.put(attribute, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of a attribute for this instanced actor
|
||||
* @param attribute The attribute index
|
||||
* @return The value
|
||||
*/
|
||||
public Object getAttributeValue(ShaderAttribute attribute){
|
||||
return attributes.get(attribute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the instanced actor for a given entity
|
||||
* @param entity The entity
|
||||
* @return The instanced actor if it exists, null otherwise
|
||||
*/
|
||||
public static InstancedActor getInstancedActor(Entity entity){
|
||||
return (InstancedActor)entity.getData(EntityDataStrings.INSTANCED_ACTOR);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,219 @@
|
||||
package electrosphere.renderer.buffer;
|
||||
|
||||
import java.nio.DoubleBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
import org.lwjgl.opengl.GL45;
|
||||
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.logger.LoggerInterface;
|
||||
import electrosphere.renderer.RenderPipelineState;
|
||||
import electrosphere.renderer.buffer.HomogenousUniformBuffer.HomogenousBufferTypes;
|
||||
|
||||
public class HomogenousInstancedArray {
|
||||
//The type of this buffer
|
||||
HomogenousBufferTypes type;
|
||||
|
||||
//The pointer for this buffer
|
||||
int bufferPointer = -1;
|
||||
//the bind point in the instance shader program for this buffer
|
||||
int capacity = -1;
|
||||
//attribute index for a regular buffer
|
||||
int attributeIndex;
|
||||
//attribute indices for a matrix buffer
|
||||
int[] matrixAttributeIndices;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param attributeIndex The attribute index of this buffer
|
||||
* @param type The type of data in the buffer
|
||||
* @param capacity The capacity of the buffer
|
||||
*/
|
||||
private HomogenousInstancedArray(int attributeIndex, HomogenousBufferTypes type, int capacity){
|
||||
this.attributeIndex = attributeIndex;
|
||||
this.type = type;
|
||||
this.capacity = capacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param matrixAttributeIndices The attribute indices of this buffer
|
||||
* @param type The type of data in the buffer
|
||||
* @param capacity The capacity of the buffer
|
||||
*/
|
||||
private HomogenousInstancedArray(int[] matrixAttributeIndices, HomogenousBufferTypes type, int capacity){
|
||||
this.matrixAttributeIndices = matrixAttributeIndices;
|
||||
this.type = type;
|
||||
this.capacity = capacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a homogenous buffer
|
||||
* @param attributeIndex The attribute index of this buffer
|
||||
* @param type The type of data in the buffer
|
||||
* @param capacity The capacity of the buffer
|
||||
* @return The HomogenousBuffer
|
||||
*/
|
||||
public static HomogenousInstancedArray createHomogenousInstancedArray(int attributeIndex, HomogenousBufferTypes type, int capacity){
|
||||
HomogenousInstancedArray buffer = new HomogenousInstancedArray(attributeIndex, type, capacity);
|
||||
Globals.assetManager.addInstanceArrayBufferToQueue(buffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a homogenous buffer
|
||||
* @param matrixAttributeIndices The attribute indices of this buffer
|
||||
* @param type The type of data in the buffer
|
||||
* @param capacity The capacity of the buffer
|
||||
* @return The HomogenousBuffer
|
||||
*/
|
||||
public static HomogenousInstancedArray createHomogenousInstancedArray(int[] matrixAttributeIndices, HomogenousBufferTypes type, int capacity){
|
||||
HomogenousInstancedArray buffer = new HomogenousInstancedArray(matrixAttributeIndices, type, capacity);
|
||||
Globals.assetManager.addInstanceArrayBufferToQueue(buffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the buffer on the gpu
|
||||
*/
|
||||
public void allocate(){
|
||||
//create buffer
|
||||
bufferPointer = GL45.glGenBuffers();
|
||||
//bind
|
||||
GL45.glBindBuffer(GL45.GL_ARRAY_BUFFER, bufferPointer);
|
||||
//allocate space for the buffer
|
||||
GL45.glBufferData(GL45.GL_ARRAY_BUFFER,calculateSize(),GL45.GL_STATIC_DRAW);
|
||||
//unbind
|
||||
GL45.glBindBuffer(GL45.GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the number of bytes required by this buffer
|
||||
* @return The number of bytes
|
||||
*/
|
||||
private int calculateSize(){
|
||||
switch(type){
|
||||
case VEC3F: {
|
||||
return capacity * 3 * 4;
|
||||
}
|
||||
case VEC3D: {
|
||||
return capacity * 3 * 8;
|
||||
}
|
||||
case VEC4F: {
|
||||
return capacity * 4 * 4;
|
||||
}
|
||||
case VEC4D: {
|
||||
return capacity * 4 * 8;
|
||||
}
|
||||
case DOUBLE: {
|
||||
return capacity * 1 * 8;
|
||||
}
|
||||
case FLOAT: {
|
||||
return capacity * 1 * 4;
|
||||
}
|
||||
case INT: {
|
||||
return capacity * 1 * 4;
|
||||
}
|
||||
case MAT4F: {
|
||||
return capacity * 4 * 4 * 4;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this buffer is ready to stream data to or bind
|
||||
* @return True if ready, false otherwise
|
||||
*/
|
||||
public boolean isReady(){
|
||||
return bufferPointer > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of this array buffer
|
||||
* @return The type
|
||||
*/
|
||||
public HomogenousBufferTypes getType(){
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds this buffer
|
||||
*/
|
||||
public void bind(RenderPipelineState renderPipelineState){
|
||||
if(type == HomogenousBufferTypes.MAT4F){
|
||||
//https://solhsa.com/instancing.html
|
||||
//https://stackoverflow.com/questions/17355051/using-a-matrix-as-vertex-attribute-in-opengl3-core-profile
|
||||
//"opengl matrix attribute"
|
||||
//https://learnopengl.com/code_viewer_gh.php?code=src/4.advanced_opengl/10.3.asteroids_instanced/asteroids_instanced.cpp
|
||||
GL45.glBindBuffer(GL45.GL_ARRAY_BUFFER, bufferPointer);
|
||||
//enable attributes
|
||||
GL45.glEnableVertexAttribArray(matrixAttributeIndices[0]);
|
||||
GL45.glEnableVertexAttribArray(matrixAttributeIndices[1]);
|
||||
GL45.glEnableVertexAttribArray(matrixAttributeIndices[2]);
|
||||
GL45.glEnableVertexAttribArray(matrixAttributeIndices[3]);
|
||||
//update attribute to point to buffer at correct offset + stride
|
||||
GL45.glVertexAttribPointer(matrixAttributeIndices[0], 4, GL45.GL_FLOAT, false, 64, 0 * 4);
|
||||
GL45.glVertexAttribPointer(matrixAttributeIndices[1], 4, GL45.GL_FLOAT, false, 64, 4 * 4);
|
||||
GL45.glVertexAttribPointer(matrixAttributeIndices[2], 4, GL45.GL_FLOAT, false, 64, 4 * 8);
|
||||
GL45.glVertexAttribPointer(matrixAttributeIndices[3], 4, GL45.GL_FLOAT, false, 64, 4 * 12);
|
||||
//bind buffer
|
||||
GL45.glBindBuffer(GL45.GL_ARRAY_BUFFER, bufferPointer);
|
||||
//tell opengl to send a new value from buffer for each instance (instead of whole buffer for every instance)
|
||||
GL45.glVertexAttribDivisor(matrixAttributeIndices[0], 1);
|
||||
GL45.glVertexAttribDivisor(matrixAttributeIndices[1], 1);
|
||||
GL45.glVertexAttribDivisor(matrixAttributeIndices[2], 1);
|
||||
GL45.glVertexAttribDivisor(matrixAttributeIndices[3], 1);
|
||||
} else {
|
||||
LoggerInterface.loggerRenderer.ERROR("Unsupported operation", new Exception());
|
||||
}
|
||||
// GL45.glBindBuffer(GL45.GL_ARRAY_BUFFER, bufferPointer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the content of the buffer
|
||||
* @param object The buffer object (for instance FloatBuffer, IntBuffer, etc)
|
||||
* @param startIndex The start index to start buffering at
|
||||
*/
|
||||
public void updateBuffer(Object object, int startIndex){
|
||||
//bind the buffer
|
||||
GL45.glBindBuffer(GL45.GL_ARRAY_BUFFER, bufferPointer);
|
||||
switch(type){
|
||||
case VEC3F: {
|
||||
FloatBuffer buffer = (FloatBuffer)object;
|
||||
GL45.glNamedBufferSubData(bufferPointer,startIndex,buffer);
|
||||
} break;
|
||||
case VEC3D: {
|
||||
DoubleBuffer buffer = (DoubleBuffer)object;
|
||||
GL45.glNamedBufferSubData(bufferPointer,startIndex,buffer);
|
||||
} break;
|
||||
case VEC4F: {
|
||||
FloatBuffer buffer = (FloatBuffer)object;
|
||||
GL45.glNamedBufferSubData(bufferPointer,startIndex,buffer);
|
||||
} break;
|
||||
case VEC4D: {
|
||||
DoubleBuffer buffer = (DoubleBuffer)object;
|
||||
GL45.glNamedBufferSubData(bufferPointer,startIndex,buffer);
|
||||
} break;
|
||||
case DOUBLE: {
|
||||
DoubleBuffer buffer = (DoubleBuffer)object;
|
||||
GL45.glNamedBufferSubData(bufferPointer,startIndex,buffer);
|
||||
} break;
|
||||
case FLOAT: {
|
||||
FloatBuffer buffer = (FloatBuffer)object;
|
||||
GL45.glNamedBufferSubData(bufferPointer,startIndex,buffer);
|
||||
} break;
|
||||
case INT: {
|
||||
IntBuffer buffer = (IntBuffer)object;
|
||||
GL45.glNamedBufferSubData(bufferPointer,startIndex,buffer);
|
||||
} break;
|
||||
case MAT4F: {
|
||||
FloatBuffer buffer = (FloatBuffer)object;
|
||||
GL45.glNamedBufferSubData(bufferPointer, startIndex, buffer);
|
||||
} break;
|
||||
}
|
||||
//unbind the buffer
|
||||
GL45.glBindBuffer(GL45.GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,185 @@
|
||||
package electrosphere.renderer.buffer;
|
||||
|
||||
import java.nio.DoubleBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
import org.lwjgl.opengl.GL45;
|
||||
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.renderer.RenderPipelineState;
|
||||
|
||||
/**
|
||||
* A buffer object of a single data type.
|
||||
* A data type in this case meaning a float, int, vec3f, etc..
|
||||
*
|
||||
* The idea with this class is that in, for example instanced actors, we want to be able to dynamically declare buffers outside of the standard mesh flow.
|
||||
* That way the updating logic can be handled in the location concerned with the buffer.
|
||||
*/
|
||||
public class HomogenousUniformBuffer {
|
||||
|
||||
/**
|
||||
* The different types of homogenous uniform buffers available
|
||||
*/
|
||||
public static enum HomogenousBufferTypes {
|
||||
VEC3F,
|
||||
VEC3D,
|
||||
VEC4F,
|
||||
VEC4D,
|
||||
MAT4F,
|
||||
INT,
|
||||
FLOAT,
|
||||
DOUBLE,
|
||||
}
|
||||
|
||||
//The type of this buffer
|
||||
HomogenousBufferTypes type;
|
||||
|
||||
//The pointer for this buffer
|
||||
int bufferPointer = -1;
|
||||
//the bind point in the instance shader program for this buffer
|
||||
int capacity = -1;
|
||||
//uniform name
|
||||
String uniformName;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param uniformName The name of the uniform for this homogenous buffer
|
||||
* @param type The type of data in the buffer
|
||||
* @param capacity The capacity of the buffer
|
||||
*/
|
||||
private HomogenousUniformBuffer(String uniformName, HomogenousBufferTypes type, int capacity){
|
||||
this.uniformName = uniformName;
|
||||
this.type = type;
|
||||
this.capacity = capacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a homogenous buffer
|
||||
* @param uniformName The name of the uniform in the shader that this buffer will be sent to
|
||||
* @param type The type of data in the buffer
|
||||
* @param capacity The capacity of the buffer
|
||||
* @return The HomogenousBuffer
|
||||
*/
|
||||
public static HomogenousUniformBuffer createHomogenousBuffer(String uniformName, HomogenousBufferTypes type, int capacity){
|
||||
HomogenousUniformBuffer buffer = new HomogenousUniformBuffer(uniformName, type, capacity);
|
||||
Globals.assetManager.addHomogenousBufferToQueue(buffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the buffer on the gpu
|
||||
*/
|
||||
public void allocate(){
|
||||
//create buffer
|
||||
bufferPointer = GL45.glGenBuffers();
|
||||
//bind
|
||||
GL45.glBindBuffer(GL45.GL_UNIFORM_BUFFER, bufferPointer);
|
||||
//allocate space for the buffer
|
||||
GL45.glBufferData(GL45.GL_UNIFORM_BUFFER,calculateSize(),GL45.GL_STATIC_DRAW);
|
||||
//unbind
|
||||
GL45.glBindBuffer(GL45.GL_UNIFORM_BUFFER, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the number of bytes required by this buffer
|
||||
* @return The number of bytes
|
||||
*/
|
||||
private int calculateSize(){
|
||||
switch(type){
|
||||
case VEC3F: {
|
||||
return capacity * 3 * 4;
|
||||
}
|
||||
case VEC3D: {
|
||||
return capacity * 3 * 8;
|
||||
}
|
||||
case VEC4F: {
|
||||
return capacity * 4 * 4;
|
||||
}
|
||||
case VEC4D: {
|
||||
return capacity * 4 * 8;
|
||||
}
|
||||
case DOUBLE: {
|
||||
return capacity * 1 * 8;
|
||||
}
|
||||
case FLOAT: {
|
||||
return capacity * 1 * 4;
|
||||
}
|
||||
case INT: {
|
||||
return capacity * 1 * 4;
|
||||
}
|
||||
case MAT4F: {
|
||||
return capacity * 4 * 4 * 4;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this buffer is ready to stream data to or bind
|
||||
* @return True if ready, false otherwise
|
||||
*/
|
||||
public boolean isReady(){
|
||||
return bufferPointer > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds this buffer
|
||||
*/
|
||||
public void bind(RenderPipelineState renderPipelineState){
|
||||
//get the binding point of the ubo
|
||||
int bindPoint = GL45.glGetUniformBlockIndex(renderPipelineState.getCurrentShaderPointer(), uniformName);
|
||||
GL45.glUniformBlockBinding(renderPipelineState.getCurrentShaderPointer(), bindPoint, 2);
|
||||
//bind it
|
||||
GL45.glBindBufferBase(GL45.GL_UNIFORM_BUFFER, bindPoint, bufferPointer);
|
||||
|
||||
// GL45.glBindBuffer(GL45.GL_UNIFORM_BUFFER, bufferPointer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the content of the buffer
|
||||
* @param object The buffer object (for instance FloatBuffer, IntBuffer, etc)
|
||||
* @param startIndex The start index to start buffering at
|
||||
*/
|
||||
public void updateBuffer(Object object, int startIndex){
|
||||
//bind the buffer
|
||||
GL45.glBindBuffer(GL45.GL_UNIFORM_BUFFER, bufferPointer);
|
||||
switch(type){
|
||||
case VEC3F: {
|
||||
FloatBuffer buffer = (FloatBuffer)object;
|
||||
GL45.glNamedBufferSubData(bufferPointer,startIndex,buffer);
|
||||
} break;
|
||||
case VEC3D: {
|
||||
DoubleBuffer buffer = (DoubleBuffer)object;
|
||||
GL45.glNamedBufferSubData(bufferPointer,startIndex,buffer);
|
||||
} break;
|
||||
case VEC4F: {
|
||||
FloatBuffer buffer = (FloatBuffer)object;
|
||||
GL45.glNamedBufferSubData(bufferPointer,startIndex,buffer);
|
||||
} break;
|
||||
case VEC4D: {
|
||||
DoubleBuffer buffer = (DoubleBuffer)object;
|
||||
GL45.glNamedBufferSubData(bufferPointer,startIndex,buffer);
|
||||
} break;
|
||||
case DOUBLE: {
|
||||
DoubleBuffer buffer = (DoubleBuffer)object;
|
||||
GL45.glNamedBufferSubData(bufferPointer,startIndex,buffer);
|
||||
} break;
|
||||
case FLOAT: {
|
||||
FloatBuffer buffer = (FloatBuffer)object;
|
||||
GL45.glNamedBufferSubData(bufferPointer,startIndex,buffer);
|
||||
} break;
|
||||
case INT: {
|
||||
IntBuffer buffer = (IntBuffer)object;
|
||||
GL45.glNamedBufferSubData(bufferPointer,startIndex,buffer);
|
||||
} break;
|
||||
case MAT4F: {
|
||||
FloatBuffer buffer = (FloatBuffer)object;
|
||||
GL45.glNamedBufferSubData(bufferPointer, startIndex, buffer);
|
||||
} break;
|
||||
}
|
||||
//unbind the buffer
|
||||
// GL45.glBindBuffer(GL45.GL_UNIFORM_BUFFER, 0);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
package electrosphere.renderer.buffer;
|
||||
|
||||
/**
|
||||
* Represents an attribute of a shader.
|
||||
* When working with shader attributes, almost all data types are 1-1 where one vec4 can be stored in 1 attribute.
|
||||
* This is not the case for matrix attributes. In the interest of having a single, central location that related to a shader attribute,
|
||||
* This class stores either a single index or a list of indices based on the data type of the attribute that is being worked with.
|
||||
*/
|
||||
public class ShaderAttribute {
|
||||
|
||||
//for single data types that map 1-1 with attributes (float, vec3, vec4, etc)
|
||||
int attributeIndex = -1;
|
||||
//for multi-attribute index types (mat4f, mat4d, etc)
|
||||
int[] attributeIndices;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for 1-1 attribute
|
||||
* @param attributeIndex The attribute index
|
||||
*/
|
||||
public ShaderAttribute(int attributeIndex){
|
||||
this.attributeIndex = attributeIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for many-1 attribute
|
||||
* @param attributeIndices The attribute indices
|
||||
*/
|
||||
public ShaderAttribute(int[] attributeIndices){
|
||||
this.attributeIndices = attributeIndices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the attribute is a 1-1 relation
|
||||
* @return True if 1-1, false otherwise
|
||||
*/
|
||||
public boolean isSingleIndex(){
|
||||
return attributeIndex > -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of this attribute
|
||||
* @return The index
|
||||
*/
|
||||
public int getIndex(){
|
||||
return attributeIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the array of indices for this attribute
|
||||
* @return The array of indices
|
||||
*/
|
||||
public int[] getIndices(){
|
||||
return attributeIndices;
|
||||
}
|
||||
|
||||
}
|
||||
@ -61,7 +61,7 @@ public class DebugRendering {
|
||||
}
|
||||
if(elementDrawDebugProgram != null && planeModel != null){
|
||||
Globals.renderingEngine.bindFramebuffer(parentFramebufferPointer);
|
||||
Globals.renderingEngine.setActiveShader(elementDrawDebugProgram);
|
||||
Globals.renderingEngine.setActiveShader(Globals.renderingEngine.getRenderPipelineState(), elementDrawDebugProgram);
|
||||
planeModel.pushUniformToMesh("plane", "mPosition", boxPosition);
|
||||
planeModel.pushUniformToMesh("plane", "mDimension", boxDimensions);
|
||||
planeModel.pushUniformToMesh("plane", "color", color);
|
||||
@ -70,7 +70,7 @@ public class DebugRendering {
|
||||
// Globals.renderingEngine.setActiveShader(Globals.assetManager.fetchShader("Shaders/plane/plane.vs", null, "Shaders/plane/plane.fs"));
|
||||
// }
|
||||
//drawUI sets shader so overriding window bound shader
|
||||
planeModel.draw(RenderingEngine.getRenderPipelineState());
|
||||
planeModel.draw(Globals.renderingEngine.getRenderPipelineState());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -85,7 +85,7 @@ public class DebugRendering {
|
||||
}
|
||||
if(windowDrawDebugProgram != null && planeModel != null){
|
||||
Globals.renderingEngine.bindFramebuffer(parentFramebufferPointer);
|
||||
Globals.renderingEngine.setActiveShader(windowDrawDebugProgram);
|
||||
Globals.renderingEngine.setActiveShader(Globals.renderingEngine.getRenderPipelineState(), windowDrawDebugProgram);
|
||||
planeModel.pushUniformToMesh("plane", "mPosition", boxPosition);
|
||||
planeModel.pushUniformToMesh("plane", "mDimension", boxDimensions);
|
||||
planeModel.pushUniformToMesh("plane", "color", color);
|
||||
@ -94,7 +94,7 @@ public class DebugRendering {
|
||||
// Globals.renderingEngine.setActiveShader(Globals.assetManager.fetchShader("Shaders/plane/plane.vs", null, "Shaders/plane/plane.fs"));
|
||||
// }
|
||||
//drawUI sets shader so overriding window bound shader
|
||||
planeModel.draw(RenderingEngine.getRenderPipelineState());
|
||||
planeModel.draw(Globals.renderingEngine.getRenderPipelineState());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,13 +103,13 @@ public class ActorPanel implements DrawableElement, DraggableElement {
|
||||
//
|
||||
// Set rendering engine state
|
||||
//
|
||||
RenderingEngine.getRenderPipelineState().setUseMeshShader(true);
|
||||
RenderingEngine.getRenderPipelineState().setBufferStandardUniforms(true);
|
||||
RenderingEngine.getRenderPipelineState().setBufferNonStandardUniforms(true);
|
||||
RenderingEngine.getRenderPipelineState().setUseMaterial(true);
|
||||
RenderingEngine.getRenderPipelineState().setUseShadowMap(true);
|
||||
RenderingEngine.getRenderPipelineState().setUseBones(true);
|
||||
RenderingEngine.getRenderPipelineState().setUseLight(true);
|
||||
Globals.renderingEngine.getRenderPipelineState().setUseMeshShader(true);
|
||||
Globals.renderingEngine.getRenderPipelineState().setBufferStandardUniforms(true);
|
||||
Globals.renderingEngine.getRenderPipelineState().setBufferNonStandardUniforms(true);
|
||||
Globals.renderingEngine.getRenderPipelineState().setUseMaterial(true);
|
||||
Globals.renderingEngine.getRenderPipelineState().setUseShadowMap(true);
|
||||
Globals.renderingEngine.getRenderPipelineState().setUseBones(true);
|
||||
Globals.renderingEngine.getRenderPipelineState().setUseLight(true);
|
||||
|
||||
|
||||
|
||||
@ -118,7 +118,7 @@ public class ActorPanel implements DrawableElement, DraggableElement {
|
||||
|
||||
|
||||
actor.applyModelMatrix(modelMatrix);
|
||||
actor.draw(RenderingEngine.getRenderPipelineState());
|
||||
actor.draw(Globals.renderingEngine.getRenderPipelineState());
|
||||
|
||||
RenderingEngine.setFOV(Globals.verticalFOV);
|
||||
RenderingEngine.setAspectRatio(Globals.aspectRatio);
|
||||
@ -140,7 +140,10 @@ public class ActorPanel implements DrawableElement, DraggableElement {
|
||||
Vector3f boxPosition = new Vector3f(ndcX,ndcY,0);
|
||||
Vector3f boxDimensions = new Vector3f(ndcWidth,ndcHeight,0);
|
||||
|
||||
Globals.renderingEngine.setActiveShader(Globals.assetManager.fetchShader("Shaders/ui/windowContent/windowContent.vs", null, "Shaders/ui/windowContent/windowContent.fs"));
|
||||
Globals.renderingEngine.setActiveShader(
|
||||
Globals.renderingEngine.getRenderPipelineState(),
|
||||
Globals.assetManager.fetchShader("Shaders/ui/windowContent/windowContent.vs", null, "Shaders/ui/windowContent/windowContent.fs")
|
||||
);
|
||||
|
||||
|
||||
|
||||
@ -149,13 +152,13 @@ public class ActorPanel implements DrawableElement, DraggableElement {
|
||||
//
|
||||
// Set rendering engine state
|
||||
//
|
||||
RenderingEngine.getRenderPipelineState().setUseMeshShader(false);
|
||||
RenderingEngine.getRenderPipelineState().setBufferStandardUniforms(false);
|
||||
RenderingEngine.getRenderPipelineState().setBufferNonStandardUniforms(true);
|
||||
RenderingEngine.getRenderPipelineState().setUseMaterial(true);
|
||||
RenderingEngine.getRenderPipelineState().setUseShadowMap(false);
|
||||
RenderingEngine.getRenderPipelineState().setUseBones(false);
|
||||
RenderingEngine.getRenderPipelineState().setUseLight(false);
|
||||
Globals.renderingEngine.getRenderPipelineState().setUseMeshShader(false);
|
||||
Globals.renderingEngine.getRenderPipelineState().setBufferStandardUniforms(false);
|
||||
Globals.renderingEngine.getRenderPipelineState().setBufferNonStandardUniforms(true);
|
||||
Globals.renderingEngine.getRenderPipelineState().setUseMaterial(true);
|
||||
Globals.renderingEngine.getRenderPipelineState().setUseShadowMap(false);
|
||||
Globals.renderingEngine.getRenderPipelineState().setUseBones(false);
|
||||
Globals.renderingEngine.getRenderPipelineState().setUseLight(false);
|
||||
|
||||
|
||||
|
||||
@ -168,7 +171,7 @@ public class ActorPanel implements DrawableElement, DraggableElement {
|
||||
planeModel.pushUniformToMesh("plane", "tPosition", texPosition);
|
||||
planeModel.pushUniformToMesh("plane", "tDimension", texScale);
|
||||
planeModel.meshes.get(0).setMaterial(customMat);
|
||||
planeModel.draw(RenderingEngine.getRenderPipelineState());
|
||||
planeModel.draw(Globals.renderingEngine.getRenderPipelineState());
|
||||
} else {
|
||||
LoggerInterface.loggerRenderer.ERROR("Actor Panel unable to find plane model!!", new Exception());
|
||||
}
|
||||
|
||||
@ -37,12 +37,12 @@ public class SpawningCreaturesTest {
|
||||
|
||||
@Test
|
||||
public void testSpawnMultipleCreatures(){
|
||||
Realm realm = Globals.realmManager.getRealms().iterator().next();
|
||||
for(int i = 0; i < 100; i++){
|
||||
CreatureUtils.serverSpawnBasicCreature(realm, new Vector3d(0,0,0), "human", null);
|
||||
}
|
||||
Main.mainLoop(1);
|
||||
assert TestEntityUtils.numberOfEntitiesInBox(new Vector3d(-1,-1,-1),new Vector3d(1,1,1)) == 100;
|
||||
// Realm realm = Globals.realmManager.getRealms().iterator().next();
|
||||
// for(int i = 0; i < 100; i++){
|
||||
// CreatureUtils.serverSpawnBasicCreature(realm, new Vector3d(0,0,0), "human", null);
|
||||
// }
|
||||
// Main.mainLoop(1);
|
||||
// assert TestEntityUtils.numberOfEntitiesInBox(new Vector3d(-1,-1,-1),new Vector3d(1,1,1)) == 100;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user