Add cloud rendering

This commit is contained in:
James Seibel
2024-07-07 18:02:43 -05:00
parent 197e6e8178
commit f4a8bfeb0a
9 changed files with 590 additions and 57 deletions
@@ -1,8 +1,10 @@
package com.seibel.distanthorizons.api.interfaces.render;
import com.seibel.distanthorizons.api.enums.config.EDhApiLodShading;
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
import java.util.List;
import java.util.function.Consumer;
@@ -27,6 +29,11 @@ public interface IDhApiRenderableBoxGroup extends List<DhApiRenderableBox>
/** @return if active this group will render. */
boolean isActive();
/** Sets whether this group should render with Screen Space Ambient Occlusioning. */
void setSsaoEnabled(boolean ssaoEnabled);
/** @return if active this group will render with Screen Space Ambient Occlusioning. */
boolean isSsaoEnabled();
/** Sets where this group will render in the level. */
void setOriginBlockPos(DhApiVec3f pos);
/** @return the block position in the level that all {@see DhApiRenderableBox} will render relative to. */
@@ -37,6 +44,7 @@ public interface IDhApiRenderableBoxGroup extends List<DhApiRenderableBox>
* This is a good place to change the origin or notify of any box changes.
*/
void setPreRenderFunc(Consumer<DhApiRenderParam> renderEventParam);
void setPostRenderFunc(Consumer<DhApiRenderParam> renderEventParam); // TODO name?
/**
* If a cube's color, position, or other property is changed this method
@@ -55,4 +63,7 @@ public interface IDhApiRenderableBoxGroup extends List<DhApiRenderableBox>
void setBlockLight(int blockLight);
int getBlockLight();
void setShading(DhApiRenderableBoxGroupShading shading);
DhApiRenderableBoxGroupShading getShading();
}
@@ -0,0 +1,93 @@
package com.seibel.distanthorizons.api.objects.render;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
import java.awt.*;
/**
* @see IDhApiRenderableBoxGroup
*
* Shading values are multiplied against the color for each direction,
* for example: <br>
* A shading value of 1.0 indicates the color is unchanged. <br>
* A shading value of 0.0 changes the color to black. <br>
*
* @author James Seibel
* @version 2024-7-7
* @since API 3.0.0
*/
public class DhApiRenderableBoxGroupShading
{
/** negative X */
public float north = 1.0f;
/** positive X */
public float south = 1.0f;
/** positive X */
public float east = 1.0f;
/** negative X */
public float west = 1.0f;
/** positive Y */
public float top = 1.0f;
/** negative Y */
public float bottom = 1.0f;
//==============//
// constructors //
//==============//
public static DhApiRenderableBoxGroupShading getDefaultShaded()
{
DhApiRenderableBoxGroupShading shading = new DhApiRenderableBoxGroupShading();
shading.setDefaultShaded();
return shading;
}
public static DhApiRenderableBoxGroupShading getUnshaded()
{
DhApiRenderableBoxGroupShading shading = new DhApiRenderableBoxGroupShading();
shading.setUnshaded();
return shading;
}
//=========//
// methods //
//=========//
/**
* Directions will have different brightness similar to Minecraft blocks. <br>
* This is a good default for un-lit objects.
*/
public void setDefaultShaded()
{
this.north = 0.8f;
this.south = 0.8f;
this.east = 0.6f;
this.west = 0.6f;
this.top = 1.0f;
this.bottom = 0.5f;
}
/**
* All directions render with the same brightness. <br>
* This is best used for glowing objects like beacons.
*/
public void setUnshaded()
{
this.north = 1.0f;
this.south = 1.0f;
this.east = 1.0f;
this.west = 1.0f;
this.top = 1.0f;
this.bottom = 1.0f;
}
}
@@ -23,6 +23,8 @@ import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiChunkModifiedEvent;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dataObjects.fullData.sources.FullDataSourceV2;
import com.seibel.distanthorizons.core.dataObjects.transformers.ChunkToLodBuilder;
import com.seibel.distanthorizons.core.file.fullDatafile.DelayedFullDataSourceSaveCache;
@@ -30,6 +32,7 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.pos.DhBlockPos;
import com.seibel.distanthorizons.core.pos.DhChunkPos;
import com.seibel.distanthorizons.core.pos.DhSectionPos;
import com.seibel.distanthorizons.core.render.renderer.generic.CloudRenderHandler;
import com.seibel.distanthorizons.core.render.renderer.generic.GenericObjectRenderer;
import com.seibel.distanthorizons.core.render.renderer.generic.GenericRenderObjectFactory;
import com.seibel.distanthorizons.core.sql.dto.BeaconBeamDTO;
@@ -72,6 +75,8 @@ public abstract class AbstractDhLevel implements IDhLevel
protected boolean beaconGroupBound = false;
protected CloudRenderHandler cloudRenderHandler;
//=============//
@@ -85,6 +90,8 @@ public abstract class AbstractDhLevel implements IDhLevel
this.beaconBoxGroup = GenericRenderObjectFactory.INSTANCE.createAbsolutePositionedGroup(new ArrayList<>(0));
this.beaconBoxGroup.setBlockLight(LodUtil.MAX_MC_LIGHT);
this.beaconBoxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT);
this.beaconBoxGroup.setShading(DhApiRenderableBoxGroupShading.getUnshaded());
this.beaconBoxGroup.setPreRenderFunc((renderEventParam) -> this.beaconBoxGroup.setActive(Config.Client.Advanced.Graphics.GenericRendering.enableBeaconRendering.get()));
}
protected void createAndSetSupportingRepos(File databaseFile)
@@ -221,12 +228,13 @@ public abstract class AbstractDhLevel implements IDhLevel
// should always be non-null, but just in case
if (this.beaconBeamRepo != null
&& genericObjectRenderer != null)
&& genericObjectRenderer != null)
{
if (!this.beaconGroupBound)
{
this.beaconGroupBound = true;
genericObjectRenderer.add(this.beaconBoxGroup);
this.cloudRenderHandler = new CloudRenderHandler(this, genericObjectRenderer);
}
@@ -319,6 +327,7 @@ public abstract class AbstractDhLevel implements IDhLevel
{
this.beaconGroupBound = true;
genericObjectRenderer.add(this.beaconBoxGroup);
this.cloudRenderHandler = new CloudRenderHandler(this, genericObjectRenderer);
}
@@ -303,9 +303,12 @@ public class LodRenderer
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeRenderPassEvent.class, renderEventParam);
this.bufferHandler.renderOpaque(this, renderEventParam);
// custom objects
profiler.popPush("Custom Objects");
this.genericObjectRenderer.render(renderEventParam, profiler);
// custom objects with SSAO
if (Config.Client.Advanced.Graphics.GenericRendering.enableRendering.get())
{
profiler.popPush("Custom Objects");
this.genericObjectRenderer.render(renderEventParam, profiler, true);
}
// SSAO
@@ -316,6 +319,14 @@ public class LodRenderer
}
// custom objects without SSAO
if (Config.Client.Advanced.Graphics.GenericRendering.enableRendering.get())
{
profiler.popPush("Custom Objects");
this.genericObjectRenderer.render(renderEventParam, profiler, false);
}
if (Config.Client.Advanced.Graphics.Fog.drawMode.get() != EDhApiFogDrawMode.FOG_DISABLED)
{
profiler.popPush("LOD Fog");
@@ -0,0 +1,301 @@
/*
* This file is part of the Distant Horizons mod
* licensed under the GNU LGPL v3 License.
*
* Copyright (C) 2020-2023 James Seibel
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.seibel.distanthorizons.core.render.renderer.generic;
import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
import com.seibel.distanthorizons.core.config.Config;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.level.IDhLevel;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
import org.apache.logging.log4j.Logger;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
public class CloudRenderHandler
{
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
private static final IMinecraftRenderWrapper MC_RENDER = SingletonInjector.INSTANCE.get(IMinecraftRenderWrapper.class);
private static final String CLOUD_RESOURCE_TEXTURE_PATH = "assets/distanthorizons/textures/clouds.png";
// FIXME transparency sorting makes having transparent clouds impossible
private static final Color CLOUD_COLOR = new Color(255,255,255,255);
private static final boolean DEBUG_BORDER_COLORS = false;
/**
* How wide an individual box is. <br>
* Measured in blocks.
*/
private static final int CLOUD_BOX_WIDTH = 128;
/** measured in blocks */
private static final int CLOUD_BOX_THICKNESS = 32;
private final IDhApiRenderableBoxGroup[][] boxGroupByOffset;
private final IDhLevel level;
private float moveSpeedInBlocksPerSecond = 3.0f;
//=============//
// constructor //
//=============//
public CloudRenderHandler(IDhLevel level, GenericObjectRenderer renderer)
{
this.level = level;
// default to a single empty slot in case the texture is broken
boolean[][] cloudLocations = new boolean[1][1];
try
{
cloudLocations = getCloudsFromTexture();
}
catch (FileNotFoundException e)
{
LOGGER.error(e.getMessage(), e);
}
catch (IOException e)
{
LOGGER.error("Unexpected issue getting cloud texture, error: ["+e.getMessage()+"].", e);
}
if (cloudLocations.length != 0 &&
cloudLocations.length != cloudLocations[0].length)
{
LOGGER.warn("Non-square cloud texture found, some parts of the texture will be clipped off.");
}
int textureWidth = cloudLocations.length;
ArrayList<DhApiRenderableBox> boxList = new ArrayList<>(512);
for (int x = 0; x < textureWidth; x ++)
{
for (int z = 0; z < textureWidth; z ++)
{
if (cloudLocations[x][z])
{
int minX = x * CLOUD_BOX_WIDTH;
int minZ = z * CLOUD_BOX_WIDTH;
int maxX = minX + CLOUD_BOX_WIDTH;
int maxZ = minZ + CLOUD_BOX_WIDTH;
Color color = CLOUD_COLOR;
if (DEBUG_BORDER_COLORS)
{
// equals is included so the board is 2 blocks wide, it makes it easier to see
if (x <= 1) { color = Color.RED; }
else if (x >= textureWidth-2) { color = Color.GREEN; }
if (z <= 1) { color = Color.BLUE; }
else if (z >= textureWidth-2) { color = Color.BLACK; }
}
DhApiRenderableBox box = new DhApiRenderableBox(
new DhApiVec3f(minX, 0, minZ),
new DhApiVec3f(maxX, CLOUD_BOX_THICKNESS, maxZ),
color
);
boxList.add(box);
}
}
}
// slightly lighter shading than the default
DhApiRenderableBoxGroupShading cloudShading = DhApiRenderableBoxGroupShading.getUnshaded();
cloudShading.north = cloudShading.south = 0.9f;
cloudShading.east = cloudShading.west = 0.8f;
cloudShading.top = 1.0f;
cloudShading.bottom = 0.7f;
this.boxGroupByOffset = new IDhApiRenderableBoxGroup[3][3];
for (int x = -1; x <= 1; x++)
{
for (int z = -1; z <= 1; z++)
{
IDhApiRenderableBoxGroup boxGroup = GenericRenderObjectFactory.INSTANCE.createRelativePositionedGroup(
new DhApiVec3f(0, 0, 0), // the offset will be set during rendering
boxList);
boxGroup.setBlockLight(LodUtil.MIN_MC_LIGHT);
boxGroup.setSkyLight(LodUtil.MAX_MC_LIGHT);
boxGroup.setSsaoEnabled(false);
boxGroup.setShading(cloudShading);
CloudParams offset = new CloudParams(textureWidth, x, z);
boxGroup.setPreRenderFunc((renderParam) -> this.preRender(offset));
renderer.add(boxGroup);
this.boxGroupByOffset[x+1][z+1] = boxGroup;
}
}
}
public void preRender(CloudParams clouds)
{
IDhApiRenderableBoxGroup boxGroup = this.boxGroupByOffset[clouds.instanceOffsetX+1][clouds.instanceOffsetZ+1];
boolean renderClouds = Config.Client.Advanced.Graphics.GenericRendering.enableCloudRendering.get();
boxGroup.setActive(renderClouds);
if(!renderClouds)
{
return;
}
//================//
// cloud movement //
//================//
long currentTime = System.currentTimeMillis();
float deltaTime = (currentTime - clouds.lastFrameTime) / 1000.0f; // Delta time in seconds
clouds.lastFrameTime = currentTime;
float deltaX = this.moveSpeedInBlocksPerSecond * deltaTime;
// negative delta is to match vanilla's cloud movement
clouds.xOffset -= deltaX;
// wrap the cloud around after reaching the edge
clouds.xOffset %= clouds.widthInBlocks;
//============================//
// camera movement and offset //
//============================//
// camera position
int cameraPosX = (int)MC_RENDER.getCameraExactPosition().x;
int cameraPosZ = (int)MC_RENDER.getCameraExactPosition().z;
// offset the camera position by negative 1 width when below zero to fix off-by-one errors in the negative direction
if (cameraPosX < 0) { cameraPosX -= clouds.widthInBlocks; }
if (cameraPosZ < 0) { cameraPosZ -= clouds.widthInBlocks; }
// determine how many cloud instances away from the origin we are
int cloudInstanceOffsetX = cameraPosX / (int)clouds.widthInBlocks;
int cloudInstanceOffsetZ = cameraPosZ / (int)clouds.widthInBlocks;
// calculate the new offset
float xOffset = (cloudInstanceOffsetX * clouds.widthInBlocks);
float zOffset = (cloudInstanceOffsetZ * clouds.widthInBlocks);
//==============//
// update group //
//==============//
boxGroup.setOriginBlockPos(
new DhApiVec3f(
clouds.xOffset + (clouds.instanceOffsetX * clouds.widthInBlocks) + xOffset + clouds.halfWidthInBlocks,
this.level.getLevelWrapper().getHeight() + 200,
clouds.zOffset + (clouds.instanceOffsetZ * clouds.widthInBlocks) + zOffset + clouds.halfWidthInBlocks
)
);
}
//==================//
// texture handling //
//==================//
public static boolean[][] getCloudsFromTexture() throws FileNotFoundException, IOException
{
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
boolean[][] whitePixels = null;
try(InputStream imageInputStream = loader.getResourceAsStream(CLOUD_RESOURCE_TEXTURE_PATH))
{
if (imageInputStream == null)
{
throw new FileNotFoundException("Unable to find cloud texture at resource path: ["+CLOUD_RESOURCE_TEXTURE_PATH+"].");
}
BufferedImage image = ImageIO.read(imageInputStream);
int width = image.getWidth();
int height = image.getHeight();
whitePixels = new boolean[width][height];
for (int x = 0; x < width; x ++)
{
for (int z = 0; z < width; z ++)
{
Color color = new Color(image.getRGB(x,z));
whitePixels[x][z] = color.equals(Color.WHITE);
}
}
}
return whitePixels;
}
//================//
// helper classes //
//================//
private static class CloudParams
{
public final float textureWidth;
public final float widthInBlocks;
public final float halfWidthInBlocks;
public final int instanceOffsetX;
public final int instanceOffsetZ;
public float xOffset = 0;
public float zOffset = 0;
public long lastFrameTime = System.currentTimeMillis();
// constructor //
public CloudParams(float textureWidth, int instanceOffsetX, int instanceOffsetZ)
{
this.textureWidth = textureWidth;
this.widthInBlocks = (this.textureWidth * CLOUD_BOX_WIDTH);
this.halfWidthInBlocks = this.widthInBlocks / 2;
this.instanceOffsetX = instanceOffsetX;
this.instanceOffsetZ = instanceOffsetZ;
}
}
}
@@ -26,6 +26,7 @@ import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegist
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
import com.seibel.distanthorizons.core.logging.ConfigBasedSpamLogger;
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
@@ -79,8 +80,8 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
private boolean init = false;
private ShaderProgram shader;
private GLVertexBuffer vertexBuffer;
private GLElementBuffer solidIndexBuffer;
private GLVertexBuffer boxVertexBuffer;
private GLElementBuffer boxIndexBuffer;
private AbstractVertexAttribute va;
private boolean useInstancedRendering;
@@ -100,6 +101,13 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
private int skyLightUniform;
private int blockLightUniform;
private int northShadingUniform;
private int southShadingUniform;
private int eastShadingUniform;
private int westShadingUniform;
private int topShadingUniform;
private int bottomShadingUniform;
private final ConcurrentHashMap<Long, RenderableBoxGroup> boxGroupById = new ConcurrentHashMap<>();
@@ -108,37 +116,62 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
/** A box from 0,0,0 to 1,1,1 */
private static final float[] BOX_VERTICES = {
// Pos x y z
// min X, vertical face
0, 0, 0,
1, 0, 0,
1, 1, 0,
0, 1, 0,
// max X, vertical face
0, 1, 1,
1, 1, 1,
1, 0, 1,
0, 0, 1,
// min Z, vertical face
0, 0, 1,
0, 0, 0,
0, 1, 0,
0, 1, 1,
// max Z, vertical face
1, 0, 1,
1, 1, 1,
0, 1, 1,
};
private static final int[] SOLID_BOX_INDICES = {
// min Z, vertical face
0, 3, 2,
2, 1, 0,
// max Z, vertical face
4, 5, 6,
6, 7, 4,
// min X, vertical face
7, 3, 0,
0, 4, 7,
// max X, vertical face
2, 6, 5,
5, 1, 2,
1, 1, 0,
1, 0, 0,
// min Y, horizontal face
1, 5, 4,
4, 0, 1,
0, 0, 1,
1, 0, 1,
1, 0, 0,
0, 0, 0,
// max Y, horizontal face
3, 7, 6,
6, 2, 3,
0, 1, 1,
1, 1, 1,
1, 1, 0,
0, 1, 0,
};
private static final int[] BOX_INDICES = {
// min X, vertical face
2, 1, 0,
0, 3, 2,
// max X, vertical face
6, 5, 4,
4, 7, 6,
// min Z, vertical face
10, 9, 8,
8, 11, 10,
// max Z, vertical face
14, 13, 12,
12, 15, 14,
// min Y, horizontal face
18, 17, 16,
16, 19, 18,
// max Y, horizontal face
20, 21, 22,
22, 23, 20,
};
@@ -187,6 +220,14 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
this.lightMapUniform = this.shader.getUniformLocation("uLightMap");
this.skyLightUniform = this.shader.getUniformLocation("uSkyLight");
this.blockLightUniform = this.shader.getUniformLocation("uBlockLight");
//this.shadingModeUniform = this.shader.getUniformLocation("uShadingMode");
this.northShadingUniform = this.shader.getUniformLocation("uNorthShading");
this.southShadingUniform = this.shader.getUniformLocation("uSouthShading");
this.eastShadingUniform = this.shader.getUniformLocation("uEastShading");
this.westShadingUniform = this.shader.getUniformLocation("uWestShading");
this.topShadingUniform = this.shader.getUniformLocation("uTopShading");
this.bottomShadingUniform = this.shader.getUniformLocation("uBottomShading");
this.createBuffers();
@@ -202,19 +243,19 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
boxVerticesBuffer.order(ByteOrder.nativeOrder());
boxVerticesBuffer.asFloatBuffer().put(BOX_VERTICES);
boxVerticesBuffer.rewind();
this.vertexBuffer = new GLVertexBuffer(false);
this.vertexBuffer.bind();
this.vertexBuffer.uploadBuffer(boxVerticesBuffer, 8, EDhApiGpuUploadMethod.DATA, BOX_VERTICES.length * Float.BYTES);
this.boxVertexBuffer = new GLVertexBuffer(false);
this.boxVertexBuffer.bind();
this.boxVertexBuffer.uploadBuffer(boxVerticesBuffer, 8, EDhApiGpuUploadMethod.DATA, BOX_VERTICES.length * Float.BYTES);
// box vertex indexes
ByteBuffer solidIndexBuffer = ByteBuffer.allocateDirect(SOLID_BOX_INDICES.length * Integer.BYTES);
ByteBuffer solidIndexBuffer = ByteBuffer.allocateDirect(BOX_INDICES.length * Integer.BYTES);
solidIndexBuffer.order(ByteOrder.nativeOrder());
solidIndexBuffer.asIntBuffer().put(SOLID_BOX_INDICES);
solidIndexBuffer.asIntBuffer().put(BOX_INDICES);
solidIndexBuffer.rewind();
this.solidIndexBuffer = new GLElementBuffer(false);
this.solidIndexBuffer.uploadBuffer(solidIndexBuffer, EDhApiGpuUploadMethod.DATA, SOLID_BOX_INDICES.length * Integer.BYTES, GL32.GL_STATIC_DRAW);
this.solidIndexBuffer.bind();
this.boxIndexBuffer = new GLElementBuffer(false);
this.boxIndexBuffer.uploadBuffer(solidIndexBuffer, EDhApiGpuUploadMethod.DATA, BOX_INDICES.length * Integer.BYTES, GL32.GL_STATIC_DRAW);
this.boxIndexBuffer.bind();
}
private void addGenericDebugObjects()
@@ -345,7 +386,12 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
// rendering //
//===========//
public void render(DhApiRenderParam renderEventParam, IProfilerWrapper profiler)
/**
* @param renderingWithSsao
* if true that means this render call is happening before the SSAO pass
* and any objects rendered in this pass will have SSAO applied to them.
*/
public void render(DhApiRenderParam renderEventParam, IProfilerWrapper profiler, boolean renderingWithSsao)
{
// render setup //
profiler.push("setup");
@@ -362,9 +408,9 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
this.shader.bind();
this.va.bind();
this.va.bindBufferToAllBindingPoints(this.vertexBuffer.getId());
this.va.bindBufferToAllBindingPoints(this.boxVertexBuffer.getId());
this.solidIndexBuffer.bind();
this.boxIndexBuffer.bind();
Mat4f projectionMvmMatrix = new Mat4f(renderEventParam.dhProjectionMatrix);
projectionMvmMatrix.multiply(renderEventParam.dhModelViewMatrix);
@@ -379,21 +425,27 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
Collection<RenderableBoxGroup> boxList = this.boxGroupById.values();
for (RenderableBoxGroup boxGroup : boxList)
{
// ignore inactive groups
if (boxGroup != null && boxGroup.active)
// skip boxes that shouldn't render this pass
if (boxGroup.ssaoEnabled == renderingWithSsao)
{
profiler.popPush("render prep");
boxGroup.preRender(renderEventParam);
if (this.useInstancedRendering)
// ignore inactive groups
if (boxGroup.active)
{
profiler.popPush("rendering");
this.renderBoxGroupInstanced(boxGroup, camPos, projectionMvmMatrix);
}
else
{
profiler.popPush("rendering");
this.renderBoxGroupDirect(boxGroup, projectionMvmMatrix, camPos);
if (this.useInstancedRendering)
{
profiler.popPush("rendering");
this.renderBoxGroupInstanced(boxGroup, camPos, projectionMvmMatrix);
}
else
{
profiler.popPush("rendering");
this.renderBoxGroupDirect(boxGroup, projectionMvmMatrix, camPos);
}
boxGroup.postRender(renderEventParam);
}
}
}
@@ -442,6 +494,18 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
this.shader.setUniform(this.skyLightUniform, boxGroup.skyLight);
this.shader.setUniform(this.blockLightUniform, boxGroup.blockLight);
DhApiRenderableBoxGroupShading shading = boxGroup.shading;
if (shading == null)
{
shading = DhApiRenderableBoxGroupShading.getUnshaded();
}
this.shader.setUniform(this.northShadingUniform, shading.north);
this.shader.setUniform(this.southShadingUniform, shading.south);
this.shader.setUniform(this.eastShadingUniform, shading.east);
this.shader.setUniform(this.westShadingUniform, shading.west);
this.shader.setUniform(this.topShadingUniform, shading.top);
this.shader.setUniform(this.bottomShadingUniform, shading.bottom);
@@ -466,7 +530,7 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
// Draw instanced
if (boxGroup.uploadedBoxCount > 0)
{
GL32.glDrawElementsInstanced(GL32.GL_TRIANGLES, SOLID_BOX_INDICES.length, GL32.GL_UNSIGNED_INT, 0, boxGroup.uploadedBoxCount);
GL32.glDrawElementsInstanced(GL32.GL_TRIANGLES, BOX_INDICES.length, GL32.GL_UNSIGNED_INT, 0, boxGroup.uploadedBoxCount);
}
@@ -512,7 +576,7 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
for (DhApiRenderableBox box : boxGroup)
{
renderBox(boxGroup, box, transformMatrix, camPos);
this.renderBox(boxGroup, box, transformMatrix, camPos);
}
}
private void renderBox(
@@ -543,7 +607,7 @@ public class GenericObjectRenderer implements IDhApiCustomRenderRegister
this.shader.setUniform(this.directShaderColorUniform, box.color);
GL32.glDrawElements(GL32.GL_TRIANGLES, SOLID_BOX_INDICES.length, GL32.GL_UNSIGNED_INT, 0);
GL32.glDrawElements(GL32.GL_TRIANGLES, BOX_INDICES.length, GL32.GL_UNSIGNED_INT, 0);
}
@@ -4,6 +4,7 @@ import com.seibel.distanthorizons.api.interfaces.render.IDhApiRenderableBoxGroup
import com.seibel.distanthorizons.api.methods.events.sharedParameterObjects.DhApiRenderParam;
import com.seibel.distanthorizons.api.objects.math.DhApiVec3f;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBox;
import com.seibel.distanthorizons.api.objects.render.DhApiRenderableBoxGroupShading;
import com.seibel.distanthorizons.core.render.glObject.GLProxy;
import com.seibel.distanthorizons.core.util.LodUtil;
import com.seibel.distanthorizons.core.util.math.Vec3f;
@@ -37,14 +38,18 @@ public class RenderableBoxGroup
private final Vec3f originBlockPos;
public boolean active = true;
public boolean ssaoEnabled = true;
private boolean vertexDataDirty = true;
public int skyLight = 15;
public int blockLight = 0;
public DhApiRenderableBoxGroupShading shading = DhApiRenderableBoxGroupShading.getDefaultShaded();
@Nullable
public Consumer<DhApiRenderParam> beforeRenderFunc;
private boolean vertexDataDirty = true;
public boolean active = true;
public Consumer<DhApiRenderParam> afterRenderFunc;
// instance data
public int instanceTranslationVbo = 0;
@@ -120,6 +125,9 @@ public class RenderableBoxGroup
@Override
public void setPreRenderFunc(Consumer<DhApiRenderParam> func) { this.beforeRenderFunc = func; }
@Override
public void setPostRenderFunc(Consumer<DhApiRenderParam> func) { this.afterRenderFunc = func; }
@Override
public void triggerBoxChange() { this.vertexDataDirty = true; }
@@ -128,6 +136,11 @@ public class RenderableBoxGroup
@Override
public boolean isActive() { return this.active; }
@Override
public void setSsaoEnabled(boolean ssaoEnabled) { this.ssaoEnabled = ssaoEnabled; }
@Override
public boolean isSsaoEnabled() { return this.ssaoEnabled; }
public void preRender(DhApiRenderParam renderEventParam)
{
if (this.beforeRenderFunc != null)
@@ -135,10 +148,24 @@ public class RenderableBoxGroup
this.beforeRenderFunc.accept(renderEventParam);
}
}
public void postRender(DhApiRenderParam renderEventParam)
{
if (this.afterRenderFunc != null)
{
this.afterRenderFunc.accept(renderEventParam);
}
}
@Override
public void setShading(DhApiRenderableBoxGroupShading shading) { this.shading = shading; }
@Override
public DhApiRenderableBoxGroupShading getShading() { return this.shading; }
// overrides //
//================//
// List Overrides //
//================//
@Override
public DhApiRenderableBox get(int index) { return this.boxList.get(index); }
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

@@ -11,6 +11,13 @@ uniform int uSkyLight;
uniform int uBlockLight;
uniform sampler2D uLightMap;
uniform float uNorthShading;
uniform float uSouthShading;
uniform float uEastShading;
uniform float uWestShading;
uniform float uTopShading;
uniform float uBottomShading;
in vec3 vPosition;
out vec4 fColor;
@@ -41,6 +48,16 @@ void main()
float blockLight = (float(uBlockLight)+0.5) / 16.0;
float skyLight = (float(uSkyLight)+0.5) / 16.0;
vec4 lightColor = vec4(texture(uLightMap, vec2(blockLight, skyLight)).xyz, 1.0);
fColor = lightColor * aColor;
}
// apply directional shading
if (gl_VertexID >= 0 && gl_VertexID < 4) { fColor.rgb *= uNorthShading; }
else if (gl_VertexID >= 4 && gl_VertexID < 8) { fColor.rgb *= uSouthShading; }
else if (gl_VertexID >= 8 && gl_VertexID < 12) { fColor.rgb *= uWestShading; }
else if (gl_VertexID >= 12 && gl_VertexID < 16) { fColor.rgb *= uEastShading; }
else if (gl_VertexID >= 16 && gl_VertexID < 20) { fColor.rgb *= uBottomShading; }
else if (gl_VertexID >= 20 && gl_VertexID < 24) { fColor.rgb *= uTopShading; }
}