Render Reference - Stencils

Render Kütüphanesi Referansları

Bu sayfa, Render Kütüphanesini belgelemeye adanmış bir dizi sayfadan oluşan Render Referansının bir parçasıdır.

Diğer Render Referansları sayfaları şunlardır:

Giriş

Şablonlar hakkında bilgi edinmeden önce, Render Hedefleri hakkında temel bilgilere sahip olmanızda fayda vardır. Uzman olmanız gerekmez, ancak temel bilgileri anlamak bu sayfadaki her şeyi daha kolay takip etmenizi sağlayacaktır.

Ayrıca, bu kılavuzda sık sık byte kelimesini, 0 ve 255arasındaki bir tamsayıyı ifade etmek için kullanacağız. Bu, 8 bitlik bir veriyi temsil eder. Lua bu terimi özel olarak kullanmasa da, programlamada yaygın bir kavramdır, bu yüzden işleri basitleştirmek için kullanıyoruz.

Şablonlar nedir?

Şablonlar, Render Hedefleri üzerindeki çizim işlemlerini piksel bazında kontrol etmenizi (veya "maskelemenizi") sağlayan bir sistemdir. Render Hedefine (ana oyun
görünümü gibi) bir şey çizildiğinde, Şablon sistemi değiştirilmek üzere olan her piksel için mantıksal kontroller (bunları daha sonra ele alacağız) gerçekleştirir. Ardından, o pikselin çizim işlemiyle güncellenmesi mi yoksa olduğu gibi bırakılması mı gerektiğine karar verir.

Şablonlar genellikle 3D efektler için kullanılır, ancak bunların tamamen 2D olarak çalıştığını anlamak önemlidir. Şablonlar 2D piksellerle çalışır ve 3D nesnelerle yalnızca bu nesneler 2D Render Hedefine çizildiğinde (veya "rasterize edildiğinde") etkileşime girer.

Şablonlar Ne İçin Kullanılır?

Şablonlar, aşağıdakiler dahil olmak üzere her türlü yaratıcı efekt için kullanılmıştır:

  • İçeriden dışarıdan daha büyük görünen imkansız odalar.
  • Oyuncuların içinden görebildiği kurşun delikleri.
  • Başlangıçta penceresi olmayan duvarlara pencere eklemek.
  • Portal oyunundaki gibi portallar

Şablon Sisteminin Parçaları Nelerdir?

Bu Bölümü Okuma

Aşağıdaki bölümde, kullanılabilir Stencil işlevleri, işlemleri ve kavramları, çizim işlemi sırasında yürütüldükleri sırayla tanımlanmakta ve açıklanmaktadır. Çizim işleminden
etkilenen her piksel, diğer piksellerden bağımsız olarak, tam olarak aynı mantığa tabidir.
Bu bölümü, for etkilenen her piksel üzerinde yinelenen bir döngü olarak düşünebilirsiniz. Bir pikselin bu mantıkta izleyebileceği üç (3) olası yol vardır
. Her yolun sonunda, döngü bir sonraki piksele devam eder. Döngünün hangi noktasında
olduğumuza dair notlar for gösterilecektir [In this Format]

Şablon Sisteminin Parçaları

[Prior to the draw operation]

  • Şablon Tamponu, ait olduğu Render Hedefi üzerindeki her bir piksel için bir byte (Burada "Şablon değeri" veya "Şablon Tamponu değeri" olarak adlandırılır) tutar.
    • Varsayılan olarak, her pikselin Stencil değeri 0.
  • Referans Değeri, byte Şablon Tamponu değerlerinin karşılaştırıldığı bir değerdir.

Bir çizim işlemi gerçekleştirildiğinde, etkilenen her pikselin Stencil Tampon değeri Referans Değeri ile karşılaştırılır.

[A draw operation has just been executed]
[At this point, the Stencil configuration cannot be changed.]
[This is the start of the loop that iterates over the pixels affected by the draw operation]

Bir pikselin Karşılaştırma İşlevini Geçip Geçmediğine bağlı olarak, değeri mevcut Stencil yapılandırmasına bağlı olarak potansiyel olarak değiştirilebilir.

  • İşlemler , belirli bir pikselin Geçti veya Kaldı durumuna bağlı olarak Stencil Tampon değerini değiştirir. İşlemler arasında mevcut değeri bir (1) artırmak, mevcut değeri Referans Değeri ile değiştirmek, hiçbir değişiklik yapmamak ve diğerleri bulunur. Olası
    İşlemlerin tam listesi burada bulunabilir
  • Yazma Maskesi byte Stencil Tamponuna yazılmadan önce tüm değerlerle bitwise AND işlemi uygulanacak bir maske.
    • Varsayılan olarak, Yazma Maskesi yazılan değerlerde herhangi bir değişiklik yapmayacak şekilde ayarlanmıştır.
  • Başarısız İşlem , Karşılaştırma İşlevini Geçemeyen pikseller üzerinde gerçekleştirilir.
    [This pixel is done and the next one can be processed.]

Karşılaştırma İşlevini geçen pikseller için, çizim işlemiyle değiştirilmeden önce geçmeleri gereken ek bir kontrol daha vardır.

  • Derinlik Testi (veya "Z testi"), pikselin mevcut Derinlik Tamponu değerini çizim işleminin Derinlik değeriyle karşılaştırır.

Karşılaştırma İşlevi'nden farklı olarak, bu karşılaştırma sabittir ve yapılandırılamaz.

  • Z Başarısız İşlemi , mevcut Derinlik Tamponu değeri çizim işleminin önerilen derinlik değerinden düşük olan pikseller için Şablon Tamponu üzerinde gerçekleştirilir. Bu, çizim işleminin mevcut pikselin arkasında çizildiği için bu pikselde görünmemesi gerektiğini gösterir.
    [The next pixel can be processed.]

Bir piksel hem Karşılaştırma İşlevi hem de Derinlik Testini geçerse, Geçti olarak kabul edilir ve içeriği çizim işlemiyle değiştirilir/düzenlenir. Bu, pikselin Renk, Derinlik ve Şablon Tamponu değerlerini etkiler.

  • Geçiş İşlemi , Karşılaştırma İşlevi ve Derinlik Testini geçen ve çizim işlemi tarafından güncellenen pikseller için Şablon Tamponunda gerçekleştirilir.
    [The next pixel can be processed.]

Aşağıdaki akış şeması, anlaşılmasını kolaylaştırmak için yukarıdaki metinle aynı bilgileri özetlemektedir.

Bu Parçalar Ne Yapmak İçin Kullanılabilir?

Yaygın Kullanım Modeli

Pratik uygulamalarda, Stenciler aşağıdaki şekilde kullanılır:

  1. Şablon sistemini yapılandırın
  2. Şablon Tampon değerlerini ayarlamak için çizim işlemleri gerçekleştirin
  3. Şablon sistemini yeniden yapılandırın
  4. 1-2. adımlardaki Stencil Tampon değerleri ile maskelenen çizim işlemlerini gerçekleştirin

Stencil Tamponunu tek bir geçişle yapılandırılamayacak şekilde yapılandırmak için 1-2. adımların ve 3-4. adımların birden çok kez tekrarlanması oldukça yaygındır (buna "geçiş" denir ve bir pikselin başarılı/başarısız durumunu belirtmek için kullanılan terimle karıştırılmamalıdır).

Örnek: Basit 2D Maskeleme

Bu örnek, yukarıda özetlenen Yaygın Kullanım Desenini izleyen 2D içerik üzerinde basit bir maskeleme işlemini göstermektedir.

  • İlk olarak, Stencil sistemini, kullanmadığımız parçalar da dahil olmak üzere yapılandıracağız, çünkü diğer eklentilerin Stencil sistemini kullandıklarında kendi arkalarını temizleyeceklerine güvenemiyoruz ve onların yapılandırmalarının sonuçlarımızı etkilemesini istemiyoruz.
  • Ardından, ekrana hiçbir şey çizmeden, çizmek istediğimiz piksellerin Stencil Tampon değerlerini değiştirecek bir çizim işlemi gerçekleştirerek maskemizi oluşturacağız.
  • Sonra, yeni oluşturduğumuz maskeyi bozmak istemediğimiz için, çizim işlemleri sırasında Stencil Tamponunu değiştirmeyi durdurmak üzere Stencil sistemini yeniden yapılandıracağız.
  • Son olarak, Stencil Tamponundaki değerlerle maskelenmiş olarak, ekranda görüntülemek istediğimiz içeriği çizeceğiz.
local COLOR_BLACK = Color( 0, 0, 0 ) local COLOR_BLUE = Color( 34, 19, 233 ) local MATERIAL_COLOR = Material( "color" ) -- Maskemizi oluşturmak için kullanılacak bir çizim işlemi gerçekleştirir. -- Bu, kanca kodunun okunmasını kolaylaştırmak için ayrı bir işlevdir. local function DrawMask() -- Bu rengi veya malzemeyi ayarlamamız yeterlidir, böylece tamamen şeffaf bir şekil çizmediğimizden emin olabiliriz. -- Şeffaf bir şekil çizilirse, pikseller etkilenmez ve bu da maskenin oluşturulmasını engeller. -- maskenin oluşturulmasını engelleyecektir. surface.SetDrawColor( COLOR_BLACK ) surface.SetMaterial( MATERIAL_COLOR ) -- Maskeyi çizin. surface.DrawTexturedRectRotated( -- Ekranın ortasına yerleştirin. ScrW()/2, ScrH()/2, -- Boyutunu ekran boyutuna göre ayarlayın ScrW()/4, ScrH()/4, -- Mevcut zamana göre döndürün CurTime() * 100 ) end -- Stencils ile maskeleyeceğimiz bir çizim işlemi gerçekleştirir. -- Bu, kanca kodunun okunmasını kolaylaştırmak için ayrı bir işlevdir. local function DrawContent() -- Bu sefer, seçtiğimiz renk görsel olarak önemlidir. surface.SetDrawColor( COLOR_BLUE ) surface.SetMaterial( MATERIAL_COLOR ) -- İçeriği çizer. -- Bu, daire şeklinde hareket eden ve saat yönünün tersine/saat yönünde dönen bir dikdörtgendir. surface.DrawTexturedRectRotated( -- Maskelemeyi daha net görebilmemiz için ekranın ortasında zıplar. ScrW()/2 + math.sin( CurTime() * 4 ) * ScrH()/8, ScrH()/2 + math.cos( CurTime() * 4 ) * ScrH()/8, -- Boyutunu ekran boyutuna göre ayarlayın ScrW()/4, ScrH()/4, -- Maskenin ters yönünde dönmesini sağlayın. CurTime() * 100 * -1 ) end hook.Add( "HUDPaint", "StencilExampleHud", function() -- Maske katmanını görmek istiyorsanız, bu satırı yorumlayabilirsiniz. render.SetStencilEnable( true ) -- Öncelikle, şu anda kullanmadığımız Stencil sisteminin parçalarını yapılandırarak, yaptığımız işe etki etmeyeceklerinden emin olalım. ------ Tüm piksellerin Stencil değeri 0 olan bir Stencil Tamponu ile başladığımızdan emin olun. render.ClearStencil() ------ 255, tüm bitlerin 1 (11111111) olduğu 8 bit (1 bayt) değerine karşılık gelir ve bu, hiçbir şeyi değiştirmeyecek bir bit maskesidir. render.SetStencilTestMask( 255 ) render.SetStencilWriteMask( 255 ) ------ Bir piksel tamamen geçerse veya derinlik testinde başarısız olursa, Stencil Tampon değerini değiştirmeyin ------ (mevcut değeri KORUYUN) render.SetStencilPassOperation( STENCILOPERATION_KEEP ) render.SetStencilZFailOperation( STENCILOPERATION_KEEP ) -- Şimdi, kullanacağımız Stencil sisteminin parçalarını yapılandıralım ------ Bir maske oluşturuyoruz, bu yüzden şu anda yaptığımız hiçbir şeyin ekrana çizilmesini istemiyoruz ------ Tüm pikseller Karşılaştırma İşlevini geçmemelidir (ASLA geçmemelidir). render.SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_NEVER ) ------ Bir piksel geçemediğinde, ki hepsi geçmemelidir, mevcut Stencil değerini ------ Referans Değeri ne olursa olsun ------ Bunun için istediğimiz Referans Değeri'ni kullanabiliriz; bunların özel bir anlamı yoktur. render.SetStencilReferenceValue( 9 ) render.SetStencilFailOperation( STENCILOPERATION_REPLACE ) -- Bu noktada, maskemizi oluşturmak için çizim işlemlerini gerçekleştirmeye hazırız. DrawMask() -- Şimdi, az önce oluşturduğumuz maskeyi kullanabilmemiz için Stencil sistemini yeniden yapılandırmamız gerekiyor. ------ Pass ve Z Failure işlemlerinde olduğu gibi, bir piksel ------ Karşılaştırma İşlevinde başarısız olursa Stencil Tamponunu değiştirmek istemiyoruz, çünkü bu maskeyi değiştirecektir. render.SetStencilFailOperation( STENCILOPERATION_KEEP ) ------ Referans Değeri ile eşleşen (EŞİT olan) pikselleri geçirmek (ve dolayısıyla çizmek) istiyoruz. render.SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_EQUAL ) -- Sonunda maskelemek istediğimiz içeriği çizmeye hazırız. DrawContent() render.SetStencilEnable( false ) end )
Çıktı:
Yukarıdaki klipte neler olduğunu görselleştirmemize yardımcı olmak için, aşağıdaki videoda Stencil sistemini etkinleştiren satırı yorumladım, böylece hem maskeyi (siyah) hem de içeriği (mavi) aynı anda görebiliriz.

Örnek: İmkansız Bir Alan Oluşturmak

Bu örnek, Stencil'lerin yaygın olarak kullanıldığı alanlardan birini göstermektedir: İmkansız alanlar (aynı zamanda "içeriden daha büyük" veya "Öklid dışı geometri" olarak da adlandırılır)

Temel kavram şudur:

  • İmkansız alanın dışını çizin.
    • Başka bir boyuta açılan bir kapı yapıyorsanız, bu, efekti yerleştireceğiniz kapı çerçevesi olacaktır.
  • Efekti görmek istediğiniz açıklığın boyut ve şekline uygun bir maske oluşturun.
    • Bir kapı söz konusu olduğunda, bu kapının boyut ve şekline sahip bir şey olacaktır.
    • Dörtgenler, standart bir özellik olarak arka yüz kesme özelliğine sahip oldukları için bu rol için kolay bir seçimdir.
  • Daha önce oluşturduğumuz maskeyi kullanarak iç alanı (iç kısımdaki daha büyük olan) çizin.
    • Aşağıdaki örnekte iç alan kısa bir tüneldir, ancak bu herhangi bir şey olabilir.
    • İlginç bilgi: Portal oyunundaki portallarda bu, bir "iç" alan değil, karşı portaldan dışarıya bakan bir manzaraydı.
AddCSLuaFile() DEFINE_BASECLASS( "base_anim" ) ENT.PrintName = "İmkansız Geometri" ENT.Category = "Eğlence + Oyunlar" -- Son olarak renderlandığı için yarı saydam render grubunu kullanmamız önemlidir. -- Bunun yerine opak kullanırsak, yarı saydam nesneler imkansız geometrinin üzerine çizilir -- ve efekt bozulur. ENT.RenderGroup = RENDERGROUP_TRANSLUCENT ENT.Spawnable = true ENT.AdminOnly = false if SERVER then function ENT:Initialize() self:SetModel( "models/props_phx/construct/metal_plate1.mdl" ) self:PhysicsInit( SOLID_VPHYSICS ) self:SetMoveType( MOVETYPE_VPHYSICS ) self:SetSolid( SOLID_VPHYSICS ) local phys = self:GetPhysicsObject() if phys:IsValid() then phys:Wake() end end end if CLIENT then local COLOR_BLACK = Color( 0, 0, 0 ) -- Açıklık maskesinin boyutu local OPENING_WIDTH = 20 local OPENING_HEIGHT = 20 -- Açıklık maskesinin varlığın merkezinden ne kadar uzağa yerleştirileceği local OPENING_DEPTH = 3.2 function ENT:OnRemove( isFullUpdate ) -- İstemci tarafı modellerinin manuel olarak kaldırılması gerekir if self.clientsideModel and IsValid( self.clientsideModel ) then self.clientsideModel:Remove() end end function ENT:Initialize() -- Bu istemci tarafı modelini, varlığın içini çizmek için kullanacağız. self.clientsideModel = ClientsideModel( "models/props_phx/construct/metal_plate1.mdl", RENDERGROUP_OPAQUE ) self.clientsideModel:SetNoDraw( true ) end -- Sadece bir kolaylık işlevi. Bununla -- render.DrawModel() arasındaki temel fark, bunun el fenerlerini de render etmesidir. function ENT:DrawClientsideModel( model, pos, angles ) self.clientsideModel:SetModel( model ) self.clientsideModel:SetPos( pos ) self.clientsideModel:SetAngles( angles ) self.clientsideModel:DrawModel() render.RenderFlashlights( function() self.clientsideModel:DrawModel() end ) end function ENT:DrawInterior() local interiorAngles = self:GetAngles() local interiorPos = self:LocalToWorld( Vector( 0, 0, -44.3 ) ) -- Tesadüfen, bu iki modelin kökenleri uyumlu olduğundan, onları aynı konum ve açıda sorunsuz bir şekilde çizebiliriz. Bu, diğer modellerde her zaman geçerli olmayabilir. self:DrawClientsideModel( "models/props_phx/construct/metal_tube.mdl", interiorPos, interiorAngles ) self:DrawClientsideModel( "models/props_phx/construct/metal_plate1.mdl", interiorPos, interiorAngles ) end -- Açıklık maskesi, varlıktan uzak olan tek bir dörtgendir. function ENT:DrawOpeningMask() render.SetColorMaterial() render.DrawQuad( self:LocalToWorld( Vector( OPENING_WIDTH, OPENING_HEIGHT, OPENING_DEPTH ) ), self:LocalToWorld( Vector( OPENING_WIDTH, -OPENING_HEIGHT, OPENING_DEPTH ) ), self:LocalToWorld( Vector( -OPENING_WIDTH, -OPENING_HEIGHT, OPENING_DEPTH ) ), self:LocalToWorld( Vector( -OPENING_WIDTH, OPENING_HEIGHT, OPENING_DEPTH ) ), COLOR_BLACK ) end function ENT:Draw() self:DrawModel() -- Halo sistemi de Stencils kullanır, bu yüzden çizim yaparken bunlarla uğraşmamak için nazik davranacağız -- Bunu yapmazsak, Halo sistemi bozulur ve varlık physgun ile yakalandığında tüm ekran çok rahatsız edici bir şekilde yanıp söner. -- local isDrawingHalo = halo.RenderedEntity() == self if isDrawingHalo then return end -- Stencil sistemini, sorun yaratmayacağını bildiğimiz değerlere sıfırlayalım. render.ClearStencil() render.SetStencilWriteMask( 255 ) render.SetStencilTestMask( 255 ) render.SetStencilPassOperation( STENCILOPERATION_KEEP ) render.SetStencilZFailOperation( STENCILOPERATION_KEEP ) render.SetStencilEnable( true ) -- Açma maskesini temsil eden değer olarak Stencil Tampon değeri 1'i kullanacağız render.SetStencilReferenceValue( 1 ) -- Şu anda sadece Derinlik Testi ile ilgileniyoruz, bu yüzden karşılaştırma fonksiyonuyla uğraşmayın. render.SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_ALWAYS ) -- Açma maskesini oluşturmaya başlayın. render.SetStencilPassOperation( STENCILOPERATION_REPLACE ) -- Burada, bir dörtgenin sadece önden bakıldığında çizildiğine güveniyoruz. -- Arkadan bakıldığında ise hiç çizilmez. Buna "arka yüz eleme" denir ve -- bu olmadan, iç kısım arkadan bakıldığında bile varlığın üzerine çizilir. self:DrawOpeningMask() -- Maske oluşturulduktan sonra değiştirmeyin. render.SetStencilFailOperation( STENCILOPERATION_KEEP ) -- Artık sadece maskenin ayarlandığı yerleri çizmek istiyoruz (Stencil Tampon değerleri Referans Değeri ile eşleşir). render.SetStencilCompareFunction( STENCILCOMPARISONFUNCTION_EQUAL ) -- Maskeli piksellerdeki Derinlik Tamponunu temizleyin -- Aksi takdirde, varlığın pikselleri ve arkasındaki tüm yüzeyler her zaman iç kısmın önünde olacak ve bu nedenle iç kısım asla çizilmeyecektir. -- render.ClearBuffersObeyStencil( 0, 0, 0, 255, true ) render.ClearBuffersObeyStencil( 0, 0, 0, 255, true ) self:DrawInterior() render.SetStencilEnable( false ) end end
Çıktı: Aşağıdaki gif şunu göstermektedir:
  • İmkansız alana açılan açıklığın maskesi

  • Açıklığın "içine" yerleştirmek istediğimiz iç alan

  • Sadece açıklığın olduğu yerde çizilmek üzere maskelenmiş iç mekan

  • Çizilen varlık ile maskeli iç mekan

Tüm sunucular · GmodTR Launcher · Rehber · GMod Wiki · GmodTR nedir? · Sunucu ekle · Discord