gpt4 book ai didi

reflection - 在 SCNProgram 传递的 Metal 着色器中使用哪些正确的矩阵值以获得正确的 Chrome 反射

转载 作者:行者123 更新时间:2023-12-04 15:36:53 24 4
gpt4 key购买 nike

我正在开发一个应用程序,它应该在天空盒内渲染一个 chrome 风格的反射球体状物体(使用六面立方体贴图)。

我在 Swift 中通过不同的方法使用 Scenekit 来做到这一点。

只要我让 Scenekit 完成所有工作,一切都很好并且完美反射(reflect)(参见下面的图 1)——换句话说,使用 Metal 度为 1.0、粗糙度为 0.0 和颜色 UIColor.white 的标准 SCNMaterial(使用 .physicallyBased 作为光照模型)附加到节点几何体的第一个 Material (包括定向光)。

Figure 1 - correct reflection

但目标是使用 SCNProgram相反,(附在节点的 Material 上)有它自己的顶点和片段着色器——对应于关于它的苹果文档。我有一个工作场景,但是对象上的反射是错误的(如下图 2 所示)

Figure 2 - wrong refelction

主要问题是:从 scn_nodescn_frame(在 shaders.metal 文件中)到 哪些矩阵值是正确的使用,以获得与 Scenekit 在图 1 中所做的相同的对象反射。但是仅将 SCNProgram 与着色器一起使用(没有灯光)。不幸的是,Apple 没有提供很多关于 SCNProgram 提交给着色器的不同矩阵的信息,以及使用哪个矩阵的目的或种类的示例。

这是我当前的顶点着色器,我假设其中使用了一些错误的矩阵(我留下了一些注释掉的代码,以显示已经测试过的内容,而不是注释掉的代码对应于图 2 的 1:1):

vertex SimpleVertexChromeOrig myVertexChromeOrig(MyVertexInput in [[ stage_in ]],
constant SCNSceneBuffer& scn_frame [[buffer(0)]],
constant MyNodeBuffer& scn_node [[buffer(1)]])
{

SimpleVertexChromeOrig OUT;

OUT.position = scn_node.modelViewProjectionTransform * float4(in.position, 1.0);
// OUT.position = scn_frame.viewProjectionTransform * float4(in.position, 1.0);

float4 eyeSpacePosition = scn_frame.viewTransform * float4(in.position, 1.0);
float3 eyeSpaceEyeVector = normalize(-eyeSpacePosition).xyz;


// float3 eyeSpaceNormal = normalize(scn_frame.inverseViewTransform * float4(in.normal, 1.0)).xyz;
float3 eyeSpaceNormal = normalize(scn_node.normalTransform * float4(in.normal, 1.0)).xyz;

// Reflection and Refraction Vectors
float3 eyeSpaceReflection = reflect(-eyeSpaceEyeVector, eyeSpaceNormal);
OUT.worldSpaceReflection = (scn_node.inverseModelViewTransform * float4(eyeSpaceReflection, 1.0)).xyz;
// OUT.worldSpaceReflection = (scn_node.modelViewTransform * float4(eyeSpaceReflection, 1.0)).xyz;
// OUT.worldSpaceReflection = (scn_node.modelTransform * float4(eyeSpaceReflection, 1.0)).xyz;

return OUT;
}

这是当前的片段着色器(非常默认的立方体贴图采样器):

fragment float4 myFragmentChromeOrig(SimpleVertexChromeOrig in [[stage_in]],
texturecube<float, access::sample> cubeTexture [[texture(0)]],
sampler cubeSampler [[sampler(0)]])
{

float3 reflection = cubeTexture.sample(cubeSampler, in.worldSpaceReflection).rgb;

float4 color;
color.rgb = reflection;
color.a = 1.0;

return color;
}

这是我从 NodeBuffer 获得的矩阵(由 SCNProgram 自动提供)——它们必须只在着色器文件的结构中定义才能像这样访问:

struct MyNodeBuffer {
float4x4 modelTransform;
float4x4 inverseModelTransform;
float4x4 modelViewTransform;
float4x4 inverseModelViewTransform;
float4x4 normalTransform;
float4x4 modelViewProjectionTransform;
float4x4 inverseModelViewProjectionTransform;
};

这是顶点输入结构:

typedef struct {
float3 position [[ attribute(SCNVertexSemanticPosition) ]];
float3 normal [[ attribute(SCNVertexSemanticNormal) ]]; // Phil
} MyVertexInput;

这是由顶点着色器填充的 Stuct:

struct SimpleVertexChromeOrig
{
float4 position [[position]];
float3 worldSpaceReflection;
};

(天空盒始终通过包含六张图像的 SCNMaterialContent 属性提供,并附加到 sceneView.scene.background.contents)

最佳答案

有许多可能的公式适用于此,但我在下面列出了一个似乎对我有用的公式。注释解释了每个步骤。

vertex SimpleVertexChromeOrig myVertexChromeOrig(MyVertexInput in [[stage_in]],
constant SCNSceneBuffer& scn_frame [[buffer(0)]],
constant MyNodeBuffer& scn_node [[buffer(1)]])
{
float4 modelSpacePosition(in.position, 1.0f);
float4 modelSpaceNormal(in.normal, 0.0f);

// We'll be computing the reflection in eye space, so first we find the eye-space
// position. This is also used to compute the clip-space position below.
float4 eyeSpacePosition = scn_node.modelViewTransform * modelSpacePosition;

// We compute the eye-space normal in the usual way.
float3 eyeSpaceNormal = (scn_node.normalTransform * modelSpaceNormal).xyz;

// The view vector in eye space is just the vector from the eye-space position.
float3 eyeSpaceViewVector = normalize(-eyeSpacePosition.xyz);

// To find the reflection vector, we reflect the (inbound) view vector about the normal.
float4 eyeSpaceReflection = float4(reflect(-eyeSpaceViewVector, eyeSpaceNormal), 0.0f);

// To sample the cubemap, we want a world-space reflection vector, so multiply
// by the inverse view transform to go back from eye space to world space.
float3 worldSpaceReflection = (scn_frame.inverseViewTransform * eyeSpaceReflection).xyz;

SimpleVertexChromeOrig out;
out.position = scn_frame.projectionTransform * eyeSpacePosition;
out.worldSpaceReflection = worldSpaceReflection;
return out;
}

fragment float4 myFragmentChromeOrig(SimpleVertexChromeOrig in [[stage_in]],
texturecube<float, access::sample> cubeTexture [[texture(0)]],
sampler cubeSampler [[sampler(0)]])
{
// Since the reflection vector's length will vary under interpolation, we normalize it
// and flip it from the assumed right-hand space of the world to the left-hand space
// of the interior of the cubemap.
float3 worldSpaceReflection = normalize(in.worldSpaceReflection) * float3(1.0f, 1.0f, -1.0f);

float3 reflection = cubeTexture.sample(cubeSampler, worldSpaceReflection).rgb;
float4 color;
color.rgb = reflection;
color.a = 1.0;
return color;
}

关于reflection - 在 SCNProgram 传递的 Metal 着色器中使用哪些正确的矩阵值以获得正确的 Chrome 反射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59454958/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com