visual shader work
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2025-05-19 11:14:54 -04:00
parent 8bee3bf71a
commit 501d2898b7
7 changed files with 176 additions and 165 deletions

View File

@ -8,7 +8,7 @@ struct Material {
sampler2D diffuse; sampler2D diffuse;
sampler2D specular; sampler2D specular;
float shininess; float shininess;
}; };
in vec3 FragPos; in vec3 FragPos;
in vec3 ViewFragPos; in vec3 ViewFragPos;

View File

@ -1895,6 +1895,8 @@ Renderer code cleanup
(05/19/2025) (05/19/2025)
Renderer code cleanup Renderer code cleanup
Shader uniform parsing from source code
Visual shader uniform location caching

View File

@ -287,7 +287,7 @@ public class Globals {
//initialize required windows //initialize required windows
WindowUtils.initBaseWindows(); WindowUtils.initBaseWindows();
//init default shaderProgram //init default shaderProgram
defaultMeshShader = VisualShader.smartAssembleShader(false,true); defaultMeshShader = VisualShader.smartAssembleShader();
//init terrain shader program //init terrain shader program
terrainShaderProgram = VisualShader.loadSpecificShader("/Shaders/entities/terrain2/terrain2.vs", "/Shaders/entities/terrain2/terrain2.fs"); terrainShaderProgram = VisualShader.loadSpecificShader("/Shaders/entities/terrain2/terrain2.vs", "/Shaders/entities/terrain2/terrain2.fs");
blockShader = VisualShader.loadSpecificShader("/Shaders/entities/block/block.vs", "/Shaders/entities/block/block.fs"); blockShader = VisualShader.loadSpecificShader("/Shaders/entities/block/block.vs", "/Shaders/entities/block/block.fs");

View File

@ -208,7 +208,7 @@ public class RenderUtils {
VisualShader shader = VisualShader.smartAssembleOITProgram(false, true); VisualShader shader = VisualShader.smartAssembleOITProgram();
particleMesh.setShader(shader); particleMesh.setShader(shader);
@ -391,7 +391,7 @@ public class RenderUtils {
Material mat = new Material(); Material mat = new Material();
mat.setDiffuse(AssetDataStrings.TEXTURE_TEAL_TRANSPARENT); mat.setDiffuse(AssetDataStrings.TEXTURE_TEAL_TRANSPARENT);
sphereMesh.setMaterial(mat); sphereMesh.setMaterial(mat);
sphereMesh.setShader(VisualShader.smartAssembleShader(false, true)); sphereMesh.setShader(VisualShader.smartAssembleShader());
GL40.glBindVertexArray(0); GL40.glBindVertexArray(0);
sphereMesh.setParent(model); sphereMesh.setParent(model);
model.getMeshes().add(sphereMesh); model.getMeshes().add(sphereMesh);
@ -446,7 +446,7 @@ public class RenderUtils {
Material mat = new Material(); Material mat = new Material();
mat.setDiffuse(AssetDataStrings.TEXTURE_TEAL_TRANSPARENT); mat.setDiffuse(AssetDataStrings.TEXTURE_TEAL_TRANSPARENT);
sphereMesh.setMaterial(mat); sphereMesh.setMaterial(mat);
sphereMesh.setShader(VisualShader.smartAssembleShader(false, true)); sphereMesh.setShader(VisualShader.smartAssembleShader());
GL40.glBindVertexArray(0); GL40.glBindVertexArray(0);
sphereMesh.setParent(model); sphereMesh.setParent(model);
model.getMeshes().add(sphereMesh); model.getMeshes().add(sphereMesh);
@ -533,7 +533,7 @@ public class RenderUtils {
Material mat = new Material(); Material mat = new Material();
mat.setDiffuse(AssetDataStrings.TEXTURE_TEAL_TRANSPARENT); mat.setDiffuse(AssetDataStrings.TEXTURE_TEAL_TRANSPARENT);
sphereMesh.setMaterial(mat); sphereMesh.setMaterial(mat);
sphereMesh.setShader(VisualShader.smartAssembleShader(false, true)); sphereMesh.setShader(VisualShader.smartAssembleShader());
GL40.glBindVertexArray(0); GL40.glBindVertexArray(0);
sphereMesh.setParent(model); sphereMesh.setParent(model);
model.getMeshes().add(sphereMesh); model.getMeshes().add(sphereMesh);

View File

@ -29,9 +29,6 @@ import electrosphere.renderer.shader.VisualShader;
public class MeshLoader { public class MeshLoader {
public static Mesh createMeshFromAIScene(AIMesh mesh, ModelPretransforms.MeshMetadata metadata){ public static Mesh createMeshFromAIScene(AIMesh mesh, ModelPretransforms.MeshMetadata metadata){
boolean has_bones = false;
boolean apply_lighting = true;
Mesh rVal = new Mesh(mesh.mName().dataString()); Mesh rVal = new Mesh(mesh.mName().dataString());
// //
@ -223,7 +220,6 @@ public class MeshLoader {
// //
PointerBuffer boneBuffer = mesh.mBones(); PointerBuffer boneBuffer = mesh.mBones();
if(boneBuffer != null){ if(boneBuffer != null){
has_bones = true;
while(boneBuffer.hasRemaining()){ while(boneBuffer.hasRemaining()){
long currentAddr = boneBuffer.get(); long currentAddr = boneBuffer.get();
AIBone currentBoneData = AIBone.createSafe(currentAddr); AIBone currentBoneData = AIBone.createSafe(currentAddr);
@ -335,9 +331,9 @@ public class MeshLoader {
if(!EngineState.EngineFlags.HEADLESS){ if(!EngineState.EngineFlags.HEADLESS){
rVal.setShader(VisualShader.smartAssembleShader(has_bones, apply_lighting)); rVal.setShader(VisualShader.smartAssembleShader());
rVal.setShader(VisualShader.smartAssembleShader(has_bones, apply_lighting)); rVal.setShader(VisualShader.smartAssembleShader());
rVal.setOITShader(VisualShader.smartAssembleOITProgram(has_bones, apply_lighting)); rVal.setOITShader(VisualShader.smartAssembleOITProgram());
} }

View File

@ -0,0 +1,106 @@
package electrosphere.renderer.shader;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A uniform in a shader program
*/
public class ShaderUniform {
/**
* Pattern for grabbing uniforms
*/
private static final Pattern uniformCapture = Pattern.compile("^\\s*uniform\\s+([a-zA-Z0-9]+)\\s+([a-zA-Z]+)\\s*;\\s*$", Pattern.MULTILINE);
/**
* Constant for an unknown location
*/
public static final int LOCATION_NOT_KNOWN = -1;
/**
* The name of the uniform
*/
private String name;
/**
* The type of the uniform
*/
private String type;
/**
* The location of this uniform
*/
private int location = ShaderUniform.LOCATION_NOT_KNOWN;
/**
* Creates a shader uniform
* @param name The name of the uniform
* @param type The type of the uniform
*/
public ShaderUniform(String name, String type){
this.name = name;
this.type = type;
}
/**
* Gets the name of the uniform
* @return The name
*/
public String getName() {
return name;
}
/**
* Gets the type of the uniform
* @return The type
*/
public String getType() {
return type;
}
/**
* Gets the location of the uniform
* @return The location
*/
public int getLocation() {
return location;
}
/**
* Sets the location of the uniform
* @param location The location
*/
public void setLocation(int location) {
this.location = location;
}
/**
* Parses the uniforms from a source file's content
* @param sourceContent The source file's content
* @return The list of uniforms
*/
public static List<ShaderUniform> parseUniforms(String sourceContent){
List<ShaderUniform> rVal = new LinkedList<ShaderUniform>();
Matcher matcher = uniformCapture.matcher(sourceContent);
while(matcher.find()){
String uniformType = matcher.group(1);
String uniformName = matcher.group(2);
if(uniformType.equals("Material")){
//special flow for materials
ShaderUniform newUniform;
newUniform = new ShaderUniform("material.diffuse", "sampler2D");
rVal.add(newUniform);
newUniform = new ShaderUniform("material.specular", "sampler2D");
rVal.add(newUniform);
} else {
ShaderUniform newUniform = new ShaderUniform(uniformName, uniformType);
rVal.add(newUniform);
}
}
return rVal;
}
}

View File

@ -29,24 +29,27 @@ public class VisualShader implements Shader {
/** /**
* The vertex shader location * The vertex shader location
*/ */
int vertexShader; private int vertexShader;
/** /**
* The fragment shader location * The fragment shader location
*/ */
int fragmentShader; private int fragmentShader;
/** /**
* The shader's ID * The shader's ID
*/ */
int shaderId; private int shaderId;
/**
* Map of uniform name -> data about the uniform
*/
private Map<String,ShaderUniform> uniformNameMap = new HashMap<String,ShaderUniform>();
/** /**
* The map of uniform location -> current value of uniform * The map of uniform location -> current value of uniform
*/ */
public Map<Integer,Object> uniformMap = new HashMap<Integer,Object>(); public Map<Integer,Object> uniformValueMap = new HashMap<Integer,Object>();
/** /**
* The map of path -> already compiled shader * The map of path -> already compiled shader
@ -95,84 +98,20 @@ public class VisualShader implements Shader {
/** /**
* Smart assembles a shader * Smart assembles a shader
* @param ContainsBones true if the mesh contains bones
* @param apply_lighting true if lighting should be applied
* @return The visual shader * @return The visual shader
*/ */
public static VisualShader smartAssembleShader(boolean ContainsBones, boolean apply_lighting){ public static VisualShader smartAssembleShader(){
//return shader if it has already been compiled //return shader if it has already been compiled
String shaderKey = ContainsBones + "-" + apply_lighting; String vertShaderPath = "/Shaders/VertexShader.vs";
if(alreadyCompiledMap.containsKey(shaderKey)){ String fragShaderPath = "/Shaders/FragmentShader.fs";
return alreadyCompiledMap.get(shaderKey); String key = VisualShader.getShaderKey(vertShaderPath, fragShaderPath);
if(alreadyCompiledMap.containsKey(key)){
return alreadyCompiledMap.get(key);
} }
String vertex_shader_path = ""; VisualShader rVal = VisualShader.loadSpecificShader(vertShaderPath, fragShaderPath);
if(ContainsBones){ alreadyCompiledMap.put(key,rVal);
vertex_shader_path = "/Shaders/VertexShader.vs";
} else {
vertex_shader_path = "/Shaders/VertexShaderNoBones.vs";
}
String fragment_shader_path = "/Shaders/FragmentShader.fs";
//
//Create ShaderProgram object
//
VisualShader rVal = new VisualShader();
//
//Read in shader programs
//
String vertexShaderSource = VisualShader.recursivelyPreprocessFile(vertex_shader_path);
String fragmentShaderSource = VisualShader.recursivelyPreprocessFile(fragment_shader_path);
//Creates a new shader object and assigns its 'pointer' to the integer "vertexShader"
rVal.vertexShader = GL40.glCreateShader(GL40.GL_VERTEX_SHADER);
//This alerts openGL to the presence of a vertex shader and points the shader at its source
GL40.glShaderSource(rVal.vertexShader, vertexShaderSource);
//Compiles the source for the vertex shader object
GL40.glCompileShader(rVal.vertexShader);
//The following tests if the vertex shader compiles successfully
int success;
success = GL40.glGetShaderi(rVal.vertexShader, GL40.GL_COMPILE_STATUS);
if (success != GL40.GL_TRUE) {
LoggerInterface.loggerRenderer.WARNING("Vertex Shader failed to compile!");
LoggerInterface.loggerRenderer.WARNING("Source is: ");
LoggerInterface.loggerRenderer.WARNING(GL40.glGetShaderSource(rVal.vertexShader));
LoggerInterface.loggerRenderer.ERROR("Runtime Exception", new RuntimeException(GL40.glGetShaderInfoLog(rVal.vertexShader)));
}
//Creates and opengl object for a fragment shader and assigns its 'pointer' to the integer fragmentShader
rVal.fragmentShader = GL40.glCreateShader(GL40.GL_FRAGMENT_SHADER);
//This points the opengl shadder object to its proper source
GL40.glShaderSource(rVal.fragmentShader, fragmentShaderSource);
//This compiles the shader object
GL40.glCompileShader(rVal.fragmentShader);
//This tests for the success of the compile attempt
success = GL40.glGetShaderi(rVal.fragmentShader, GL40.GL_COMPILE_STATUS);
if (success != GL40.GL_TRUE) {
LoggerInterface.loggerRenderer.WARNING("Fragment Shader failed to compile!");
LoggerInterface.loggerRenderer.WARNING("Source is: ");
LoggerInterface.loggerRenderer.WARNING(GL40.glGetShaderSource(rVal.fragmentShader));
LoggerInterface.loggerRenderer.ERROR("Runtime Exception", new RuntimeException(GL40.glGetShaderInfoLog(rVal.fragmentShader)));
}
//This creates a shader program opengl object and assigns its 'pointer' to the integer shaderProgram
rVal.shaderId = GL40.glCreateProgram();
//This attaches the vertex and fragment shaders to the program
GL40.glAttachShader(rVal.shaderId, rVal.vertexShader);
GL40.glAttachShader(rVal.shaderId, rVal.fragmentShader);
//This links the program to the GPU (I think its to the GPU anyway)
GL40.glLinkProgram(rVal.shaderId);
//Tests for the success of the shader program creation
success = GL40.glGetProgrami(rVal.shaderId, GL40.GL_LINK_STATUS);
if (success != GL40.GL_TRUE) {
throw new RuntimeException(GL40.glGetProgramInfoLog(rVal.shaderId));
}
//Deletes the individual shader objects to free up memory
GL40.glDeleteShader(rVal.vertexShader);
GL40.glDeleteShader(rVal.fragmentShader);
alreadyCompiledMap.put(shaderKey,rVal);
//check program status //check program status
if(!GL45.glIsProgram(rVal.shaderId)){ if(!GL45.glIsProgram(rVal.shaderId)){
@ -189,80 +128,19 @@ public class VisualShader implements Shader {
* @param apply_lighting True if should apply lighting * @param apply_lighting True if should apply lighting
* @return The int-pointer to the shader compiled * @return The int-pointer to the shader compiled
*/ */
public static VisualShader smartAssembleOITProgram(boolean ContainsBones, boolean apply_lighting){ public static VisualShader smartAssembleOITProgram(){
//return shader if it has already been compiled //return shader if it has already been compiled
String shaderKey = "oit" + ContainsBones + "-" + apply_lighting; String vertShaderPath = "/Shaders/core/oit/general/VertexShader.vs";
if(alreadyCompiledMap.containsKey(shaderKey)){ String fragShaderPath = "/Shaders/core/oit/general/FragmentShader.fs";
return alreadyCompiledMap.get(shaderKey); String key = "oit" + VisualShader.getShaderKey(vertShaderPath, fragShaderPath);
if(alreadyCompiledMap.containsKey(key)){
return alreadyCompiledMap.get(key);
} }
String vertex_shader_path = "";
if(ContainsBones){ VisualShader rVal = VisualShader.loadSpecificShader(vertShaderPath, fragShaderPath);
vertex_shader_path = "/Shaders/core/oit/general/VertexShader.vs"; alreadyCompiledMap.put(key,rVal);
} else {
vertex_shader_path = "/Shaders/core/oit/general/VertexShaderNoBones.vs";
}
String fragment_shader_path = "/Shaders/core/oit/general/FragmentShader.fs";
//
//Create ShaderProgram object
//
VisualShader rVal = new VisualShader();
//
//Read in shader programs
//
String vertexShaderSource = VisualShader.recursivelyPreprocessFile(vertex_shader_path);
String fragmentShaderSource = VisualShader.recursivelyPreprocessFile(fragment_shader_path);
//Creates a new shader object and assigns its 'pointer' to the integer "vertexShader"
rVal.vertexShader = GL40.glCreateShader(GL40.GL_VERTEX_SHADER);
//This alerts openGL to the presence of a vertex shader and points the shader at its source
GL40.glShaderSource(rVal.vertexShader, vertexShaderSource);
//Compiles the source for the vertex shader object
GL40.glCompileShader(rVal.vertexShader);
//The following tests if the vertex shader compiles successfully
int success;
success = GL40.glGetShaderi(rVal.vertexShader, GL40.GL_COMPILE_STATUS);
if (success != GL40.GL_TRUE) {
LoggerInterface.loggerRenderer.WARNING("Vertex Shader failed to compile!");
LoggerInterface.loggerRenderer.WARNING("Source is: ");
LoggerInterface.loggerRenderer.WARNING(GL40.glGetShaderSource(rVal.vertexShader));
LoggerInterface.loggerRenderer.ERROR("Runtime Exception", new RuntimeException(GL40.glGetShaderInfoLog(rVal.vertexShader)));
}
//Creates and opengl object for a fragment shader and assigns its 'pointer' to the integer fragmentShader
rVal.fragmentShader = GL40.glCreateShader(GL40.GL_FRAGMENT_SHADER);
//This points the opengl shadder object to its proper source
GL40.glShaderSource(rVal.fragmentShader, fragmentShaderSource);
//This compiles the shader object
GL40.glCompileShader(rVal.fragmentShader);
//This tests for the success of the compile attempt
success = GL40.glGetShaderi(rVal.fragmentShader, GL40.GL_COMPILE_STATUS);
if (success != GL40.GL_TRUE) {
LoggerInterface.loggerRenderer.WARNING("Fragment Shader failed to compile!");
LoggerInterface.loggerRenderer.WARNING("Source is: ");
LoggerInterface.loggerRenderer.WARNING(GL40.glGetShaderSource(rVal.fragmentShader));
LoggerInterface.loggerRenderer.ERROR("Runtime Exception", new RuntimeException(GL40.glGetShaderInfoLog(rVal.fragmentShader)));
}
//This creates a shader program opengl object and assigns its 'pointer' to the integer shaderProgram
rVal.shaderId = GL40.glCreateProgram();
//This attaches the vertex and fragment shaders to the program
GL40.glAttachShader(rVal.shaderId, rVal.vertexShader);
GL40.glAttachShader(rVal.shaderId, rVal.fragmentShader);
//This links the program to the GPU (I think its to the GPU anyway)
GL40. glLinkProgram(rVal.shaderId);
//Tests for the success of the shader program creation
success = GL40.glGetProgrami(rVal.shaderId, GL40.GL_LINK_STATUS);
if(success != GL40.GL_TRUE){
throw new Error(GL40.glGetProgramInfoLog(rVal.shaderId));
}
//Deletes the individual shader objects to free up memory
GL40.glDeleteShader(rVal.vertexShader);
GL40.glDeleteShader(rVal.fragmentShader);
alreadyCompiledMap.put(shaderKey,rVal);
//check program status //check program status
rVal.validate(); rVal.validate();
@ -425,6 +303,14 @@ public class VisualShader implements Shader {
GL40.glDeleteShader(rVal.vertexShader); GL40.glDeleteShader(rVal.vertexShader);
GL40.glDeleteShader(rVal.fragmentShader); GL40.glDeleteShader(rVal.fragmentShader);
Globals.renderingEngine.checkError(); Globals.renderingEngine.checkError();
//Parse all the uniformns from the source code
for(ShaderUniform uniform : ShaderUniform.parseUniforms(vertexShaderSource)){
rVal.uniformNameMap.put(uniform.getName(),uniform);
}
for(ShaderUniform uniform : ShaderUniform.parseUniforms(fragmentShaderSource)){
rVal.uniformNameMap.put(uniform.getName(),uniform);
}
//check program status //check program status
if(!GL45.glIsProgram(rVal.shaderId)){ if(!GL45.glIsProgram(rVal.shaderId)){
@ -444,10 +330,10 @@ public class VisualShader implements Shader {
// //
//Error checking //Error checking
if(uniformName == null || uniformName.equals("")){ if(uniformName == null || uniformName.equals("")){
throw new IllegalArgumentException("Trying to set invalid uniform name"); throw new Error("Trying to set invalid uniform name");
} }
if(this.getId() != openGLState.getActiveShader().getId()){ if(this.getId() != openGLState.getActiveShader().getId()){
throw new IllegalStateException("Trying to set uniform on shader that is not active"); throw new Error("Trying to set uniform on shader that is not active");
} }
// //
@ -464,7 +350,7 @@ public class VisualShader implements Shader {
if(uniformLocation == INVALID_UNIFORM_NAME){ if(uniformLocation == INVALID_UNIFORM_NAME){
LoggerInterface.loggerRenderer.DEBUG_LOOP("Searched for uniform in a shader that does not contain it. Uniform name: \"" + uniformName + "\""); LoggerInterface.loggerRenderer.DEBUG_LOOP("Searched for uniform in a shader that does not contain it. Uniform name: \"" + uniformName + "\"");
} else { } else {
ShaderUtils.setUniform(openGLState, this.uniformMap, uniformLocation, value); ShaderUtils.setUniform(openGLState, this.uniformValueMap, uniformLocation, value);
} }
} }
@ -474,6 +360,17 @@ public class VisualShader implements Shader {
* @return The location of the uniform * @return The location of the uniform
*/ */
public int getUniformLocation(String uniformName){ public int getUniformLocation(String uniformName){
if(this.uniformNameMap.containsKey(uniformName)){
ShaderUniform uniform = this.uniformNameMap.get(uniformName);
if(uniform.getLocation() == ShaderUniform.LOCATION_NOT_KNOWN){
int rVal = GL40.glGetUniformLocation(this.getId(), uniformName);
if(Globals.renderingEngine.checkError()){
LoggerInterface.loggerRenderer.WARNING("Uniform failed with shader id " + this.getId());
}
uniform.setLocation(rVal);
}
return uniform.getLocation();
}
int rVal = GL40.glGetUniformLocation(this.getId(), uniformName); int rVal = GL40.glGetUniformLocation(this.getId(), uniformName);
if(Globals.renderingEngine.checkError()){ if(Globals.renderingEngine.checkError()){
LoggerInterface.loggerRenderer.WARNING("Uniform failed with shader id " + this.getId()); LoggerInterface.loggerRenderer.WARNING("Uniform failed with shader id " + this.getId());
@ -481,6 +378,16 @@ public class VisualShader implements Shader {
return rVal; return rVal;
} }
/**
* Gets a shader key
* @param vertShader The vertex shader
* @param fragShader The fragment shader
* @return The key
*/
private static String getShaderKey(String vertShader, String fragShader){
return vertShader + "_" + fragShader;
}
@Override @Override
public int getId() { public int getId() {