无主之地2配置高吗|看真人裸体BBBBB|秋草莓丝瓜黄瓜榴莲色多多|真人強奷112分钟|精品一卡2卡3卡四卡新区|日本成人深夜苍井空|八十年代动画片

網易首頁 > 網易號 > 正文 申請入駐

Unity預計算輻照度全局光照PRTGI實踐與拓展(上)

0
分享至


【USparkle專欄】如果你深懷絕技,愛“搞點研究”,樂于分享也博采眾長,我們期待你的加入,讓智慧的火花碰撞交織,讓知識的傳遞生生不息!

這是侑虎科技第1983篇文章,感謝作者AkiKurisu供稿。歡迎轉發分享,未經作者授權請勿轉載。如果您有任何獨到的見解或者發現也歡迎聯系我們,一起探討。(QQ群:793972859)

作者主頁:

https://www.zhihu.com/people/akikurisu

在知乎平臺上,最早由網易根據育碧在GDC上分享的《Global Illumination in Tom Clancy's The Division》提出了實時PRTGI(預計算輻射度全局光照)技術的實現思路。隨后,AKG4e3提供了示例工程,其內容涵蓋從理論到實踐的PRTGI實現過程(參見《預計算輻照度全局光照(PRTGI)從理論到實戰》)。方木君則在《Unity 移動端可用實時GI方案細節補充》中,對局部光源(Local Light)的重光照(Relight)及優化方案進行了擴展。

本文內容基于上述項目的Fork版本,在學習過程中進行了進一步完善與擴展。部分修改已記錄于本人的Fork倉庫(AkiKurisu/UnityPRTGI)中。但由于后續開發需要在Forward渲染路徑下進行,相關修改已集成至其他項目,該Fork版本已停止維護。

后續還將結合其他在URP下實現的相關Feature進行整理與開源,敬請期待。


流程概述

先總結一下《預計算輻照度全局光照(PRTGI)從理論到實戰》的項目中的流程,方便后續對比:

1. 離線烘焙生成Surfel(總計512*Probe)

2. 按Probe順序存儲Surfel

3. 運行時Probe拿到對應的512個Surfel

4. Relight所有Probe

烘焙提速

原作者使用Camera.RenderToCubemap來抓取Cubemap,這個函數在GPU上的開銷實際不大,手動渲染每一個面的成本并沒有減少,但可以考慮改成使用另一個拓展方法,來在構建RenderList的時候忽略非靜態物體:

public static bool RenderToCubemap(
this Camera camera,
Texture target,
int faceMask,
StaticEditorFlags culledFlags);

通過不同場景的性能測試,烘焙這里更拖延速度的是CPU側設置Material Shader的開銷,由于需要分別設置Shader來采樣Position、Albedo、Normal數據,實際開銷約等于

次Shader設置,時間復雜度為

所以優化方式就是使用一個Shader,烘焙時只需要設置一次,每個Probe烘焙時通過切換Keyword來抓取所需數據。

#pragma multi_compile _ _GBUFFER_WORLDPOS _GBUFFER_NORMAL

float4 frag (v2f i) : SV_Target
{
#if defined(_GBUFFER_WORLDPOS)
// Output world position
return float4(i.worldPos, 1.0);
#elif defined(_GBUFFER_NORMAL)
// Output world space normal
return float4(i.normal, 1.0);
#else
// Default output albedo
half4 albedo = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv) * _Color;
return albedo;
#endif
}
private static void SetGlobalGBufferCaptureMode(GBufferCaptureMode captureMode)
{
// Enable the specific keyword based on capture mode
switch (captureMode)
{
case GBufferCaptureMode.WorldPosition:
Shader.EnableKeyword("_GBUFFER_WORLDPOS");
Shader.DisableKeyword("_GBUFFER_NORMAL");
break;
case GBufferCaptureMode.Normal:
Shader.DisableKeyword("_GBUFFER_WORLDPOS");
Shader.EnableKeyword("_GBUFFER_NORMAL");
break;
case GBufferCaptureMode.Albedo:
Shader.DisableKeyword("_GBUFFER_WORLDPOS");
Shader.DisableKeyword("_GBUFFER_NORMAL");
break;
}
}

// 對于每個Probe執行下面的代碼
SetGlobalGBufferCaptureMode(GBufferCaptureMode.WorldPosition);
camera.RenderToCubemap(_worldPosRT, -1, StaticEditorFlags.ContributeGI);
SetGlobalGBufferCaptureMode(GBufferCaptureMode.Normal);
camera.RenderToCubemap(_normalRT, -1, StaticEditorFlags.ContributeGI);
SetGlobalGBufferCaptureMode(GBufferCaptureMode.Albedo);
camera.RenderToCubemap(_albedoRT, -1, StaticEditorFlags.ContributeGI);

如此一來時間復雜度為O(1),大大提升了復雜場景下的烘焙速度。

球諧優化

由于Unity 2023、Unity 6相關版本未在國內普及,其新增的APV(Adaptive Probe Volume)系統,國內相關技術討論較少。然而,作為Unity官方新推出的GI方案,APV有大量值得學習的優化技巧。

PRT(Precomputed Radiance Transfer)和APV實際上師出同門,共通點是都不需要UV2、比LightMap方便,需要烘焙,僅支持靜態場景,兩者的核心差異在于:

  • APV:每個Probe離線存儲球諧系數,不支持動態光照(如TOD系統),但因為存儲了SkyVisibility,可以實現動態的天光遮蔽。

  • PRT:存儲Radiance數據和SkyVisibility,支持動態光照。

PRT缺點也很明顯,因為要存儲的數據更多了,使得實踐上Probe放置的密度小于APV的密度,這使得高頻的Diffuse信息會被忽略,所以更適合(半)室外。

盡管應用場景不同,APV作為Unity官方實現,其優化策略具有重要的參考價值。

原項目SH.hlsl中的球諧函數實現使用大量條件判斷:

// 老版本 - 大量分支判斷
float SH(in int l, in int m, in float3 s)
{
if (l == 0) return kSHBasis0;
if (l == 1 && m == -1) return kSHBasis1 * y;
if (l == 1 && m == 0) return kSHBasis1 * z;
// ... 更多條件判斷
return0.0;
}


// 在循環中重復調用
for (int shIndex = 0; shIndex < 9; shIndex++)
{
contribution = SHProject(shIndex, dir) * totalRadiance * 4.0 * PI / SampleCount;
// 每次調用都要執行完整的條件判斷邏輯
}

這種GPU上的條件分支會導致Warp Divergence,且影響性能。

下面是參考Unity的SphericalHarmonics.hlsl的實現方式,使用向量化方式來優化。

對照用的公式,數學不好不會推也沒事:


向量化版本:

// 新版本 - 向量化計算
void EvaluateSH9(in float3 dir, out float sh[9])
{
float x = dir.x;
float y = dir.y;
float z = dir.z;

// L0 (constant)
sh[0] = 1.0; // Constant term (will be multiplied by kSHBasisCoef[0])

// L1 (linear)
sh[1] = y; // Y_1_-1
sh[2] = z; // Y_1_0
sh[3] = x; // Y_1_1

// L2 (quadratic)
sh[4] = x * y; // Y_2_-2
sh[5] = y * z; // Y_2_-1
sh[6] = 3.0 * z * z - 1.0; // Y_2_0 (Equals 2.0 * z * z - x * x - y * y)
sh[7] = x * z; // Y_2_1
sh[8] = x * x - y * y; // Y_2_2

// Apply kSHBasisCoef to get the final SH basis values
[unroll]
for (int i = 0; i < 9; ++i)
{
sh[i] = sh[i] * kSHBasisCoef[i];
}
}

// 優化后的使用方式
float shCoeffs[9];
EvaluateSH9(dir, shCoeffs); // 一次計算所有系數

[unroll]
for (int shIndex = 0; shIndex < 9; shIndex++)
{
contribution = shCoeffs[shIndex] * totalRadiance * 4.0 * PI / SampleCount;
// 直接數組訪問,無分支判斷
}

這種方式可以連續訪問,性能更好。

除了向量化外,APV系統中一個巧妙的優化是在球諧系數上預除PI,減少Radiance轉為Irradiance時的ALU開銷:

// Clamped cosine convolution coefs (pre-divided by PI)
// See https://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/
#define kClampedCosine0 1.0f
#define kClampedCosine1 2.0f / 3.0f
#define kClampedCosine2 1.0f / 4.0f


static const float kClampedCosineCoefs[] = {
kClampedCosine0, kClampedCosine1, kClampedCosine1, kClampedCosine1,
kClampedCosine2, kClampedCosine2, kClampedCosine2, kClampedCosine2, kClampedCosine2
};

這個優化基于Sébastien Lagarde的經典文章《Pi or not to Pi in game lighting equation》。什么時候改乘PI也是實時渲染中一個比較經典的問題,例如URP中的Lambert BRDF就沒有除PI,目的是簡化燈光流程,讓燈光顏色調整時所見即所得。

3D紋理

原作者存儲球諧是將27位float存在一個巨大的ComputeBuffer中,這導致需要使用定點數Encode并且使用較多的原子操作。

這個方式弊病很多,一方面沒有利用GPU的優勢(對3D紋理的硬件優化),另一方面原子操作導致寫入前需要Clear,需要使用雙緩沖來維護,內存翻倍。

// 使用定點數存儲小數, 因為 compute shader 的 InterlockedAdd 不支持 float
// array size: 3x9=27
RWStructuredBuffer _coefficientSH9;


// storage to volume
if(_indexInProbeVolume >= 0)
{
constint coefficientByteSize = 27;
int offset = _indexInProbeVolume * coefficientByteSize;
for(int i = 0; i < 9; i++)
{
InterlockedAdd(_coefficientVoxel[offset + i * 3 + 0], EncodeFloatToInt(c[i].x));
InterlockedAdd(_coefficientVoxel[offset + i * 3 + 1], EncodeFloatToInt(c[i].y));
InterlockedAdd(_coefficientVoxel[offset + i * 3 + 2], EncodeFloatToInt(c[i].z));
}
}

我將其修改為probeSizeX,probeSizeZ,probeSizeY*9大小,格式為RGB111110Float的3D紋理。雖然這樣還是會有一定的CacheMiss,但相比使用ComputeBuffer來存儲球諧系數性能更好,并且可以方便在FrameDebugger中查看。

// Layout: [probeSizeX, probeSizeZ, probeSizeY * 9]
RWTexture3D _coefficientVoxel3D;


if (_indexInProbeVolume >= 0)
{
// Write to 3D texture
int3 texCoord = ProbeIndexToTexture3DCoord(_indexInProbeVolume, index, _coefficientVoxelSize);
_coefficientVoxel3D[texCoord] = groupCoefficients[0];
}


需要注意Relight時為了計算MultiBounce我們依然需要訪問上一幀的球諧系數,這使得在一個線程中可能存在同時訪問和寫入的可能,所以只是將ComputeBuffer修改為3D紋理后,還不能去除雙緩沖,還需要之后的幾步優化。

并行規約

由于改成3D紋理,我們需要解決原來作者沒處理的球諧系數求和問題,這本質是GPU中的多線程求和問題即并行規約問題。


無需掌握底層原理,英偉達直接提供了最佳實踐:

《Optimizing Parallel Reduction in CUDA》

https://developer.download.nvidia.cn/assets/cuda/files/reduction.pdf

在CS中實現起來非常簡單,我們有512個Thread,剛好是2次冪,因此可以直接使用PPT中的方法3。


// Parallel reduction
for (uint stride = 256; stride > 0; stride >>= 1)
{
if (groupIndex < stride)
{
groupCoefficients[groupIndex] += groupCoefficients[groupIndex + stride];
}


GroupMemoryBarrierWithGroupSync();
}

由于利用了多線程能力,帶寬換時間,性能大概提升2倍,還有兩個進階版本可以更有效利用帶寬,但代碼實在有些繁瑣,用第三種基本足夠了。


但需要注意這里如果直接存所有二階球諧系數(27個float)到LDS后再并行規約,可能會導致超出閾值或使用了過多寄存器造成性能下降,為了消除該問題,我將二階球諧的9個維度放在循環里分別進行規約。

UNITY_UNROLL
for (int shIndex = 0; shIndex < 9; shIndex++)
{
float3 contribution = ...;

groupCoefficients[groupIndex] = contribution;
GroupMemoryBarrierWithGroupSync();

// Parallel reduction for non-power-of-2 size
for (uint stride = ThreadCount / 2; stride > 0; stride >>= 1)
{
if (groupIndex < stride)
{
groupCoefficients[groupIndex] += groupCoefficients[groupIndex + stride];
}
GroupMemoryBarrierWithGroupSync();
}

// Write results
if (groupIndex == 0 && _indexInProbeVolume >= 0)
{
uint3 texCoord = ProbeIndexToTexture3DCoord(_indexInProbeVolume, shIndex, _coefficientVoxelSize);
_coefficientVoxel3D[texCoord] = groupCoefficients[0];
}

GroupMemoryBarrierWithGroupSync();
}

但這樣明顯會增多同步次數,后續我們會再次來優化這部分。

分幀Relight

由于現有方法是需要每幀遍歷所有Probe進行Relight,這導致場景越大或Probe密度越大,Relight成本越高,時間復雜度為$O(N_\text{probes})$。為了性能可控,我們可以利用Diffuse GI低頻的特點,將Relight的步驟分攤到多幀。

void DoRelight(CommandBuffer cmd, PRTProbeVolume volume)
{
volume.SwapCoefficientVoxels();

// 如果是多幀Relight,則不需要清空體素
if (!multiFrameRelight)
volume.ClearCoefficientVoxel(cmd);

// May only update a subset of probes each frame
using (ListPool .Get( outvar probesToUpdate))
{
volume.GetProbesToUpdate(probesToUpdate);
foreach (var probe in probesToUpdate)
{
probe.ReLight(cmd, _relightCS, _relightKernel);
}
}

// Advance volume render frame
volume.AdvanceRenderFrame();
}

// 滾動獲取當前幀要更新的Probe
public void GetProbesToUpdate(List probes )
{
for (int i = _currentProbeUpdateIndex; i < _currentProbeUpdateIndex + probesToUpdateCount; i++)
{
probes.Add(Probes[i]);
}
}

public void AdvanceRenderFrame()
{
// Advance the update index for next frame
_currentProbeUpdateIndex = (_currentProbeUpdateIndex + probesToUpdateCount) % Probes.Length;
}


回到文章《Global Illumination in Tom Clancy's The Division》的方案,這并不是使用簡單的輪詢法(Round Robin),而是將一組組Probe劃分為一個個Sector,每幀Relight兩組,并且對于相機周圍的Probe再額外Relight一組。

這里是否要劃分Sector筆者覺得不太重要,但Relight玩家相機附近的Probe確實是有必要的,我們可以修改為每幀計算相機附近的Probe,添加到上面的GetProbesToUpdate中。

/// 
/// Update local probe indices based on camera position
///
private void UpdateLocalProbeIndices()
{
if (!_mainCamera || Probes == null || Probes.Length == 0)
return;

Vector3 cameraPos = _mainCamera.transform.position;

// Only recalculate if camera has moved significantly
if (Vector3.Distance(cameraPos, _lastCameraPosition) < CameraMovementThreshold)
return;

_lastCameraPosition = cameraPos;
_localProbeIndices.Clear();

// Convert camera position to probe grid coordinates for more efficient distance calculation
Vector3 gridPos = (cameraPos - transform.position) / probeGridSize;

// Calculate distances from camera to all probes using grid coordinates
using (ListPool<(int index, float distance)>.Get(outvar probeDistances))
{
for (int i = 0; i < Probes.Length; i++)
{
if (Probes[i])
{
// Calculate probe position in grid coordinates
Vector3 probeGridPos = (Probes[i].transform.position - transform.position) / probeGridSize;

// Use squared distance for efficiency (avoiding sqrt)
float sqrDistance = (gridPos - probeGridPos).sqrMagnitude;
probeDistances.Add((i, sqrDistance));
}
}

// Sort by distance and take the closest ones
probeDistances.Sort(static (a, b) => a.distance.CompareTo(b.distance));

int count = Mathf.Min(localProbeCount, probeDistances.Count);
for (int i = 0; i < count; i++)
{
_localProbeIndices.Add(probeDistances[i].index);
}
}
}

Forward+多光源適配

理論上只要添加_FOWARD_PLUS宏后就可以使用了,但從URP 14后會遇到一個離譜的編譯問題。

Can't find included file `Packages/com.unity.render-pipelines.ps5/ShaderLibrary/API/FoveatedRendering_PSSL.hlsl`

CS的編譯似乎無視了SHADER_API_PS5宏,導致找不到平臺文件報錯,問題是散修開發者也沒PS5平臺的引擎拓展。

國內有開發者咨詢了Unity官方,得到的AI答復是:URP14.0.7及之后的版本下計算著色器庫文件引用問題。

https://developer.unity.cn/ask/question/66dfb568edbc2a001cb709d3

因此在不修改源碼的情況下,最佳的解決方案就是本地創建一個空的com.unity.render-pipelines.ps5庫,里面寫一個空的FoveatedRendering_PSSL.hlsl。

然后我們在LightLoop前加上下面的代碼,初始化Cluster需要拿到Surfel的屏幕坐標和世界坐標:

#if _FORWARD_PLUS
float2 uv = ComputeNormalizedDeviceCoordinates(surfel.position, UNITY_MATRIX_VP);
InputData inputData = (InputData)0;
inputData.normalizedScreenSpaceUV = uv;
inputData.positionWS = surfel.position;
#endif
uint pixelLightCount = GetAdditionalLightsCount();
LIGHT_LOOP_BEGIN(pixelLightCount) // 這里會創建Cluster
// Light Loop...
LIGHT_LOOP_END


體積霧適配

《Global Illumination in Tom Clancy's The Division》文章分享中也談到了體積霧可以在Raymarch時同時采樣PRT Volume,筆者這里使用了一個開源的體積光方案:

CristianQiu/Unity-URP-Volumetric-Light

https://github.com/CristianQiu/Unity-URP-Volumetric-Light

把其中采樣APV的貢獻改成采樣PRT Volume后,就實現了類似的效果:


陰影緩存


《Global Illumination in Tom Clancy's The Division》和《 實時PRTGI技術與實現 》文章中都提到不在視錐內的物體會被CSM剔除,因此對于離屏物體,我們需要添加一個Shadow Cache來保留最近一次有效的主光源陰影信息。

// mainlight shadow
float4 shadowCoord = TransformWorldToShadowCoord(surfel.position);
if (!BEYOND_SHADOW_FAR(shadowCoord))
{
// Shadow is valid, sample and update cache
atten = SampleShadowmap(
TEXTURE2D_ARGS(_MainLightShadowmapTexture, sampler_MainLightShadowmapTexture),
shadowCoord,
GetMainLightShadowSamplingData(),
GetMainLightShadowParams(),
false
);


// Update shadow cache with new valid result
_shadowCache[surfelGlobalIndex] = atten;
}
else
{
// Shadow is invalid, use cached result if available
atten = _shadowCache[surfelGlobalIndex];
}

Surfel合并Brick

我們回過頭看下現在的數據存儲,對于每個Probe我們都存放了其512個Surfel數據,如果兩個Probe挨著很近,那很大概率Surfel的數據是比較重復的,對于離得很近、方向基本一致的Surfel,我們實際可以清理一部分冗余數據。


《Global Illumination in Tom Clancy's The Division》文章中的全境封鎖給予了一個方案,即根據Grid大小(4×4×4)和Surfel的法線的主方向來聚集為Brick。同一個Brick中的Surfel數據就可以提取一下特征(比如對于坐標相同、法線方向相近的Surfel進行合并)。

下面是數據結構:

/// 
/// Represents the indices of a Surfel
///
[Serializable]
publicstruct SurfelIndices
{
publicint start;

publicint end;
}

///
/// Represents a 4x4x4 brick containing merged Surfels
///
publicclassSurfelBrick
{
publicreadonly List SurfelIndices = new();

publicreadonly HashSet ReferencedProbes = new();
}

SurfelBrick即為烘焙時的Brick存儲結構,由于Surfel不再唯一對應一個Probe,我們還需要在烘焙期間存儲Probe的引用關系,直到存儲數據時再扁平化為索引。

從實現細節上來講,對于每個Probe完成Sample后,需要將Surfel注冊到一個具有HashGrid結構的BrickManager中(根據Surfel世界坐標和主方向計算Hash),BrickPool找到對應位置的SurfelBrick將其添加或合并,并記錄引用的Probe。

其次因為Surfel被合并為Brick,Probe不再直接引用其烘焙階段命中的512個Surfel,在序列化前我們需要額外的數據來存儲Relight時Probe所需的數據。 參考文章《Global Illumination in Tom Clancy's The Division》,下面是一個示例:

/// 
/// Factor structure: contains Brick index and the contribution weight of that Brick to the Probe
///
[Serializable]
publicstruct BrickFactor
{
publicint brickIndex;

publicfloat weight;
}

///
/// Factor range: each Probe stores the range of Factors it uses
///
[Serializable]
publicstruct FactorIndices
{
publicint start;

publicint count;
}

這里BrickFactor對應了一個Brick對于一個Probe的貢獻權重,可以離線通過Brick中所有Surfel的平均法線計算,空間換時間。FactorIndices即是一個Probe所對應的Factor范圍。

最后我們根據Probe順序將FactorIndices、BrickFactor、SurfelIndices和Surfel進行排序,盡可能保證數據訪問時的連續性。

結合上面的數據結構,下面是從烘焙到使用的新流程:

1. Probe發射512個射線采樣生成Surfel

2. Surfel合并聚集到Brick

3. Brick平均法線計算Probe貢獻系數,存到Factor中

4. 存儲Factor、Brick、以及合并后的全部Surfel

5. 運行時Volume拿到全部Surfel、Brick、Factor數據,提交GPU

6. Relight所有Brick

7. Relight所有Factor

為了驗證數據正確,這里優先編寫一下Brick的Gizmos視圖,方便在編輯器看到各個Brick對選中Probe的貢獻值以及Brick中各個Surfel方向是否朝向一致。


我們對比下性能,因為Surfel數據大量進行了合并,Relight Brick開銷非常小,而Probe在Relight時采樣的Brick數量也遠遠小于原先的512個,因此開銷也有所下降。但需要注意這個合并實際會讓GI精度下降,所以對于室內部分,我認為肯定是需要結合SSGI使用的。

注意這里開啟了Multi Frame Relight來控制每幀更新的Probe數量(這里為1幀15個Probe)。



在我們完成Surfel和Probe的Relight分離后,還可以額外獲得兩個免費的優化效果:

1. 由于不再存在3D紋理的寫入和讀取沖突,Relight不再需要歷史幀緩沖,可以減少一張3D紋理使用。

2. 由于ProbeRelight所需的Brick變少了(從512減到小于256),足夠我們將二階球諧27個float直接寫入LDS中。現在的并行規約代碼如下:

#define ThreadCount 256 // Max Brick Num
groupshared float3 groupCoefficients[9][ThreadCount];

// Compute all SH coefficients at once using vectorized approach
float shCoeffs[9];
EvaluateSH9(dir, shCoeffs);

float weight = 4.0 * PI / sampleCount;

// Process each SH coefficient and store to LDS
UNITY_UNROLL
for (int shIndex = 0; shIndex < 9; shIndex++)
{
float3 contribution = shCoeffs[shIndex] * totalRadiance * weight;

groupCoefficients[shIndex][groupIndex] = contribution;
}
GroupMemoryBarrierWithGroupSync();

// Parallel reduction for non-power-of-2 size
for (uint stride = ThreadCount / 2; stride > 0; stride >>= 1)
{
if (groupIndex < stride)
{
UNITY_UNROLL
for (int shIndex = 0; shIndex < 9; shIndex++)
{
groupCoefficients[shIndex][groupIndex] += groupCoefficients[shIndex][groupIndex + stride];
}
}
GroupMemoryBarrierWithGroupSync();
}

那么上半部分就是這些了,下半部分我們繼續優化和拓展PRTGI。

參考文章

[1] 實時PRTGI技術與實現

https://zhuanlan.zhihu.com/p/541137978

[2] 預計算輻照度全局光照(PRTGI)從理論到實戰

https://zhuanlan.zhihu.com/p/571673961

[3] Unity移動端可用實時GI方案細節補充

https://zhuanlan.zhihu.com/p/654050347

[4] Global Illumination in Tom Clancy's The Division

[5] Pi or not to Pi in game lighting equation

https://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/

文末,再次感謝AkiKurisu的分享, 作者主頁:https://www.zhihu.com/people/akikurisu, 如果您有任何獨到的見解或者發現也歡迎聯系我們,一起探討。(QQ群: 793972859 )。


近期精彩回顧



特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相關推薦
熱點推薦
3換2交易達成,火箭一口氣簽3人!1米83次輪狀元兩大優勢完美適配

3換2交易達成,火箭一口氣簽3人!1米83次輪狀元兩大優勢完美適配

童叔不飆車
2026-06-26 01:04:26
徐帆回應離婚才9個月,68歲馮小剛和養女貼臉拍照親密 ,關系很好

徐帆回應離婚才9個月,68歲馮小剛和養女貼臉拍照親密 ,關系很好

滄海一書客
2026-05-31 18:08:08
第一個面臨消失的職業,不是幼師,不是快遞員,而是這幾種工作?

第一個面臨消失的職業,不是幼師,不是快遞員,而是這幾種工作?

你是我心中最美星空
2026-06-26 06:20:24
名記曝光:湖人6換4!老詹決定四?先簽后換,值得嗎?

名記曝光:湖人6換4!老詹決定四?先簽后換,值得嗎?

籃球盛世
2026-06-25 16:30:36
徹底失控 廣東高考出分,結果完全超出所有人預判,幾家歡喜幾家愁

徹底失控 廣東高考出分,結果完全超出所有人預判,幾家歡喜幾家愁

金哥說新能源車
2026-06-26 02:49:48
萬卓索娃拒檢遭四年重罰,王欣瑜柏林站亞軍變冠軍的呼聲為何一夜之間刷屏全網?

萬卓索娃拒檢遭四年重罰,王欣瑜柏林站亞軍變冠軍的呼聲為何一夜之間刷屏全網?

TVB的四小花
2026-06-26 02:13:48
這回,輪到煙草員工開始沒心情上班了?金鐵飯碗咋就不香了?

這回,輪到煙草員工開始沒心情上班了?金鐵飯碗咋就不香了?

世界圈
2026-06-04 08:26:44
常年不祭祖不上墳的家庭,久而久之,大多會出現這幾種結局

常年不祭祖不上墳的家庭,久而久之,大多會出現這幾種結局

老特有話說
2026-06-23 14:08:53
王楚然膚若凝脂,氣質絕塵,大骨架子看起來很健康

王楚然膚若凝脂,氣質絕塵,大骨架子看起來很健康

喜歡歷史的阿繁
2026-06-26 01:52:04
交易風暴!老大也被換!狼隊+猛龍,哪隊更合適?

交易風暴!老大也被換!狼隊+猛龍,哪隊更合適?

籃球盛世
2026-06-26 01:20:56
隨著德國1-2輸厄瓜多爾,科特迪瓦2-0勝庫拉索,E組3支球隊晉級!

隨著德國1-2輸厄瓜多爾,科特迪瓦2-0勝庫拉索,E組3支球隊晉級!

安海客
2026-06-26 06:24:53
1988年老山前線有功師長李德金,在開會途中被副職當場控制

1988年老山前線有功師長李德金,在開會途中被副職當場控制

磊子講史
2026-06-23 18:15:42
帶狀皰疹疫苗又立大功?打完不僅防“纏腰龍”,癡呆風險也降了!

帶狀皰疹疫苗又立大功?打完不僅防“纏腰龍”,癡呆風險也降了!

愛醫斯坦
2026-06-23 17:15:46
韓紅“走個面”事件升級!有網友解除捐贈,曬出一年多的扣款記錄

韓紅“走個面”事件升級!有網友解除捐贈,曬出一年多的扣款記錄

火山詩話
2026-06-25 06:54:35
離職多年還能收到工作的消息:怎么忍住不罵的?

離職多年還能收到工作的消息:怎么忍住不罵的?

采采
2026-06-17 17:22:34
火箭3換2得次輪狀元!身高不夠但體重超標,烏度卡要他頂防大個

火箭3換2得次輪狀元!身高不夠但體重超標,烏度卡要他頂防大個

漫川舟船
2026-06-26 04:57:20
內鬼浮出水面!柬埔寨電詐園區幕后黑手,竟是我們信任的商會會長

內鬼浮出水面!柬埔寨電詐園區幕后黑手,竟是我們信任的商會會長

夢史
2026-06-22 23:45:10
你無意中發現了不得的事?網友:大保健里遇見嫂子

你無意中發現了不得的事?網友:大保健里遇見嫂子

夜深愛雜談
2026-05-28 07:59:33
克洛普:安帥給巴西帶來戰術紀律;挪威和日本已達到強隊水平

克洛普:安帥給巴西帶來戰術紀律;挪威和日本已達到強隊水平

懂球帝
2026-06-25 21:58:31
什么信號?“站在光里”的基金經理紛紛限購,年內業績TOP10均已閉門謝客

什么信號?“站在光里”的基金經理紛紛限購,年內業績TOP10均已閉門謝客

財聯社
2026-06-25 14:32:41
2026-06-26 07:19:00
侑虎科技UWA incentive-icons
侑虎科技UWA
游戲/VR性能優化平臺
1590文章數 987關注度
往期回顧 全部

科技要聞

存儲成本壓力山大!蘋果罕見全球提價

頭條要聞

超巴西獨享第1 德國1-2厄瓜多爾時隔12年重返淘汰賽

頭條要聞

超巴西獨享第1 德國1-2厄瓜多爾時隔12年重返淘汰賽

體育要聞

世界杯最動人一吻:我若離世 你就改嫁吧

娛樂要聞

這國產劇太裝了,居然還熱播第一?

財經要聞

又有紙尿褲送檢后被檢測出甲酰胺!

汽車要聞

老板們的新座駕!65萬元起,尊界V800/V680開啟預訂

態度原創

房產
家居
數碼
健康
軍事航空

房產要聞

城市精英集體出手!科學城這一現象級熱銷紅盤,憑何成為共識之選?

家居要聞

綠意盎然 自然之境

數碼要聞

突發!蘋果全面漲價:MacBook Neo上漲900元

醫生如何快速診斷腦梗和腦出血?

軍事要聞

特朗普:現在到了關注朝鮮問題的時候了

無障礙瀏覽 進入關懷版