İlk kez gölge eşleme sorunları


9

Gölgelendiricileri kullanarak OpenGL'de ilk kez temel gölge haritalama uyguladım ve bazı sorunlarla karşılaşıyorum. Aşağıda, oluşturulan sahnemin bir örneğini görebilirsiniz:

resim açıklamasını buraya girin

Takip ettiğim gölge eşleme işlemi, ışığı bakış açısından bir Görünüm Matrisi ile normal oluşturma için kullanılan projeksiyon ve model matrislerini kullanarak sahneyi çerçeve arabelleğine oluşturmamdır.

İkinci geçişte, yukarıdaki MVP matrisini ışık bakış açısından, pozisyonu ışık boşluğuna dönüştüren köşe gölgelendiricisine gönderirim. Parça gölgelendirici perspektif bölünür ve konumu doku koordinatlarına değiştirir.

İşte tepe gölgelendiricim,


#version 150 core

uniform mat4 ModelViewMatrix;
uniform mat3 NormalMatrix;
uniform mat4 MVPMatrix;
uniform mat4 lightMVP;

uniform float scale;

in vec3 in_Position;
in vec3 in_Normal;
in vec2 in_TexCoord;

smooth out vec3 pass_Normal;
smooth out vec3 pass_Position;
smooth out vec2 TexCoord;
smooth out vec4 lightspace_Position;

void main(void){
    pass_Normal = NormalMatrix * in_Normal; 
    pass_Position = (ModelViewMatrix * vec4(scale * in_Position, 1.0)).xyz;
    lightspace_Position = lightMVP * vec4(scale * in_Position, 1.0);
    TexCoord = in_TexCoord;

    gl_Position = MVPMatrix * vec4(scale * in_Position, 1.0);
}

Ve parça gölgelendiricim,


#version 150 core

struct Light{
    vec3 direction;
};

uniform Light light;
uniform sampler2D inSampler;
uniform sampler2D inShadowMap;

smooth in vec3 pass_Normal;
smooth in vec3 pass_Position;
smooth in vec2 TexCoord;
smooth in vec4 lightspace_Position;

out vec4 out_Color;


float CalcShadowFactor(vec4 lightspace_Position){

    vec3 ProjectionCoords = lightspace_Position.xyz / lightspace_Position.w;

    vec2 UVCoords;
    UVCoords.x = 0.5 * ProjectionCoords.x + 0.5;
    UVCoords.y = 0.5 * ProjectionCoords.y + 0.5;

    float Depth = texture(inShadowMap, UVCoords).x;
    if(Depth < (ProjectionCoords.z + 0.001)) return 0.5;
    else return 1.0;
}

void main(void){

    vec3 Normal = normalize(pass_Normal);
    vec3 light_Direction = -normalize(light.direction);
    vec3 camera_Direction = normalize(-pass_Position);
    vec3 half_vector = normalize(camera_Direction + light_Direction);

    float diffuse = max(0.2, dot(Normal, light_Direction));
    vec3 temp_Color = diffuse * vec3(1.0);

    float specular = max( 0.0, dot( Normal, half_vector) );

    float shadowFactor = CalcShadowFactor(lightspace_Position);

    if(diffuse != 0 && shadowFactor > 0.5){
        float fspecular = pow(specular, 128.0);
        temp_Color += fspecular;
    }

    out_Color = vec4(shadowFactor * texture(inSampler, TexCoord).xyz * temp_Color, 1.0);
}

Sorunlardan biri resimde gördüğünüz gibi kendi kendine gölgeleme, sandığın kendi üzerine kendi gölge atması var. Ne denedim çokgen ofset (yani glEnable (POLYGON_OFFSET_FILL), glPolygonOffset (GLfloat, GLfloat)) etkinleştirmek ama çok değişmedi. Parça gölgelendiricide gördüğünüz gibi, 0.001 statik ofset değerini koydum, ancak çok kullanışlı olmayan daha arzu edilen efektler elde etmek için ışığın mesafesine bağlı olarak değeri değiştirmek zorundayım. Ayrıca çerçeveciye dönüştürdüğümde ön yüz toplama kullanmayı denedim, bu çok fazla değişmedi.

Diğer sorun, Işığın görüş frustumunun dışındaki piksellerin gölgeli olması. Gölgeleme yapabilmesi gereken tek nesne sandıktır. Sanırım daha uygun projeksiyon seçmeli ve matrisleri görüntülemeliyim, ama bunu nasıl yapacağımdan emin değilim. Ortografik bir projeksiyon seçmem gereken bazı yaygın uygulamalar nelerdir?

Biraz dolaşmaktan, bu sorunların o kadar da önemsiz olmadığını anlıyorum. Herkes bu sorunlara uygulamak kolay çözüm var mı? Bana bazı ek ipuçları verebilir misiniz?

Kodum hakkında daha fazla bilgiye ihtiyacınız olup olmadığını lütfen bana sorun.

İşte sandığın yakın planının gölge eşlemeli ve eşlemesiz karşılaştırması. Kendi kendine gölgeleme daha görünür.


Sorunlarınızı daha ayrıntılı olarak açıklamanız gerekir. Sorunlarınızla ilgili bir cümleniz var ve bir sonraki cümle bir tane için düzeltmeyi öneriyor. Sorunların tam olarak ne olduğunu ve bunu düzeltmek için zaten ne yaptığınızı bize bildirin .
MichaelHouse

Yazımı düzenledim, umarım şimdi daha iyidir.
Grieverheart

Yanıtlar:


6

Işığın karşı karşıya olduğu çokgenleri gölgelememelisiniz.

Parça gölgelendiricinizi aşağıdaki kodla değiştirdim.

float CalcShadowFactor(vec4 lightspace_Position)
{

    vec3 ProjectionCoords = lightspace_Position.xyz / lightspace_Position.w;

    vec2 UVCoords;
    UVCoords.x = 0.5 * ProjectionCoords.x + 0.5;
    UVCoords.y = 0.5 * ProjectionCoords.y + 0.5;

    float Depth = texture(inShadowMap, UVCoords).x;
    if(Depth < (ProjectionCoords.z + 0.001)) return 0.5;
    else return 1.0;
}

void main(void)
{

    vec3 Normal = normalize(pass_Normal);
    vec3 light_Direction = -normalize(light.direction);
    vec3 camera_Direction = normalize(-pass_Position);
    vec3 half_vector = normalize(camera_Direction + light_Direction);

    float fndotl = dot(Normal, light_Direction);
    float shadowFactor = CalcShadowFactor(lightspace_Position);
    float diffuse = max(0.0, fndotl) * shadowFactor + 0.2;
    vec3 temp_Color = vec3(diffuse);

    float specular = max( 0.0, dot( Normal, half_vector) );

    if(shadowFactor > 0.9){
        float fspecular = pow(specular, 128.0);
        temp_Color += fspecular;
    }

    out_Color = vec4(shadowFactor * texture(inSampler, TexCoord).xyz * temp_Color, 1.0);
}

8

Kendi kendine gölgeleme ile ilgili olarak, sadece neyi kastettiğinizden emin değilim - ekran görüntünüzdeki sandıkta herhangi bir "gölge akne" görmüyorum. Işıktan uzağa bakan yüzlerin karanlık olduğunu kastediyorsanız, elbette öyleler - olmalılar! :) Yan yüz biraz tuhaf görünüyor, diyagonal aşağı yarı aydınlık ve yarı gölgeli bölünmüş. Aydınlatma için N nokta L kullanıyorsanız ve olmaması gereken iyi normaller (yani bu küp üzerinde sert normaller) var.

Çokgen ofsetinin kullanılması ve / veya arka yüzlerin gölge haritasına çizilmesi, gölge akne için standart çözümlerdir (gerçekten ... geçici çözümler).

Projeksiyon matrisine gelince, ışığı bir kamera olarak düşünmelisiniz. Eğer bir nokta ışığı, bir perspektif kamera ve yön ışığı ise bir ortografik kamera gibi olurdu. Projeksiyon matrisini, ışığın görüş alanını, en boy oranını vb. Kullanarak bir kamera için yaptığınız gibi yapılandırın.

Piksel gölgelendiriciyi pikselleri yalnızca ışığın görünüm frustumunda çizecek şekilde sınırlamak için, gölge haritası UV'lerini hesapladıktan sonra, sadece 0 ile 1 arasında olup olmadığını kontrol edin ve discarddeğilse (veya ışığın rengini sıfıra ayarlayın). Başka bir yol, gölge haritası dokusunu "kenarlığa kenetleme" moduna ayarlamak ve sıfır kenarlık rengini ayarlamaktır, bu da gölge haritasının dışındaki her şeyin tamamen gölgelenmesini sağlar.


İşte kutunun bir closeup ve gölge eşleme bağlantısı olan ve olmayan karşılaştırma . Kendinden gölgeleme burada daha görünür. Nokta ışıkları için neden bir perspektif kamera, yön için ise ortografik kullanmak istediğinizi açıklayabilir misiniz?
Grieverheart

Tamam, bu çekimde gölge sivilce gibi görünüyor. Yüzleri gölge haritasına (ön yüzlere değil) geri çekmek bunu düzeltmelidir. Bunu denediğini söylediğini biliyorum, ama belki bir şeyler ters gitti? Sadece glCullFace(GL_FRONT). Noktaya karşı yöne gelince, her şey ışınlarla ilgilidir. Kamera ışınları bir perspektif kameradaki bir noktaya yakınsamakta ve ışık ışınları bir nokta ışıktaki bir noktaya yaklaşmaktadır; kamera ışınları bir ortografik kamera için paraleldir ve ışık ışınları yönlü bir ışık için paraleldir.
Nathan Reed

Anlıyorum. Burada ile ve yüz itlaf olmadan başka karşılaştırmadır. Alt kısımda yüz kaldırma özelliği etkin. Işık görüntüleme matrisim için kendi kendine gölgeleme problemini etkilememesi gereken ortografik projeksiyon kullanmaya çalışacağım, değil mi? Belki klip aralığım çok büyük (yani 0,1 ila 100 arası)?
Grieverheart

Bunlar tamamen aynı görünüyor. Sahnenin geri kalanı için arka yüz toplama kullanıyorsunuz, değil mi? Yaptın mı glEnable(GL_CULL_FACE)?
Nathan Reed

Tam olarak aynı değiller, kutuya yakından bakın. Yukarıdaki resimde gölge çizgisi dışbükeyken, alttaki çizgi içbükeydir.
Grieverheart

3

Işıklar görünümünün dışındaki pikseller karanlıktır, çünkü ışık derinliği dokusunun dışından örneklenirler.

Tepe noktasını projeksiyon matrisi ile dönüştürdüğünüzde parçanın klip koordinatlarını [lightspace_Position] alırsınız. Daha sonra bunu doku koordinatlarına dönüştürüyorsunuz [UVCoords]. Bununla birlikte, bir parçanın klip alanı koordinatları yine de -1.0 ila 1.0 aralığının dışında (ekran dışı ve dolayısıyla kırpılmış) olabilir ve bu nedenle dönüştürülen doku koordinatları, dokunuzun 0.0 ila 1.0 aralığının dışında olabilir.

Bunu dene:

if(UVCoords.x >= 0.0 && UVCoords.x <= 1.0 && UVCoords.y >= 0.0 && UVCoords.y <= 1.0 && (Depth < (ProjectionCoords.z + 0.001)))
    return 0.5;

Ayrıca bir yanlılık matrisini [lightMVP] cihazınızla çarpabilir ve parça gölgelendiricinizde koordinat dönüşümü yapmaktan kaçınabilirsiniz.


Önyargı matrisi genellikle insanların gittiği yoldur. Bir fragman gölgesindeki dallanma kodundan çok daha hızlıdır.
Ian Young
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.