Open Builderb0y opened 7 years ago
Updated preview B3 with a bugfix for "upPosition". The sun, moon and shadow light positions are updated when applying the celestial rotation. This happens after rendering the basic sky with "gbuffers_skybasic" and before rendering the sun/moon with "gbuffers_skytextured".
I'm assuming it's not possible to change that order such that celestial rotation is calculated before skybasic rendering?
It could be pre-calculated, but it will be more complex:
Are the sun, moon and shadow light positions really needed in gbuffers_skybasic?
I personally use skybasic for cloud rendering, which makes the issue very noticeable on low frame rates. Still, it's on my todo list to move that to composite instead, since there's no need to render clouds when you're not looking at them. Also, why does celestial rotation need to be un-rotated for skybasic rendering anyway?
If the celestial rotation is applied before basic sky rendering, then the basic sky will rotate together with the sun and moon.
I have now re-written most of my sky rendering code to run in composite (minus the clouds and auroras, which are still work in progress), and I'm now in the interesting position that the "top" half of the sky is rendered in skybasic, but the bottom half is rendered in composite. This is done so that stars/custom skyboxes will still render normally in the top half, but the bottom half gets overwritten by my infinite oceans. This works quite well, except during sunset, because the sun position is used to calculate sunset colors. As such, moving your head left or right quickly causes the 2 halves to "split up". So yes, I'd say that having an accurate sun position in the skybasic stage is still needed (if reasonable). If not reasonable, I'll see if I can figure out how to calculate it manually like I did for upPosition.
I've now gone ahead and calculated it manually. Partially to maintain compatibility with older versions of optifine, but mostly because I'm tired of waiting for this issue to be fixed. For anyone else who happens to need accurate sun/moon/up positions in the skybasic stage:
uniform int worldTime;
uniform mat4 gbufferModelView;
varying vec3 sunPosNorm;
varying vec3 upPosNorm;
const float sunRotation = radians(30.0); //sunPathRotation converted to radians. Must match the value set in the .fsh stage!
const vec2 sunData = vec2(cos(sunRotation), -sin(sunRotation)); //don't need an entire matrix to rotate the sun position since it's z position is always 0 before being rotated, and its x position doesn't actually change after being rotated.
void main() {
gl_Position = ftransform();
//minecraft's native calculateCelestialAngle() function, optimized and ported to GLSL.
float ang = fract(worldTime / 24000.0 - 0.25);
ang = (ang + (cos(ang * 3.14159265358979) * -0.5 + 0.5 - ang) / 3.0) * 6.28318530717959; //0-2pi, rolls over from 2pi to 0 at noon.
sunPosNorm = normalize((gbufferModelView * vec4(vec3(-sin(ang), cos(ang) * sunData) * 100.0, 1.0)).xyz); //sunData * cos(ang) is the result of simplifying the rotation matrix by removing values that don't actually matter.
upPosNorm = gbufferModelView[1].xyz;
}
Also, 2 things I noticed while figuring this out: 1: Setting sunPathRotation in the vertex stage doesn't seem to do anything, it must be set in the fragment stage in order to actually change the sun's rotation angle. 2: The sunAngle uniform seems to always be set to 0.0. Are either of these things intended?
The "sunPathRotation" is only checked in the fragment shader: reference The "sunAngle" value should be valid, it is calculated as:
celestialAngle = mc.world.getCelestialAngle(partialTicks);
sunAngle = (celestialAngle < 0.75f) ? celestialAngle + 0.25f : celestialAngle - 0.75f;
float angle = celestialAngle * (-360.0f);
float angleInterval = shadowAngleInterval > 0.0f ? (angle % shadowAngleInterval - (shadowAngleInterval * 0.5f)) : 0.0f;
if (sunAngle <= 0.5)
{
// day time
glRotatef(angle - angleInterval, 0.0f, 0.0f, 1.0f);
glRotatef(sunPathRotation, 1.0f, 0.0f, 0.0f); //rotate
shadowAngle = sunAngle;
}
else
{
// night time
glRotatef(angle + 180.0f - angleInterval, 0.0f, 0.0f, 1.0f);
glRotatef(sunPathRotation, 1.0f, 0.0f, 0.0f); //rotate
shadowAngle = sunAngle - 0.5f;
}
...
setProgramUniform1f("sunAngle", sunAngle);
The "sunPathRotation" is only checked in the fragment shader: reference
Right, I must have missed that being fragment-only. Set that value as soon as I discovered it and never bothered looking it up again after that. Still though, is there a specific reason it's only checked in the fragment stage?
The "sunAngle" value should be valid, it is calculated as:
Well, it's still broken for me. Tested in final, composite, terrain, entities, and skybasic.
gl_FragData[0] = vec4(sunAngle, fract(sunAngle), abs(sunAngle), 1.0);
All of them seem to return 0.0, regardless of the time.
Most options are checked only in the fragment shaders. The option parser is relatively simple. The "sunAngle" is only updated when a shadow map is defined, probably a bug.
Here's some simple code that demonstrates this bug: (for gbuffers_skybasic.fsh, .vsh file is not required). Set the max framerate to 5 to make the issue more noticeable.
Un-comment one of the demos, and you'll see that demo 1 will make the horizon line jump up and down relative to the terrain when quickly rotating the camera up or down. Demo 2 on the other hand keeps the horizon where it should be. It's a decent workaround for upPosition, since it's always at (0.0, 1.0, 0.0) before being rotated by the model view matrix. However, this is not true for sunPosition or moonPosition, which also use values from the previous frame.
Using version HD_U_D4 for MC1.10.2.