WIP: getting a more or less correct ring texture coordinate!

This commit is contained in:
benpm
2025-07-09 15:01:21 -06:00
parent 92d42925b4
commit ca8bdf86a6
4 changed files with 96 additions and 57 deletions

View File

@@ -38,6 +38,7 @@ out vec3 ellipsoidNormalCameraSpace;
out vec3 levelWeights;
out vec3 positionCameraSpace;
out vec3 positionWorldSpace;
out vec3 posObjSpace;
#if USE_ACCURATE_NORMALS
out vec3 ellipsoidTangentThetaCameraSpace;
@@ -133,6 +134,7 @@ void main() {
ellipsoidNormalCameraSpace = mat3(modelViewTransform) * pair.normal;
positionCameraSpace = vec3(modelViewTransform * vec4(pair.position, 1.0));
positionWorldSpace = vec3(modelTransform * dvec4(pair.position, 1.0));
posObjSpace = pair.position;
#if SHADOW_MAPPING_ENABLED
shadowCoords = vec4(shadowMatrix * dvec4(pair.position, 1.0));

View File

@@ -38,6 +38,7 @@ out vec3 ellipsoidNormalCameraSpace;
out vec3 levelWeights;
out vec3 positionCameraSpace;
out vec3 positionWorldSpace;
out vec3 posObjSpace;
#if USE_ACCURATE_NORMALS
out vec3 ellipsoidTangentThetaCameraSpace;
@@ -117,6 +118,7 @@ void main() {
ellipsoidNormalCameraSpace = patchNormalCameraSpace;
positionCameraSpace = p;
positionWorldSpace = vec3(inverseViewTransform * dvec4(p, 1.0));
posObjSpace = vec3(inverseViewTransform * dvec4(p, 1.0));
#if SHADOW_MAPPING_ENABLED
shadowCoords = vec4(shadowMatrix * dvec4(p, 1.0));

View File

@@ -52,6 +52,10 @@ uniform vec2 vertexResolution;
#endif // SHOW_HEIGHT_RESOLUTION
uniform vec3 lightDirectionCameraSpace;
uniform vec3 lightDirectionObjSpace;
uniform vec3 lightDirectionWorldSpace;
uniform mat4 modelViewTransform;
uniform float ringSize;
#if PERFORM_SHADING
uniform float orenNayarRoughness;
@@ -70,10 +74,13 @@ uniform sampler1D ringTextureTransparency;
uniform vec2 textureOffset;
uniform vec3 sunPositionWorld; // NEW: world coordinates
uniform vec3 camPositionWorld; // NEW: world coordinates
#endif // USE_RING_SHADOWS
#endif // SHADOW_MAPPING_ENABLED
in vec3 posObjSpace; // Fragment position in object space
#if USE_ECLIPSE_SHADOWS
#define NSEclipseShadowsMinusOne #{nEclipseShadows}
@@ -277,49 +284,44 @@ Fragment getFragment() {
#if USE_RING_SHADOWS
// Calculate ring shadow by projecting ring texture directly onto surface
// Assume ring lies in the XZ plane (Y=0) in object space
vec3 surfaceToSun = -normalize(sunPositionWorld - positionWorldSpace); // Use world coordinates
vec3 surfaceToSun = normalize(lightDirectionObjSpace); // Use world coordinates
vec3 p = posObjSpace;
// Find intersection of light ray with ring plane (Y=0)
// Ray equation: P = positionWorldSpace + t * surfaceToSun
// For ring plane: P.y = 0, so t = -positionWorldSpace.y / surfaceToSun.y
if (abs(surfaceToSun.y) > 0.001) { // Avoid division by zero
float t = -positionWorldSpace.y / surfaceToSun.y;
if (abs(surfaceToSun.y) > 1e-8) { // Avoid division by zero
float t = -p.y / surfaceToSun.y;
if (t > 0.0) { // Ray intersects ring plane in front of surface
vec3 ringIntersection = positionWorldSpace + t * surfaceToSun;
vec3 ringIntersection = p + t * surfaceToSun;
// Calculate distance from ring center
float ringRadius = length(ringIntersection.xz);
// Calculate distance from ring center
float ringRadius = length(ringIntersection.xz);
// Convert radius to texture coordinate based on ring texture mapping
// Radius \in [textureOffset.x, textureOffset.y] maps to texCoord \in [0,1]
float texCoord = ((ringRadius / ringSize) - textureOffset.x) / (textureOffset.y - textureOffset.x);
if (texCoord >= 0.0 && texCoord <= 1.0) {
// Sample ring transparency texture
vec4 transparency = texture(ringTextureTransparency, texCoord);
// Determine which side of ring we're viewing from (matches ring shader logic)
float lerpFactor = dot(camPositionWorld, sunPositionWorld);
// Convert radius to texture coordinate based on ring texture mapping
// Radius \in [textureOffset.x, textureOffset.y] maps to texCoord \in [0,1]
float texCoord = (ringRadius - textureOffset.x) / (textureOffset.y - textureOffset.x);
// Sample appropriate ring texture based on viewing direction
vec4 ringColor = mix(texture(ringTextureFwrd, texCoord), texture(ringTextureBckwrd, texCoord), lerpFactor);
if (texCoord >= 0.0 && texCoord <= 1.0) {
// Sample ring transparency texture
vec4 transparency = texture(ringTextureTransparency, texCoord);
// Determine which side of ring we're viewing from (matches ring shader logic)
float lerpFactor = dot(camPositionWorld, sunPositionWorld);
// Sample appropriate ring texture based on viewing direction
vec4 ringColor = mix(texture(ringTextureFwrd, texCoord), texture(ringTextureBckwrd, texCoord), lerpFactor);
// Calculate shadow factor based on ring opacity
float ringOpacity = transparency.a;
shadow = 1.0 - ringOpacity;
shadow = clamp(shadow + 0.3, 0.0, 1.0); // Add ambient light similar to original
}
if (t < 1000.0) {
shadow = 0.0;
}
// Calculate shadow factor based on ring opacity
float ringOpacity = transparency.a;
shadow = 1.0 - ringOpacity;
shadow = clamp(shadow + 0.3, 0.0, 1.0); // Add ambient light similar to original
}
frag.color.rgb = vec3(0.0, ringRadius / ringSize, 0.0);
}
#endif // USE_RING_SHADOWS
if (shadow < 1.0) {
frag.color.rgb = vec3(0.0, 1.0, 0.0);
}
#endif
frag.color.a *= opacity;

View File

@@ -1232,8 +1232,8 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&,
_globalRenderer.program->setIgnoreUniformLocationError(IgnoreError::No);
}
const glm::mat4 modelViewTransform = glm::mat4(viewTransform * _cachedModelTransform);
const glm::mat4 modelViewProjectionTransform =
glm::mat4 modelViewTransform = glm::mat4(viewTransform * _cachedModelTransform);
glm::mat4 modelViewProjectionTransform =
data.camera.sgctInternal.projectionMatrix() * modelViewTransform;
// Upload the uniform variables
@@ -1257,9 +1257,9 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&,
}
using namespace layers;
const bool nightLayersActive =
bool nightLayersActive =
!_layerManager.layerGroup(Group::ID::NightLayers).activeLayers().empty();
const bool waterLayersActive =
bool waterLayersActive =
!_layerManager.layerGroup(Group::ID::WaterMasks).activeLayers().empty();
if (nightLayersActive || waterLayersActive || _performShading) {
@@ -1268,44 +1268,76 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&,
const glm::vec3 directionToSunCameraSpace = glm::vec3(viewTransform *
glm::dvec4(directionToSunWorldSpace, 0));
// @TODO (abock, 2020-04-14); This is just a bandaid for issue #1136. The better
// way is to figure out with the uniform is optimized away. I assume that it is
// because the shader doesn't get recompiled when the last layer of the night
// or water is disabled; so the shader thinks it has to do the calculation, but
// there are actually no layers left
const glm::vec3 directionToSunObjSpace = glm::vec3(_cachedInverseModelTransform *
glm::dvec4(directionToSunWorldSpace, 0));
using IgnoreError = ghoul::opengl::ProgramObject::IgnoreError;
_localRenderer.program->setIgnoreUniformLocationError(IgnoreError::Yes);
_localRenderer.program->setUniform(
_globalRenderer.program->setIgnoreUniformLocationError(IgnoreError::Yes);
_globalRenderer.program->setUniform(
"lightDirectionCameraSpace",
-glm::normalize(directionToSunCameraSpace)
);
_localRenderer.program->setIgnoreUniformLocationError(IgnoreError::Yes);
_globalRenderer.program->setUniform(
"lightDirectionObjSpace",
-glm::normalize(directionToSunObjSpace)
);
_globalRenderer.program->setIgnoreUniformLocationError(IgnoreError::Yes);
}
// Local shader
_localRenderer.program->setUniform(
"projectionTransform",
data.camera.sgctInternal.projectionMatrix()
modelViewTransform = glm::mat4(viewTransform * _cachedModelTransform);
modelViewProjectionTransform =
data.camera.sgctInternal.projectionMatrix() * modelViewTransform;
_globalRenderer.program->setUniform(
"lightDirectionWorldSpace",
glm::vec3(glm::normalize(directionToLightSource(data.modelTransform.translation, _lightSourceNode)))
);
// Upload the uniform variables
_localRenderer.program->setUniform(
"modelViewProjectionTransform",
modelViewProjectionTransform
);
_localRenderer.program->setUniform("modelViewTransform", modelViewTransform);
if (_useAccurateNormals && hasHeightLayer) {
// Apply an extra scaling to the height if the object is scaled
_localRenderer.program->setUniform(
"heightScale",
static_cast<float>(
glm::compMax(data.modelTransform.scale) * data.camera.scaling()
)
);
}
using namespace layers;
nightLayersActive =
!_layerManager.layerGroup(Group::ID::NightLayers).activeLayers().empty();
waterLayersActive =
!_layerManager.layerGroup(Group::ID::WaterMasks).activeLayers().empty();
if (nightLayersActive || waterLayersActive || _performShading) {
const glm::dvec3 directionToSunWorldSpace =
directionToLightSource(data.modelTransform.translation, _lightSourceNode);
const glm::vec3 directionToSunCameraSpace = glm::vec3(viewTransform *
glm::dvec4(directionToSunWorldSpace, 0));
// @TODO (abock, 2020-04-14); This is just a bandaid for issue #1136. The better
// way is to figure out with the uniform is optimized away. I assume that it is
// because the shader doesn't get recompiled when the last layer of the night
// or water is disabled; so the shader thinks it has to do the calculation, but
// there are actually no layers left
const glm::vec3 directionToSunObjSpace = glm::vec3(_cachedInverseModelTransform *
glm::dvec4(directionToSunWorldSpace, 0));
using IgnoreError = ghoul::opengl::ProgramObject::IgnoreError;
_globalRenderer.program->setIgnoreUniformLocationError(IgnoreError::Yes);
_globalRenderer.program->setUniform(
_localRenderer.program->setIgnoreUniformLocationError(IgnoreError::Yes);
_localRenderer.program->setUniform(
"lightDirectionCameraSpace",
-glm::normalize(directionToSunCameraSpace)
);
_globalRenderer.program->setIgnoreUniformLocationError(IgnoreError::Yes);
_localRenderer.program->setUniform(
"lightDirectionObjSpace",
-glm::normalize(directionToSunObjSpace)
);
_localRenderer.program->setIgnoreUniformLocationError(IgnoreError::Yes);
}
int globalCount = 0;
@@ -1517,6 +1549,7 @@ void RenderableGlobe::renderChunkGlobally(const Chunk& chunk, const RenderData&
program.setUniform("textureOffset", _ringsComponent->textureOffset());
program.setUniform("sunPositionObj", _ringsComponent->sunPositionObj());
program.setUniform("camPositionObj", _ringsComponent->camPositionObj());
program.setUniform("ringSize", (float)_ringsComponent->size());
}
}
else if (_shadowMappingProperties.shadowMapping && _shadowComponent) {
@@ -1696,8 +1729,8 @@ void RenderableGlobe::renderChunkLocally(const Chunk& chunk, const RenderData& d
}
program.setUniform("textureOffset", _ringsComponent->textureOffset());
program.setUniform("sunPositionObj", glm::vec3(0.0f));
program.setUniform("camPositionWorld", data.camera.positionVec3()); // pass camera world position
program.setUniform("sunPositionObj", _ringsComponent->sunPositionObj());
program.setUniform("camPositionObj", _ringsComponent->camPositionObj());
}
}
else if (_shadowMappingProperties.shadowMapping) {