8 moments

- Use 8 power moments
- Fix compile errors with trig moments
This commit is contained in:
Jozufozu 2025-02-17 20:12:17 -08:00
parent cb87961b19
commit 4eba43b2d6
8 changed files with 104 additions and 68 deletions

View file

@ -12,5 +12,6 @@ public class Samplers {
public static final GlTextureUnit LIGHT_SECTIONS = GlTextureUnit.T6;
public static final GlTextureUnit ZEROTH_MOMENT = GlTextureUnit.T7;
public static final GlTextureUnit MOMENTS = GlTextureUnit.T8;
public static final GlTextureUnit MOMENTS0 = GlTextureUnit.T8;
public static final GlTextureUnit MOMENTS1 = GlTextureUnit.T9;
}

View file

@ -10,6 +10,7 @@ import dev.engine_room.flywheel.backend.Samplers;
import dev.engine_room.flywheel.backend.compile.IndirectPrograms;
import dev.engine_room.flywheel.backend.gl.GlTextureUnit;
import net.minecraft.client.Minecraft;
import net.minecraft.util.Mth;
public class MboitFramebuffer {
@ -18,7 +19,8 @@ public class MboitFramebuffer {
private final int vao;
public int zerothMoment;
public int moments;
public int moments0;
public int moments1;
public int accumulate;
private int lastWidth = -1;
@ -44,10 +46,11 @@ public class MboitFramebuffer {
GL46.glNamedFramebufferTexture(fbo, GL46.GL_DEPTH_ATTACHMENT, mainRenderTarget.getDepthTextureId(), 0);
GL46.glNamedFramebufferDrawBuffers(fbo, new int[]{GL46.GL_COLOR_ATTACHMENT0, GL46.GL_COLOR_ATTACHMENT1});
GL46.glNamedFramebufferDrawBuffers(fbo, new int[]{GL46.GL_COLOR_ATTACHMENT0, GL46.GL_COLOR_ATTACHMENT1, GL46.GL_COLOR_ATTACHMENT2});
GL46.glClearNamedFramebufferfv(fbo, GL46.GL_COLOR, 0, new float[]{0, 0, 0, 0});
GL46.glClearNamedFramebufferfv(fbo, GL46.GL_COLOR, 1, new float[]{0, 0, 0, 0});
GL46.glClearNamedFramebufferfv(fbo, GL46.GL_COLOR, 2, new float[]{0, 0, 0, 0});
GlStateManager._glBindFramebuffer(GL46.GL_FRAMEBUFFER, fbo);
}
@ -62,10 +65,13 @@ public class MboitFramebuffer {
Samplers.ZEROTH_MOMENT.makeActive();
GlStateManager._bindTexture(zerothMoment);
Samplers.MOMENTS.makeActive();
GlStateManager._bindTexture(moments);
Samplers.MOMENTS0.makeActive();
GlStateManager._bindTexture(moments0);
GL46.glNamedFramebufferDrawBuffers(fbo, new int[]{GL46.GL_COLOR_ATTACHMENT2});
Samplers.MOMENTS1.makeActive();
GlStateManager._bindTexture(moments1);
GL46.glNamedFramebufferDrawBuffers(fbo, new int[]{GL46.GL_COLOR_ATTACHMENT3});
GL46.glClearNamedFramebufferfv(fbo, GL46.GL_COLOR, 0, new float[]{0, 0, 0, 0});
@ -100,13 +106,18 @@ public class MboitFramebuffer {
}
public void delete() {
GL46.glDeleteTextures(zerothMoment);
GL46.glDeleteTextures(moments);
GL46.glDeleteTextures(accumulate);
deleteTextures();
GL46.glDeleteFramebuffers(fbo);
GL46.glDeleteVertexArrays(vao);
}
private void deleteTextures() {
GL46.glDeleteTextures(zerothMoment);
GL46.glDeleteTextures(moments0);
GL46.glDeleteTextures(moments1);
GL46.glDeleteTextures(accumulate);
}
private void createTextures(int width, int height) {
if (lastWidth == width && lastHeight == height) {
return;
@ -115,16 +126,17 @@ public class MboitFramebuffer {
lastWidth = width;
lastHeight = height;
GL46.glDeleteTextures(zerothMoment);
GL46.glDeleteTextures(moments);
GL46.glDeleteTextures(accumulate);
deleteTextures();
zerothMoment = GL46.glCreateTextures(GL46.GL_TEXTURE_2D);
moments = GL46.glCreateTextures(GL46.GL_TEXTURE_2D);
moments0 = GL46.glCreateTextures(GL46.GL_TEXTURE_2D);
moments1 = GL46.glCreateTextures(GL46.GL_TEXTURE_2D);
accumulate = GL46.glCreateTextures(GL46.GL_TEXTURE_2D);
GL46.glTextureStorage2D(zerothMoment, 1, GL32.GL_R16F, width, height);
GL46.glTextureStorage2D(moments, 1, GL32.GL_RGBA16F, width, height);
GL46.glTextureStorage2D(moments0, 1, GL32.GL_RGBA16F, width, height);
GL46.glTextureStorage2D(moments1, 1, GL32.GL_RGBA16F, width, height);
GL46.glTextureStorage2D(accumulate, 1, GL32.GL_RGBA16F, width, height);
// for (int tex : new int[]{zerothMoment, moments, composite}) {
@ -136,7 +148,38 @@ public class MboitFramebuffer {
// }
GL46.glNamedFramebufferTexture(fbo, GL46.GL_COLOR_ATTACHMENT0, zerothMoment, 0);
GL46.glNamedFramebufferTexture(fbo, GL46.GL_COLOR_ATTACHMENT1, moments, 0);
GL46.glNamedFramebufferTexture(fbo, GL46.GL_COLOR_ATTACHMENT2, accumulate, 0);
GL46.glNamedFramebufferTexture(fbo, GL46.GL_COLOR_ATTACHMENT1, moments0, 0);
GL46.glNamedFramebufferTexture(fbo, GL46.GL_COLOR_ATTACHMENT2, moments1, 0);
GL46.glNamedFramebufferTexture(fbo, GL46.GL_COLOR_ATTACHMENT3, accumulate, 0);
}
float circleToParameter(float angle) {
float x = Mth.cos(angle);
float y = Mth.sin(angle);
float result = Mth.abs(y) - Mth.abs(x);
result = (x < 0.0f) ? (2.0f - result) : result;
result = (y < 0.0f) ? (6.0f - result) : result;
result += (angle >= 2.0f * Mth.PI) ? 8.0f : 0.0f;
return result;
}
void computeWrappingZoneParameters(float[] out) {
computeWrappingZoneParameters(out, 0.1f * Mth.PI);
}
/*! Given an angle in radians providing the size of the wrapping zone, this
function computes all constants required by the shader.*/
void computeWrappingZoneParameters(float[] p_out_wrapping_zone_parameters, float new_wrapping_zone_angle) {
p_out_wrapping_zone_parameters[0] = new_wrapping_zone_angle;
p_out_wrapping_zone_parameters[1] = Mth.PI - 0.5f * new_wrapping_zone_angle;
if (new_wrapping_zone_angle <= 0.0f) {
p_out_wrapping_zone_parameters[2] = 0.0f;
p_out_wrapping_zone_parameters[3] = 0.0f;
} else {
float zone_end_parameter = 7;
float zone_begin_parameter = circleToParameter(2.0f * Mth.PI - new_wrapping_zone_angle);
p_out_wrapping_zone_parameters[2] = 1.0f / (zone_end_parameter - zone_begin_parameter);
p_out_wrapping_zone_parameters[3] = 1.0f - zone_end_parameter * p_out_wrapping_zone_parameters[2];
}
}
}

View file

@ -21,7 +21,8 @@ flat in uvec2 _flw_ids;
#ifdef _FLW_OIT
#ifdef _FLW_GENERATE_MOMENTS
layout (location = 0) out float _flw_zerothMoment_out;
layout (location = 1) out vec4 _flw_moments_out;
layout (location = 1) out vec4 _flw_moments0_out;
layout (location = 2) out vec4 _flw_moments1_out;
#endif
#ifdef _FLW_RESOLVE_MOMENTS
layout (location = 0) out vec4 _flw_accumulate_out;
@ -133,7 +134,7 @@ void _flw_main() {
#ifdef _FLW_GENERATE_MOMENTS
generateMoments(depth, 1 - color.a, vec4(0), _flw_zerothMoment_out, _flw_moments_out);
generateMoments(depth, 1 - color.a, _flw_zerothMoment_out, _flw_moments0_out, _flw_moments1_out);
#endif
#ifdef _FLW_RESOLVE_MOMENTS

View file

@ -2,6 +2,16 @@
This header defines utility functions to deal with complex numbers and
complex polynomials.*/
void sincos(float theta, out float s, out float c) {
s = sin(theta);
c = cos(theta);
}
float saturate(float a) {
return clamp(a, 0., 1.);
}
/*! Returns the complex conjugate of the given complex number (i.e. it changes
the sign of the y-component).*/
vec2 Conjugate(vec2 Z){
@ -45,11 +55,11 @@ vec2 Cube(vec2 Z){
\sa SquareRoot() */
vec2 SquareRootUnsafe(vec2 Z){
float ZLengthSq=dot(Z, Z);
float ZLengthInv=rsqrt(ZLengthSq);
float ZLengthInv=inversesqrt(ZLengthSq);
vec2 UnnormalizedRoot=Z*ZLengthInv+vec2(1.0f, 0.0f);
float UnnormalizedRootLengthSq=dot(UnnormalizedRoot, UnnormalizedRoot);
float NormalizationFactorInvSq=UnnormalizedRootLengthSq*ZLengthInv;
float NormalizationFactor=rsqrt(NormalizationFactorInvSq);
float NormalizationFactor=inversesqrt(NormalizationFactorInvSq);
return NormalizationFactor*UnnormalizedRoot;
}
/*! This utility function computes one square root of the given complex value.
@ -65,7 +75,7 @@ vec2 SquareRoot(vec2 Z){
other roots can be found by multiplication by cubic roots of unity.
\note This function has various discontinuities.*/
vec2 CubicRoot(vec2 Z){
float Argument=atan2(Z.y, Z.x);
float Argument=atan(Z.y, Z.x);
float NewArgument=Argument/3.0f;
vec2 NormalizedRoot;
sincos(NewArgument, NormalizedRoot.y, NormalizedRoot.x);

View file

@ -5,17 +5,7 @@
roots of polynomials up to degree four are defined.
*/
//#include "flywheel:internal/mboit/trigonometric_moment_math.glsl"
void sincos(float theta, out float s, out float c) {
s = sin(theta);
c = cos(theta);
}
float saturate(float a) {
return clamp(a, 0., 1.);
}
#include "flywheel:internal/mboit/trigonometric_moment_math.glsl"
/*! Given coefficients of a quadratic polynomial A*x^2+B*x+C, this function

View file

@ -17,7 +17,7 @@
const float moment_bias = 0.25;
const float overestimation = 0.25;
const vec4 wrapping_zone_parameters = vec4(0.);
const vec4 wrapping_zone_parameters = vec4(0.31415927, 2.984513, 2.7934167, -18.553917);
void clip(float a) {
@ -28,7 +28,7 @@ void clip(float a) {
// jozu: The trigonometric moments and higher order power moments rely on a second render target
// which the java side is not set up to support. Trying to enable them as is will cause compile errors also.
#define NUM_MOMENTS 4
#define NUM_MOMENTS 8
#define SINGLE_PRECISION 1
@ -40,15 +40,15 @@ void clip(float a) {
vector of moments.moment vector. The shader that calls this function must
provide the required render targets.*/
#if NUM_MOMENTS == 4
void generateMoments(float depth, float transmittance, vec4 wrapping_zone_parameters, out float b_0, out vec4 b)
void generateMoments(float depth, float transmittance, out float b_0, out vec4 b)
#elif NUM_MOMENTS == 6
#if USE_R_RG_RBBA_FOR_MBOIT6
void generateMoments(float depth, float transmittance, vec4 wrapping_zone_parameters, out float b_0, out vec2 b_12, out vec4 b_3456)
void generateMoments(float depth, float transmittance, out float b_0, out vec2 b_12, out vec4 b_3456)
#else
void generateMoments(float depth, float transmittance, vec4 wrapping_zone_parameters, out float b_0, out vec2 b_12, out vec2 b_34, out vec2 b_56)
void generateMoments(float depth, float transmittance, out float b_0, out vec2 b_12, out vec2 b_34, out vec2 b_56)
#endif
#elif NUM_MOMENTS == 8
void generateMoments(float depth, float transmittance, vec4 wrapping_zone_parameters, out float b_0, out vec4 b_even, out vec4 b_odd)
void generateMoments(float depth, float transmittance, out float b_0, out vec4 b_even, out vec4 b_odd)
#endif
{
transmittance = max(transmittance, 0.000001);
@ -57,7 +57,7 @@ void generateMoments(float depth, float transmittance, vec4 wrapping_zone_parame
b_0 = absorbance;
#if TRIGONOMETRIC
float phase = fma(depth, wrapping_zone_parameters.y, wrapping_zone_parameters.y);
vec2 circle_point = vec2(sin(phas), cos(phase));
vec2 circle_point = vec2(sin(phase), cos(phase));
vec2 circle_point_pow2 = Multiply(circle_point, circle_point);
#if NUM_MOMENTS == 4
@ -98,10 +98,8 @@ void generateMoments(float depth, float transmittance, vec4 wrapping_zone_parame
#else//MOMENT_GENERATION is disabled
layout (binding = 7) uniform sampler2D _flw_zeroth_moment_sampler;
layout (binding = 8) uniform sampler2D _flw_moments_sampler;
#if USE_R_RG_RBBA_FOR_MBOIT6
uniform sampler2D extra_moments;
#endif
layout (binding = 8) uniform sampler2D _flw_moments0_sampler;
layout (binding = 9) uniform sampler2D _flw_moments1_sampler;
/*! This function is to be called from the shader that composites the
transparent fragments. It reads the moments and calls the appropriate
@ -120,7 +118,7 @@ void resolveMoments(out float transmittance_at_depth, out float total_transmitta
#if NUM_MOMENTS == 4
#if TRIGONOMETRIC
vec4 b_tmp = texelFetch(_flw_moments_sampler, idx0, 0);
vec4 b_tmp = texelFetch(_flw_moments0_sampler, idx0, 0);
vec2 trig_b[2];
trig_b[0] = b_tmp.xy;
trig_b[1] = b_tmp.zw;
@ -133,7 +131,7 @@ void resolveMoments(out float transmittance_at_depth, out float total_transmitta
#endif
transmittance_at_depth = computeTransmittanceAtDepthFrom2TrigonometricMoments(b_0, trig_b, depth, moment_bias, overestimation, wrapping_zone_parameters);
#else
vec4 b_1234 = texelFetch(_flw_moments_sampler, idx0, 0).xyzw;
vec4 b_1234 = texelFetch(_flw_moments0_sampler, idx0, 0).xyzw;
#if SINGLE_PRECISION
vec2 b_even = b_1234.yw;
vec2 b_odd = b_1234.xz;
@ -158,14 +156,14 @@ void resolveMoments(out float transmittance_at_depth, out float total_transmitta
ivec2 idx2 = idx0;
#if TRIGONOMETRIC
vec2 trig_b[3];
trig_b[0] = texelFetch(_flw_moments_sampler, idx0, 0).xy;
trig_b[0] = texelFetch(_flw_moments0_sampler, idx0, 0).xy;
#if USE_R_RG_RBBA_FOR_MBOIT6
vec4 tmp = texelFetch(extra_moments, idx0, 0);
trig_b[1] = tmp.xy;
trig_b[2] = tmp.zw;
#else
trig_b[1] = texelFetch(_flw_moments_sampler, idx1, 0).xy;
trig_b[2] = texelFetch(_flw_moments_sampler, idx2, 0).xy;
trig_b[1] = texelFetch(_flw_moments1_sampler, idx1, 0).xy;
trig_b[2] = texelFetch(_flw_moments0_sampler, idx2, 0).xy;
#endif
#if SINGLE_PRECISION
trig_b[0] /= b_0;
@ -178,14 +176,14 @@ void resolveMoments(out float transmittance_at_depth, out float total_transmitta
#endif
transmittance_at_depth = computeTransmittanceAtDepthFrom3TrigonometricMoments(b_0, trig_b, depth, moment_bias, overestimation, wrapping_zone_parameters);
#else
vec2 b_12 = texelFetch(_flw_moments_sampler, idx0, 0).xy;
vec2 b_12 = texelFetch(_flw_moments0_sampler, idx0, 0).xy;
#if USE_R_RG_RBBA_FOR_MBOIT6
vec4 tmp = texelFetch(extra_moments, idx0, 0);
vec2 b_34 = tmp.xy;
vec2 b_56 = tmp.zw;
#else
vec2 b_34 = texelFetch(_flw_moments_sampler, idx1, 0).xy;
vec2 b_56 = texelFetch(_flw_moments_sampler, idx2, 0).xy;
vec2 b_34 = texelFetch(_flw_moments1_sampler, idx1, 0).xy;
vec2 b_56 = texelFetch(_flw_moments0_sampler, idx2, 0).xy;
#endif
#if SINGLE_PRECISION
vec3 b_even = vec3(b_12.y, b_34.y, b_56.y);
@ -209,8 +207,8 @@ void resolveMoments(out float transmittance_at_depth, out float total_transmitta
#endif
#elif NUM_MOMENTS == 8
#if TRIGONOMETRIC
vec4 b_tmp = texelFetch(_flw_moments_sampler, idx0, 0);
vec4 b_tmp2 = texelFetch(_flw_moments_sampler, idx1, 0);
vec4 b_tmp = texelFetch(_flw_moments0_sampler, idx0, 0);
vec4 b_tmp2 = texelFetch(_flw_moments1_sampler, idx1, 0);
#if SINGLE_PRECISION
vec2 trig_b[4] = {
b_tmp2.xy / b_0,
@ -229,15 +227,15 @@ void resolveMoments(out float transmittance_at_depth, out float total_transmitta
transmittance_at_depth = computeTransmittanceAtDepthFrom4TrigonometricMoments(b_0, trig_b, depth, moment_bias, overestimation, wrapping_zone_parameters);
#else
#if SINGLE_PRECISION
vec4 b_even = texelFetch(_flw_moments_sampler, idx0, 0);
vec4 b_odd = texelFetch(_flw_moments_sampler, idx1, 0);
vec4 b_even = texelFetch(_flw_moments0_sampler, idx0, 0);
vec4 b_odd = texelFetch(_flw_moments1_sampler, idx1, 0);
b_even /= b_0;
b_odd /= b_0;
const float bias_vector[8] = { 0, 0.75, 0, 0.67666666666666664, 0, 0.63, 0, 0.60030303030303034 };
#else
vec4 b_even_q = texelFetch(_flw_moments_sampler, idx0, 0);
vec4 b_odd_q = texelFetch(_flw_moments_sampler, idx1, 0);
vec4 b_even_q = texelFetch(_flw_moments0_sampler, idx0, 0);
vec4 b_odd_q = texelFetch(_flw_moments1_sampler, idx1, 0);
// Dequantize the moments
vec4 b_even;

View file

@ -21,7 +21,7 @@ float circleToParameter(vec2 circle_point){
returns 1.0, otherwise 0.0 or a linear ramp in the wrapping zone.*/
float getRootWeightFactor(float reference_parameter, float root_parameter, vec4 wrapping_zone_parameters){
float binary_weight_factor=(root_parameter<reference_parameter)?1.0f:0.0f;
float linear_weight_factor=saturate(mad(root_parameter, wrapping_zone_parameters.z, wrapping_zone_parameters.w));
float linear_weight_factor=saturate(fma(root_parameter, wrapping_zone_parameters.z, wrapping_zone_parameters.w));
return binary_weight_factor+linear_weight_factor;
}
@ -47,7 +47,7 @@ float computeTransmittanceAtDepthFrom2TrigonometricMoments(float b_0, vec2 trig_
float D22=RealPart(b[0]-D00*Multiply(L20, Conjugate(L20))-D11*Multiply(L21, Conjugate(L21)));
float InvD22=1.0f/D22;
// Solve a linear system to get the relevant polynomial
float phase = mad(depth, wrapping_zone_parameters.y, wrapping_zone_parameters.y);
float phase = fma(depth, wrapping_zone_parameters.y, wrapping_zone_parameters.y);
vec2 circle_point;
sincos(phase, circle_point.y, circle_point.x);
vec2 c[3] = {
@ -125,7 +125,7 @@ float computeTransmittanceAtDepthFrom3TrigonometricMoments(float b_0, vec2 trig_
float D33=RealPart(b[0]-D00*Multiply(L30, Conjugate(L30))-D11*Multiply(L31, Conjugate(L31))-D22*Multiply(L32, Conjugate(L32)));
float InvD33=1.0f/D33;
// Solve a linear system to get the relevant polynomial
float phase = mad(depth, wrapping_zone_parameters.y, wrapping_zone_parameters.y);
float phase = fma(depth, wrapping_zone_parameters.y, wrapping_zone_parameters.y);
vec2 circle_point;
sincos(phase, circle_point.y, circle_point.x);
vec2 circle_point_pow2 = Multiply(circle_point, circle_point);
@ -230,7 +230,7 @@ float computeTransmittanceAtDepthFrom4TrigonometricMoments(float b_0, vec2 trig_
float D44=RealPart(b[0]-D00*Multiply(L40, Conjugate(L40))-D11*Multiply(L41, Conjugate(L41))-D22*Multiply(L42, Conjugate(L42))-D33*Multiply(L43, Conjugate(L43)));
float InvD44=1.0/D44;
// Solve a linear system to get the relevant polynomial
float phase = mad(depth, wrapping_zone_parameters.y, wrapping_zone_parameters.y);
float phase = fma(depth, wrapping_zone_parameters.y, wrapping_zone_parameters.y);
vec2 circle_point;
sincos(phase, circle_point.y, circle_point.x);
vec2 circle_point_pow2 = Multiply(circle_point, circle_point);

View file

@ -52,13 +52,6 @@ public class ShulkerBoxVisual extends AbstractBlockEntityVisual<ShulkerBoxBlockE
instances = InstanceTree.create(instancerProvider(), ModelTrees.of(ModelLayers.SHULKER, PATHS_TO_PRUNE, texture, MATERIAL));
lid = instances.childOrThrow("lid");
lid.instance()
.color(255, 255, 255, 255);
instances.childOrThrow("base")
.instance()
.color(255, 255, 255, 255);
initialPose = createInitialPose();
applyTransform(partialTick);
}