【问题标题】:SGV Gradients Darker at StopsSGV 渐变在停止处变暗
【发布时间】:2020-04-16 20:33:21
【问题描述】:

我正在尝试制作一个带有阴影的行星的球形图像,以便在浏览器中渲染以用于模拟网页,但我一直在与一个我似乎无法弄清楚的奇怪视觉问题作斗争。

这是 SVG 的图像片段,它在 Chrome 中显示(在 IE 中也会发生)然后放大 3 倍:

您会注意到,就在日/夜终结符上方,有一条较暗的暗水平带,宽度约为其在终结符上方距离的 1/3。那应该在那里,我不知道它为什么在那里或如何摆脱它。

这是 HTML 片段中的 SVG 代码,便于查看:

<div style="position:absolute; z-index:1; margin:15px; 
            width:640px; height:640px; 
            background-color:black">

  <svg id="svgEa" style="width:100%; height:100%;" viewBox="-5000 -5000 10000 10000" preserveAspectRatio="xMidYMid meet" clip-path="url(#svgEaClip)" transform="scale(1.0,1.0)" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
                <!-- NOTE: All internal units are in KM (or %)  -->
    
                <defs id="defsEa">
                    <clipPath id="svgEaClip">
                        <rect width="100%" height="100%" />
                    </clipPath>
                    <linearGradient id="lgdEaSphere">
                        <stop style="stop-color:#ffffff;stop-opacity:1.00;" offset="0.00" id="stopEarthCenter" />
                        <stop style="stop-color:#dfffef;stop-opacity:1.00" offset="0.30" id="stopEarthInner" />
                        <stop style="stop-color:#91ffc8;stop-opacity:1.00" offset="0.31" id="stopEarthMid" />
                        <stop style="stop-color:#00A064;stop-opacity:1.00" offset="0.95264" id="stopEarthOuter" />
                        <stop style="stop-color:#44ffff;stop-opacity:0.66" offset="0.95264" id="stopAirInner" />
                        <stop style="stop-color:#44ffff;stop-opacity:0.10" offset="1.00" id="stopAirOuter"  />
                    </linearGradient>
                    <radialGradient id="rgdEaSphere"  xlink:href="#lgdEaSphere"
                        gradientUnits="userSpaceOnUse"
                        cx="0" cy="0"
                        fx="0" fy="0"
                        r="3339.05" 
                        />
    
                    <linearGradient id="lgdEaNightSide" 
                        x1="0%" y1="0%" x2="0%" y2="100%"
                        spreadMethod="pad" >
                        <stop style="stop-color:#000000;stop-opacity:0.7;" offset="0.00" id="stopEaMidnight" />
                        <!-- this stop seems to cause the artifact -->
                        <stop style="stop-color:#000000;stop-opacity:0.6;" offset="0.99" id="stopEaDusk" /> 
                        <stop style="stop-color:#000000;stop-opacity:0.5;" offset="1.00" id="stopEaTerminator" />
                    </linearGradient>
                </defs>
    
                <g id="gEaAll" transform="scale(1.2,1.2)" >
                    <g id="gEaSunFacing" >
                        <!-- contains everything that stays oriented with the Sun -->
                        <circle
                            id="cEarthAir"
                            cx="0" cy="0" r="3339.05"
                            style="display:inline;fill-opacity:1;fill:url(#rgdEaSphere)" />
                        <!--  overlay to give Earth a night side.  -->
                        <path id="pNight" 
                            style="stroke:none; fill:url(#lgdEaNightSide)"
                            d="M -3189.05,0 
                                A 3189.05,15945.25 0 1,1 3189.05,0
                                Z" 
                            />
                    </g>
                </g>
    
            </svg>

</div>

(如果您愿意,可以将其保存到 HTML (.html) 文件(添加 html 和 body 标签),然后在浏览器中运行以查看它。或者将其保存到 SVG 文件(.svg),并删除 div 和 br 标签,如果你想在上面使用任何 SVG 工具。

这个伪影发生在线性渐变停止点之一的位置,特别是第 33 行的#stopEaDusk,在线性渐变#lgdEaNightSide 中,它被用作覆盖路径#pNight 的填充。这个伪影可能看起来很微弱,但在不缩小 300% 时它是真实的并且更加明显。我实际的 SVG 也有一个免费的 #pDay 覆盖,我删除了它以简化代码。但是当它被添加时,我得到了三个这样的暗带伪影,一个在上面,一个在另一侧的相应位置(我有另一个黎明/黄昏停止),一个在两个叠加层相遇的中点.当它们三个都可见时,它看起来很可怕,所以我不能忽略它。

其他要点:

  • 据我所知,这不仅仅是here 建议的视觉错觉,因为即使被炸毁,它仍然存在。如果是,我仍然需要修复它。
  • 我不相信它是 old Chrome bug 中建议的 this answer,因为它看起来不同,但主要是因为我在 IE 中也看到它(尽管它可能更微弱)。

tl,dr:是什么导致了这个黑暗带,我该如何摆脱它?


这里的问题似乎有些混乱,所以请允许我澄清一下。线性渐变lgdEaNightSide 是为显式效果而编写的,它似乎正在这样做,但它产生了一种不希望的副作用,不是预期的,并且就我对 SVG 的理解而言,应该发生。

想要的效果是 pNight 叠加层添加: 1. 70% 的暗度,在其弧线的顶部(非常高且在屏幕外),平滑地着色到 60% 的暗度,向下 99%。 2. 然后从 60% 暗度 99% 下降到 50% 暗度 100% 下降。这是为了提供一个类似黄昏的过渡区域。

但是,除此之外,它还添加了不希望的效果: - 在下降约 98.8% 处,突然变暗 - 然后在下降到大约 99.2% 时,它又突然变轻了。

这不应该发生,据我所知,我编写的 SVG不应该这样做。

我正在寻找的是如何保持第一个(期望的)效果,同时摆脱第二个(不希望的)效果。

我不需要被告知是第二站导致了问题。我知道,我在上面说过,并在代码 cmets 中指出了这一点。我不需要答案来告诉我我已经知道的。我要找的是:

  1. 如何在保留我最初编写它的视觉效果的同时修复它,以及

  2. 为什么会发生,当 AFAIK 时,它应该发生。

【问题讨论】:

    标签: html svg graphics linear-gradients


    【解决方案1】:

    代码没有问题。

    存在条纹是因为显示器没有足够的颜色来表示细微的变化。您正在尝试在大面积上更改 10% 的不透明度,这对于大多数显示器来说是不可能的。

    您可以通过切换屏幕来确定这是显示器问题。根据显示器的质量和像素密度,您会看到略有不同的结果。一些浏览器使用抖动,它通过像素化的权衡来减少色带。

    解决这个问题的唯一方法是像 Prince 那样引入更多的颜色变化。

    另一个帖子的回答很好地解释了这个概念。值得一读,但我会引用解决方案来节省人们的点击次数。 https://stackoverflow.com/a/11274627/6794536

    如果您想让当前的 24 位颜色不那么明显 监控,您可以:

    • 更改您的设计,在您的设计中引入微妙的颜色变化 渐变(例如从深蓝色到灰绿色)。这导致不同的 RGB 通道位可以在不同时间转换,打破你的 带成更小的差异化颜色。

    • 更改设计以增加动态范围(例如,从纯 白色到纯黑色),以便您可以使用更多颜色条。

    • 更改设计以减少渐变的总距离 发生,减少带的宽度。

    …或以上的某种组合。

    我实施了这个策略,但并不完美。如果您真的想摆脱色带,您将不得不做出其他权衡。例如,您可能无法使用纯黑色。

    <div style="position:absolute; z-index:1; margin:15px; 
                width:640px; height:640px; 
                background-color:#0c0c26">
    
      <svg id="svgEa" style="width:100%; height:100%;" viewBox="-5000 -5000 10000 10000" preserveAspectRatio="xMidYMid meet" clip-path="url(#svgEaClip)" transform="scale(1.0,1.0)" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
                    <!-- NOTE: All internal units are in KM (or %)  -->
        
                    <defs id="defsEa">
                        <clipPath id="svgEaClip">
                            <rect width="100%" height="100%" />
                        </clipPath>
                        <linearGradient id="lgdEaSphere">
                            <stop style="stop-color:#ffffff;stop-opacity:1.00;" offset="0.00" id="stopEarthCenter" />
                            <stop style="stop-color:#dfffef;stop-opacity:1.00" offset="0.30" id="stopEarthInner" />
                            <stop style="stop-color:#91ffc8;stop-opacity:1.00" offset="0.31" id="stopEarthMid" />
                            <stop style="stop-color:#00A064;stop-opacity:1.00" offset="0.95264" id="stopEarthOuter" />
                            <stop style="stop-color:#44ffff;stop-opacity:0.66" offset="0.95264" id="stopAirInner" />
                            <stop style="stop-color:#44ffff;stop-opacity:0.10" offset="1.00" id="stopAirOuter"  />
                        </linearGradient>
                        <radialGradient id="rgdEaSphere"  xlink:href="#lgdEaSphere"
                            gradientUnits="userSpaceOnUse"
                            cx="0" cy="0"
                            fx="0" fy="0"
                            r="3339.05" 
                            />
        
                        <linearGradient id="lgdEaNightSide" x1="0%" y1="0%" x2="0%" y2="100%" spreadMethod="pad">
                            <stop style="stop-color:#00033e;stop-opacity:0.7;" offset="0.00" id="stopEaMidnight"></stop>
                            <!-- this stop seems to cause the artifact -->
                            <stop style="stop-color:#090d24;stop-opacity:0.6;" offset="0.99" id="stopEaDusk"></stop> 
                            <stop style="stop-color:#000;stop-opacity:0.5;" offset="1.00" id="stopEaTerminator"></stop>
                        </linearGradient>
                    </defs>
        
                    <g id="gEaAll" transform="scale(1.2,1.2)" >
                        <g id="gEaSunFacing" >
                            <!-- contains everything that stays oriented with the Sun -->
                            <circle
                                id="cEarthAir"
                                cx="0" cy="0" r="3339.05"
                                style="display:inline;fill-opacity:1;fill:url(#rgdEaSphere)" />
                            <!--  overlay to give Earth a night side.  -->
                            <path id="pNight" 
                                style="stroke:none; fill:url(#lgdEaNightSide)"
                                d="M -3189.05,0 
                                    A 3189.05,15945.25 0 1,1 3189.05,0
                                    Z" 
                                />
                        </g>
                    </g>
        
                </svg>
    
    </div>

    【讨论】:

    • 我已经在两个不同的显示器上试过了。但我想我理解你的意思,我会尝试你的解决方案,看看是否有帮助..
    • 好的,我已经尝试了您的更改,它们似乎确实有效。感谢您的帮助!
    【解决方案2】:

    这是因为您在叠加层的渐变中使用了额外的停止值。当您在叠加层中使用线性渐变(lgdEaNightSide)时,可以为地球提供如下所示的夜晚。

    您可以看到您使用了两个偏移值,一个是at 0.99,另一个是at 1。这就是你的水平带越来越暗的原因。

    <linearGradient id="lgdEaNightSide" x1="0%" y1="0%" x2="0%" y2="100%" spreadMethod="pad">
      <stop style="stop-color:#000000;stop-opacity:0.7;" offset="0.00" id="stopEaMidnight" />
      <!-- this stop seems to cause the artifact -->
      <stop style="stop-color:#000000;stop-opacity:0.6;" offset="0.99" id="stopEaDusk" />
      <stop style="stop-color:#000000;stop-opacity:0.5;" offset="1.00" id="stopEaTerminator" />
    </linearGradient>
    

    只需删除一个额外的停止值,它就会起作用,请在下面找到工作代码:

    <div style="position:absolute; z-index:1; margin:15px; 
        width:640px; height:640px; 
        background-color:black">
    
      <svg id="svgEa" style="width:100%; height:100%;" viewBox="-5000 -5000 10000 10000" preserveAspectRatio="xMidYMid meet" clip-path="url(#svgEaClip)" transform="scale(1.0,1.0)" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
          <!-- NOTE: All internal units are in KM (or %)  -->
    
          <defs id="defsEa">
            <clipPath id="svgEaClip">
              <rect width="100%" height="100%" />
            </clipPath>
            <linearGradient id="lgdEaSphere">
              <stop style="stop-color:#ffffff;stop-opacity:1.00;" offset="0.00"
                    id="stopEarthCenter" />
              <stop style="stop-color:#dfffef;stop-opacity:1.00" offset="0.30"
                    id="stopEarthInner" />
              <stop style="stop-color:#91ffc8;stop-opacity:1.00" offset="0.31"
                    id="stopEarthMid" />
              <stop style="stop-color:#00A064;stop-opacity:1.00" offset="0.95264"
                    id="stopEarthOuter" />
              <stop style="stop-color:#44ffff;stop-opacity:0.66" offset="0.95264"
                    id="stopAirInner" />
              <stop style="stop-color:#44ffff;stop-opacity:0.10" offset="1.00"
                    id="stopAirOuter" />
            </linearGradient>
            <radialGradient id="rgdEaSphere" xlink:href="#lgdEaSphere"
                            gradientUnits="userSpaceOnUse" cx="0" cy="0" fx="0"
                            fy="0" r="3339.05" />
    
            <linearGradient id="lgdEaNightSide" x1="0%" y1="0%" x2="0%" y2="100%"
                            spreadMethod="pad">
              <stop style="stop-color:#000000;stop-opacity:0.7;" offset="0.00"
                    id="stopEaMidnight" />
              <!-- this stop seems to cause the artifact -->
              <stop style="stop-color:#000000;stop-opacity:0.5;" offset="1.00"
                    id="stopEaTerminator" />
            </linearGradient>
          </defs>
    
          <g id="gEaAll" transform="scale(1.2,1.2)">
            <g id="gEaSunFacing">
              <!-- contains everything that stays oriented with the Sun -->
              <circle id="cEarthAir" cx="0" cy="0" r="3339.05"
                      style="display:inline;fill-opacity:1;fill:url(#rgdEaSphere)" />
              <!--  overlay to give Earth a night side.  -->
              <path id="pNight" style="stroke:none; fill:url(#lgdEaNightSide)" d="M -3189.05,0 
                            A 3189.05,15945.25 0 1,1 3189.05,0
                            Z" />
            </g>
          </g>
    
        </svg>
    
    </div>

    【讨论】:

    • 那个停止是因为它应该在那里,它正在从黑暗到​​明亮的更快的渐变。它需要在那里,据我了解,它应该导致这个暗带。该停止应该标记它开始更快变亮的位置。它不应该使任何东西变暗,它肯定会导致它变暗一会儿,然后恢复到较浅的阴影。
    • 如果您认为该站点有问题,请解释它是什么。但是那个停止是故意的,是为了达到我想要的效果。问题是它在某种程度上也导致了我不想要的效果(黑暗带),这似乎不符合我所理解的 SVG 标准、文档或功能。我对 SVG 的理解是这不应该发生。如果 SVG 或我的理解有问题,那很好,但需要解释一下,或者至少,如何修复它并仍然保持我想要的效果。
    • 我们知道 创建一个渐变,改变颜色。额外的 标签创建了另一个渐变(颜色变化,渐变)。这就是原因,额外的停止会产生额外的颜色变化。这绝对可以解决您的问题,让我考虑创建一个演示来展示给您。我无法理解的是为什么它是故意的,它在做什么?
    • 请解释为什么停止会产生这种效果。我知道停止是如何工作的,我知道停止应该做什么,不应该这样做。我希望最后 1% 的形状从 60% 的不透明度变为 50% 的不透明度。这就是那个停止应该做的事情。它的编写方式,它应该这样做。据我了解,在那个停止中没有什么会导致它在 98.8% 处突然变暗,然后在 99.2% 高度处突然变亮..
    • 停止会产生这种效果,因为偏移值彼此非常接近(0.99 到 1),因此不会产生渐变效果。如果将第二个 的偏移值更改为 9 之类的其他值,您可以看到差异。我还在这里创建了一个 jsfiddle,您可以通过操作偏移值来检查 - jsfiddle.net/szwnfxky/2
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-09
    • 1970-01-01
    • 1970-01-01
    • 2011-06-02
    • 1970-01-01
    • 2014-02-10
    • 1970-01-01
    相关资源
    最近更新 更多