<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts | Ziqi Lu</title><link>https://assassin-plus.github.io/portfolio/post/</link><atom:link href="https://assassin-plus.github.io/portfolio/post/index.xml" rel="self" type="application/rss+xml"/><description>Posts</description><generator>Hugo Blox Builder (https://hugoblox.com)</generator><language>en-us</language><lastBuildDate>Sun, 01 Sep 2024 00:00:00 +0200</lastBuildDate><image><url>https://assassin-plus.github.io/portfolio/media/icon_hu_982c5d63a71b2961.png</url><title>Posts</title><link>https://assassin-plus.github.io/portfolio/post/</link></image><item><title>Procedural Texturing | Real-time Rendering Chapter 6.3</title><link>https://assassin-plus.github.io/portfolio/post/procedural-texturing/</link><pubDate>Sun, 01 Sep 2024 00:00:00 +0200</pubDate><guid>https://assassin-plus.github.io/portfolio/post/procedural-texturing/</guid><description>&lt;h1 id="procedural-texturing"&gt;Procedural Texturing&lt;/h1&gt;
&lt;p&gt;Although procedural textures are commonly used in offline rendering applications, image textures are far more common in real-time rendering. This is due to the extremely &lt;em&gt;high efficiency of the image texturing hardware&lt;/em&gt; in modern GPUs, which can perform many billions of texture accesses in a second. However, GPU architectures are evolving toward &lt;em&gt;less expensive computation and (relatively) more costly memory access&lt;/em&gt;. These trends have made procedural textures find greater use in real-time applications.&lt;/p&gt;
&lt;p&gt;Volume textures are a particularly attractive application for procedural texturing, given the high storage costs of volume image textures. One of the most common is using one or more &lt;strong&gt;noise&lt;/strong&gt; functions to generate values. A noise function is often sampled at successive powers-of-two frequencies, called &lt;em&gt;octaves&lt;/em&gt;. Each octave is given a weight, usually falling as the frequency increases, and the sum of these weighted samples is called a &lt;em&gt;turbulence&lt;/em&gt; function.&lt;/p&gt;
&lt;p&gt;Other procedural methods are possible. For example, a cellular texture is formed by measuring distances from each location to a set of “feature points” scattered through space. Mapping the resulting closest distances in various ways.&lt;/p&gt;
&lt;p&gt;When generating a procedural two-dimensional texture, parameterization issues (UV) can pose even more difficulties than for authored textures, where stretching or seam artifacts can be manually touched up or worked around.&lt;/p&gt;
&lt;p&gt;Antialiasing procedural textures is both harder and easier than &lt;strong&gt;antialiasing&lt;/strong&gt; image textures. On one hand, precomputation methods such as mipmapping are not available, putting the burden on the programmer. On the other, the procedural texture author has “inside information” about the texture content and so can tailor it to avoid aliasing. This is particularly true for procedural textures created by summing multiple noise functions. The frequency of each noise function is known, so any frequencies that would cause aliasing can be discarded, actually making the computation less costly.&lt;/p&gt;</description></item><item><title>Premultiplied Alphas and Compositing | Real-time Rendering Chapter 5.5.3</title><link>https://assassin-plus.github.io/portfolio/post/premultiplied-alpha/</link><pubDate>Sat, 17 Feb 2024 00:00:00 +0200</pubDate><guid>https://assassin-plus.github.io/portfolio/post/premultiplied-alpha/</guid><description>&lt;h1 id="premultiplied-alphas-and-compositing"&gt;Premultiplied Alphas and Compositing&lt;/h1&gt;
&lt;p&gt;The over operator is also used for blending together photographs or synthetic renderings of objects. This process is called compositing. The image formed by the alpha channel is sometimes called the &lt;strong&gt;matte&lt;/strong&gt;. It shows the silhouette shape of the object.&lt;/p&gt;
&lt;p&gt;One way to use synthetic RGBα data is with &lt;em&gt;&lt;strong&gt;premultiplied alphas&lt;/strong&gt;&lt;/em&gt; (also known as &lt;em&gt;&lt;strong&gt;associated alphas&lt;/strong&gt;&lt;/em&gt;). That is, the RGB values are multiplied by the alpha value before being used. This makes the compositing over equation more efficient:&lt;/p&gt;
$$\mathbf{c_O=c_S'+(1-\alpha_S)c_d}$$&lt;p&gt;where $\mathbf{c_S'}$ is the premultiplied source channel.Premultiplied alpha also makes it possible to use over and additive blending &lt;em&gt;without changing the blend state&lt;/em&gt;, since the source color is now added in during blending.&lt;/p&gt;
&lt;p&gt;Rendering synthetic images dovetails naturally with premultiplied alphas. An antialiased opaque object rendered over a black background provides premultiplied values by default.&lt;/p&gt;
&lt;p&gt;Another way images are stored is with unmultiplied alphas, also known as unassociated alphas or even as the mind-bending term nonpremultiplied alphas.It is best to use premultiplied data whenever filtering and blending is performed, as operations such as linear interpolation &lt;em&gt;do not work correctly&lt;/em&gt; using unmultiplied alphas. Artifacts such as black fringes around the edges of objects can result.&lt;/p&gt;
&lt;p&gt;For image-manipulation applications, an unassociated alpha is useful to mask a photograph without affecting the underlying image’s original data. Also, an unassociated alpha means that the &lt;strong&gt;full precision range&lt;/strong&gt; of the color channels can be used.&lt;/p&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;care must be taken to properly convert unmultiplied RGBα values to and from the linear space used for computer graphics computations.
{: .prompt-warning }&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Image file formats that support alpha include PNG (unassociated alpha only), OpenEXR (associated only), and TIFF (both types of alpha).&lt;/p&gt;</description></item><item><title>Intro 2 CUDA</title><link>https://assassin-plus.github.io/portfolio/post/intro2cuda/</link><pubDate>Tue, 12 Dec 2023 00:00:00 +0000</pubDate><guid>https://assassin-plus.github.io/portfolio/post/intro2cuda/</guid><description>&lt;h1 id="intro-2-cuda"&gt;Intro 2 CUDA&lt;/h1&gt;
&lt;h2 id="streams"&gt;Streams&lt;/h2&gt;
&lt;h3 id="page-locked-host-memory"&gt;Page-Locked Host Memory&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaHostAlloc((void**)&amp;amp;a, N*sizeof(int), cudaHostAllocDefault);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaFreeHost(a);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;page-locked / pinned host memory:
os guarantees that the memory is resident in physical memory and won&amp;rsquo;t be paged out to disk.&lt;/p&gt;
&lt;p&gt;simultaneously pinned memory opt out of the feature of virtual memory.&lt;/p&gt;
&lt;h3 id="multiple-streams"&gt;Multiple Streams&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaStream_t stream1, stream2;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaStreamCreate(&amp;amp;stream1);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaStreamCreate(&amp;amp;stream2);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaMemcpyAsync(d_a, a, N*sizeof(int), cudaMemcpyHostToDevice, stream1);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaMemcpyAsync(d_b, b, N*sizeof(int), cudaMemcpyHostToDevice, stream2);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kernel&amp;lt;&amp;lt;&amp;lt;grid1, block1, 0, stream1&amp;gt;&amp;gt;&amp;gt;(d_a, N);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kernel&amp;lt;&amp;lt;&amp;lt;grid2, block2, 0, stream2&amp;gt;&amp;gt;&amp;gt;(d_b, N);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaStreamSynchronize(stream1);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaStreamSynchronize(stream2);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaStreamDestroy(stream1);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaStreamDestroy(stream2);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="gpu-work-schedule"&gt;GPU Work Schedule&lt;/h3&gt;
&lt;p&gt;Be aware of the GPU work schedule.
There are different execution units to execute different types of instructions, such as copy, compute, and so on.
And &lt;strong&gt;the order of code dependencies is equal to the order written in the code&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="multi-gpu"&gt;Multi-GPU&lt;/h2&gt;
&lt;h3 id="zero-copy-host-memory"&gt;Zero-Copy Host Memory&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaHostAlloc((void**)&amp;amp;a, N*sizeof(int), cudaHostAllocWriteCombined | cudaHostAllocMapped);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;cudaHostAllocWriteCombined: this flag indicates that the runtime should allocate the buffer as write-combined, which will not change functionality in application
but represents a performance enhancement for buffers that will be read only by the GPU.&lt;/p&gt;
&lt;p&gt;Write-combined memory can be extremely inefficient in scenarios where CPU also needs to perform reads from the buffer.&lt;/p&gt;
&lt;p&gt;cudaHostAllocMapped: the buffers can be accessed from the GPU. However, since there is a difference between the virtual address space of the CPU and the GPU,
the call to cudaHostAlloc() will return a CPU pointer, which is then mapped to a GPU pointer using cudaHostGetDevicePointer().&lt;/p&gt;
&lt;h3 id="portable-pinned-memory"&gt;Portable Pinned Memory&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;This is neccesary when you use multiple GPUs.&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaHostAlloc((void**)&amp;amp;a, N*sizeof(int), cudaHostAllocPortable);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When a buffer is allocated as pinned, they will only &lt;strong&gt;appear&lt;/strong&gt; page-locked to the thread that allocated them. If another thread tries to access the buffer, they will see the buffer as standard pageable memory.&lt;/p&gt;
&lt;p&gt;To support portable pinned memory and zero-copy memory in multi-GPU systems, the code need two notable changes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;deviceID&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;cudaSetDevice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;deviceID&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nf"&gt;cudaSetDeviceFlags&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cudaDeviceMapHost&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We need a call to cudaSetDevice() to enable every thread controls a different GPU.&lt;/p&gt;
&lt;p&gt;In addition, as we use zero-copy in order to access these buffers directly from the GPU, we use cudaHostGetDevicePointer() to get the valid device pointers for the host memory.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;float *a, *b, *partial_c;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;float *dev_a, *dev_b, *dev_partial_c;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//allocate memory on the CPU side
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;a = data-&amp;gt;a;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;b = data-&amp;gt;b;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;partial_c = (float *)malloc(blocksPerGrid *　sizeof(float));
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaHostGetDevicePointer(&amp;amp;dev_a, a, 0);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaHostGetDevicePointer(&amp;amp;dev_b, b, 0);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cudaMalloc((void**)&amp;amp;dev_partial_c, blocksPerGrid * sizeof(float));
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dev_a += data-&amp;gt;offset;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dev_b += data-&amp;gt;offset;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;kernel&amp;lt;&amp;lt;&amp;lt;blocksPerGrid, threadsPerBlock&amp;gt;&amp;gt;&amp;gt;(dev_a, dev_b, dev_partial_c);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Contrast Adjustments</title><link>https://assassin-plus.github.io/portfolio/post/color-grading/</link><pubDate>Thu, 27 Jul 2023 00:00:00 +0000</pubDate><guid>https://assassin-plus.github.io/portfolio/post/color-grading/</guid><description>&lt;h1 id="调整反差的工具"&gt;调整反差的工具&lt;/h1&gt;
&lt;p&gt;LIFT GAMMA GAIN&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lift: 调整趾部&lt;/li&gt;
&lt;li&gt;Gamma：更改中间调的分布&lt;/li&gt;
&lt;li&gt;Gain：调整高光&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Contrast &amp;amp; Pivot&lt;/p&gt;
&lt;p&gt;Contrast：线性地改变图像的黑白位
Pivot：分配Contrast在黑位白位之间区域的权重&lt;/p&gt;
&lt;h2 id="ycbcrrgb下的luma调整"&gt;Y&amp;rsquo;CbCr/RGB下的LUMA调整&lt;/h2&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;大多数调色系统的一级反差控制使用RGB图像处理方式，即调整图像亮度时，是对所有三个色彩分量进行等量且同步调整的。由此产生的调整，会对图像饱和度产生明显影响。
单独操控Y&amp;rsquo;CbCr的Y通道，对图像的饱和度没有可测量的效果（即矢量波形保持不变）。然而，图像的感知饱和度确实有改变。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id="用log调色控件微调反差"&gt;用LOG调色控件微调反差&lt;/h1&gt;
&lt;h2 id="使用offsetexposure和contarst微调反差"&gt;使用OFFSET、EXPOSURE和CONTARST微调反差&lt;/h2&gt;
&lt;p&gt;在套用LUT之前使用这些控件！
这样可以控制图像反差并找回一些图像细节，因为可能在套用LUT时会被裁切&lt;/p&gt;
&lt;h2 id="使用shadowmidtone和highlight微调反差"&gt;使用SHADOW、MIDTONE和HIGHLIGHT微调反差&lt;/h2&gt;
&lt;p&gt;他们被设计为用于log素材正常化之前的调整&lt;/p&gt;
&lt;p&gt;这些控件对图像的影响完全取决于图像本身有多少反差。
Shadow：影响影调的底部三分之一
Midtone：影响范围广泛的中间调
Highlight：影响高光的顶部三分之一&lt;/p&gt;
&lt;h1 id="设置适当的高光和暗部"&gt;设置适当的高光和暗部&lt;/h1&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;对高光的感知与阴影的深度有关。某些时候压低阴影而高光保留不动比提高高光更好。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="保持中间调的同时将白位合法化"&gt;保持中间调的同时将白位合法化&lt;/h2&gt;
&lt;p&gt;压低Gain的同时将中间调提高以补偿影响，也可以通过降低一点暗部来保持反差。&lt;/p&gt;
&lt;h2 id="尝试用降低中间调替代压低暗部的操作"&gt;尝试用降低中间调替代压低暗部的操作&lt;/h2&gt;
&lt;p&gt;不是每个图像都要求把暗部压到0%，有时候降低中间调可以达到相同的效果。&lt;/p&gt;
&lt;h1 id="反差和视觉感知"&gt;反差和视觉感知&lt;/h1&gt;
&lt;h2 id="利用环境效应"&gt;利用环境效应&lt;/h2&gt;
&lt;p&gt;提高高光令阴影看起来更暗，同时尽量避免平均中间调看起来比原来更亮。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;提高Gain&lt;/li&gt;
&lt;li&gt;为了减少图像的感知亮度，降低Gamma。这导致高光减少了一点，但是上步中提起高光幅度很大，不会有太大影响&lt;/li&gt;
&lt;li&gt;降低中间调的同时阴影降低的有点太多，提高Lift作为补偿&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="增加图像感知锐度"&gt;增加图像感知锐度&lt;/h2&gt;
&lt;p&gt;调整反差的另一个效应：增加对比度可以让画面细节变得更锐。&lt;/p&gt;
&lt;h1 id="如何处理曝光问题素材"&gt;如何处理曝光问题素材&lt;/h1&gt;
&lt;h2 id="曝光不足"&gt;曝光不足&lt;/h2&gt;
&lt;p&gt;试图增加亮度和中间调时，通常：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;会增加噪点&lt;/li&gt;
&lt;li&gt;饱和度过高/欠饱和&lt;/li&gt;
&lt;li&gt;暗部细节不足&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;提高中间调比调整白位更好&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;使用曲线控制器，将中间调偏低区域伸展，同时保持中间调偏上的区域不变以获得扎实的阴影。&lt;/p&gt;
&lt;h2 id="过曝"&gt;过曝&lt;/h2&gt;
&lt;p&gt;先做取舍：是否需要压过曝部分&lt;/p&gt;
&lt;p&gt;如果过曝面积不太大：&lt;/p&gt;
&lt;h3 id="为过曝区域添加颜色"&gt;为过曝区域添加颜色&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;降低Gain，将高光合法化&lt;/li&gt;
&lt;li&gt;如果有需要，用Gamma提高中间调&lt;/li&gt;
&lt;li&gt;使用HSL选色的Luma控件&lt;/li&gt;
&lt;li&gt;将Gain推向某种颜色，即补色&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="为过曝区域添加辉光"&gt;为过曝区域添加辉光&lt;/h3&gt;
&lt;p&gt;若夸张的过曝不能避免，光晕和溢出可以软化过渡区域的边缘，也能让画面更加舒服&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;降低Gain，将高光合法化，同时提高Gamma补偿&lt;/li&gt;
&lt;li&gt;使用HSL选色的Luma控件分离出过曝区域&lt;/li&gt;
&lt;li&gt;使用HSL选色中的Blur或Soften，模糊键控蒙版，最终要令蒙版比曝光过度的区域更大，边缘更柔软&lt;/li&gt;
&lt;li&gt;用Lift或Gamma来提亮选中的键控区域，类似晕染和溢出会逐渐出现。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="使用通道混合器重建被裁切的通道"&gt;使用通道混合器重建被裁切的通道&lt;/h3&gt;
&lt;p&gt;由于显著过曝而造成的某个通道分配不均，导致难看的图像高光。检查RGB分量示波器，如果某个通道远高于110%，但是其他通道都没有，那么可以使用这类方法。&lt;/p&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;这是最后的方法，目的是找回更多图像数据而不是让图像更漂亮。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;调整色彩和反差，达到色彩平衡（一级校色），先别担心裁切位置，只需要进行整体校正。在这种情况下，offset来重新编排三个色彩通道的位置，先降低红色通道，再使用“Master Offset”来降低整体图像信号，使图像阴影密度更多&lt;/li&gt;
&lt;li&gt;创建新节点进行通道修复。这次调整所作的校正将要放在之前的校正上。也即使用Layer Mixer&lt;/li&gt;
&lt;li&gt;选择新节点，检查哪个通道在被裁切的区域内有更多的细节。&lt;/li&gt;
&lt;li&gt;使用 RGB Mixer / Channel Blending / Channel isolation / Blend mode来混和绿色与蓝色通道给红色通道。&lt;/li&gt;
&lt;li&gt;使用Luma限定控件分离出过曝高光区域，然后柔化边缘并使用该键控蒙版来限制通道混合的影响范围。&lt;/li&gt;
&lt;li&gt;最后添加额外的校色操作，整体图像进行调色&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>