Bóng đèn điểm paraboloid kép trong thiết lập ánh sáng hoãn lại


10

Tôi đã chơi xung quanh với mã hướng dẫn / mẫu này cho thấy việc triển khai ánh sáng trước đơn giản, đây là một loại thiết lập ánh sáng bị trì hoãn.

Tôi đang trong quá trình thực hiện các bóng sáng điểm, sử dụng các bản đồ bóng hai mặt. Tôi đang theo mô tả này của DPM: http://gamedevelop.eu/en/tutorials/dual-paraboloid-shadow-mapping.htmlm

Tôi có thể tạo ra các bản đồ bóng, và chúng có vẻ ổn.

Tôi tin rằng vấn đề hiện tại tôi gặp phải là trong trình đổ bóng pixel của tôi, tìm kiếm một giá trị độ sâu trong bản đồ bóng khi kết xuất đèn điểm.

Đây là mã shader ánh sáng điểm của tôi: http://olhovsky.com/shadow_mapping/PointLight.fx

Các chức năng pixel shader quan tâm là PointLightMeshShadowPS.

Có ai nhìn thấy một lỗi rõ ràng trong chức năng đó?

Hy vọng rằng ai đó đã giải quyết vấn đề này trước đây :)

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

Như bạn có thể thấy trong các hình ảnh ở trên, bóng của bài đăng không khớp với vị trí của bài đăng, vì vậy một số biến đổi bị sai ở đâu đó ...

Đây là những gì nó trông giống như khi ánh sáng điểm rất gần mặt đất (gần như chạm đất).

nhập mô tả hình ảnh ở đây

Khi ánh sáng điểm di chuyển gần mặt đất hơn, các bóng kết hợp với nhau và chạm dọc theo đường mà hai bản đồ bóng gặp nhau (nghĩa là dọc theo mặt phẳng nơi camera ánh sáng được lật để chụp hai bản đồ bóng).


Biên tập:

Thêm thông tin:

nhập mô tả hình ảnh ở đây

Khi tôi di chuyển ánh sáng điểm ra khỏi điểm gốc, có một đường thẳng song song với vectơ "bên phải" của camera ánh sáng cắt bóng. Hình trên cho thấy kết quả của việc di chuyển ánh sáng điểm sang trái. Nếu tôi di chuyển ánh sáng điểm sang phải, thay vào đó sẽ có một đường cắt tương đương ở bên phải. Vì vậy, tôi nghĩ rằng điều này chỉ ra rằng tôi đang chuyển đổi một cái gì đó không chính xác trong trình đổ bóng pixel, như tôi nghĩ.


Chỉnh sửa: Để làm cho câu hỏi này rõ ràng hơn, đây là một vài đoạn mã.

Đây là đoạn mã mà tôi hiện đang sử dụng để vẽ một đốm sáng bị che khuất . Điều này hoạt động và sử dụng ánh xạ bóng như bạn mong đợi.

VertexShaderOutputMeshBased SpotLightMeshVS(VertexShaderInput input)
{
    VertexShaderOutputMeshBased output = (VertexShaderOutputMeshBased)0;    
    output.Position = mul(input.Position, WorldViewProjection);

    //we will compute our texture coords based on pixel position further
    output.TexCoordScreenSpace = output.Position;
    return output;
}

//////////////////////////////////////////////////////
// Pixel shader to compute spot lights with shadows
//////////////////////////////////////////////////////
float4 SpotLightMeshShadowPS(VertexShaderOutputMeshBased input) : COLOR0
{
    //as we are using a sphere mesh, we need to recompute each pixel position into texture space coords
    float2 screenPos = PostProjectionSpaceToScreenSpace(input.TexCoordScreenSpace) + GBufferPixelSize;
    //read the depth value
    float depthValue = tex2D(depthSampler, screenPos).r;

    //if depth value == 1, we can assume its a background value, so skip it
    //we need this only if we are using back-face culling on our light volumes. Otherwise, our z-buffer
    //will reject this pixel anyway

    //if depth value == 1, we can assume its a background value, so skip it
    clip(-depthValue + 0.9999f);

    // Reconstruct position from the depth value, the FOV, aspect and pixel position
    depthValue*=FarClip;

    //convert screenPos to [-1..1] range
    float3 pos = float3(TanAspect*(screenPos*2 - 1)*depthValue, -depthValue);

    //light direction from current pixel to current light
    float3 lDir = LightPosition - pos;

    //compute attenuation, 1 - saturate(d2/r2)
    float atten = ComputeAttenuation(lDir);

    // Convert normal back with the decoding function
    float4 normalMap = tex2D(normalSampler, screenPos);
    float3 normal = DecodeNormal(normalMap);

    lDir = normalize(lDir);

    // N dot L lighting term, attenuated
    float nl = saturate(dot(normal, lDir))*atten;

    //spot light cone
    half spotAtten = min(1,max(0,dot(lDir,LightDir) - SpotAngle)*SpotExponent);
    nl *= spotAtten;

    //reject pixels outside our radius or that are not facing the light
    clip(nl -0.00001f);

    //compute shadow attenuation

    float4 lightPosition = mul(mul(float4(pos,1),CameraTransform), MatLightViewProjSpot);

    // Find the position in the shadow map for this pixel
    float2 shadowTexCoord = 0.5 * lightPosition.xy / 
                            lightPosition.w + float2( 0.5, 0.5 );
    shadowTexCoord.y = 1.0f - shadowTexCoord.y;
    //offset by the texel size
    shadowTexCoord += ShadowMapPixelSize;

    // Calculate the current pixel depth
    // The bias is used to prevent floating point errors 
    float ourdepth = (lightPosition.z / lightPosition.w) - DepthBias;

    nl = ComputeShadowPCF7Linear(nl, shadowTexCoord, ourdepth);

    float4 finalColor;

    //As our position is relative to camera position, we dont need to use (ViewPosition - pos) here
    float3 camDir = normalize(pos);

    // Calculate specular term
    float3 h = normalize(reflect(lDir, normal));
    float spec = nl*pow(saturate(dot(camDir, h)), normalMap.b*50);
    finalColor = float4(LightColor * nl, spec); 

    //output light
    return finalColor * LightBufferScale;
}

Bây giờ đây là mã ánh sáng điểm mà tôi đang sử dụng, có một số lỗi trong quá trình chuyển đổi thành không gian ánh sáng khi sử dụng bản đồ bóng:

VertexShaderOutputMeshBased PointLightMeshVS(VertexShaderInput input)
{
    VertexShaderOutputMeshBased output = (VertexShaderOutputMeshBased)0;    
    output.Position = mul(input.Position, WorldViewProjection);

    //we will compute our texture coords based on pixel position further
    output.TexCoordScreenSpace = output.Position;
    return output;
}

float4 PointLightMeshShadowPS(VertexShaderOutputMeshBased input) : COLOR0
{
    // as we are using a sphere mesh, we need to recompute each pixel position 
    // into texture space coords
    float2 screenPos = 
        PostProjectionSpaceToScreenSpace(input.TexCoordScreenSpace) + GBufferPixelSize;

    // read the depth value
    float depthValue = tex2D(depthSampler, screenPos).r;

    // if depth value == 1, we can assume its a background value, so skip it
    // we need this only if we are using back-face culling on our light volumes. 
    // Otherwise, our z-buffer will reject this pixel anyway
    clip(-depthValue + 0.9999f);

    // Reconstruct position from the depth value, the FOV, aspect and pixel position
    depthValue *= FarClip;

    // convert screenPos to [-1..1] range
    float3 pos = float3(TanAspect*(screenPos*2 - 1)*depthValue, -depthValue);

    // light direction from current pixel to current light
    float3 lDir = LightPosition - pos;

    // compute attenuation, 1 - saturate(d2/r2)
    float atten = ComputeAttenuation(lDir);

    // Convert normal back with the decoding function
    float4 normalMap = tex2D(normalSampler, screenPos);
    float3 normal = DecodeNormal(normalMap);

    lDir = normalize(lDir);

    // N dot L lighting term, attenuated
    float nl = saturate(dot(normal, lDir))*atten;

    /* shadow stuff */

    float4 lightPosition = mul(mul(float4(pos,1),CameraTransform), LightViewProj);

    //float4 lightPosition = mul(float4(pos,1), LightViewProj);
    float posLength = length(lightPosition);
    lightPosition /= posLength;

    float ourdepth = (posLength - NearClip) / (FarClip - NearClip) - DepthBias;
    //float ourdepth = (lightPosition.z / lightPosition.w) - DepthBias;

    if(lightPosition.z > 0.0f)
    {
        float2 vTexFront;
        vTexFront.x =  (lightPosition.x /  (1.0f + lightPosition.z)) * 0.5f + 0.5f; 
        vTexFront.y =  1.0f - ((lightPosition.y /  (1.0f + lightPosition.z)) * 0.5f + 0.5f);    

        nl = ComputeShadow(FrontShadowMapSampler, nl, vTexFront, ourdepth);
    }
    else
    {
        // for the back the z has to be inverted        
        float2 vTexBack;
        vTexBack.x =  (lightPosition.x /  (1.0f - lightPosition.z)) * 0.5f + 0.5f; 
        vTexBack.y =  1.0f - ((lightPosition.y /  (1.0f - lightPosition.z)) * 0.5f + 0.5f); 

        nl = ComputeShadow(BackShadowMapSampler, nl, vTexBack, ourdepth);
    }

    /* shadow stuff */

    // reject pixels outside our radius or that are not facing the light
    clip(nl - 0.00001f);

    float4 finalColor;
    //As our position is relative to camera position, we dont need to use (ViewPosition - pos) here
    float3 camDir = normalize(pos);

    // Calculate specular term
    float3 h = normalize(reflect(lDir, normal));
    float spec = nl*pow(saturate(dot(camDir, h)), normalMap.b*100);
    finalColor = float4(LightColor * nl, spec);

    return finalColor * LightBufferScale;
}

và bạn nói rằng bản đồ bóng tối không có vấn đề gì / (ý tôi là nếu bạn ghi bản đồ bóng vào bản đồ họa thì chúng sẽ làm tối các điểm chính xác?)
Ali1S232

Bạn có chắc chắn 100% FOV của máy ảnh hiển thị từ vị trí của nguồn sáng là chính xác không?
Roy T.

Máy ảnh kết xuất từ ​​vị trí nguồn của ánh sáng không có ma trận chiếu, bởi vì phép chiếu được thực hiện thủ công để có độ cong paraboloid. Tôi sẽ kiểm tra mã đó, ý kiến ​​hay đấy Roy T.
Olhovsky

Gajet: "Ý tôi là nếu bạn ghi các bản đồ bóng vào bản đồ họa thì chúng sẽ làm tối các điểm chính xác?" Bản đồ bóng lưu trữ bóng trong không gian ánh sáng, nếu tôi nhìn vào bản đồ, không có cách nào dễ dàng để biết chắc chắn rằng chúng đúng vì tôi thấy chúng trong không gian màn hình. "Texturemap" là gì - ý bạn là một kết cấu? Bản đồ bóng kết cấu.
Olhovsky

Roy T.: Di chuyển ánh sáng xung quanh cho thấy bản đồ bóng bị cắt bớt, do đó, có một vấn đề với sự biến đổi khi thực sự sử dụng bóng, không chỉ khi tạo ra nó.
Olhovsky

Câu trả lời:


2

Với PIX, bạn có thể gỡ lỗi các pixel bị cô lập, có thể bạn tìm thấy lỗi theo cách này. FOV hoặc một lỗi chiếu là một gợi ý nóng. Hay bạn đã quên sự biến đổi thế giới?!


bạn cũng có thể thử gỡ lỗi với NVidia-fxComposer
Ali1S232

Tôi không nghĩ rằng việc nhìn chằm chằm vào các giá trị mã lắp ráp sẽ giúp tôi rất nhiều vào thời điểm này, bởi vì tôi gặp khó khăn trong việc hiểu cách chuyển đổi nên được thực hiện ngay từ đầu. Vì vậy, xem giá trị nào trong đăng ký 10, hoặc bất cứ nơi nào, sẽ không thực sự có ích.
Olhovsky

"Hoặc bạn đã quên sự biến đổi thế giới?!" Tôi thực sự đã quên áp dụng biến đổi thế giới khi tạo bản đồ bóng - doh! Điều này hoạt động bây giờ, để lại tất cả các shader như tôi đã có chúng.
Olhovsky

1

Này Olhovsky, câu hỏi thử thách hay. Tôi biết nỗi đau của bạn, tôi đã thực hiện Trì hoãn bóng mờ, Ánh sáng suy luận và bóng tối trong công việc cuối cùng của tôi. Đó thực sự là niềm vui lớn, nhưng cũng rất đau khi nó không hoạt động như mong đợi.

Tôi nghĩ rằng lời khuyên với PIX thực sự là một điều tốt. Bạn không cần phải lộn xộn với các hướng dẫn trình biên dịch của trình đổ bóng, nhưng bạn có thể nhìn vào bản đồ bóng và các mục tiêu kết xuất khác, chọn một pixel và gọi trình đổ bóng pixel của nó và bước qua nó và cả trình tạo bóng đỉnh của nó.

Thủ thuật gỡ lỗi chung cho loại tình huống này bao gồm đơn giản hóa hiện trường.

Một ý tưởng xuất hiện trong đầu tôi là: đặt máy ảnh ở cùng vị trí với nguồn sáng có cùng fovy và các thuộc tính khác như trong đèn chiếu sáng. Bây giờ bạn có thể dễ dàng so sánh các giá trị trong pixel-shader. Pixel-xy trong kết xuất đồ họa thông thường cho đối tượng hiện tại của bạn phải giống với pixel-xy được tính toán để tra cứu trong bóng tối, miễn là nó có cùng độ phân giải.

Một số khác là chuyển sang chiếu hình chính tả, đưa ra một cái gì đó dễ dàng, có thể dự đoán và kiểm tra được. Càng đơn giản, bạn càng có thể kiểm tra từng bước tính toán.

Ngoài ra, bạn có thể chỉ ra cách bạn tạo ma trận tính toán vị trí trong bản đồ bóng cho pixel hiện tại, đó là sự chuyển đổi từ không gian màn hình sang không gian ánh sáng?


Chỉ nhìn thấy bản đồ bóng là một Parabloid, điều đó khiến cho việc gỡ lỗi trở nên khó khăn hơn và ý tưởng đặt máy ảnh ở vị trí ánh sáng để so sánh vị trí và vị trí pixel hiện tại trong bản đồ bóng tối sẽ không hoạt động,
đừng bận tâm

Nếu bạn quan tâm, hãy gửi cho tôi một email tại kris@olhovsky.com và tôi sẽ trả lời với một bản sao dự án của tôi. Mặt khác: CameraTransformMa trận thực sự là ma trận thế giới của máy ảnh hiện đang xem cảnh. Các LightViewProjma trận thực sự chỉ là ma trận trên thế giới của ánh sáng, như ma trận điểm của ánh sáng chỉ là nhận dạng ma trận.
Olhovsky

Bạn có thể thực hiện một dự án C ++ đơn giản với nó không? Cũng cần có sự biến đổi parabloid phải không?
Maik ngày

Phép biến đổi paraboloid nằm trong pixel shader tôi liên kết trong câu hỏi. Các kỹ năng C ++ của tôi quá hạn chế để tạo ra một dự án C ++ nhanh chóng, gói gọn toàn bộ đường truyền kết xuất bị trì hoãn mà tôi nghĩ :) Tuy nhiên, nếu bạn thành thạo C ++, thì tôi nghĩ rằng không quá khó để đọc mã C # của tôi. Đặc biệt là vì hầu hết mối quan tâm thực sự nằm ở pixel shader, và có lẽ với các ma trận được truyền cho nó.
Olhovsky

Tôi đã tham khảo g_mDPView và g_mDPWorldView. Bạn có thể chỉ ra cách họ được tính toán.
Maik ngày
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.