block item texture work

This commit is contained in:
austin 2025-01-25 18:02:22 -05:00
parent f875f4a80f
commit 851e95f3e5
14 changed files with 374 additions and 7 deletions

View File

@ -8,6 +8,11 @@
"id" : 1,
"name" : "brick",
"texture" : "/Textures/Ground/Dirt2_256.png"
},
{
"id" : 2,
"name" : "grass",
"texture" : "/Textures/Ground/GrassTileable256.png"
}
]
}

View File

@ -0,0 +1,96 @@
#version 450 core
#extension GL_ARB_shading_language_include : require
#include "../../lib/lights.fs"
//texture defines
#define ATLAS_ELEMENT_DIM 256.0
#define ATLAS_DIM 8192.0
#define ATLAS_EL_PER_ROW 32
#define ATLAS_NORMALIZED_ELEMENT_WIDTH 0.031 //within the single texture within the atlas, we use this so we never go over the end of the texture
#define ATLAS_NORMALIZED_ELEMENT_WIDTH_FULL 0.03125 //used to properly shift from texture to texture in the atlas
struct Material {
sampler2D diffuse;
sampler2D specular;
float shininess;
};
in vec3 FragPos;
in vec3 ViewFragPos;
in vec3 Normal;
in vec2 uv;
in vec4 FragPosLightSpace;
uniform int blockAtlasIndex; //index of the block type in the texture atlas
uniform vec3 viewPos;
uniform Material material;
/**
Used for light cluster calculation
*/
uniform mat4 view;
/**
The output
*/
out vec4 FragColor;
// function prototypes
vec3 getColor(vec2 uv, vec3 normal, int blockIndex, Material material);
void main(){
vec3 norm = normalize(Normal);
vec3 viewDir = normalize(viewPos - FragPos);
//grab light intensity
vec3 lightIntensity = vec3(calcLightIntensityTotal(norm));
//get color of base texture
vec3 textureColor = getColor(uv, norm, blockAtlasIndex, material);
//shadow
float shadow = ShadowCalculation(FragPosLightSpace, normalize(-directLight.direction), -norm);
//
//point light calculations
uint clusterIndex = findCluster(ViewFragPos, zNear, zFar);
uint pointLightCount = clusters[clusterIndex].count;
for(int i = 0; i < pointLightCount; i++){
uint pointLightIndex = clusters[clusterIndex].lightIndices[i];
PointLight pointLight = pointLight[pointLightIndex];
lightIntensity = lightIntensity + CalcPointLight(pointLight, norm, FragPos, viewDir);
}
//error checking on light clusters
if(pointLightCount > MAX_LIGHTS_PER_CLUSTER){
FragColor = vec4(1.0f,0.0f,0.0f,1);
return;
}
//calculate final color
vec3 finalColor = textureColor * lightIntensity * max(shadow,0.4);
//this final calculation is for transparency
FragColor = vec4(finalColor, 1);
}
/**
* The function that gets the texture color based on the triplanar texture mapping and the voxel type at each point along the vert.
* See the triplanar mapping wiki article for an explanation of math involved.
*/
vec3 getColor(vec2 uv, vec3 normal, int blockIndex, Material material){
//the uv of the texture clamped within the atlas
vec2 actualUv = vec2(
(fract(uv.x) * ATLAS_NORMALIZED_ELEMENT_WIDTH) + (mod(blockIndex,ATLAS_EL_PER_ROW) * ATLAS_NORMALIZED_ELEMENT_WIDTH_FULL),
(fract(uv.y) * ATLAS_NORMALIZED_ELEMENT_WIDTH) + (round(blockIndex / ATLAS_EL_PER_ROW) * ATLAS_NORMALIZED_ELEMENT_WIDTH_FULL)
);
//albedo for the X texture
vec3 color = texture(material.diffuse, actualUv).rgb;
return color;
}

View File

@ -0,0 +1,53 @@
//Vertex Shader
#version 330 core
//defines
#define TEXTURE_MAP_SCALE 1.0
#define MODEL_TOTAL_DIM 16.0
//input buffers
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 4) in vec2 aTex;
//coordinate space transformation matrices
uniform mat4 transform;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform mat4 lightSpaceMatrix;
//output buffers
out vec3 Normal;
out vec3 FragPos;
out vec3 ViewFragPos;
out vec2 uv;
out vec4 FragPosLightSpace;
void main() {
//normalize posiiton and normal
vec4 FinalVertex = vec4(aPos, 1.0);
vec4 FinalNormal = vec4(aNormal, 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;
uv = aTex;
//shadow map stuff
FragPosLightSpace = lightSpaceMatrix * vec4(FragPos, 1.0);
//set final position with opengl space
gl_Position = projection * view * model * FinalVertex;
}

View File

@ -1312,6 +1312,9 @@ Update flush method in tests to account for faster loading
Allow pre-setting queued asset path
Fix asset manager texture queueing (was not pushing queued textures into loaded texture map)
Model for single block (hooked up to item as well)
Single block model custom shader
Data-defined actor per-mesh uniform overrides
Proper textures on each block item

View File

@ -14,6 +14,8 @@ public class AssetDataStrings {
*/
public static final String SHADER_DEFAULT_VERT = "Shaders/VertexShader.vs";
public static final String SHADER_DEFAULT_FRAG = "Shaders/FragmentShader.fs";
public static final String SHADER_BLOCK_SINGLE_VERT = "Shaders/entities/blocksingle/block.vs";
public static final String SHADER_BLOCK_SINGLE_FRAG = "Shaders/entities/blocksingle/block.fs";
/**
* The basic geometry of the engine

View File

@ -16,9 +16,11 @@ import electrosphere.engine.assetmanager.AssetDataStrings;
import electrosphere.engine.assetmanager.queue.QueuedTexture;
import electrosphere.game.data.block.BlockData;
import electrosphere.game.data.block.BlockType;
import electrosphere.game.data.item.Item;
import electrosphere.game.data.voxel.VoxelData;
import electrosphere.game.data.voxel.VoxelType;
import electrosphere.logger.LoggerInterface;
import electrosphere.renderer.RenderUtils;
import electrosphere.renderer.texture.TextureAtlas;
import electrosphere.util.FileUtils;
@ -123,6 +125,13 @@ public class InitialAssetLoading {
//put coords in map
Globals.blockTextureAtlas.putTypeCoord(type.getId(),iterator);
//once the atlas has been created, need to check if items have already been created
//if items have been created, must update the hard-coded shader values to reflect the actual atlas values
if(Globals.gameConfigCurrent.getItemMap().getItem(type.getName()) != null){
Item item = Globals.gameConfigCurrent.getItemMap().getItem(type.getName());
item.getGraphicsTemplate().getModel().getUniforms().get(RenderUtils.MESH_NAME_BLOCK_SINGLE).put("blockAtlasIndex",iterator);
}
//iterate
iterator++;
}

View File

@ -1,5 +1,8 @@
package electrosphere.entity.types.common;
import java.util.Map;
import java.util.Set;
import org.joml.Quaterniond;
import org.joml.Vector3d;
import org.ode4j.ode.DBody;
@ -158,9 +161,24 @@ public class CommonEntityUtils {
if(graphicsTemplate.getModel() != null && graphicsTemplate.getModel().getIdleData() != null){
ClientIdleTree.attachTree(entity, graphicsTemplate.getModel().getIdleData());
}
if(graphicsTemplate.getModel() != null && graphicsTemplate.getModel().getUniforms() != null){
Actor creatureActor = EntityUtils.getActor(entity);
Map<String,Map<String,Object>> meshUniformMap = graphicsTemplate.getModel().getUniforms();
Set<String> meshNames = meshUniformMap.keySet();
for(String meshName : meshNames){
Map<String,Object> uniforms = meshUniformMap.get(meshName);
Set<String> uniformNames = uniforms.keySet();
for(String uniformName : uniformNames){
Object value = uniforms.get(uniformName);
creatureActor.setUniformOnMesh(meshName, uniformName, value);
}
}
}
}
Actor creatureActor = EntityUtils.getActor(entity);
//apply uniforms if they are pre-set
///
///
/// HITBOX DATA

View File

@ -1,5 +1,7 @@
package electrosphere.game.data.graphics;
import java.util.Map;
import electrosphere.game.data.creature.type.IdleData;
/**
@ -17,22 +19,59 @@ public class NonproceduralModel {
*/
IdleData idleData;
/**
* Uniform values set ahead of time
*/
Map<String,Map<String,Object>> uniforms;
/**
* Gets the path of the model
* @return The path of the model
*/
public String getPath() {
return path;
}
/**
* Sets the path of the model
* @param path The path of the model
*/
public void setPath(String path) {
this.path = path;
}
/**
* Gets the idle data of the model
* @return The idle data of the model
*/
public IdleData getIdleData() {
return idleData;
}
/**
* Sets the idle data of the model
* @param idleData The idle data of the model
*/
public void setIdleData(IdleData idleData) {
this.idleData = idleData;
}
/**
* Gets the uniforms set on the model
* @return The map of uniform name -> uniform value, or null if no uniforms are set
*/
public Map<String,Map<String,Object>> getUniforms(){
return uniforms;
}
/**
* Sets the uniform map for the model
* @param uniforms The map of uniform name -> uniform value
*/
public void setUniforms(Map<String,Map<String,Object>> uniforms){
this.uniforms = uniforms;
}
}

View File

@ -1,13 +1,17 @@
package electrosphere.game.data.item;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import electrosphere.engine.Globals;
import electrosphere.engine.assetmanager.AssetDataStrings;
import electrosphere.game.data.block.BlockType;
import electrosphere.game.data.common.CommonEntityType;
import electrosphere.game.data.common.item.SpawnItemDescription;
import electrosphere.game.data.graphics.GraphicsTemplate;
import electrosphere.game.data.graphics.NonproceduralModel;
import electrosphere.renderer.RenderUtils;
/**
* Data on a given item
@ -127,6 +131,13 @@ public class Item extends CommonEntityType {
blockItemGraphicsTemplate.setModel(modelData);
rVal.setGraphicsTemplate(blockItemGraphicsTemplate);
//set uniforms for the model
Map<String,Map<String,Object>> meshUniformMap = new HashMap<String,Map<String,Object>>();
Map<String,Object> uniforms = new HashMap<String,Object>();
uniforms.put("blockAtlasIndex",Globals.blockTextureAtlas.getVoxelTypeOffset(blockType.getId()));
meshUniformMap.put(RenderUtils.MESH_NAME_BLOCK_SINGLE,uniforms);
modelData.setUniforms(meshUniformMap);
//set usage
ItemUsage usage = new ItemUsage();

View File

@ -27,6 +27,11 @@ import org.lwjgl.util.par.ParShapesMesh;
* Utilities to assist with rendering
*/
public class RenderUtils {
/**
* Name of the mesh for the single block model
*/
public static final String MESH_NAME_BLOCK_SINGLE = "cube";
@ -542,7 +547,7 @@ public class RenderUtils {
*/
public static Model createBlockSingleModel(){
Model model = new Model();
Mesh cubeMesh = new Mesh("cube");
Mesh cubeMesh = new Mesh(RenderUtils.MESH_NAME_BLOCK_SINGLE);
cubeMesh.generateVAO();
//buffer coords
@ -615,7 +620,7 @@ public class RenderUtils {
Material mat = new Material();
mat.set_diffuse(AssetDataStrings.TEXTURE_BLOCK_ATLAS);
cubeMesh.setMaterial(mat);
cubeMesh.setShader(VisualShader.smartAssembleShader(false, true));
cubeMesh.setShader(VisualShader.loadSpecificShader(AssetDataStrings.SHADER_BLOCK_SINGLE_VERT, AssetDataStrings.SHADER_BLOCK_SINGLE_FRAG));
GL40.glBindVertexArray(0);
cubeMesh.setParent(model);
model.getMeshes().add(cubeMesh);

View File

@ -7,6 +7,7 @@ import electrosphere.game.data.creature.type.bonegroups.BoneGroup;
import electrosphere.logger.LoggerInterface;
import electrosphere.renderer.OpenGLState;
import electrosphere.renderer.RenderPipelineState;
import electrosphere.renderer.actor.ActorUniformMap.UniformValue;
import electrosphere.renderer.model.Bone;
import electrosphere.renderer.model.Model;
import electrosphere.renderer.texture.Texture;
@ -33,6 +34,7 @@ import org.joml.Vector4d;
* - Texture overrides
* - Bone overrides
* - Static Morphs (think scaling something, but from creatures.json)
* - Static uniforms per mesh
*/
public class Actor {
@ -72,6 +74,11 @@ public class Actor {
//The list of bone groups
List<BoneGroup> boneGroups;
/**
* A map of mesh -> uniforms to apply to the mesh
*/
ActorUniformMap uniformMap = new ActorUniformMap();
//Controls whether the actor should obey frustum culling
boolean frustumCull = true;
@ -441,6 +448,15 @@ public class Actor {
overrideTextureObject.bind(openGLState);
}
}
//apply uniform overrides
if(this.uniformMap.getMeshes() != null && this.uniformMap.getMeshes().size() > 0){
for(String meshName : this.uniformMap.getMeshes()){
List<UniformValue> uniforms = this.uniformMap.getUniforms(meshName);
for(UniformValue uniform : uniforms){
model.pushUniformToMesh(meshName, uniform.getUniformName(), uniform.getValue());
}
}
}
model.draw(renderPipelineState,openGLState);
model.getShaderMask().clear();
model.setTextureMask(null);
@ -624,6 +640,16 @@ public class Actor {
return boneRotators.get(bone);
}
/**
* Sets the value of a uniform on a given mesh within this actor
* @param meshName The name of the mesh
* @param uniformName The name of the uniform
* @param value The value of the uniform
*/
public void setUniformOnMesh(String meshName, String uniformName, Object value){
this.uniformMap.setUniform(meshName, uniformName, value);
}
public void setActorStaticMorph(ActorStaticMorph staticMorph){
this.staticMorph = staticMorph;
}

View File

@ -0,0 +1,97 @@
package electrosphere.renderer.actor;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Map of mesh -> uniforms to apply to that mesh
*/
public class ActorUniformMap {
/**
* Map of mesh -> uniforms to push to that mesh
*/
Map<String,List<UniformValue>> meshMap = new HashMap<String,List<UniformValue>>();
/**
* Sets the value of a uniform for a given mesh
* @param meshName The name of the mesh
* @param uniformName The name of the uniform
* @param value The value of the uniform
*/
public void setUniform(String meshName, String uniformName, Object value){
List<UniformValue> uniforms = null;
if(meshMap.containsKey(meshName)){
uniforms = meshMap.get(meshName);
} else {
uniforms = new LinkedList<UniformValue>();
meshMap.put(meshName,uniforms);
}
uniforms.add(new UniformValue(uniformName,value));
}
/**
* Gets the list of uniforms to apply to a given mesh
* @param meshName The name of the mesh
* @return The list of uniforms to apply to the mesh, or null if no uniforms are defined
*/
public List<UniformValue> getUniforms(String meshName){
return meshMap.get(meshName);
}
/**
* Gets the set of names of meshes that have uniforms set
* @return The set of mesh names that have uniforms set
*/
public Set<String> getMeshes(){
return meshMap.keySet();
}
/**
* A uniform value
*/
public static class UniformValue {
/**
* The name of the uniform
*/
String uniformName;
/**
* The value of the uniform
*/
Object value;
/**
* Constructor
* @param uniformName Name of the uniform
* @param value Value of the uniform
*/
public UniformValue(String uniformName, Object value){
this.uniformName = uniformName;
this.value = value;
}
/**
* Gets the name of the uniform
* @return The name of the uniform
*/
public String getUniformName() {
return uniformName;
}
/**
* Gets the value of the uniform
* @return The value of the uniform
*/
public Object getValue() {
return value;
}
}
}

View File

@ -322,17 +322,20 @@ public class Mesh {
}
if(currentUniformRaw instanceof Matrix4d){
Matrix4d currentUniform = (Matrix4d)currentUniformRaw;
GL40.glUniformMatrix4dv(glGetUniformLocation(openGLState.getActiveShader().getId(), key), false, currentUniform.get(new double[16]));
openGLState.getActiveShader().setUniform(openGLState, key, currentUniform);
// GL40.glUniformMatrix4dv(glGetUniformLocation(openGLState.getActiveShader().getId(), key), false, currentUniform.get(new double[16]));
Globals.renderingEngine.checkError();
}
if(currentUniformRaw instanceof Vector3f){
Vector3f currentUniform = (Vector3f)currentUniformRaw;
glUniform3fv(glGetUniformLocation(openGLState.getActiveShader().getId(), key), currentUniform.get(BufferUtils.createFloatBuffer(3)));
openGLState.getActiveShader().setUniform(openGLState, key, currentUniform);
// glUniform3fv(glGetUniformLocation(openGLState.getActiveShader().getId(), key), currentUniform.get(BufferUtils.createFloatBuffer(3)));
Globals.renderingEngine.checkError();
}
if(currentUniformRaw instanceof Integer){
int currentInform = (Integer)currentUniformRaw;
glUniform1i(glGetUniformLocation(openGLState.getActiveShader().getId(), key), currentInform);
int currentUniform = (Integer)currentUniformRaw;
openGLState.getActiveShader().setUniform(openGLState, key, currentUniform);
// glUniform1i(glGetUniformLocation(openGLState.getActiveShader().getId(), key), currentUniform);
Globals.renderingEngine.checkError();
}
}

View File

@ -55,7 +55,7 @@ public class MainContentPipeline implements RenderPipeline {
renderPipelineState.setSelectedShader(SelectedShaderEnum.PRIMARY);
renderPipelineState.setUseMeshShader(true);
renderPipelineState.setBufferStandardUniforms(true);
renderPipelineState.setBufferNonStandardUniforms(false);
renderPipelineState.setBufferNonStandardUniforms(true); //true so that pre-programmed (in data) uniforms are pushed to gpu when rendering each mesh
renderPipelineState.setUseMaterial(true);
renderPipelineState.setUseShadowMap(true);
renderPipelineState.setUseBones(true);