Stable Diffusion ile Seamless Texture Üretimi: Oyun ve Web Tasarımı için Döngüsel Doku Oluşturma

Oyun geliştirme veya web tasarımı projelerinde çalışıyorsanız, seamless (dikişsiz) texture üretiminin ne kadar can sıkıcı bir süreç olduğunu iyi bilirsiniz. Photoshop’ta saatlerce uğraşmak, offset filtrelerle dokuyu kontrol etmek, kenarlardaki geçişleri elle düzeltmek… Stable Diffusion bu süreci kökten değiştiriyor. Doğru yapılandırılmış bir pipeline ile dakikalar içinde production-ready seamless texture’lar üretebilirsiniz.

Seamless Texture Nedir ve Neden Önemlidir

Bir texture’ın seamless olması, yani döngüsel olması demek; o dokuyu bir yüzeye tile ettiğinizde kenarların birbirine mükemmel şekilde geçmesi demektir. Oyun motorlarında (Unity, Unreal Engine) zemin kaplamaları, duvar yüzeyleri, kumaş veya taş dokuları için bu şart. Web tasarımında ise arkaplan pattern’leri için kritik.

Stable Diffusion’ın bu konuda sunduğu avantajlar:

  • Hız: Manuel Photoshop işlemine kıyasla 10-20 kat daha hızlı üretim
  • Çeşitlilik: Aynı stil içinde yüzlerce varyasyon
  • Kalite: 2K ve 4K çözünürlükte gerçekçi dokular
  • Kontrol: ControlNet ile tam stil yönetimi
  • Batch üretim: Scriptlerle toplu doku üretimi

Gereksinimler ve Kurulum

Öncelikle sisteminizin hazır olması gerekiyor. Bu rehber için AUTOMATIC1111 WebUI kullanacağız çünkü seamless texture özellikleri bu arayüzde en iyi şekilde destekleniyor.

Sistem Gereksinimleri

  • GPU: NVIDIA RTX 3060 veya üzeri (minimum 8GB VRAM)
  • RAM: 16GB sistem RAM
  • Disk: En az 20GB boş alan
  • İşletim Sistemi: Ubuntu 22.04 veya Windows 11

AUTOMATIC1111 Kurulumu (Ubuntu)

# Önce bağımlılıkları yükleyelim
sudo apt update && sudo apt install -y git python3-pip python3-venv wget curl

# CUDA toolkit kontrolü
nvidia-smi
nvcc --version

# AUTOMATIC1111'i klonlayalım
git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git
cd stable-diffusion-webui

# Python sanal ortamı oluştur
python3 -m venv venv
source venv/bin/activate

# Başlatma scripti ile ilk kurulum
./webui.sh --skip-torch-cuda-test

Model indirme işlemi için Hugging Face CLI kullanmak çok daha pratik:

# HuggingFace CLI kur
pip install huggingface_hub

# Realistic Vision v5.1 - genel amaçlı dokular için
huggingface-cli download --repo-type model 
  SG161222/Realistic_Vision_V5.1_noVAE 
  --local-dir models/Stable-diffusion/realistic_vision_v51

# DreamShaper XL - stylize dokular için
huggingface-cli download --repo-type model 
  Lykon/dreamshaper-xl-1-0 
  --local-dir models/Stable-diffusion/dreamshaper_xl

Tiled VAE ve ControlNet Kurulumu

Seamless texture üretimi için iki kritik extension gerekiyor:

cd stable-diffusion-webui

# Extensions klasörüne geç
cd extensions

# Tiled VAE (büyük çözünürlükler için şart)
git clone https://github.com/pkuliyi2015/multidiffusion-upscaler-for-automatic1111.git

# ControlNet (tile modeli için)
git clone https://github.com/Mikubill/sd-webui-controlnet.git

# Seamless Tiling extension
git clone https://github.com/scriptit/sd-seamless-tiling.git

# WebUI'yi yeniden başlat
cd ..
./webui.sh --xformers --enable-insecure-extension-access

Temel Seamless Texture Üretimi

Arayüz üzerinden çalışmak yerine API üzerinden otomatize etmek sysadmin mantığına daha uygun. AUTOMATIC1111’in REST API’sini kullanarak işi scriptleyelim.

API ile Temel Seamless Texture Üretimi

#!/usr/bin/env python3
# seamless_texture_gen.py - Temel seamless texture üretimi

import requests
import base64
import json
import os
from PIL import Image
import io

WEBUI_URL = "http://localhost:7860"

def generate_seamless_texture(
    prompt,
    negative_prompt="blurry, low quality, seam, edge artifact",
    width=1024,
    height=1024,
    steps=30,
    cfg_scale=7,
    output_dir="./textures"
):
    """
    Seamless texture üretimi için temel fonksiyon.
    Tiling parametresi kritik - her iki yönde de aktif olmalı.
    """
    
    payload = {
        "prompt": prompt,
        "negative_prompt": negative_prompt,
        "width": width,
        "height": height,
        "steps": steps,
        "cfg_scale": cfg_scale,
        "sampler_name": "DPM++ 2M Karras",
        # Seamless tiling için kritik parametre
        "tiling": True,
        "batch_size": 1,
        "n_iter": 1,
        "seed": -1,
        "restore_faces": False,
        "override_settings": {
            # VRAM optimizasyonu için
            "sd_vae_decode_method": "Full",
            "sd_vae_encode_method": "Full"
        }
    }
    
    response = requests.post(
        f"{WEBUI_URL}/sdapi/v1/txt2img",
        json=payload,
        timeout=120
    )
    
    if response.status_code != 200:
        raise Exception(f"API hatasi: {response.status_code} - {response.text}")
    
    result = response.json()
    
    os.makedirs(output_dir, exist_ok=True)
    
    for i, img_data in enumerate(result['images']):
        img_bytes = base64.b64decode(img_data)
        img = Image.open(io.BytesIO(img_bytes))
        
        # Dosya adını prompt'tan türet
        safe_name = prompt[:30].replace(" ", "_").replace(",", "")
        output_path = f"{output_dir}/{safe_name}_{i}.png"
        img.save(output_path, "PNG")
        print(f"Kaydedildi: {output_path}")
    
    return result

# Örnek kullanım
if __name__ == "__main__":
    textures = [
        "rough stone wall texture, medieval, photorealistic, 4k",
        "wet asphalt road texture, realistic, detailed",
        "oak wood planks texture, natural grain, high detail",
        "green moss covered ground texture, forest floor",
        "red brick wall texture, old weathered, realistic"
    ]
    
    for texture_prompt in textures:
        print(f"Uretiliyor: {texture_prompt[:40]}...")
        generate_seamless_texture(texture_prompt)

Toplu Üretim Script’i

Gerçek dünya senaryosunda bir oyun için onlarca doku üretmeniz gerekebilir. Bunu paralel işlemlerle hızlandıralım:

#!/bin/bash
# batch_texture_gen.sh - Toplu texture üretimi

WEBUI_URL="http://localhost:7860"
OUTPUT_DIR="/var/game-assets/textures/$(date +%Y%m%d)"
PYTHON_SCRIPT="/opt/sd-tools/seamless_texture_gen.py"
LOG_FILE="/var/log/texture_gen.log"

mkdir -p "$OUTPUT_DIR"

# Texture listesini dosyadan oku
TEXTURE_LIST="/opt/sd-tools/texture_prompts.txt"

echo "$(date): Batch texture uretimi basliyor" >> "$LOG_FILE"

# Her satir bir prompt
while IFS= read -r prompt; do
    # Bos satirlari atla
    [[ -z "$prompt" || "$prompt" == #* ]] && continue
    
    echo "Isleniyor: $prompt" | tee -a "$LOG_FILE"
    
    python3 "$PYTHON_SCRIPT" 
        --prompt "$prompt" 
        --output-dir "$OUTPUT_DIR" 
        --width 1024 
        --height 1024 
        --steps 30 
        2>> "$LOG_FILE"
    
    # Rate limiting - API'yi boğmamak için
    sleep 2
    
done < "$TEXTURE_LIST"

echo "$(date): Tamamlandi. Cikti: $OUTPUT_DIR" >> "$LOG_FILE"

# Sonuçları Slack'e bildir (opsiyonel)
if command -v curl &> /dev/null && [ -n "$SLACK_WEBHOOK" ]; then
    curl -s -X POST "$SLACK_WEBHOOK" 
        -H 'Content-type: application/json' 
        -d "{"text": "Texture batch tamamlandi: $OUTPUT_DIR"}"
fi

ControlNet ile Gelişmiş Seamless Texture

ControlNet’in tile modeli, mevcut bir texture’ı base alarak varyasyonlar üretmek için mükemmel. Özellikle bir referans texture’ınız varsa ve onu farklı stillere uyarlamak istiyorsanız:

#!/usr/bin/env python3
# controlnet_seamless.py - ControlNet tile ile gelismis texture uretimi

import requests
import base64
import json
from PIL import Image
import io
import os

WEBUI_URL = "http://localhost:7860"

def image_to_base64(image_path):
    """Gorsel dosyasini base64'e donustur"""
    with open(image_path, "rb") as f:
        return base64.b64encode(f.read()).decode("utf-8")

def generate_with_controlnet_tile(
    prompt,
    reference_image_path,
    output_dir="./textures/controlnet",
    steps=35,
    cfg_scale=8,
    controlnet_weight=0.8
):
    """
    ControlNet tile modeli ile referans-tabanli seamless texture uretimi.
    reference_image_path: Temel alinacak texture dosyasi
    controlnet_weight: 0.5-1.0 arasi, dusuk=daha fazla yaraticilik
    """
    
    ref_image_b64 = image_to_base64(reference_image_path)
    
    # Referans gorsel boyutunu al
    ref_img = Image.open(reference_image_path)
    width, height = ref_img.size
    
    payload = {
        "prompt": prompt,
        "negative_prompt": "low quality, blurry, distorted, seam visible",
        "width": width,
        "height": height,
        "steps": steps,
        "cfg_scale": cfg_scale,
        "sampler_name": "DPM++ 2M Karras",
        "tiling": True,
        "seed": -1,
        "alwayson_scripts": {
            "controlnet": {
                "args": [
                    {
                        "enabled": True,
                        "module": "tile_resample",
                        "model": "control_v11f1e_sd15_tile",
                        "weight": controlnet_weight,
                        "image": ref_image_b64,
                        "resize_mode": 1,
                        "lowvram": False,
                        "processor_res": 512,
                        "guidance_start": 0.0,
                        "guidance_end": 1.0,
                        "control_mode": 0,
                        "pixel_perfect": True
                    }
                ]
            }
        }
    }
    
    print(f"ControlNet tile ile isleniyor: {os.path.basename(reference_image_path)}")
    
    response = requests.post(
        f"{WEBUI_URL}/sdapi/v1/txt2img",
        json=payload,
        timeout=180
    )
    
    if response.status_code != 200:
        raise Exception(f"Hata: {response.status_code}")
    
    result = response.json()
    os.makedirs(output_dir, exist_ok=True)
    
    for i, img_data in enumerate(result['images'][:-1]):  # Son gorsel ControlNet preview
        img_bytes = base64.b64decode(img_data)
        img = Image.open(io.BytesIO(img_bytes))
        
        base_name = os.path.splitext(os.path.basename(reference_image_path))[0]
        output_path = f"{output_dir}/{base_name}_variant_{i}.png"
        img.save(output_path, "PNG")
        print(f"Kaydedildi: {output_path}")
    
    return output_dir

# Toplu varyasyon uretimi
if __name__ == "__main__":
    reference_textures = [
        ("/assets/base/stone_base.png", "granite stone texture, dark gray, photorealistic"),
        ("/assets/base/wood_base.png", "dark oak wood texture, rich grain, high detail"),
        ("/assets/base/grass_base.png", "summer meadow grass texture, bright green"),
    ]
    
    for ref_path, prompt in reference_textures:
        if os.path.exists(ref_path):
            generate_with_controlnet_tile(prompt, ref_path)
        else:
            print(f"Referans bulunamadi: {ref_path}")

Seamless Kalite Doğrulama

Üretilen texture’ların gerçekten seamless olup olmadığını doğrulamak şart. Göz kararı kontrol yerine otomatik doğrulama yapan bir script:

#!/usr/bin/env python3
# validate_seamless.py - Texture seamless kalite kontrolu

import numpy as np
from PIL import Image
import os
import sys
import glob

def check_seamless_quality(image_path, threshold=15.0):
    """
    Texture'in seamless kalitesini kontrol eder.
    
    Yontem: Sol-sag ve ust-alt kenar piksellerini karsilastir.
    threshold: Maksimum izin verilen ortalama piksel farki (0-255 skala)
    
    Doner: (bool, float) - gecti/kaldi, hata skoru
    """
    img = Image.open(image_path).convert("RGB")
    arr = np.array(img, dtype=np.float32)
    
    h, w, c = arr.shape
    border = max(2, min(10, h // 50))  # Dinamik kenar genisligi
    
    # Sol ve sag kenarlar
    left_edge = arr[:, :border, :]
    right_edge = arr[:, w-border:, :]
    
    # Ust ve alt kenarlar
    top_edge = arr[:border, :, :]
    bottom_edge = arr[h-border:, :, :]
    
    # Ortalama fark hesapla
    h_diff = np.mean(np.abs(left_edge - right_edge))
    v_diff = np.mean(np.abs(top_edge - bottom_edge))
    
    avg_diff = (h_diff + v_diff) / 2
    passed = avg_diff <= threshold
    
    return passed, avg_diff

def validate_texture_batch(texture_dir, output_report="./validation_report.txt"):
    """Bir dizindeki tum texture'lari dogrula ve rapor olustur"""
    
    texture_files = glob.glob(os.path.join(texture_dir, "*.png"))
    texture_files.extend(glob.glob(os.path.join(texture_dir, "*.jpg")))
    
    if not texture_files:
        print(f"Texture bulunamadi: {texture_dir}")
        return
    
    results = []
    passed_count = 0
    failed_count = 0
    
    for texture_path in sorted(texture_files):
        try:
            passed, score = check_seamless_quality(texture_path)
            status = "GECTI" if passed else "KALDI"
            
            if passed:
                passed_count += 1
            else:
                failed_count += 1
            
            result_line = f"{status} | Skor: {score:.2f} | {os.path.basename(texture_path)}"
            results.append(result_line)
            print(result_line)
            
        except Exception as e:
            error_line = f"HATA  | {os.path.basename(texture_path)}: {str(e)}"
            results.append(error_line)
            print(error_line)
    
    # Raporu kaydet
    with open(output_report, "w") as f:
        f.write(f"Texture Seamless Dogrulama Raporun")
        f.write(f"Toplam: {len(texture_files)} | Gecti: {passed_count} | Kaldi: {failed_count}n")
        f.write("=" * 60 + "n")
        f.write("n".join(results))
    
    print(f"nOzet: {passed_count}/{len(texture_files)} gecti")
    print(f"Rapor: {output_report}")

if __name__ == "__main__":
    texture_dir = sys.argv[1] if len(sys.argv) > 1 else "./textures"
    validate_texture_batch(texture_dir)

Otomatik Upscale Pipeline

Oyun projelerinde genellikle 2K veya 4K texture gerekiyor. 1024×1024 üretip sonra upscale etmek hem daha hızlı hem de daha kaliteli:

#!/bin/bash
# upscale_pipeline.sh - Texture upscale otomasyonu
# Real-ESRGAN kullanarak 4x upscale yapar

REALESRGAN_PATH="/opt/Real-ESRGAN"
INPUT_DIR="${1:-./textures}"
OUTPUT_DIR="${2:-./textures_4k}"
MODEL="${3:-realesrgan-x4plus}"  # veya realesrgan-x4plus-anime

# Real-ESRGAN kurulu mu kontrol et
if [ ! -f "$REALESRGAN_PATH/realesrgan-ncnn-vulkan" ]; then
    echo "Real-ESRGAN bulunamadi: $REALESRGAN_PATH"
    echo "Kurmak icin: https://github.com/xinntao/Real-ESRGAN/releases"
    exit 1
fi

mkdir -p "$OUTPUT_DIR"

echo "Upscale islemi basliyor..."
echo "Kaynak: $INPUT_DIR"
echo "Hedef: $OUTPUT_DIR (4x upscale)"

# Her PNG dosyasini isle
for texture in "$INPUT_DIR"/*.png; do
    [ -f "$texture" ] || continue
    
    filename=$(basename "$texture" .png)
    output_file="$OUTPUT_DIR/${filename}_4k.png"
    
    if [ -f "$output_file" ]; then
        echo "Atlanıyor (mevcut): $filename"
        continue
    fi
    
    echo "Upscale: $filename -> ${filename}_4k"
    
    "$REALESRGAN_PATH/realesrgan-ncnn-vulkan" 
        -i "$texture" 
        -o "$output_file" 
        -n "$MODEL" 
        -s 4 
        -f png 
        2>/dev/null
    
    if [ $? -eq 0 ]; then
        # Boyut bilgisini logla
        size=$(du -sh "$output_file" | cut -f1)
        echo "  Tamamlandi: $size"
    else
        echo "  HATA: $filename upscale basarisiz"
    fi
    
done

echo ""
echo "Tamamlandi. 4K textureler: $OUTPUT_DIR"
ls -lh "$OUTPUT_DIR" | tail -5

Systemd Service ile Otomatik Üretim

Stable Diffusion WebUI’yi her seferinde elle başlatmak yerine systemd service olarak konfigüre edin:

# /etc/systemd/system/stable-diffusion.service

[Unit]
Description=Stable Diffusion WebUI
After=network.target
Wants=network.target

[Service]
Type=simple
User=sduser
Group=sduser
WorkingDirectory=/home/sduser/stable-diffusion-webui

# CUDA ve Python path
Environment="PATH=/home/sduser/stable-diffusion-webui/venv/bin:/usr/local/cuda/bin:/usr/bin:/bin"
Environment="CUDA_VISIBLE_DEVICES=0"
Environment="PYTHONPATH=/home/sduser/stable-diffusion-webui"

# API modu ile baslat, xformers ile VRAM optimizasyonu
ExecStart=/home/sduser/stable-diffusion-webui/venv/bin/python launch.py 
    --api 
    --nowebui 
    --xformers 
    --medvram 
    --port 7860 
    --listen 
    --no-download-sd-model

Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal
SyslogIdentifier=stable-diffusion

# Kaynak limitleri
LimitNOFILE=65536
TimeoutStartSec=120

[Install]
WantedBy=multi-user.target

Service’i aktif edin:

# Service dosyasini yukle ve etkinlestir
sudo systemctl daemon-reload
sudo systemctl enable stable-diffusion
sudo systemctl start stable-diffusion

# Durum kontrolu
sudo systemctl status stable-diffusion

# Log takibi
sudo journalctl -u stable-diffusion -f

# API hazir mi test et
curl -s http://localhost:7860/sdapi/v1/progress | python3 -m json.tool

Gerçek Dünya Senaryosu: Oyun Projesi Asset Pipeline

Bir indie oyun stüdyosunda çalıştığınızı düşünün. Sanatçı ekibi her hafta yeni texture setleri istiyor. Bu pipeline’ı şöyle yapılandırabilirsiniz:

  • Pazartesi sabahı: Cron job ile haftalık texture batch’i otomatik başlar
  • Prompt dosyası: Git reposunda tutulur, sanatçılar PR ile günceller
  • Kalite kontrolü: Validation script başarısız texture’ları otomatik filtreler
  • Upscale: Başarılı texture’lar 4K’ya upscale edilir
  • Delivery: Sonuçlar NFS paylaşımına veya S3 bucket’a otomatik yüklenir
  • Bildirim: Slack webhook ile ekip bilgilendirilir

Bu akışta bir sanatçının manuel olarak yapacağı iş sadece prompt listesini güncellemek oluyor. Gerisi tamamen otomatize.

Prompt Mühendisliği İpuçları

Seamless texture için etkili prompt yapısı:

  • Materyal tipi: “rough stone”, “smooth marble”, “weathered wood”
  • Stil belirteci: “photorealistic”, “stylized”, “hand-painted”
  • Teknik terimler: “seamless texture”, “tileable pattern”, “no visible seams”
  • Kalite etiketleri: “4k”, “high detail”, “professional”, “game ready”
  • Negative prompt’ta şunlar şart: “seam, edge, border, frame, watermark, text”

Negative prompt genellikle şöyle bir template kullanın:

seam visible, edge artifact, border, frame, watermark, text, signature, 
blurry, low quality, jpeg artifacts, noise, grain, distorted, 
asymmetric pattern, obvious repeat, tile visible

Sonuç

Stable Diffusion ile seamless texture üretimi, doğru pipeline kurulduğunda gerçekten oyun değiştirici bir araç haline geliyor. AUTOMATIC1111’in tiling özelliği temel ihtiyacı karşılarken, ControlNet tile modeli referans bazlı varyasyonlar için devreye giriyor. Validation script’i ile kalite güvencesi, Real-ESRGAN ile upscale, systemd service ile sürekli çalışır durum ve cron ile otomasyon bir araya geldiğinde sysadmin perspektifinden baktığınızda bu bir texture fabrikasına dönüşüyor.

GPU maliyetlerini düşünürseniz: RTX 3080 ile saatte ortalama 200-300 adet 1024×1024 seamless texture üretebilirsiniz. Bunu harici bir texture satın alma maliyetiyle karşılaştırın. Kurulum zamanı ve model optimizasyonuna harcanan efor, orta büyüklükte bir projede bile kısa sürede kendini amorti ediyor.

Bir sonraki adım olarak LoRA eğitimine bakmanızı öneririm. Stüdyonuza veya projenize özel bir stil LoRA’sı eğitirseniz, tüm texture’larınız tutarlı bir sanatsal dile sahip olacak. Bu konu için ayrı bir yazı hazırlıyorum.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir