Compare commits
5 Commits
2025-11-16
...
dff5d6fab2
| Author | SHA1 | Date | |
|---|---|---|---|
| dff5d6fab2 | |||
| ef37a7a2e6 | |||
| 8d42d5741f | |||
| f18d6143d1 | |||
| 0a03509323 |
86
CLAUDE.md
86
CLAUDE.md
@@ -4,7 +4,16 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||||||
|
|
||||||
## Project Overview
|
## Project Overview
|
||||||
|
|
||||||
This is a cross-platform Shadertoy-like fragment shader viewer built with SDL3 + OpenGL 3.3. The application loads and displays GLSL shaders from the `shaders/` directory with runtime switching capabilities.
|
This is a cross-platform Shadertoy-like fragment shader viewer built with SDL3. It supports two rendering backends:
|
||||||
|
- **SDL3 GPU** (default): renders via Vulkan on Linux/Windows and Metal on macOS.
|
||||||
|
- **OpenGL 3.3** (fallback): the original backend, used automatically if SDL3 GPU init fails.
|
||||||
|
|
||||||
|
Selection at launch:
|
||||||
|
```bash
|
||||||
|
./shadertoy --backend=gpu # force SDL3 GPU
|
||||||
|
./shadertoy --backend=opengl # force OpenGL
|
||||||
|
./shadertoy --backend=auto # default: GPU first, fall back to OpenGL on failure
|
||||||
|
```
|
||||||
|
|
||||||
## Build and Development Commands
|
## Build and Development Commands
|
||||||
|
|
||||||
@@ -30,13 +39,21 @@ make macos_debug
|
|||||||
make linux_debug
|
make linux_debug
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Compiling Shaders to SPIR-V
|
||||||
|
The SDL3 GPU backend reads compiled SPIR-V (`.frag.spv`) at runtime. Run this after touching any `.vk.glsl` file:
|
||||||
|
```bash
|
||||||
|
cmake --build build --target compile_shaders
|
||||||
|
```
|
||||||
|
Requires `glslc` (Debian/Ubuntu: `apt install glslang-tools`; macOS: `brew install glslang`).
|
||||||
|
|
||||||
### Running the Application
|
### Running the Application
|
||||||
```bash
|
```bash
|
||||||
./shadertoy [SHADER_PATH] [-F|--fullscreen]
|
./shadertoy [SHADER_NAME_OR_PATH] [-F|--fullscreen] [--backend=auto|gpu|opengl]
|
||||||
|
|
||||||
# Examples:
|
# Examples:
|
||||||
./shadertoy shaders/test.frag.glsl
|
./shadertoy test # auto backend, shaders/test/
|
||||||
./shadertoy -F shaders/fractal_pyramid.frag.glsl
|
./shadertoy --backend=gpu seascape # force SDL3 GPU (Vulkan/Metal)
|
||||||
|
./shadertoy -F shaders/fractal_pyramid # explicit folder path, fullscreen
|
||||||
```
|
```
|
||||||
|
|
||||||
**Runtime Controls:**
|
**Runtime Controls:**
|
||||||
@@ -46,28 +63,49 @@ make linux_debug
|
|||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
### Core Design
|
### Layered design
|
||||||
All application logic resides in `src/main.cpp` (~469 lines) - a monolithic design that's straightforward to understand. Key components:
|
- `src/main.cpp` — SDL3 window, event loop, shader-list scanning, dispatch to a backend.
|
||||||
|
- `src/rendering/shader_backend.hpp` — abstract `IShaderBackend` interface + `ShaderMetadata` / `ShaderUniforms` / `ShaderProgramSpec` shared types. Two factories: `makeOpenGLBackend()`, `makeSdl3GpuBackend()`.
|
||||||
|
- `src/rendering/opengl_shader_backend.{hpp,cpp}` — OpenGL 3.3 implementation. Loads `<folder>/<name>.gl.glsl` at runtime.
|
||||||
|
- `src/rendering/sdl3gpu/sdl3gpu_shader_backend.{hpp,cpp}` — SDL3 GPU implementation. Loads `<folder>/<name>.frag.spv` (Linux/Windows) or `<folder>/<name>.frag.msl` (macOS); shares one passthrough vertex shader from `shaders/_common/passthrough.vert.{spv,msl}`.
|
||||||
|
- `src/rendering/sdl3gpu/shader_factory.hpp` — small helper that loads a shader binary/source from disk and creates an `SDL_GPUShader`.
|
||||||
|
|
||||||
1. **Shader Loading System** - Automatic directory scanning of `.glsl` files, sorted alphabetically
|
### Shader folder layout
|
||||||
2. **OpenGL Rendering** - Single fullscreen quad with fragment shader using GL_TRIANGLE_STRIP
|
One folder per shader, under `shaders/`:
|
||||||
3. **Event Loop** - SDL3-based with vsync (SDL_GL_SwapWindow + 1ms delay)
|
```
|
||||||
4. **Resource Path Resolution** - Multi-path fallback system for executable, relative, and macOS bundle paths
|
shaders/<name>/
|
||||||
|
<name>.gl.glsl # OpenGL GLSL 3.30 (handwritten)
|
||||||
|
<name>.vk.glsl # Vulkan GLSL 4.50 (handwritten)
|
||||||
|
<name>.frag.msl # Metal Shading Language (handwritten)
|
||||||
|
<name>.frag.spv # generated by `make compile_shaders` from .vk.glsl
|
||||||
|
meta.txt # Name / Author / iChannelN
|
||||||
|
shaders/_common/
|
||||||
|
passthrough.vk.glsl # shared fullscreen-triangle vertex (Vulkan)
|
||||||
|
passthrough.vert.spv # generated
|
||||||
|
passthrough.vert.msl # handwritten Metal
|
||||||
|
```
|
||||||
|
Folders starting with `_` or `.` are skipped by the scanner. The `meta.txt` parser is in `Rendering::parseMetaFile`.
|
||||||
|
|
||||||
|
### Backend selection logic (`main.cpp`)
|
||||||
|
1. Parse `--backend=...` flag (default `auto`).
|
||||||
|
2. If not OpenGL: create a window with no flags, instantiate `Sdl3GpuShaderBackend`. If `init()` fails AND choice was `auto`, destroy the window and continue. If choice was `gpu`, exit with error.
|
||||||
|
3. Otherwise: create a window with `SDL_WINDOW_OPENGL` and instantiate `OpenGLShaderBackend`.
|
||||||
|
|
||||||
### Global State (main.cpp)
|
### Global State (main.cpp)
|
||||||
```cpp
|
```cpp
|
||||||
shader_list_ // Vector of discovered .glsl shader paths
|
shader_list_ // Vector<ShaderEntry { folder, base_name }>
|
||||||
current_shader_index_ // Active shader in rotation
|
current_shader_index_ // Active shader in rotation
|
||||||
current_program_ // OpenGL shader program handle
|
|
||||||
shader_start_ticks_ // Base time for iTime uniform calculation
|
shader_start_ticks_ // Base time for iTime uniform calculation
|
||||||
window_ // SDL3 window pointer
|
window_ // SDL3 window pointer
|
||||||
shaders_directory_ // Shader directory path (resolved at startup)
|
backend_ // unique_ptr<IShaderBackend>
|
||||||
|
shaders_directory_ // Shaders root path (resolved at startup)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Dependencies
|
### Dependencies
|
||||||
- **SDL3** - Window/input management, OpenGL context
|
- **SDL3** ≥ 3.2 — windowing, events, GPU API (`SDL_gpu.h`)
|
||||||
- **GLAD** - OpenGL 3.3 loader (statically linked via `third_party/glad/`)
|
- **GLAD** — OpenGL 3.3 loader (used only by the OpenGL backend, statically linked via `third_party/glad/`)
|
||||||
- **C++17 stdlib** - filesystem, fstream, vector, algorithms
|
- **C++17 stdlib** — filesystem, fstream, vector, algorithms
|
||||||
|
- Build-time tool: `glslc` (only required to regenerate `.frag.spv`)
|
||||||
|
|
||||||
### Platform-Specific Code
|
### Platform-Specific Code
|
||||||
Uses preprocessor defines (`WINDOWS_BUILD`, `MACOS_BUILD`, `LINUX_BUILD`) for:
|
Uses preprocessor defines (`WINDOWS_BUILD`, `MACOS_BUILD`, `LINUX_BUILD`) for:
|
||||||
@@ -77,6 +115,22 @@ Uses preprocessor defines (`WINDOWS_BUILD`, `MACOS_BUILD`, `LINUX_BUILD`) for:
|
|||||||
|
|
||||||
## Shader System
|
## Shader System
|
||||||
|
|
||||||
|
### Authoring a shader (manual steps)
|
||||||
|
For each new shader, three handwritten files live in `shaders/<name>/`:
|
||||||
|
1. **`<name>.gl.glsl`** — OpenGL GLSL 3.30 (the original Shadertoy-style format described below).
|
||||||
|
2. **`<name>.vk.glsl`** — Vulkan GLSL 4.50 with explicit `layout(set=3, binding=0) uniform ShadertoyUBO { float iTime; vec2 iResolution; } u;` and `layout(set=2, binding=N) uniform sampler2D` for any texture channel.
|
||||||
|
3. **`<name>.frag.msl`** — Metal Shading Language. Entry point must be named `<name>_fs`. Uniforms come in via `[[buffer(0)]]`; samplers via `[[texture(N)]] [[sampler(N)]]`.
|
||||||
|
|
||||||
|
After editing any `.vk.glsl`, rebuild SPIR-V: `cmake --build build --target compile_shaders`.
|
||||||
|
|
||||||
|
The MSL is **not** auto-generated — write it by hand following the same convention as `aee_2026/source/core/rendering/sdl3gpu/msl/*.msl.h`.
|
||||||
|
|
||||||
|
### Shadertoy → Vulkan/Metal porting cheatsheet
|
||||||
|
- `iResolution` is `vec2` here (no `.xy`). Reconstruct vec3 manually if needed.
|
||||||
|
- Replace `texture(iChannel0, ...)` calls — no texture channels currently wired through the GPU backend (planned).
|
||||||
|
- The shared vertex stage emits `vUV` already in Shadertoy convention `(0,0)` bottom-left → `(1,1)` top-right; multiply by `iResolution` to get `fragCoord`.
|
||||||
|
- The Y axis is flipped in NDC inside the shared vertex shader so Vulkan/Metal render right-side-up like OpenGL.
|
||||||
|
|
||||||
### Shader Format (GLSL 3.3 Core)
|
### Shader Format (GLSL 3.3 Core)
|
||||||
All shaders must follow this structure:
|
All shaders must follow this structure:
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ set(OpenGL_GL_PREFERENCE GLVND)
|
|||||||
# --- LISTA EXPLÍCITA DE FUENTES ---
|
# --- LISTA EXPLÍCITA DE FUENTES ---
|
||||||
set(APP_SOURCES
|
set(APP_SOURCES
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
|
src/rendering/shader_backend.cpp
|
||||||
|
src/rendering/opengl_shader_backend.cpp
|
||||||
|
src/rendering/sdl3gpu/sdl3gpu_shader_backend.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# Fuentes de librerías de terceros
|
# Fuentes de librerías de terceros
|
||||||
@@ -29,6 +32,21 @@ set(EXTERNAL_SOURCES
|
|||||||
find_package(SDL3 REQUIRED CONFIG REQUIRED COMPONENTS SDL3)
|
find_package(SDL3 REQUIRED CONFIG REQUIRED COMPONENTS SDL3)
|
||||||
message(STATUS "SDL3 encontrado: ${SDL3_INCLUDE_DIRS}")
|
message(STATUS "SDL3 encontrado: ${SDL3_INCLUDE_DIRS}")
|
||||||
|
|
||||||
|
# --- COMPILACIÓN DE SHADERS (Vulkan SPIR-V) ---
|
||||||
|
find_program(GLSLC_EXE NAMES glslc)
|
||||||
|
if(GLSLC_EXE)
|
||||||
|
message(STATUS "glslc encontrado: ${GLSLC_EXE}")
|
||||||
|
add_custom_target(compile_shaders
|
||||||
|
COMMAND ${CMAKE_COMMAND}
|
||||||
|
-D GLSLC=${GLSLC_EXE}
|
||||||
|
-D SHADERS_DIR=${CMAKE_SOURCE_DIR}/shaders
|
||||||
|
-P ${CMAKE_SOURCE_DIR}/tools/shaders/compile_shaders.cmake
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
COMMENT "Compiling .vk.glsl shaders to SPIR-V")
|
||||||
|
else()
|
||||||
|
message(STATUS "glslc no encontrado — el target compile_shaders no estará disponible")
|
||||||
|
endif()
|
||||||
|
|
||||||
# --- AÑADIR EJECUTABLE ---
|
# --- AÑADIR EJECUTABLE ---
|
||||||
add_executable(${PROJECT_NAME} ${APP_SOURCES} ${EXTERNAL_SOURCES})
|
add_executable(${PROJECT_NAME} ${APP_SOURCES} ${EXTERNAL_SOURCES})
|
||||||
|
|
||||||
|
|||||||
40
Makefile
40
Makefile
@@ -11,11 +11,12 @@ APP_NAME := Shadertoy
|
|||||||
RELEASE_FOLDER := shadertoy_release
|
RELEASE_FOLDER := shadertoy_release
|
||||||
RESOURCE_FILE := release/shadertoy.res
|
RESOURCE_FILE := release/shadertoy.res
|
||||||
|
|
||||||
# Versión automática basada en la fecha actual (específica por SO)
|
# Versión automática basada en la fecha actual (formato YYYY.MM.DD para que
|
||||||
|
# CFBundleShortVersionString del bundle macOS sea conforme a la spec de Apple).
|
||||||
ifeq ($(OS),Windows_NT)
|
ifeq ($(OS),Windows_NT)
|
||||||
VERSION := $(shell powershell -Command "Get-Date -Format 'yyyy-MM-dd'")
|
VERSION := $(shell powershell -Command "Get-Date -Format 'yyyy.MM.dd'")
|
||||||
else
|
else
|
||||||
VERSION := $(shell date +%Y-%m-%d)
|
VERSION := $(shell date +%Y.%m.%d)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Variables específicas para Windows (usando APP_NAME)
|
# Variables específicas para Windows (usando APP_NAME)
|
||||||
@@ -35,6 +36,9 @@ LINUX_RELEASE := $(TARGET_NAME)-$(VERSION)-linux.tar.gz
|
|||||||
# Lista completa de archivos fuente
|
# Lista completa de archivos fuente
|
||||||
APP_SOURCES := \
|
APP_SOURCES := \
|
||||||
src/main.cpp \
|
src/main.cpp \
|
||||||
|
src/rendering/shader_backend.cpp \
|
||||||
|
src/rendering/opengl_shader_backend.cpp \
|
||||||
|
src/rendering/sdl3gpu/sdl3gpu_shader_backend.cpp \
|
||||||
third_party/glad/src/glad.c \
|
third_party/glad/src/glad.c \
|
||||||
third_party/jail_audio.cpp
|
third_party/jail_audio.cpp
|
||||||
|
|
||||||
@@ -128,8 +132,28 @@ macos_debug:
|
|||||||
macos_release:
|
macos_release:
|
||||||
@echo "Creando release para macOS - Version: $(VERSION)"
|
@echo "Creando release para macOS - Version: $(VERSION)"
|
||||||
|
|
||||||
# Verificar e instalar create-dmg si es necesario
|
# Verifica dependencias necesarias (create-dmg). Si falta, intenta instalarla
|
||||||
@which create-dmg > /dev/null || (echo "Instalando create-dmg..." && brew install create-dmg)
|
# con brew; si brew tampoco está, indica el comando exacto al usuario.
|
||||||
|
@command -v create-dmg >/dev/null 2>&1 || { \
|
||||||
|
echo ""; \
|
||||||
|
echo "============================================"; \
|
||||||
|
echo " Falta la dependencia: create-dmg"; \
|
||||||
|
echo "============================================"; \
|
||||||
|
if command -v brew >/dev/null 2>&1; then \
|
||||||
|
echo " Instalando con: brew install create-dmg"; \
|
||||||
|
brew install create-dmg || { \
|
||||||
|
echo ""; \
|
||||||
|
echo " ERROR: 'brew install create-dmg' ha fallado."; \
|
||||||
|
echo " Ejecuta el comando manualmente y vuelve a probar."; \
|
||||||
|
exit 1; \
|
||||||
|
}; \
|
||||||
|
else \
|
||||||
|
echo " Homebrew no está instalado."; \
|
||||||
|
echo " Instálalo desde https://brew.sh y luego ejecuta:"; \
|
||||||
|
echo " brew install create-dmg"; \
|
||||||
|
exit 1; \
|
||||||
|
fi; \
|
||||||
|
}
|
||||||
|
|
||||||
# Elimina datos de compilaciones anteriores
|
# Elimina datos de compilaciones anteriores
|
||||||
$(RMDIR) "$(RELEASE_FOLDER)"
|
$(RMDIR) "$(RELEASE_FOLDER)"
|
||||||
@@ -150,6 +174,12 @@ macos_release:
|
|||||||
cp LICENSE "$(RELEASE_FOLDER)"
|
cp LICENSE "$(RELEASE_FOLDER)"
|
||||||
cp README.md "$(RELEASE_FOLDER)"
|
cp README.md "$(RELEASE_FOLDER)"
|
||||||
|
|
||||||
|
# Actualiza versión en Info.plist
|
||||||
|
@echo "Actualizando Info.plist con versión $(VERSION)..."
|
||||||
|
@RAW_VERSION=$$(echo "$(VERSION)" | sed 's/^v//'); \
|
||||||
|
sed -i '' '/<key>CFBundleShortVersionString<\/key>/{n;s|<string>.*</string>|<string>'"$$RAW_VERSION"'</string>|;}' "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Info.plist"; \
|
||||||
|
sed -i '' '/<key>CFBundleVersion<\/key>/{n;s|<string>.*</string>|<string>'"$$RAW_VERSION"'</string>|;}' "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Info.plist"
|
||||||
|
|
||||||
# Compila la versión para procesadores Apple Silicon
|
# Compila la versión para procesadores Apple Silicon
|
||||||
$(CXX) $(APP_SOURCES) $(INCLUDES) -DMACOS_BUNDLE -DRELEASE_BUILD $(CXXFLAGS) $(LDFLAGS) -o "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS/$(TARGET_NAME)" -rpath @executable_path/../Frameworks/ -target arm64-apple-macos11
|
$(CXX) $(APP_SOURCES) $(INCLUDES) -DMACOS_BUNDLE -DRELEASE_BUILD $(CXXFLAGS) $(LDFLAGS) -o "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS/$(TARGET_NAME)" -rpath @executable_path/../Frameworks/ -target arm64-apple-macos11
|
||||||
|
|
||||||
|
|||||||
19
shaders/_common/passthrough.vert.msl
Normal file
19
shaders/_common/passthrough.vert.msl
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
// Shared fullscreen-triangle vertex shader for the SDL3 GPU backend.
|
||||||
|
// Emits uv in Shadertoy convention: (0,0) bottom-left, (1,1) top-right.
|
||||||
|
|
||||||
|
struct PassthroughVOut {
|
||||||
|
float4 pos [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
vertex PassthroughVOut passthrough_vs(uint vid [[vertex_id]]) {
|
||||||
|
const float2 positions[3] = { {-1.0, -1.0}, {3.0, -1.0}, {-1.0, 3.0} };
|
||||||
|
PassthroughVOut out;
|
||||||
|
float2 pos = positions[vid];
|
||||||
|
out.uv = pos * 0.5 + 0.5;
|
||||||
|
out.pos = float4(pos, 0.0, 1.0);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
BIN
shaders/_common/passthrough.vert.spv
Normal file
BIN
shaders/_common/passthrough.vert.spv
Normal file
Binary file not shown.
17
shaders/_common/passthrough.vk.glsl
Normal file
17
shaders/_common/passthrough.vk.glsl
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// Shared fullscreen-triangle vertex shader for the SDL3 GPU backend.
|
||||||
|
// Emits vUV in Shadertoy convention: (0,0) bottom-left, (1,1) top-right.
|
||||||
|
|
||||||
|
layout(location = 0) out vec2 vUV;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
const vec2 positions[3] = vec2[3](
|
||||||
|
vec2(-1.0, -1.0),
|
||||||
|
vec2( 3.0, -1.0),
|
||||||
|
vec2(-1.0, 3.0)
|
||||||
|
);
|
||||||
|
vec2 pos = positions[gl_VertexIndex];
|
||||||
|
vUV = pos * 0.5 + 0.5;
|
||||||
|
gl_Position = vec4(pos, 0.0, 1.0);
|
||||||
|
}
|
||||||
75
shaders/cineshader_lava/cineshader_lava.frag.msl
Normal file
75
shaders/cineshader_lava/cineshader_lava.frag.msl
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
// Cineshader Lava — edankwan
|
||||||
|
// MSL port of cineshader_lava.vk.glsl.
|
||||||
|
|
||||||
|
struct ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
float2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassthroughVOut {
|
||||||
|
float4 pos [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
static float opSmoothUnion(float d1, float d2, float k) {
|
||||||
|
float h = clamp(0.5 + 0.5 * (d2 - d1) / k, 0.0, 1.0);
|
||||||
|
return mix(d2, d1, h) - k * h * (1.0 - h);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float sdSphere(float3 p, float s) {
|
||||||
|
return length(p) - s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float map(float3 p, float iTime) {
|
||||||
|
float d = 2.0;
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
float fi = float(i);
|
||||||
|
float time = iTime * (fract(fi * 412.531 + 0.513) - 0.5) * 2.0;
|
||||||
|
d = opSmoothUnion(
|
||||||
|
sdSphere(p + sin(time + fi * float3(52.5126, 64.62744, 632.25)) * float3(2.0, 2.0, 0.8),
|
||||||
|
mix(0.5, 1.0, fract(fi * 412.531 + 0.5124))),
|
||||||
|
d,
|
||||||
|
0.4
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float3 calcNormal(float3 p, float iTime) {
|
||||||
|
const float h = 1e-5;
|
||||||
|
const float2 k = float2(1, -1);
|
||||||
|
return normalize(k.xyy * map(p + k.xyy * h, iTime) +
|
||||||
|
k.yyx * map(p + k.yyx * h, iTime) +
|
||||||
|
k.yxy * map(p + k.yxy * h, iTime) +
|
||||||
|
k.xxx * map(p + k.xxx * h, iTime));
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment float4 cineshader_lava_fs(PassthroughVOut in [[stage_in]],
|
||||||
|
constant ShadertoyUBO& U [[buffer(0)]]) {
|
||||||
|
float2 fragCoord = in.uv * U.iResolution;
|
||||||
|
float2 uv = fragCoord / U.iResolution;
|
||||||
|
|
||||||
|
float3 rayOri = float3((uv - 0.5) * float2(U.iResolution.x / U.iResolution.y, 1.0) * 6.0, 3.0);
|
||||||
|
float3 rayDir = float3(0.0, 0.0, -1.0);
|
||||||
|
|
||||||
|
float depth = 0.0;
|
||||||
|
float3 p = float3(0.0);
|
||||||
|
|
||||||
|
for (int i = 0; i < 64; i++) {
|
||||||
|
p = rayOri + rayDir * depth;
|
||||||
|
float dist = map(p, U.iTime);
|
||||||
|
depth += dist;
|
||||||
|
if (dist < 1e-6) { break; }
|
||||||
|
}
|
||||||
|
|
||||||
|
depth = min(6.0, depth);
|
||||||
|
float3 n = calcNormal(p, U.iTime);
|
||||||
|
float b = max(0.0, dot(n, float3(0.577)));
|
||||||
|
float3 col = (0.5 + 0.5 * cos((b + U.iTime * 3.0) + uv.xyx * 2.0 + float3(0, 2, 4))) * (0.85 + b * 0.35);
|
||||||
|
col *= exp(-depth * 0.15);
|
||||||
|
|
||||||
|
return float4(col, 1.0 - (depth - 0.5) / 2.0);
|
||||||
|
}
|
||||||
BIN
shaders/cineshader_lava/cineshader_lava.frag.spv
Normal file
BIN
shaders/cineshader_lava/cineshader_lava.frag.spv
Normal file
Binary file not shown.
77
shaders/cineshader_lava/cineshader_lava.vk.glsl
Normal file
77
shaders/cineshader_lava/cineshader_lava.vk.glsl
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// Name: Cineshader Lava
|
||||||
|
// Author: edankwan
|
||||||
|
// URL: https://www.shadertoy.com/view/3sySRK
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 vUV;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0) uniform ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
vec2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
float opSmoothUnion(float d1, float d2, float k) {
|
||||||
|
float h = clamp(0.5 + 0.5 * (d2 - d1) / k, 0.0, 1.0);
|
||||||
|
return mix(d2, d1, h) - k * h * (1.0 - h);
|
||||||
|
}
|
||||||
|
|
||||||
|
float sdSphere(vec3 p, float s) {
|
||||||
|
return length(p) - s;
|
||||||
|
}
|
||||||
|
|
||||||
|
float map(vec3 p) {
|
||||||
|
float d = 2.0;
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
float fi = float(i);
|
||||||
|
float time = iTime * (fract(fi * 412.531 + 0.513) - 0.5) * 2.0;
|
||||||
|
d = opSmoothUnion(
|
||||||
|
sdSphere(p + sin(time + fi * vec3(52.5126, 64.62744, 632.25)) * vec3(2.0, 2.0, 0.8), mix(0.5, 1.0, fract(fi * 412.531 + 0.5124))),
|
||||||
|
d,
|
||||||
|
0.4
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 calcNormal(in vec3 p) {
|
||||||
|
const float h = 1e-5;
|
||||||
|
const vec2 k = vec2(1, -1);
|
||||||
|
return normalize(k.xyy * map(p + k.xyy * h) +
|
||||||
|
k.yyx * map(p + k.yyx * h) +
|
||||||
|
k.yxy * map(p + k.yxy * h) +
|
||||||
|
k.xxx * map(p + k.xxx * h));
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
||||||
|
vec2 uv = fragCoord / iResolution.xy;
|
||||||
|
|
||||||
|
vec3 rayOri = vec3((uv - 0.5) * vec2(iResolution.x / iResolution.y, 1.0) * 6.0, 3.0);
|
||||||
|
vec3 rayDir = vec3(0.0, 0.0, -1.0);
|
||||||
|
|
||||||
|
float depth = 0.0;
|
||||||
|
vec3 p;
|
||||||
|
|
||||||
|
for (int i = 0; i < 64; i++) {
|
||||||
|
p = rayOri + rayDir * depth;
|
||||||
|
float dist = map(p);
|
||||||
|
depth += dist;
|
||||||
|
if (dist < 1e-6) { break; }
|
||||||
|
}
|
||||||
|
|
||||||
|
depth = min(6.0, depth);
|
||||||
|
vec3 n = calcNormal(p);
|
||||||
|
float b = max(0.0, dot(n, vec3(0.577)));
|
||||||
|
vec3 col = (0.5 + 0.5 * cos((b + iTime * 3.0) + uv.xyx * 2.0 + vec3(0, 2, 4))) * (0.85 + b * 0.35);
|
||||||
|
col *= exp(-depth * 0.15);
|
||||||
|
|
||||||
|
fragColor = vec4(col, 1.0 - (depth - 0.5) / 2.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
2
shaders/cineshader_lava/meta.txt
Normal file
2
shaders/cineshader_lava/meta.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Name: Cineshader Lava
|
||||||
|
Author: edankwan
|
||||||
42
shaders/creation/creation.frag.msl
Normal file
42
shaders/creation/creation.frag.msl
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
// Creation by Silexars — Danguafer
|
||||||
|
// MSL port of creation.vk.glsl.
|
||||||
|
|
||||||
|
struct ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
float2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassthroughVOut {
|
||||||
|
float4 pos [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
fragment float4 creation_fs(PassthroughVOut in [[stage_in]],
|
||||||
|
constant ShadertoyUBO& U [[buffer(0)]]) {
|
||||||
|
float2 fragCoord = in.uv * U.iResolution;
|
||||||
|
float t = U.iTime;
|
||||||
|
float2 r = U.iResolution;
|
||||||
|
|
||||||
|
float3 c = float3(0.0);
|
||||||
|
float l = 0.0;
|
||||||
|
float z = t;
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
float2 p = fragCoord / r;
|
||||||
|
float2 uv = p;
|
||||||
|
p -= 0.5;
|
||||||
|
p.x *= r.x / r.y;
|
||||||
|
z += 0.07;
|
||||||
|
l = length(p);
|
||||||
|
float invl = (l > 0.0) ? (1.0 / l) : 0.0;
|
||||||
|
uv += p * invl * (sin(z) + 1.0) * abs(sin(l * 9.0 - z - z));
|
||||||
|
float2 m = fract(uv) - 0.5;
|
||||||
|
float denom = length(m);
|
||||||
|
if (denom < 1e-6) denom = 1e-6;
|
||||||
|
c[i] = 0.01 / denom;
|
||||||
|
}
|
||||||
|
float L = (l > 0.0) ? l : 1.0;
|
||||||
|
return float4(c / L, t);
|
||||||
|
}
|
||||||
BIN
shaders/creation/creation.frag.spv
Normal file
BIN
shaders/creation/creation.frag.spv
Normal file
Binary file not shown.
45
shaders/creation/creation.vk.glsl
Normal file
45
shaders/creation/creation.vk.glsl
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// Name: Creation by Silexars
|
||||||
|
// Author: Danguafer
|
||||||
|
// URL: https://www.shadertoy.com/view/XsXXDn
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 vUV;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0) uniform ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
vec2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define t iTime
|
||||||
|
#define r iResolution.xy
|
||||||
|
|
||||||
|
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
||||||
|
vec3 c = vec3(0.0);
|
||||||
|
float l;
|
||||||
|
float z = t;
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
vec2 uv, p = fragCoord.xy / r;
|
||||||
|
uv = p;
|
||||||
|
p -= 0.5;
|
||||||
|
p.x *= r.x / r.y;
|
||||||
|
z += 0.07;
|
||||||
|
l = length(p);
|
||||||
|
float invl = (l > 0.0) ? (1.0 / l) : 0.0;
|
||||||
|
uv += p * invl * (sin(z) + 1.0) * abs(sin(l * 9.0 - z - z));
|
||||||
|
vec2 m = mod(uv, 1.0) - 0.5;
|
||||||
|
float denom = length(m);
|
||||||
|
if (denom < 1e-6) denom = 1e-6;
|
||||||
|
c[i] = 0.01 / denom;
|
||||||
|
}
|
||||||
|
float L = (l > 0.0) ? l : 1.0;
|
||||||
|
fragColor = vec4(c / L, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
2
shaders/creation/meta.txt
Normal file
2
shaders/creation/meta.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Name: Creation by Silexars
|
||||||
|
Author: Danguafer
|
||||||
455
shaders/cube_lines/cube_lines.frag.msl
Normal file
455
shaders/cube_lines/cube_lines.frag.msl
Normal file
@@ -0,0 +1,455 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
// Cube lines — Danil
|
||||||
|
// MSL port of cube_lines.vk.glsl. The original Shadertoy is ~780 lines and
|
||||||
|
// uses every GLSL trick (mat3 chains, arrays, fwidth-based AA, swap macros).
|
||||||
|
//
|
||||||
|
// Notes:
|
||||||
|
// - fcos() uses fwidth() like the GLSL original to soften high-frequency
|
||||||
|
// terms. The GLSL fallback path that divides by iResolution.y when
|
||||||
|
// fwidth returns 0/NaN/Inf is omitted here; the main fwidth-based
|
||||||
|
// branch covers virtually all fragments and the fallback is rarely
|
||||||
|
// hit in practice.
|
||||||
|
// - Optional Shadertoy defines (ANIM_SHAPE, ANIM_COLOR, ROTATION_SPEED,
|
||||||
|
// CAMERA_*, USE_COLOR, AA_*, ONLY_BOX, etc.) are left at their defaults
|
||||||
|
// just like the .vk.glsl ships them.
|
||||||
|
|
||||||
|
struct ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
float2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassthroughVOut {
|
||||||
|
float4 pos [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
constant float ROTATION_SPEED = 0.8999;
|
||||||
|
constant float tshift = 53.0;
|
||||||
|
constant float FDIST = 0.7;
|
||||||
|
constant float PI = 3.1415926;
|
||||||
|
constant float3 BOXDIMS = float3(0.75, 0.75, 1.25);
|
||||||
|
constant float IOR = 1.33;
|
||||||
|
|
||||||
|
static float3x3 rotx(float a) {
|
||||||
|
float s = sin(a), c = cos(a);
|
||||||
|
return float3x3(float3(1.0, 0.0, 0.0), float3(0.0, c, s), float3(0.0, -s, c));
|
||||||
|
}
|
||||||
|
static float3x3 roty(float a) {
|
||||||
|
float s = sin(a), c = cos(a);
|
||||||
|
return float3x3(float3(c, 0.0, s), float3(0.0, 1.0, 0.0), float3(-s, 0.0, c));
|
||||||
|
}
|
||||||
|
static float3x3 rotz(float a) {
|
||||||
|
float s = sin(a), c = cos(a);
|
||||||
|
return float3x3(float3(c, s, 0.0), float3(-s, c, 0.0), float3(0.0, 0.0, 1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static float3 fcos(float3 x) {
|
||||||
|
float3 w = fwidth(x);
|
||||||
|
return cos(x) * smoothstep(float3(3.14 * 2.0), float3(0.0), w);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float3 getColor(float3 p) {
|
||||||
|
p = abs(p);
|
||||||
|
p *= 1.25;
|
||||||
|
p = 0.5 * p / dot(p, p);
|
||||||
|
|
||||||
|
float t = 0.13 * length(p);
|
||||||
|
float3 col = float3(0.3, 0.4, 0.5);
|
||||||
|
col += 0.12 * fcos(6.28318 * t * 1.0 + float3(0.0, 0.8, 1.1));
|
||||||
|
col += 0.11 * fcos(6.28318 * t * 3.1 + float3(0.3, 0.4, 0.1));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 5.1 + float3(0.1, 0.7, 1.1));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 17.1 + float3(0.2, 0.6, 0.7));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 31.1 + float3(0.1, 0.6, 0.7));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 65.1 + float3(0.0, 0.5, 0.8));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 115.1 + float3(0.1, 0.4, 0.7));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 265.1 + float3(1.1, 1.4, 2.7));
|
||||||
|
col = clamp(col, 0.0, 1.0);
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void calcColor(float3 ro, float3 rd, float3 nor, float d, float len, int idx,
|
||||||
|
bool si, float td,
|
||||||
|
thread float4& colx, thread float4& colsi) {
|
||||||
|
float3 pos = ro + rd * d;
|
||||||
|
float a = 1.0 - smoothstep(len - 0.15 * 0.5, len + 0.00001, length(pos));
|
||||||
|
float3 col = getColor(pos);
|
||||||
|
colx = float4(col, a);
|
||||||
|
if (si) {
|
||||||
|
pos = ro + rd * td;
|
||||||
|
float ta = 1.0 - smoothstep(len - 0.15 * 0.5, len + 0.00001, length(pos));
|
||||||
|
col = getColor(pos);
|
||||||
|
colsi = float4(col, ta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool iBilinearPatch(float3 ro, float3 rd, float4 ps, float4 ph, float sz,
|
||||||
|
thread float& t, thread float3& norm,
|
||||||
|
thread bool& si, thread float& tsi, thread float3& normsi,
|
||||||
|
thread float& fade, thread float& fadesi) {
|
||||||
|
float3 va = float3(0.0, 0.0, ph.x + ph.w - ph.y - ph.z);
|
||||||
|
float3 vb = float3(0.0, ps.w - ps.y, ph.z - ph.x);
|
||||||
|
float3 vc = float3(ps.z - ps.x, 0.0, ph.y - ph.x);
|
||||||
|
float3 vd = float3(ps.xy, ph.x);
|
||||||
|
t = -1.0;
|
||||||
|
tsi = -1.0;
|
||||||
|
si = false;
|
||||||
|
fade = 1.0;
|
||||||
|
fadesi = 1.0;
|
||||||
|
norm = float3(0.0, 1.0, 0.0);
|
||||||
|
normsi = float3(0.0, 1.0, 0.0);
|
||||||
|
|
||||||
|
float tmp = 1.0 / (vb.y * vc.x);
|
||||||
|
float a = 0.0, b = 0.0, c = 0.0;
|
||||||
|
float d = va.z * tmp;
|
||||||
|
float e = 0.0, f = 0.0;
|
||||||
|
float g = (vc.z * vb.y - vd.y * va.z) * tmp;
|
||||||
|
float h = (vb.z * vc.x - va.z * vd.x) * tmp;
|
||||||
|
float i = -1.0;
|
||||||
|
float j = (vd.x * vd.y * va.z + vd.z * vb.y * vc.x) * tmp - (vd.y * vb.z * vc.x + vd.x * vc.z * vb.y) * tmp;
|
||||||
|
|
||||||
|
float p = dot(float3(a, b, c), rd.xzy * rd.xzy) + dot(float3(d, e, f), rd.xzy * rd.zyx);
|
||||||
|
float q = dot(float3(2.0, 2.0, 2.0) * ro.xzy * rd.xyz, float3(a, b, c)) + dot(ro.xzz * rd.zxy, float3(d, d, e)) +
|
||||||
|
dot(ro.yyx * rd.zxy, float3(e, f, f)) + dot(float3(g, h, i), rd.xzy);
|
||||||
|
float r = dot(float3(a, b, c), ro.xzy * ro.xzy) + dot(float3(d, e, f), ro.xzy * ro.zyx) + dot(float3(g, h, i), ro.xzy) + j;
|
||||||
|
|
||||||
|
if (abs(p) < 0.000001) {
|
||||||
|
float tt = -r / q;
|
||||||
|
if (tt <= 0.0) return false;
|
||||||
|
t = tt;
|
||||||
|
float3 pos = ro + t * rd;
|
||||||
|
if (length(pos) > sz) return false;
|
||||||
|
float3 grad = float3(2.0) * pos.xzy * float3(a, b, c) + pos.zxz * float3(d, d, e) + pos.yyx * float3(f, e, f) + float3(g, h, i);
|
||||||
|
norm = -normalize(grad);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
float sq = q * q - 4.0 * p * r;
|
||||||
|
if (sq < 0.0) return false;
|
||||||
|
float s = sqrt(sq);
|
||||||
|
float t0 = (-q + s) / (2.0 * p);
|
||||||
|
float t1 = (-q - s) / (2.0 * p);
|
||||||
|
float tt1 = min(t0 < 0.0 ? t1 : t0, t1 < 0.0 ? t0 : t1);
|
||||||
|
float tt2 = max(t0 > 0.0 ? t1 : t0, t1 > 0.0 ? t0 : t1);
|
||||||
|
float tt0 = tt1;
|
||||||
|
if (tt0 <= 0.0) return false;
|
||||||
|
float3 pos = ro + tt0 * rd;
|
||||||
|
bool ru = step(sz, length(pos)) > 0.5;
|
||||||
|
if (ru) {
|
||||||
|
tt0 = tt2;
|
||||||
|
pos = ro + tt0 * rd;
|
||||||
|
}
|
||||||
|
if (tt0 <= 0.0) return false;
|
||||||
|
bool ru2 = step(sz, length(pos)) > 0.5;
|
||||||
|
if (ru2) return false;
|
||||||
|
|
||||||
|
if ((tt2 > 0.0) && (!ru) && !(step(sz, length(ro + tt2 * rd)) > 0.5)) {
|
||||||
|
si = true;
|
||||||
|
fadesi = s;
|
||||||
|
tsi = tt2;
|
||||||
|
float3 tpos = ro + tsi * rd;
|
||||||
|
float3 tgrad = float3(2.0) * tpos.xzy * float3(a, b, c) + tpos.zxz * float3(d, d, e) +
|
||||||
|
tpos.yyx * float3(f, e, f) + float3(g, h, i);
|
||||||
|
normsi = -normalize(tgrad);
|
||||||
|
}
|
||||||
|
|
||||||
|
fade = s;
|
||||||
|
t = tt0;
|
||||||
|
float3 grad = float3(2.0) * pos.xzy * float3(a, b, c) + pos.zxz * float3(d, d, e) + pos.yyx * float3(f, e, f) + float3(g, h, i);
|
||||||
|
norm = -normalize(grad);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static float dot2(float3 v) { return dot(v, v); }
|
||||||
|
|
||||||
|
static float segShadow(float3 ro, float3 rd, float3 pa, float sh) {
|
||||||
|
float dm = dot(rd.yz, rd.yz);
|
||||||
|
float k1 = (ro.x - pa.x) * dm;
|
||||||
|
float k2 = (ro.x + pa.x) * dm;
|
||||||
|
float2 k5 = (ro.yz + pa.yz) * dm;
|
||||||
|
float k3 = dot(ro.yz + pa.yz, rd.yz);
|
||||||
|
float2 k4 = (pa.yz + pa.yz) * rd.yz;
|
||||||
|
float2 k6 = (pa.yz + pa.yz) * dm;
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
float2 s = float2(i & 1, i >> 1);
|
||||||
|
float t = dot(s, k4) - k3;
|
||||||
|
if (t > 0.0) {
|
||||||
|
sh = min(sh, dot2(float3(clamp(-rd.x * t, k1, k2), k5 - k6 * s) + rd * t) / (t * t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sh;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float boxSoftShadow(float3 ro, float3 rd, float3 rad, float sk) {
|
||||||
|
rd += 0.0001 * (1.0 - abs(sign(rd)));
|
||||||
|
float3 rdd = rd;
|
||||||
|
float3 roo = ro;
|
||||||
|
|
||||||
|
float3 m = 1.0 / rdd;
|
||||||
|
float3 n = m * roo;
|
||||||
|
float3 k = abs(m) * rad;
|
||||||
|
|
||||||
|
float3 t1 = -n - k;
|
||||||
|
float3 t2 = -n + k;
|
||||||
|
|
||||||
|
float tN = max(max(t1.x, t1.y), t1.z);
|
||||||
|
float tF = min(min(t2.x, t2.y), t2.z);
|
||||||
|
|
||||||
|
if (tN < tF && tF > 0.0) return 0.0;
|
||||||
|
|
||||||
|
float sh = 1.0;
|
||||||
|
sh = segShadow(roo.xyz, rdd.xyz, rad.xyz, sh);
|
||||||
|
sh = segShadow(roo.yzx, rdd.yzx, rad.yzx, sh);
|
||||||
|
sh = segShadow(roo.zxy, rdd.zxy, rad.zxy, sh);
|
||||||
|
sh = clamp(sk * sqrt(sh), 0.0, 1.0);
|
||||||
|
return sh * sh * (3.0 - 2.0 * sh);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float boxRay(float3 ro, float3 rd, float3 r, thread float3& nn, bool entering) {
|
||||||
|
rd += 0.0001 * (1.0 - abs(sign(rd)));
|
||||||
|
float3 dr = 1.0 / rd;
|
||||||
|
float3 n = ro * dr;
|
||||||
|
float3 k = r * abs(dr);
|
||||||
|
|
||||||
|
float3 pin = -k - n;
|
||||||
|
float3 pout = k - n;
|
||||||
|
float tin = max(pin.x, max(pin.y, pin.z));
|
||||||
|
float tout = min(pout.x, min(pout.y, pout.z));
|
||||||
|
if (tin > tout) return -1.0;
|
||||||
|
if (entering) {
|
||||||
|
nn = -sign(rd) * step(pin.zxy, pin.xyz) * step(pin.yzx, pin.xyz);
|
||||||
|
} else {
|
||||||
|
nn = sign(rd) * step(pout.xyz, pout.zxy) * step(pout.xyz, pout.yzx);
|
||||||
|
}
|
||||||
|
return entering ? tin : tout;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float3 bgcol(float3 rd) {
|
||||||
|
return mix(float3(0.01), float3(0.336, 0.458, 0.668), 1.0 - pow(abs(rd.z + 0.25), 1.3));
|
||||||
|
}
|
||||||
|
|
||||||
|
static float3 background(float3 ro, float3 rd, float3 l_dir, thread float& alpha) {
|
||||||
|
float t = (-BOXDIMS.z - ro.z) / rd.z;
|
||||||
|
alpha = 0.0;
|
||||||
|
float3 bgc = bgcol(rd);
|
||||||
|
if (t < 0.0) return bgc;
|
||||||
|
float2 uv = ro.xy + t * rd.xy;
|
||||||
|
float shad = boxSoftShadow((ro + t * rd), normalize(l_dir + float3(0.0, 0.0, 1.0)) * rotz(PI * 0.65), BOXDIMS, 1.5);
|
||||||
|
float aofac = smoothstep(-0.95, 0.75, length(abs(uv) - min(abs(uv), float2(0.45))));
|
||||||
|
aofac = min(aofac, smoothstep(-0.65, 1.0, shad));
|
||||||
|
float lght = max(dot(normalize(ro + t * rd + float3(0.0, -0.0, -5.0)), normalize(l_dir - float3(0.0, 0.0, 1.0)) * rotz(PI * 0.65)), 0.0);
|
||||||
|
float3 col = mix(float3(0.4), float3(0.71, 0.772, 0.895), lght * lght * aofac + 0.05) * aofac;
|
||||||
|
alpha = 1.0 - smoothstep(7.0, 10.0, length(uv));
|
||||||
|
return mix(col * length(col) * 0.8, bgc, smoothstep(7.0, 10.0, length(uv)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static float4 insides(float3 ro, float3 rd, float3 nor_c, float3 l_dir, thread float& tout) {
|
||||||
|
tout = -1.0;
|
||||||
|
|
||||||
|
float pi = 3.1415926;
|
||||||
|
|
||||||
|
if (abs(nor_c.x) > 0.5) {
|
||||||
|
rd = rd.xzy * nor_c.x;
|
||||||
|
ro = ro.xzy * nor_c.x;
|
||||||
|
} else if (abs(nor_c.z) > 0.5) {
|
||||||
|
l_dir = l_dir * roty(pi);
|
||||||
|
rd = rd.yxz * nor_c.z;
|
||||||
|
ro = ro.yxz * nor_c.z;
|
||||||
|
} else if (abs(nor_c.y) > 0.5) {
|
||||||
|
l_dir = l_dir * rotz(-pi * 0.5);
|
||||||
|
rd = rd * nor_c.y;
|
||||||
|
ro = ro * nor_c.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float curvature = 0.5;
|
||||||
|
float bil_size = 1.0;
|
||||||
|
float4 ps = float4(-bil_size, -bil_size, bil_size, bil_size) * curvature;
|
||||||
|
float4 ph = float4(-bil_size, bil_size, bil_size, -bil_size) * curvature;
|
||||||
|
|
||||||
|
float4 colx[3] = { float4(0.0), float4(0.0), float4(0.0) };
|
||||||
|
float3 dx[3] = { float3(-1.0), float3(-1.0), float3(-1.0) };
|
||||||
|
float4 colxsi[3] = { float4(0.0), float4(0.0), float4(0.0) };
|
||||||
|
int order[3] = { 0, 1, 2 };
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
if (abs(nor_c.x) > 0.5) {
|
||||||
|
ro = ro * rotz(-pi * (1.0 / 3.0));
|
||||||
|
rd = rd * rotz(-pi * (1.0 / 3.0));
|
||||||
|
} else if (abs(nor_c.z) > 0.5) {
|
||||||
|
ro = ro * rotz(pi * (1.0 / 3.0));
|
||||||
|
rd = rd * rotz(pi * (1.0 / 3.0));
|
||||||
|
} else if (abs(nor_c.y) > 0.5) {
|
||||||
|
ro = ro * rotx(pi * (1.0 / 3.0));
|
||||||
|
rd = rd * rotx(pi * (1.0 / 3.0));
|
||||||
|
}
|
||||||
|
float3 normnew;
|
||||||
|
float tnew;
|
||||||
|
bool si;
|
||||||
|
float tsi;
|
||||||
|
float3 normsi;
|
||||||
|
float fade;
|
||||||
|
float fadesi;
|
||||||
|
|
||||||
|
if (iBilinearPatch(ro, rd, ps, ph, bil_size, tnew, normnew, si, tsi, normsi, fade, fadesi)) {
|
||||||
|
if (tnew > 0.0) {
|
||||||
|
float4 tcol, tcolsi;
|
||||||
|
calcColor(ro, rd, normnew, tnew, bil_size, i, si, tsi, tcol, tcolsi);
|
||||||
|
if (tcol.a > 0.0) {
|
||||||
|
dx[i] = float3(tnew, float(si), tsi);
|
||||||
|
|
||||||
|
float dif = clamp(dot(normnew, l_dir), 0.0, 1.0);
|
||||||
|
float amb = clamp(0.5 + 0.5 * dot(normnew, l_dir), 0.0, 1.0);
|
||||||
|
|
||||||
|
{
|
||||||
|
float3 shad = float3(0.32, 0.43, 0.54) * amb + float3(1.0, 0.9, 0.7) * dif;
|
||||||
|
const float3 tcr = float3(1.0, 0.21, 0.11);
|
||||||
|
float ta = clamp(length(tcol.rgb), 0.0, 1.0);
|
||||||
|
tcol = clamp(tcol * tcol * 2.0, 0.0, 1.0);
|
||||||
|
float4 tvalx = float4(tcol.rgb * shad * 1.4 + 3.0 * (tcr * tcol.rgb) * clamp(1.0 - (amb + dif), 0.0, 1.0), min(tcol.a, ta));
|
||||||
|
tvalx.rgb = clamp(2.0 * tvalx.rgb * tvalx.rgb, 0.0, 1.0);
|
||||||
|
tvalx *= min(fade * 5.0, 1.0);
|
||||||
|
colx[i] = tvalx;
|
||||||
|
}
|
||||||
|
if (si) {
|
||||||
|
dif = clamp(dot(normsi, l_dir), 0.0, 1.0);
|
||||||
|
amb = clamp(0.5 + 0.5 * dot(normsi, l_dir), 0.0, 1.0);
|
||||||
|
float3 shad = float3(0.32, 0.43, 0.54) * amb + float3(1.0, 0.9, 0.7) * dif;
|
||||||
|
const float3 tcr = float3(1.0, 0.21, 0.11);
|
||||||
|
float ta = clamp(length(tcolsi.rgb), 0.0, 1.0);
|
||||||
|
tcolsi = clamp(tcolsi * tcolsi * 2.0, 0.0, 1.0);
|
||||||
|
float4 tvalx = float4(tcolsi.rgb * shad + 3.0 * (tcr * tcolsi.rgb) * clamp(1.0 - (amb + dif), 0.0, 1.0), min(tcolsi.a, ta));
|
||||||
|
tvalx.rgb = clamp(2.0 * tvalx.rgb * tvalx.rgb, 0.0, 1.0);
|
||||||
|
tvalx.rgb *= min(fadesi * 5.0, 1.0);
|
||||||
|
colxsi[i] = tvalx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort by dx[*].x descending (3 passes of bubble sort like the GLSL)
|
||||||
|
if (dx[0].x < dx[1].x) { float3 tv = dx[0]; dx[0] = dx[1]; dx[1] = tv; int ti = order[0]; order[0] = order[1]; order[1] = ti; }
|
||||||
|
if (dx[1].x < dx[2].x) { float3 tv = dx[1]; dx[1] = dx[2]; dx[2] = tv; int ti = order[1]; order[1] = order[2]; order[2] = ti; }
|
||||||
|
if (dx[0].x < dx[1].x) { float3 tv = dx[0]; dx[0] = dx[1]; dx[1] = tv; int ti = order[0]; order[0] = order[1]; order[1] = ti; }
|
||||||
|
|
||||||
|
tout = max(max(dx[0].x, dx[1].x), dx[2].x);
|
||||||
|
|
||||||
|
float a = 1.0;
|
||||||
|
if (dx[0].y < 0.5) {
|
||||||
|
a = colx[order[0]].a;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rul[3] = {
|
||||||
|
((dx[0].y > 0.5) && (dx[1].x <= 0.0)),
|
||||||
|
((dx[1].y > 0.5) && (dx[0].x > dx[1].z)),
|
||||||
|
((dx[2].y > 0.5) && (dx[1].x > dx[2].z))
|
||||||
|
};
|
||||||
|
for (int k = 0; k < 3; k++) {
|
||||||
|
if (rul[k]) {
|
||||||
|
float4 tcolxsi = colxsi[order[k]];
|
||||||
|
float4 tcolx = colx[order[k]];
|
||||||
|
float4 tvalx = mix(tcolxsi, tcolx, tcolx.a);
|
||||||
|
float4 tvalx2 = mix(float4(0.0), tvalx, max(tcolx.a, tcolxsi.a));
|
||||||
|
colx[order[k]] = tvalx2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float a1 = (dx[1].y < 0.5) ? colx[order[1]].a : ((dx[1].z > dx[0].x) ? colx[order[1]].a : 1.0);
|
||||||
|
float a2 = (dx[2].y < 0.5) ? colx[order[2]].a : ((dx[2].z > dx[1].x) ? colx[order[2]].a : 1.0);
|
||||||
|
float3 col = mix(mix(colx[order[0]].rgb, colx[order[1]].rgb, a1), colx[order[2]].rgb, a2);
|
||||||
|
a = max(max(a, a1), a2);
|
||||||
|
return float4(col, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment float4 cube_lines_fs(PassthroughVOut in [[stage_in]],
|
||||||
|
constant ShadertoyUBO& U [[buffer(0)]]) {
|
||||||
|
float2 fragCoord = in.uv * U.iResolution;
|
||||||
|
float iTime = U.iTime;
|
||||||
|
|
||||||
|
float3 l_dir = normalize(float3(0.0, 1.0, 0.0));
|
||||||
|
l_dir = l_dir * rotz(0.5);
|
||||||
|
float mouseY = PI * 0.49 - smoothstep(0.0, 8.5, fmod((iTime + tshift) * 0.33, 25.0))
|
||||||
|
* (1.0 - smoothstep(14.0, 24.0, fmod((iTime + tshift) * 0.33, 25.0))) * 0.55 * PI;
|
||||||
|
float mouseX = -2.0 * PI - 0.25 * (iTime * ROTATION_SPEED + tshift);
|
||||||
|
|
||||||
|
float3 eye = 4.0 * float3(cos(mouseX) * cos(mouseY), sin(mouseX) * cos(mouseY), sin(mouseY));
|
||||||
|
float3 w = normalize(-eye);
|
||||||
|
float3 up = float3(0.0, 0.0, 1.0);
|
||||||
|
float3 u = normalize(cross(w, up));
|
||||||
|
float3 v = cross(u, w);
|
||||||
|
|
||||||
|
float4 tot = float4(0.0);
|
||||||
|
float2 uv = (fragCoord - 0.5 * U.iResolution) / U.iResolution.x;
|
||||||
|
float3 rd = normalize(w * FDIST + uv.x * u + uv.y * v);
|
||||||
|
|
||||||
|
float3 ni;
|
||||||
|
float t = boxRay(eye, rd, BOXDIMS, ni, true);
|
||||||
|
float3 ro = eye + t * rd;
|
||||||
|
float2 coords = ro.xy * ni.z / BOXDIMS.xy + ro.yz * ni.x / BOXDIMS.yz + ro.zx * ni.y / BOXDIMS.zx;
|
||||||
|
float fadeborders = (1.0 - smoothstep(0.915, 1.05, abs(coords.x))) * (1.0 - smoothstep(0.915, 1.05, abs(coords.y)));
|
||||||
|
|
||||||
|
if (t > 0.0) {
|
||||||
|
float3 col = float3(0.0);
|
||||||
|
float R0 = (IOR - 1.0) / (IOR + 1.0);
|
||||||
|
R0 *= R0;
|
||||||
|
|
||||||
|
float2 theta = float2(0.0);
|
||||||
|
float3 n = float3(cos(theta.x) * sin(theta.y), sin(theta.x) * sin(theta.y), cos(theta.y));
|
||||||
|
|
||||||
|
float3 nr = n.zxy * ni.x + n.yzx * ni.y + n.xyz * ni.z;
|
||||||
|
float3 rdr = reflect(rd, nr);
|
||||||
|
float talpha;
|
||||||
|
float3 reflcol = background(ro, rdr, l_dir, talpha);
|
||||||
|
|
||||||
|
float3 rd2 = refract(rd, nr, 1.0 / IOR);
|
||||||
|
|
||||||
|
float accum = 1.0;
|
||||||
|
float3 no2 = ni;
|
||||||
|
float3 ro_refr = ro;
|
||||||
|
|
||||||
|
float4 colo[2] = { float4(0.0), float4(0.0) };
|
||||||
|
|
||||||
|
for (int j = 0; j < 2; j++) {
|
||||||
|
float tb;
|
||||||
|
float2 coords2 = ro_refr.xy * no2.z + ro_refr.yz * no2.x + ro_refr.zx * no2.y;
|
||||||
|
float3 eye2 = float3(coords2, -1.0);
|
||||||
|
float3 rd2trans = rd2.yzx * no2.x + rd2.zxy * no2.y + rd2.xyz * no2.z;
|
||||||
|
|
||||||
|
rd2trans.z = -rd2trans.z;
|
||||||
|
float4 internalcol = insides(eye2, rd2trans, no2, l_dir, tb);
|
||||||
|
if (tb > 0.0) {
|
||||||
|
internalcol.rgb *= accum;
|
||||||
|
colo[j] = internalcol;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((tb <= 0.0) || (internalcol.a < 1.0)) {
|
||||||
|
float tout = boxRay(ro_refr, rd2, BOXDIMS, no2, false);
|
||||||
|
no2 = n.zyx * no2.x + n.xzy * no2.y + n.yxz * no2.z;
|
||||||
|
float3 rout = ro_refr + tout * rd2;
|
||||||
|
float3 rdout = refract(rd2, -no2, IOR);
|
||||||
|
float fresnel2 = R0 + (1.0 - R0) * pow(1.0 - dot(rdout, no2), 1.3);
|
||||||
|
rd2 = reflect(rd2, -no2);
|
||||||
|
|
||||||
|
ro_refr = rout;
|
||||||
|
ro_refr.z = max(ro_refr.z, -0.999);
|
||||||
|
|
||||||
|
accum *= fresnel2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
float fresnel = R0 + (1.0 - R0) * pow(1.0 - dot(-rd, nr), 5.0);
|
||||||
|
col = mix(mix(colo[1].rgb * colo[1].a, colo[0].rgb, colo[0].a) * fadeborders, reflcol, pow(fresnel, 1.5));
|
||||||
|
col = clamp(col, 0.0, 1.0);
|
||||||
|
|
||||||
|
float cineshader_alpha = clamp(0.15 * dot(eye, ro), 0.0, 1.0);
|
||||||
|
tot += float4(col, cineshader_alpha);
|
||||||
|
} else {
|
||||||
|
float alpha;
|
||||||
|
tot += float4(background(eye, rd, l_dir, alpha), 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 outColor = tot;
|
||||||
|
outColor.rgb = clamp(outColor.rgb, 0.0, 1.0);
|
||||||
|
return outColor;
|
||||||
|
}
|
||||||
BIN
shaders/cube_lines/cube_lines.frag.spv
Normal file
BIN
shaders/cube_lines/cube_lines.frag.spv
Normal file
Binary file not shown.
782
shaders/cube_lines/cube_lines.vk.glsl
Normal file
782
shaders/cube_lines/cube_lines.vk.glsl
Normal file
@@ -0,0 +1,782 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// Name: Cube lines
|
||||||
|
// Author: Danil
|
||||||
|
// URL: https://www.shadertoy.com/view/NslGRN
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 vUV;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0) uniform ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
vec2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Note: Original shader uses iChannel0 for background blending (optional feature)
|
||||||
|
// Since we don't support texture channels, that line is commented out
|
||||||
|
// The shader works perfectly without it in default mode
|
||||||
|
|
||||||
|
// Created by Danil (2021+) https://cohost.org/arugl
|
||||||
|
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
|
||||||
|
// self https://www.shadertoy.com/view/NslGRN
|
||||||
|
|
||||||
|
|
||||||
|
// --defines for "DESKTOP WALLPAPERS" that use this shader--
|
||||||
|
// comment or uncomment every define to make it work (add or remove "//" before #define)
|
||||||
|
|
||||||
|
|
||||||
|
// this shadertoy use ALPHA, NO_ALPHA set alpha to 1, BG_ALPHA set background as alpha
|
||||||
|
// iChannel0 used as background if alpha ignored by wallpaper-app
|
||||||
|
//#define NO_ALPHA
|
||||||
|
//#define BG_ALPHA
|
||||||
|
//#define SHADOW_ALPHA
|
||||||
|
//#define ONLY_BOX
|
||||||
|
|
||||||
|
|
||||||
|
// save PERFORMANCE by disabling shadow
|
||||||
|
//#define NO_SHADOW
|
||||||
|
|
||||||
|
|
||||||
|
// static CAMERA position, 0.49 on top, 0.001 horizontal
|
||||||
|
//#define CAMERA_POS 0.049
|
||||||
|
|
||||||
|
|
||||||
|
// speed of ROTATION
|
||||||
|
#define ROTATION_SPEED 0.8999
|
||||||
|
|
||||||
|
|
||||||
|
// static SHAPE form, default 0.5
|
||||||
|
//#define STATIC_SHAPE 0.15
|
||||||
|
|
||||||
|
|
||||||
|
// static SCALE far/close to camera, 2.0 is default, exampe 0.5 or 10.0
|
||||||
|
//#define CAMERA_FAR 0.1
|
||||||
|
|
||||||
|
|
||||||
|
// ANIMATION shape change
|
||||||
|
//#define ANIM_SHAPE
|
||||||
|
|
||||||
|
|
||||||
|
// ANIMATION color change
|
||||||
|
//#define ANIM_COLOR
|
||||||
|
|
||||||
|
|
||||||
|
// custom COLOR, and change those const values
|
||||||
|
//#define USE_COLOR
|
||||||
|
const vec3 color_blue=vec3(0.5,0.65,0.8);
|
||||||
|
const vec3 color_red=vec3(0.99,0.2,0.1);
|
||||||
|
|
||||||
|
|
||||||
|
// use 4xAA for cube only (set 2-4-etc level of AA)
|
||||||
|
//#define AA_CUBE 4
|
||||||
|
|
||||||
|
// use 4xAA for everything - derivative filtering will not be used, look fcos2
|
||||||
|
// this is very slow - DO NOT USE
|
||||||
|
//#define AA_ALL 4
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// --shader code--
|
||||||
|
|
||||||
|
// Layers sorted and support transparency and self-intersection-transparency
|
||||||
|
// Antialiasing is only dFd. (with some dFd fixes around edges)
|
||||||
|
|
||||||
|
// using iq's intersectors: https://iquilezles.org/articles/intersectors
|
||||||
|
// using https://www.shadertoy.com/view/ltKBzG
|
||||||
|
// using https://www.shadertoy.com/view/tsVXzh
|
||||||
|
// using https://www.shadertoy.com/view/WlffDn
|
||||||
|
// using https://www.shadertoy.com/view/WslGz4
|
||||||
|
|
||||||
|
#define tshift 53.
|
||||||
|
|
||||||
|
// reflect back side
|
||||||
|
//#define backside_refl
|
||||||
|
|
||||||
|
// Camera with mouse
|
||||||
|
// #define MOUSE_control (disabled - no iMouse support)
|
||||||
|
|
||||||
|
// min(iFrame,0) does not speedup compilation in ANGLE
|
||||||
|
#define ANGLE_loops 0
|
||||||
|
|
||||||
|
|
||||||
|
// this shader discover Nvidia bug with arrays https://www.shadertoy.com/view/NslGR4
|
||||||
|
// use DEBUG with BUG, BUG trigger that bug and one layer will be white on Nvidia in OpenGL
|
||||||
|
//#define DEBUG
|
||||||
|
//#define BUG
|
||||||
|
|
||||||
|
#define FDIST 0.7
|
||||||
|
#define PI 3.1415926
|
||||||
|
#define GROUNDSPACING 0.5
|
||||||
|
#define GROUNDGRID 0.05
|
||||||
|
#define BOXDIMS vec3(0.75, 0.75, 1.25)
|
||||||
|
|
||||||
|
#define IOR 1.33
|
||||||
|
|
||||||
|
mat3 rotx(float a){float s = sin(a);float c = cos(a);return mat3(vec3(1.0, 0.0, 0.0), vec3(0.0, c, s), vec3(0.0, -s, c)); }
|
||||||
|
mat3 roty(float a){float s = sin(a);float c = cos(a);return mat3(vec3(c, 0.0, s), vec3(0.0, 1.0, 0.0), vec3(-s, 0.0, c));}
|
||||||
|
mat3 rotz(float a){float s = sin(a);float c = cos(a);return mat3(vec3(c, s, 0.0), vec3(-s, c, 0.0), vec3(0.0, 0.0, 1.0 ));}
|
||||||
|
|
||||||
|
vec3 fcos1(vec3 x) {
|
||||||
|
vec3 w = fwidth(x);
|
||||||
|
//if((length(w)==0.))return vec3(0.); // dFd fix2
|
||||||
|
//w*=0.; //test
|
||||||
|
float lw=length(w);
|
||||||
|
if((lw==0.)||isnan(lw)||isinf(lw)){vec3 tc=vec3(0.); for(int i=0;i<8;i++)tc+=cos(x+x*float(i-4)*(0.01*400./iResolution.y));return tc/8.;}
|
||||||
|
|
||||||
|
return cos(x) * smoothstep(3.14 * 2.0, 0.0, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 fcos2( vec3 x){return cos(x);}
|
||||||
|
vec3 fcos( vec3 x){
|
||||||
|
#ifdef AA_ALL
|
||||||
|
return fcos2(x);
|
||||||
|
#else
|
||||||
|
return fcos1(x);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 getColor(vec3 p)
|
||||||
|
{
|
||||||
|
// dFd fix, dFd broken on borders, but it fix only top level dFd, self intersection has border
|
||||||
|
//if (length(p) > 0.99)return vec3(0.);
|
||||||
|
p = abs(p);
|
||||||
|
|
||||||
|
p *= 01.25;
|
||||||
|
p = 0.5 * p / dot(p, p);
|
||||||
|
#ifdef ANIM_COLOR
|
||||||
|
p+=0.072*iTime;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float t = (0.13) * length(p);
|
||||||
|
vec3 col = vec3(0.3, 0.4, 0.5);
|
||||||
|
col += 0.12 * fcos(6.28318 * t * 1.0 + vec3(0.0, 0.8, 1.1));
|
||||||
|
col += 0.11 * fcos(6.28318 * t * 3.1 + vec3(0.3, 0.4, 0.1));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 5.1 + vec3(0.1, 0.7, 1.1));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 17.1 + vec3(0.2, 0.6, 0.7));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 31.1 + vec3(0.1, 0.6, 0.7));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 65.1 + vec3(0.0, 0.5, 0.8));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 115.1 + vec3(0.1, 0.4, 0.7));
|
||||||
|
col += 0.10 * fcos(6.28318 * t * 265.1 + vec3(1.1, 1.4, 2.7));
|
||||||
|
col = clamp(col, 0., 1.);
|
||||||
|
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
|
||||||
|
void calcColor(vec3 ro, vec3 rd, vec3 nor, float d, float len, int idx, bool si, float td, out vec4 colx,
|
||||||
|
out vec4 colsi)
|
||||||
|
{
|
||||||
|
|
||||||
|
vec3 pos = (ro + rd * d);
|
||||||
|
#ifdef DEBUG
|
||||||
|
float a = 1. - smoothstep(len - 0.15, len + 0.00001, length(pos));
|
||||||
|
if (idx == 0)colx = vec4(1., 0., 0., a);
|
||||||
|
if (idx == 1)colx = vec4(0., 1., 0., a);
|
||||||
|
if (idx == 2)colx = vec4(0., 0., 1., a);
|
||||||
|
if (si)
|
||||||
|
{
|
||||||
|
pos = (ro + rd * td);
|
||||||
|
float ta = 1. - smoothstep(len - 0.15, len + 0.00001, length(pos));
|
||||||
|
if (idx == 0)colsi = vec4(1., 0., 0., ta);
|
||||||
|
if (idx == 1)colsi = vec4(0., 1., 0., ta);
|
||||||
|
if (idx == 2)colsi = vec4(0., 0., 1., ta);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
float a = 1. - smoothstep(len - 0.15*0.5, len + 0.00001, length(pos));
|
||||||
|
//a=1.;
|
||||||
|
vec3 col = getColor(pos);
|
||||||
|
colx = vec4(col, a);
|
||||||
|
if (si)
|
||||||
|
{
|
||||||
|
pos = (ro + rd * td);
|
||||||
|
float ta = 1. - smoothstep(len - 0.15*0.5, len + 0.00001, length(pos));
|
||||||
|
//ta=1.;
|
||||||
|
col = getColor(pos);
|
||||||
|
colsi = vec4(col, ta);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// xSI is self intersect data, fade to fix dFd on edges
|
||||||
|
bool iBilinearPatch(in vec3 ro, in vec3 rd, in vec4 ps, in vec4 ph, in float sz, out float t, out vec3 norm,
|
||||||
|
out bool si, out float tsi, out vec3 normsi, out float fade, out float fadesi)
|
||||||
|
{
|
||||||
|
vec3 va = vec3(0.0, 0.0, ph.x + ph.w - ph.y - ph.z);
|
||||||
|
vec3 vb = vec3(0.0, ps.w - ps.y, ph.z - ph.x);
|
||||||
|
vec3 vc = vec3(ps.z - ps.x, 0.0, ph.y - ph.x);
|
||||||
|
vec3 vd = vec3(ps.xy, ph.x);
|
||||||
|
t = -1.;
|
||||||
|
tsi = -1.;
|
||||||
|
si = false;
|
||||||
|
fade = 1.;
|
||||||
|
fadesi = 1.;
|
||||||
|
norm=vec3(0.,1.,0.);normsi=vec3(0.,1.,0.);
|
||||||
|
|
||||||
|
float tmp = 1.0 / (vb.y * vc.x);
|
||||||
|
float a = 0.0;
|
||||||
|
float b = 0.0;
|
||||||
|
float c = 0.0;
|
||||||
|
float d = va.z * tmp;
|
||||||
|
float e = 0.0;
|
||||||
|
float f = 0.0;
|
||||||
|
float g = (vc.z * vb.y - vd.y * va.z) * tmp;
|
||||||
|
float h = (vb.z * vc.x - va.z * vd.x) * tmp;
|
||||||
|
float i = -1.0;
|
||||||
|
float j = (vd.x * vd.y * va.z + vd.z * vb.y * vc.x) * tmp - (vd.y * vb.z * vc.x + vd.x * vc.z * vb.y) * tmp;
|
||||||
|
|
||||||
|
float p = dot(vec3(a, b, c), rd.xzy * rd.xzy) + dot(vec3(d, e, f), rd.xzy * rd.zyx);
|
||||||
|
float q = dot(vec3(2.0, 2.0, 2.0) * ro.xzy * rd.xyz, vec3(a, b, c)) + dot(ro.xzz * rd.zxy, vec3(d, d, e)) +
|
||||||
|
dot(ro.yyx * rd.zxy, vec3(e, f, f)) + dot(vec3(g, h, i), rd.xzy);
|
||||||
|
float r =
|
||||||
|
dot(vec3(a, b, c), ro.xzy * ro.xzy) + dot(vec3(d, e, f), ro.xzy * ro.zyx) + dot(vec3(g, h, i), ro.xzy) + j;
|
||||||
|
|
||||||
|
if (abs(p) < 0.000001)
|
||||||
|
{
|
||||||
|
float tt = -r / q;
|
||||||
|
if (tt <= 0.)
|
||||||
|
return false;
|
||||||
|
t = tt;
|
||||||
|
// normal
|
||||||
|
|
||||||
|
vec3 pos = ro + t * rd;
|
||||||
|
if(length(pos)>sz)return false;
|
||||||
|
vec3 grad =
|
||||||
|
vec3(2.0) * pos.xzy * vec3(a, b, c) + pos.zxz * vec3(d, d, e) + pos.yyx * vec3(f, e, f) + vec3(g, h, i);
|
||||||
|
norm = -normalize(grad);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float sq = q * q - 4.0 * p * r;
|
||||||
|
if (sq < 0.0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float s = sqrt(sq);
|
||||||
|
float t0 = (-q + s) / (2.0 * p);
|
||||||
|
float t1 = (-q - s) / (2.0 * p);
|
||||||
|
float tt1 = min(t0 < 0.0 ? t1 : t0, t1 < 0.0 ? t0 : t1);
|
||||||
|
float tt2 = max(t0 > 0.0 ? t1 : t0, t1 > 0.0 ? t0 : t1);
|
||||||
|
float tt0 = tt1;
|
||||||
|
if (tt0 <= 0.)
|
||||||
|
return false;
|
||||||
|
vec3 pos = ro + tt0 * rd;
|
||||||
|
// black border on end of circle and self intersection with alpha come because dFd
|
||||||
|
// uncomment this to see or rename fcos2 to fcos
|
||||||
|
//sz+=0.3;
|
||||||
|
bool ru = step(sz, length(pos)) > 0.5;
|
||||||
|
if (ru)
|
||||||
|
{
|
||||||
|
tt0 = tt2;
|
||||||
|
pos = ro + tt0 * rd;
|
||||||
|
}
|
||||||
|
if (tt0 <= 0.)
|
||||||
|
return false;
|
||||||
|
bool ru2 = step(sz, length(pos)) > 0.5;
|
||||||
|
if (ru2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// self intersect
|
||||||
|
if ((tt2 > 0.) && ((!ru)) && !(step(sz, length(ro + tt2 * rd)) > 0.5))
|
||||||
|
{
|
||||||
|
si = true;
|
||||||
|
fadesi=s;
|
||||||
|
tsi = tt2;
|
||||||
|
vec3 tpos = ro + tsi * rd;
|
||||||
|
// normal
|
||||||
|
vec3 tgrad = vec3(2.0) * tpos.xzy * vec3(a, b, c) + tpos.zxz * vec3(d, d, e) +
|
||||||
|
tpos.yyx * vec3(f, e, f) + vec3(g, h, i);
|
||||||
|
normsi = -normalize(tgrad);
|
||||||
|
}
|
||||||
|
|
||||||
|
fade=s;
|
||||||
|
t = tt0;
|
||||||
|
// normal
|
||||||
|
vec3 grad =
|
||||||
|
vec3(2.0) * pos.xzy * vec3(a, b, c) + pos.zxz * vec3(d, d, e) + pos.yyx * vec3(f, e, f) + vec3(g, h, i);
|
||||||
|
norm = -normalize(grad);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float dot2( in vec3 v ) { return dot(v,v); }
|
||||||
|
|
||||||
|
float segShadow( in vec3 ro, in vec3 rd, in vec3 pa, float sh )
|
||||||
|
{
|
||||||
|
float dm = dot(rd.yz,rd.yz);
|
||||||
|
float k1 = (ro.x-pa.x)*dm;
|
||||||
|
float k2 = (ro.x+pa.x)*dm;
|
||||||
|
vec2 k5 = (ro.yz+pa.yz)*dm;
|
||||||
|
float k3 = dot(ro.yz+pa.yz,rd.yz);
|
||||||
|
vec2 k4 = (pa.yz+pa.yz)*rd.yz;
|
||||||
|
vec2 k6 = (pa.yz+pa.yz)*dm;
|
||||||
|
|
||||||
|
for( int i=0; i<4 + ANGLE_loops; i++ )
|
||||||
|
{
|
||||||
|
vec2 s = vec2(i&1,i>>1);
|
||||||
|
float t = dot(s,k4) - k3;
|
||||||
|
|
||||||
|
if( t>0.0 )
|
||||||
|
sh = min(sh,dot2(vec3(clamp(-rd.x*t,k1,k2),k5-k6*s)+rd*t)/(t*t));
|
||||||
|
}
|
||||||
|
return sh;
|
||||||
|
}
|
||||||
|
|
||||||
|
float boxSoftShadow( in vec3 ro, in vec3 rd, in vec3 rad, in float sk )
|
||||||
|
{
|
||||||
|
rd += 0.0001 * (1.0 - abs(sign(rd)));
|
||||||
|
vec3 rdd = rd;
|
||||||
|
vec3 roo = ro;
|
||||||
|
|
||||||
|
vec3 m = 1.0/rdd;
|
||||||
|
vec3 n = m*roo;
|
||||||
|
vec3 k = abs(m)*rad;
|
||||||
|
|
||||||
|
vec3 t1 = -n - k;
|
||||||
|
vec3 t2 = -n + k;
|
||||||
|
|
||||||
|
float tN = max( max( t1.x, t1.y ), t1.z );
|
||||||
|
float tF = min( min( t2.x, t2.y ), t2.z );
|
||||||
|
|
||||||
|
if( tN<tF && tF>0.0) return 0.0;
|
||||||
|
|
||||||
|
float sh = 1.0;
|
||||||
|
sh = segShadow( roo.xyz, rdd.xyz, rad.xyz, sh );
|
||||||
|
sh = segShadow( roo.yzx, rdd.yzx, rad.yzx, sh );
|
||||||
|
sh = segShadow( roo.zxy, rdd.zxy, rad.zxy, sh );
|
||||||
|
sh = clamp(sk*sqrt(sh),0.0,1.0);
|
||||||
|
return sh*sh*(3.0-2.0*sh);
|
||||||
|
}
|
||||||
|
|
||||||
|
float box(in vec3 ro, in vec3 rd, in vec3 r, out vec3 nn, bool entering)
|
||||||
|
{
|
||||||
|
rd += 0.0001 * (1.0 - abs(sign(rd)));
|
||||||
|
vec3 dr = 1.0 / rd;
|
||||||
|
vec3 n = ro * dr;
|
||||||
|
vec3 k = r * abs(dr);
|
||||||
|
|
||||||
|
vec3 pin = -k - n;
|
||||||
|
vec3 pout = k - n;
|
||||||
|
float tin = max(pin.x, max(pin.y, pin.z));
|
||||||
|
float tout = min(pout.x, min(pout.y, pout.z));
|
||||||
|
if (tin > tout)
|
||||||
|
return -1.;
|
||||||
|
if (entering)
|
||||||
|
{
|
||||||
|
nn = -sign(rd) * step(pin.zxy, pin.xyz) * step(pin.yzx, pin.xyz);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nn = sign(rd) * step(pout.xyz, pout.zxy) * step(pout.xyz, pout.yzx);
|
||||||
|
}
|
||||||
|
return entering ? tin : tout;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 bgcol(in vec3 rd)
|
||||||
|
{
|
||||||
|
return mix(vec3(0.01), vec3(0.336, 0.458, .668), 1. - pow(abs(rd.z+0.25), 1.3));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 background(in vec3 ro, in vec3 rd , vec3 l_dir, out float alpha)
|
||||||
|
{
|
||||||
|
#ifdef ONLY_BOX
|
||||||
|
alpha=0.;
|
||||||
|
return vec3(0.01);
|
||||||
|
#endif
|
||||||
|
float t = (-BOXDIMS.z - ro.z) / rd.z;
|
||||||
|
alpha=0.;
|
||||||
|
vec3 bgc = bgcol(rd);
|
||||||
|
if (t < 0.)
|
||||||
|
return bgc;
|
||||||
|
vec2 uv = ro.xy + t * rd.xy;
|
||||||
|
#ifdef NO_SHADOW
|
||||||
|
float shad=1.;
|
||||||
|
#else
|
||||||
|
float shad = boxSoftShadow((ro + t * rd), normalize(l_dir+vec3(0.,0.,1.))*rotz(PI*0.65) , BOXDIMS, 1.5);
|
||||||
|
#endif
|
||||||
|
float aofac = smoothstep(-0.95, .75, length(abs(uv) - min(abs(uv), vec2(0.45))));
|
||||||
|
aofac = min(aofac,smoothstep(-0.65, 1., shad));
|
||||||
|
float lght=max(dot(normalize(ro + t * rd+vec3(0.,-0.,-5.)), normalize(l_dir-vec3(0.,0.,1.))*rotz(PI*0.65)), 0.0);
|
||||||
|
vec3 col = mix(vec3(0.4), vec3(.71,.772,0.895), lght*lght* aofac+ 0.05) * aofac;
|
||||||
|
alpha=1.-smoothstep(7.,10.,length(uv));
|
||||||
|
#ifdef SHADOW_ALPHA
|
||||||
|
//alpha=clamp(alpha*max(lght*lght*0.95,(1.-aofac)*1.25),0.,1.);
|
||||||
|
alpha=clamp(alpha*(1.-aofac)*1.25,0.,1.);
|
||||||
|
#endif
|
||||||
|
return mix(col*length(col)*0.8,bgc,smoothstep(7.,10.,length(uv)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define swap(a,b) tv=a;a=b;b=tv
|
||||||
|
|
||||||
|
vec4 insides(vec3 ro, vec3 rd, vec3 nor_c, vec3 l_dir, out float tout)
|
||||||
|
{
|
||||||
|
tout = -1.;
|
||||||
|
vec3 trd=rd;
|
||||||
|
|
||||||
|
vec3 col = vec3(0.);
|
||||||
|
|
||||||
|
float pi = 3.1415926;
|
||||||
|
|
||||||
|
if (abs(nor_c.x) > 0.5)
|
||||||
|
{
|
||||||
|
rd = rd.xzy * nor_c.x;
|
||||||
|
ro = ro.xzy * nor_c.x;
|
||||||
|
}
|
||||||
|
else if (abs(nor_c.z) > 0.5)
|
||||||
|
{
|
||||||
|
l_dir *= roty(pi);
|
||||||
|
rd = rd.yxz * nor_c.z;
|
||||||
|
ro = ro.yxz * nor_c.z;
|
||||||
|
}
|
||||||
|
else if (abs(nor_c.y) > 0.5)
|
||||||
|
{
|
||||||
|
l_dir *= rotz(-pi * 0.5);
|
||||||
|
rd = rd * nor_c.y;
|
||||||
|
ro = ro * nor_c.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ANIM_SHAPE
|
||||||
|
float curvature = (0.001+1.5-1.5*smoothstep(0.,8.5,mod((iTime+tshift)*0.44,20.))*(1.-smoothstep(10.,18.5,mod((iTime+tshift)*0.44,20.))));
|
||||||
|
// curvature(to not const above) make compilation on Angle 15+ sec
|
||||||
|
#else
|
||||||
|
#ifdef STATIC_SHAPE
|
||||||
|
const float curvature = STATIC_SHAPE;
|
||||||
|
#else
|
||||||
|
const float curvature = .5;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
float bil_size = 1.;
|
||||||
|
vec4 ps = vec4(-bil_size, -bil_size, bil_size, bil_size) * curvature;
|
||||||
|
vec4 ph = vec4(-bil_size, bil_size, bil_size, -bil_size) * curvature;
|
||||||
|
|
||||||
|
vec4 [3]colx=vec4[3](vec4(0.),vec4(0.),vec4(0.));
|
||||||
|
vec3 [3]dx=vec3[3](vec3(-1.),vec3(-1.),vec3(-1.));
|
||||||
|
vec4 [3]colxsi=vec4[3](vec4(0.),vec4(0.),vec4(0.));
|
||||||
|
int [3]order=int[3](0,1,2);
|
||||||
|
|
||||||
|
for (int i = 0; i < 3 + ANGLE_loops; i++)
|
||||||
|
{
|
||||||
|
if (abs(nor_c.x) > 0.5)
|
||||||
|
{
|
||||||
|
ro *= rotz(-pi * (1. / float(3)));
|
||||||
|
rd *= rotz(-pi * (1. / float(3)));
|
||||||
|
}
|
||||||
|
else if (abs(nor_c.z) > 0.5)
|
||||||
|
{
|
||||||
|
ro *= rotz(pi * (1. / float(3)));
|
||||||
|
rd *= rotz(pi * (1. / float(3)));
|
||||||
|
}
|
||||||
|
else if (abs(nor_c.y) > 0.5)
|
||||||
|
{
|
||||||
|
ro *= rotx(pi * (1. / float(3)));
|
||||||
|
rd *= rotx(pi * (1. / float(3)));
|
||||||
|
}
|
||||||
|
vec3 normnew;
|
||||||
|
float tnew;
|
||||||
|
bool si;
|
||||||
|
float tsi;
|
||||||
|
vec3 normsi;
|
||||||
|
float fade;
|
||||||
|
float fadesi;
|
||||||
|
|
||||||
|
if (iBilinearPatch(ro, rd, ps, ph, bil_size, tnew, normnew, si, tsi, normsi, fade, fadesi))
|
||||||
|
{
|
||||||
|
if (tnew > 0.)
|
||||||
|
{
|
||||||
|
vec4 tcol, tcolsi;
|
||||||
|
calcColor(ro, rd, normnew, tnew, bil_size, i, si, tsi, tcol, tcolsi);
|
||||||
|
if (tcol.a > 0.0)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
vec3 tvalx = vec3(tnew, float(si), tsi);
|
||||||
|
dx[i]=tvalx;
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
colx[i]=tcol;
|
||||||
|
if (si)colxsi[i]=tcolsi;
|
||||||
|
#else
|
||||||
|
|
||||||
|
float dif = clamp(dot(normnew, l_dir), 0.0, 1.0);
|
||||||
|
float amb = clamp(0.5 + 0.5 * dot(normnew, l_dir), 0.0, 1.0);
|
||||||
|
|
||||||
|
{
|
||||||
|
#ifdef USE_COLOR
|
||||||
|
vec3 shad = 0.57 * color_blue * amb + 1.5*color_blue.bgr * dif;
|
||||||
|
const vec3 tcr = color_red;
|
||||||
|
#else
|
||||||
|
vec3 shad = vec3(0.32, 0.43, 0.54) * amb + vec3(1.0, 0.9, 0.7) * dif;
|
||||||
|
const vec3 tcr = vec3(1.,0.21,0.11);
|
||||||
|
#endif
|
||||||
|
float ta = clamp(length(tcol.rgb),0.,1.);
|
||||||
|
tcol=clamp(tcol*tcol*2.,0.,1.);
|
||||||
|
vec4 tvalx =
|
||||||
|
vec4((tcol.rgb*shad*1.4 + 3.*(tcr*tcol.rgb)*clamp(1.-(amb+dif),0.,1.)), min(tcol.a,ta));
|
||||||
|
tvalx.rgb=clamp(2.*tvalx.rgb*tvalx.rgb,0.,1.);
|
||||||
|
tvalx*=(min(fade*5.,1.));
|
||||||
|
colx[i]=tvalx;
|
||||||
|
}
|
||||||
|
if (si)
|
||||||
|
{
|
||||||
|
dif = clamp(dot(normsi, l_dir), 0.0, 1.0);
|
||||||
|
amb = clamp(0.5 + 0.5 * dot(normsi, l_dir), 0.0, 1.0);
|
||||||
|
{
|
||||||
|
#ifdef USE_COLOR
|
||||||
|
vec3 shad = 0.57 * color_blue * amb + 1.5*color_blue.bgr * dif;
|
||||||
|
const vec3 tcr = color_red;
|
||||||
|
#else
|
||||||
|
vec3 shad = vec3(0.32, 0.43, 0.54) * amb + vec3(1.0, 0.9, 0.7) * dif;
|
||||||
|
const vec3 tcr = vec3(1.,0.21,0.11);
|
||||||
|
#endif
|
||||||
|
float ta = clamp(length(tcolsi.rgb),0.,1.);
|
||||||
|
tcolsi=clamp(tcolsi*tcolsi*2.,0.,1.);
|
||||||
|
vec4 tvalx =
|
||||||
|
vec4(tcolsi.rgb * shad + 3.*(tcr*tcolsi.rgb)*clamp(1.-(amb+dif),0.,1.), min(tcolsi.a,ta));
|
||||||
|
tvalx.rgb=clamp(2.*tvalx.rgb*tvalx.rgb,0.,1.);
|
||||||
|
tvalx.rgb*=(min(fadesi*5.,1.));
|
||||||
|
colxsi[i]=tvalx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// transparency logic and layers sorting
|
||||||
|
float a = 1.;
|
||||||
|
if (dx[0].x < dx[1].x){{vec3 swap(dx[0], dx[1]);}{int swap(order[0], order[1]);}}
|
||||||
|
if (dx[1].x < dx[2].x){{vec3 swap(dx[1], dx[2]);}{int swap(order[1], order[2]);}}
|
||||||
|
if (dx[0].x < dx[1].x){{vec3 swap(dx[0], dx[1]);}{int swap(order[0], order[1]);}}
|
||||||
|
|
||||||
|
tout = max(max(dx[0].x, dx[1].x), dx[2].x);
|
||||||
|
|
||||||
|
if (dx[0].y < 0.5)
|
||||||
|
{
|
||||||
|
a=colx[order[0]].a;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !(defined(DEBUG)&&defined(BUG))
|
||||||
|
|
||||||
|
// self intersection
|
||||||
|
bool [3] rul= bool[3](
|
||||||
|
((dx[0].y > 0.5) && (dx[1].x <= 0.)),
|
||||||
|
((dx[1].y > 0.5) && (dx[0].x > dx[1].z)),
|
||||||
|
((dx[2].y > 0.5) && (dx[1].x > dx[2].z))
|
||||||
|
);
|
||||||
|
for(int k=0;k<3;k++){
|
||||||
|
if(rul[k]){
|
||||||
|
vec4 tcolxsi = vec4(0.);
|
||||||
|
tcolxsi=colxsi[order[k]];
|
||||||
|
vec4 tcolx = vec4(0.);
|
||||||
|
tcolx=colx[order[k]];
|
||||||
|
|
||||||
|
vec4 tvalx = mix(tcolxsi, tcolx, tcolx.a);
|
||||||
|
colx[order[k]]=tvalx;
|
||||||
|
|
||||||
|
vec4 tvalx2 = mix(vec4(0.), tvalx, max(tcolx.a, tcolxsi.a));
|
||||||
|
colx[order[k]]=tvalx2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float a1 = (dx[1].y < 0.5) ? colx[order[1]].a : ((dx[1].z > dx[0].x) ? colx[order[1]].a : 1.);
|
||||||
|
float a2 = (dx[2].y < 0.5) ? colx[order[2]].a : ((dx[2].z > dx[1].x) ? colx[order[2]].a : 1.);
|
||||||
|
col = mix(mix(colx[order[0]].rgb, colx[order[1]].rgb, a1), colx[order[2]].rgb, a2);
|
||||||
|
a = max(max(a, a1), a2);
|
||||||
|
return vec4(col, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage(out vec4 fragColor, in vec2 fragCoord)
|
||||||
|
{
|
||||||
|
float osc = 0.5;
|
||||||
|
vec3 l_dir = normalize(vec3(0., 1., 0.));
|
||||||
|
l_dir *= rotz(0.5);
|
||||||
|
float mouseY = 1.0 * 0.5 * PI;
|
||||||
|
// Note: MOUSE_control disabled (no iMouse support)
|
||||||
|
// #ifdef MOUSE_control
|
||||||
|
// mouseY = (1.0 - 1.15 * iMouse.y / iResolution.y) * 0.5 * PI;
|
||||||
|
// if(iMouse.y < 1.)
|
||||||
|
// #endif
|
||||||
|
#ifdef CAMERA_POS
|
||||||
|
mouseY = PI*CAMERA_POS;
|
||||||
|
#else
|
||||||
|
mouseY = PI*0.49 - smoothstep(0.,8.5,mod((iTime+tshift)*0.33,25.))*(1.-smoothstep(14.,24.0,mod((iTime+tshift)*0.33,25.))) * 0.55 * PI;
|
||||||
|
#endif
|
||||||
|
#ifdef ROTATION_SPEED
|
||||||
|
float mouseX = -2.*PI-0.25*(iTime*ROTATION_SPEED+tshift);
|
||||||
|
#else
|
||||||
|
float mouseX = -2.*PI-0.25*(iTime+tshift);
|
||||||
|
#endif
|
||||||
|
// Note: MOUSE_control disabled (no iMouse support)
|
||||||
|
// #ifdef MOUSE_control
|
||||||
|
// mouseX+=-(iMouse.x / iResolution.x) * 2. * PI;
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
#ifdef CAMERA_FAR
|
||||||
|
vec3 eye = (2. + CAMERA_FAR) * vec3(cos(mouseX) * cos(mouseY), sin(mouseX) * cos(mouseY), sin(mouseY));
|
||||||
|
#else
|
||||||
|
vec3 eye = 4. * vec3(cos(mouseX) * cos(mouseY), sin(mouseX) * cos(mouseY), sin(mouseY));
|
||||||
|
#endif
|
||||||
|
vec3 w = normalize(-eye);
|
||||||
|
vec3 up = vec3(0., 0., 1.);
|
||||||
|
vec3 u = normalize(cross(w, up));
|
||||||
|
vec3 v = cross(u, w);
|
||||||
|
|
||||||
|
vec4 tot=vec4(0.);
|
||||||
|
#if defined(AA_CUBE)||defined(AA_ALL)
|
||||||
|
#ifdef AA_CUBE
|
||||||
|
const int AA = AA_CUBE;
|
||||||
|
#else
|
||||||
|
const int AA = AA_ALL;
|
||||||
|
#endif
|
||||||
|
vec3 incol_once=vec3(0.);
|
||||||
|
bool in_once=false;
|
||||||
|
vec4 incolbg_once=vec4(0.);
|
||||||
|
bool bg_in_once=false;
|
||||||
|
vec4 outcolbg_once=vec4(0.);
|
||||||
|
bool bg_out_once=false;
|
||||||
|
for( int mx=0; mx<AA; mx++ )
|
||||||
|
for( int nx=0; nx<AA; nx++ )
|
||||||
|
{
|
||||||
|
vec2 o = vec2(mod(float(mx+AA/2),float(AA)),mod(float(nx+AA/2),float(AA))) / float(AA) - 0.5;
|
||||||
|
vec2 uv = (fragCoord + o - 0.5 * iResolution.xy) / iResolution.x;
|
||||||
|
#else
|
||||||
|
vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.x;
|
||||||
|
#endif
|
||||||
|
vec3 rd = normalize(w * FDIST + uv.x * u + uv.y * v);
|
||||||
|
|
||||||
|
vec3 ni;
|
||||||
|
float t = box(eye, rd, BOXDIMS, ni, true);
|
||||||
|
vec3 ro = eye + t * rd;
|
||||||
|
vec2 coords = ro.xy * ni.z/BOXDIMS.xy + ro.yz * ni.x/BOXDIMS.yz + ro.zx * ni.y/BOXDIMS.zx;
|
||||||
|
float fadeborders = (1.-smoothstep(0.915,1.05,abs(coords.x)))*(1.-smoothstep(0.915,1.05,abs(coords.y)));
|
||||||
|
|
||||||
|
if (t > 0.)
|
||||||
|
{
|
||||||
|
float ang = -iTime * 0.33;
|
||||||
|
vec3 col = vec3(0.);
|
||||||
|
#ifdef AA_CUBE
|
||||||
|
if(in_once)col=incol_once;
|
||||||
|
else{
|
||||||
|
in_once=true;
|
||||||
|
#endif
|
||||||
|
float R0 = (IOR - 1.) / (IOR + 1.);
|
||||||
|
R0 *= R0;
|
||||||
|
|
||||||
|
vec2 theta = vec2(0.);
|
||||||
|
vec3 n = vec3(cos(theta.x) * sin(theta.y), sin(theta.x) * sin(theta.y), cos(theta.y));
|
||||||
|
|
||||||
|
vec3 nr = n.zxy * ni.x + n.yzx * ni.y + n.xyz * ni.z;
|
||||||
|
vec3 rdr = reflect(rd, nr);
|
||||||
|
float talpha;
|
||||||
|
vec3 reflcol = background(ro, rdr, l_dir,talpha);
|
||||||
|
|
||||||
|
vec3 rd2 = refract(rd, nr, 1. / IOR);
|
||||||
|
|
||||||
|
float accum = 1.;
|
||||||
|
vec3 no2 = ni;
|
||||||
|
vec3 ro_refr = ro;
|
||||||
|
|
||||||
|
vec4 [2] colo = vec4[2](vec4(0.),vec4(0.));
|
||||||
|
|
||||||
|
for (int j = 0; j < 2 + ANGLE_loops; j++)
|
||||||
|
{
|
||||||
|
float tb;
|
||||||
|
vec2 coords2 = ro_refr.xy * no2.z + ro_refr.yz * no2.x + ro_refr.zx * no2.y;
|
||||||
|
vec3 eye2 = vec3(coords2, -1.);
|
||||||
|
vec3 rd2trans = rd2.yzx * no2.x + rd2.zxy * no2.y + rd2.xyz * no2.z;
|
||||||
|
|
||||||
|
rd2trans.z = -rd2trans.z;
|
||||||
|
vec4 internalcol = insides(eye2, rd2trans, no2, l_dir, tb);
|
||||||
|
if (tb > 0.)
|
||||||
|
{
|
||||||
|
internalcol.rgb *= accum;
|
||||||
|
colo[j]=internalcol;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((tb <= 0.) || (internalcol.a < 1.))
|
||||||
|
{
|
||||||
|
float tout = box(ro_refr, rd2, BOXDIMS, no2, false);
|
||||||
|
no2 = n.zyx * no2.x + n.xzy * no2.y + n.yxz * no2.z;
|
||||||
|
vec3 rout = ro_refr + tout * rd2;
|
||||||
|
vec3 rdout = refract(rd2, -no2, IOR);
|
||||||
|
float fresnel2 = R0 + (1. - R0) * pow(1. - dot(rdout, no2), 1.3);
|
||||||
|
rd2 = reflect(rd2, -no2);
|
||||||
|
|
||||||
|
#ifdef backside_refl
|
||||||
|
if((dot(rdout, no2))>0.5){fresnel2=1.;}
|
||||||
|
#endif
|
||||||
|
ro_refr = rout;
|
||||||
|
ro_refr.z = max(ro_refr.z, -0.999);
|
||||||
|
|
||||||
|
accum *= fresnel2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
float fresnel = R0 + (1. - R0) * pow(1. - dot(-rd, nr), 5.);
|
||||||
|
col = mix(mix(colo[1].rgb * colo[1].a, colo[0].rgb, colo[0].a)*fadeborders, reflcol, pow(fresnel, 1.5));
|
||||||
|
col=clamp(col,0.,1.);
|
||||||
|
#ifdef AA_CUBE
|
||||||
|
}
|
||||||
|
incol_once=col;
|
||||||
|
if(!bg_in_once){
|
||||||
|
bg_in_once=true;
|
||||||
|
float alpha;
|
||||||
|
incolbg_once = vec4(background(eye, rd, l_dir, alpha), 0.15);
|
||||||
|
#if defined(BG_ALPHA)||defined(ONLY_BOX)||defined(SHADOW_ALPHA)
|
||||||
|
incolbg_once.w = alpha;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float cineshader_alpha = 0.;
|
||||||
|
cineshader_alpha = clamp(0.15*dot(eye,ro),0.,1.);
|
||||||
|
vec4 tcolx = vec4(col, cineshader_alpha);
|
||||||
|
#if defined(BG_ALPHA)||defined(ONLY_BOX)||defined(SHADOW_ALPHA)
|
||||||
|
tcolx.w = 1.;
|
||||||
|
#endif
|
||||||
|
tot += tcolx;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vec4 tcolx = vec4(0.);
|
||||||
|
#ifdef AA_CUBE
|
||||||
|
if(!bg_out_once){
|
||||||
|
bg_out_once=true;
|
||||||
|
#endif
|
||||||
|
float alpha;
|
||||||
|
tcolx = vec4(background(eye, rd, l_dir, alpha), 0.15);
|
||||||
|
#if defined(BG_ALPHA)||defined(ONLY_BOX)||defined(SHADOW_ALPHA)
|
||||||
|
tcolx.w = alpha;
|
||||||
|
#endif
|
||||||
|
#ifdef AA_CUBE
|
||||||
|
outcolbg_once=tcolx;
|
||||||
|
}else tcolx=max(outcolbg_once,incolbg_once);
|
||||||
|
#endif
|
||||||
|
tot += tcolx;
|
||||||
|
}
|
||||||
|
#if defined(AA_CUBE)||defined(AA_ALL)
|
||||||
|
}
|
||||||
|
tot /= float(AA*AA);
|
||||||
|
#endif
|
||||||
|
fragColor = tot;
|
||||||
|
#ifdef NO_ALPHA
|
||||||
|
fragColor.w = 1.;
|
||||||
|
#endif
|
||||||
|
fragColor.rgb=clamp(fragColor.rgb,0.,1.);
|
||||||
|
// Note: iChannel0 line removed (texture channel not supported)
|
||||||
|
// Original line was for optional background blending when BG_ALPHA/ONLY_BOX/SHADOW_ALPHA defined
|
||||||
|
// #if defined(BG_ALPHA)||defined(ONLY_BOX)||defined(SHADOW_ALPHA)
|
||||||
|
// fragColor.rgb=fragColor.rgb*fragColor.w+texture(iChannel0, fragCoord/iResolution.xy).rgb*(1.-fragColor.w);
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
2
shaders/cube_lines/meta.txt
Normal file
2
shaders/cube_lines/meta.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Name: Cube lines
|
||||||
|
Author: Danil
|
||||||
127
shaders/dbz/dbz.frag.msl
Normal file
127
shaders/dbz/dbz.frag.msl
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
// New Leaked 3I/Atlas NASA Footage — msm01
|
||||||
|
// MSL port of dbz.vk.glsl.
|
||||||
|
|
||||||
|
struct ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
float2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassthroughVOut {
|
||||||
|
float4 pos [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
constant float NBCaps = 3.0;
|
||||||
|
|
||||||
|
static float2x2 r2d(float a) {
|
||||||
|
float c = cos(a), s = sin(a);
|
||||||
|
return float2x2(c, s, -s, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float hash12(float2 p) {
|
||||||
|
float3 p3 = fract(float3(p.xyx) * 0.1031);
|
||||||
|
p3 += dot(p3, p3.yzx + 33.33);
|
||||||
|
return fract((p3.x + p3.y) * p3.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float fbm(float2 v_p) {
|
||||||
|
float pvpx = v_p.x;
|
||||||
|
float2 V1 = float2(floor(pvpx));
|
||||||
|
float2 V2 = float2(floor(pvpx + 1.0));
|
||||||
|
return mix(hash12(V1), hash12(V2), smoothstep(0.0, 1.0, fract(pvpx)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define S(a,b,c) smoothstep(a,b,c)
|
||||||
|
|
||||||
|
fragment float4 dbz_fs(PassthroughVOut in [[stage_in]],
|
||||||
|
constant ShadertoyUBO& U [[buffer(0)]]) {
|
||||||
|
float2 fragCoord = in.uv * U.iResolution;
|
||||||
|
float2 p = float2((1.0 / U.iResolution.y) * (fragCoord.x - U.iResolution.x / 2.0),
|
||||||
|
fragCoord.y / U.iResolution.y - 0.5);
|
||||||
|
|
||||||
|
p.x = -p.x;
|
||||||
|
p *= 150.0;
|
||||||
|
|
||||||
|
float4 col = float4(0.05, 0.05, 0.15, 1.0);
|
||||||
|
|
||||||
|
float2 save1 = p;
|
||||||
|
|
||||||
|
p = p * r2d(-0.05);
|
||||||
|
col = mix(col, float4(0.2, 0.3, 0.5, 1.0),
|
||||||
|
smoothstep(75.0, 0.0, abs(p.y - 5.0 * fbm(float2(0.01 * (p.x - 33.333 * U.iTime))) + 3.5)));
|
||||||
|
p = p * r2d(0.05);
|
||||||
|
|
||||||
|
p = p * r2d(-0.05);
|
||||||
|
p *= 0.35;
|
||||||
|
p += float2(-5.0 * U.iTime, 0.0);
|
||||||
|
|
||||||
|
float2 b = fract(5.0 * p);
|
||||||
|
p = floor(5.0 * p);
|
||||||
|
if (fbm(float2(p.x * p.y)) > 0.996) {
|
||||||
|
col += clamp(1.0 - pow(3.0 * length(b + float2(-0.5)), 0.5), 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
p = save1;
|
||||||
|
float2 save3;
|
||||||
|
|
||||||
|
float Nb_Capsules = clamp(NBCaps, 0.0, 4.0);
|
||||||
|
for (float i = 0.0; i < Nb_Capsules; i++) {
|
||||||
|
p = save1;
|
||||||
|
p = p * r2d(-0.05);
|
||||||
|
p *= 2.5;
|
||||||
|
p *= 1.0 - 0.25 * i;
|
||||||
|
p += float2(150.0 * fbm(float2(0.15 * U.iTime + i * 54.321)) - 75.0,
|
||||||
|
50.0 * sin(0.25 * U.iTime + i * 54.321) - 25.0);
|
||||||
|
save3 = p;
|
||||||
|
|
||||||
|
p *= 0.04;
|
||||||
|
p.y = abs(p.y);
|
||||||
|
|
||||||
|
if (p.x > 0.0) {
|
||||||
|
col += float4(0.0, 1.0, 0.5, 1.0) * smoothstep(0.2, 0.0, abs(p.y - 0.05 * fbm(float2(1.5 * p.x - 40.0 * U.iTime))) - 0.05) * smoothstep(29.0, 0.0, abs(p.x));
|
||||||
|
col += float4(1.0, 1.0, 1.0, 1.0) * smoothstep(0.1, 0.0, abs(p.y - 0.05 * fbm(float2(1.5 * p.x - 40.0 * U.iTime))) - 0.05) * smoothstep(29.0, 0.0, abs(p.x));
|
||||||
|
}
|
||||||
|
|
||||||
|
p = save3;
|
||||||
|
p.y = abs(p.y);
|
||||||
|
p += float2(-10.0, 0.0);
|
||||||
|
p *= float2(0.75, 1.0);
|
||||||
|
|
||||||
|
col += 0.8 * float4(0.0, 1.0, 0.5, 1.0) * S(20.0, 0.0, length(p) - 25.0 + 7.0 * sin(0.30 * length(p) * atan2(p.y, p.x) + 55.0 * U.iTime));
|
||||||
|
col += 0.8 * float4(1.0, 1.0, 1.0, 1.0) * S(20.0, 0.0, length(p) - 20.0 + 7.0 * sin(0.30 * length(p) * atan2(p.y, p.x) + 55.0 * U.iTime));
|
||||||
|
|
||||||
|
p = save3;
|
||||||
|
|
||||||
|
col = mix(col, float4(1.0), 0.5 * S(10.0, 0.0, length(p + float2(5.0, 0.0)) - 20.0) * abs(sin(50.0 * U.iTime)));
|
||||||
|
col = mix(col, float4(1.0), 0.5 * S(20.0, 0.0, length(p + float2(5.0, 0.0)) - 20.0));
|
||||||
|
col = mix(col, float4(1.0), S(0.01, 0.0, length(p) - 20.0));
|
||||||
|
|
||||||
|
if (length(p) - 20.0 < 0.0) {
|
||||||
|
col = mix(col, float4(0.65, 0.68, 0.68 + 0.1 * (3.0 - i), 1.0), S(0.5, 0.0, length(p - float2(2.0, 0.0)) - 17.0));
|
||||||
|
if (S(0.0, 1.0, length(float2(3.0, 2.0) * p + float2(33.5, 0.0)) - 23.0) > 0.0) {
|
||||||
|
col = mix(col, float4(0.45, 0.55, 0.55 + 0.1 * (3.0 - i), 1.0),
|
||||||
|
0.75 * S(0.5, 0.0, length(p - float2(2.0, 0.0) + 0.5 * fbm(float2(4.5 * atan2(p.y, p.x)))) - 9.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
col = mix(col, float4(0.0), S(0.2, 0.0, abs(length(p) - 19.9) - 0.20));
|
||||||
|
col = mix(col, float4(0.5, 0.2, 0.3, 1.0)
|
||||||
|
- S(5.0, 0.0, length(p + float2(-6.0, 15.0)) - 20.0)
|
||||||
|
- S(0.25, 0.0, abs(length(p + float2(0.0, 3.0)) - 15.0) - 0.4)
|
||||||
|
- S(0.0, 1.5, p.y - 8.5)
|
||||||
|
+ 0.25 * float4(1.0, 0.5, 0.0, 1.0) * S(10.0, 0.0, abs(p.y))
|
||||||
|
,
|
||||||
|
S(0.5, 0.0, length(float2(3.0, 2.0) * p + float2(35.0, 0.0)) - 19.9));
|
||||||
|
|
||||||
|
col = mix(col, float4(0.0, 0.0, 0.0, 1.0), S(1.0, 0.0, abs(length(float2(3.0, 2.0) * p + float2(35.0, 0.0)) - 19.9) - 0.1));
|
||||||
|
col = mix(col, float4(0.0, 0.0, 0.0, 1.0), S(1.0, 0.0, abs(length(float2(3.0, 2.0) * p + float2(33.5, 0.0)) - 23.0) - 0.1));
|
||||||
|
|
||||||
|
if (p.y > 0.0) col = mix(col, float4(0.0, 0.0, 0.0, 1.0), S(1.0, 0.0, abs(length(float2(3.0, 2.0) * p + float2(29.0, 0.0)) - 30.0) - 0.1));
|
||||||
|
if (p.y < 0.0) col = mix(col, float4(0.0, 0.0, 0.0, 1.0), S(1.0, 0.0, abs(length(float2(3.0, 2.0) * p + float2(-31.0, 0.0)) - 30.0) - 0.1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return clamp(col, 0.0, 1.0);
|
||||||
|
}
|
||||||
BIN
shaders/dbz/dbz.frag.spv
Normal file
BIN
shaders/dbz/dbz.frag.spv
Normal file
Binary file not shown.
127
shaders/dbz/dbz.vk.glsl
Normal file
127
shaders/dbz/dbz.vk.glsl
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// Name: New Leaked 3I/Atlas NASA Footage
|
||||||
|
// Author: msm01
|
||||||
|
// URL: https://www.shadertoy.com/view/3ftcRr
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 vUV;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0) uniform ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
vec2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define s(a,b,c) smoothstep(a,b,c)
|
||||||
|
#define PI 3.14159
|
||||||
|
#define NBCaps 3.
|
||||||
|
|
||||||
|
mat2 r2d(float a) { float c = cos(a), s = sin(a); return mat2(c, s, -s, c); }
|
||||||
|
float metaDiamond(vec2 p, vec2 pixel, float r) { vec2 d = abs(p - pixel); return r / (d.x + d.y); }
|
||||||
|
|
||||||
|
float hash12(vec2 p) {
|
||||||
|
vec3 p3 = fract(vec3(p.xyx) * .1031);
|
||||||
|
p3 += dot(p3, p3.yzx + 33.33);
|
||||||
|
return fract((p3.x + p3.y) * p3.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
float fbm(in vec2 v_p) {
|
||||||
|
float pvpx = v_p.x;
|
||||||
|
vec2 V1 = vec2(floor(pvpx));
|
||||||
|
vec2 V2 = vec2(floor(pvpx + 1.0));
|
||||||
|
return mix(hash12(V1), hash12(V2), smoothstep(0.0, 1.0, fract(pvpx)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
||||||
|
vec2 p = vec2((1.0 / iResolution.y) * (fragCoord.x - iResolution.x / 2.0),
|
||||||
|
fragCoord.y / iResolution.y - 0.5);
|
||||||
|
|
||||||
|
p.x = -p.x;
|
||||||
|
p *= 150.0;
|
||||||
|
|
||||||
|
vec4 col = vec4(0.05, 0.05, 0.15, 1.0);
|
||||||
|
|
||||||
|
vec2 save1 = p;
|
||||||
|
vec2 save2 = p;
|
||||||
|
|
||||||
|
p *= r2d(-0.05);
|
||||||
|
col = mix(col, vec4(0.2, 0.3, 0.5, 1.0),
|
||||||
|
smoothstep(75.0, 0.0, abs(p.y - 5.0 * fbm(vec2(0.01 * (p.x - 33.333 * iTime))) + 3.5)));
|
||||||
|
p *= r2d(0.05);
|
||||||
|
|
||||||
|
p *= r2d(-0.05);
|
||||||
|
p *= 0.35;
|
||||||
|
p += vec2(-5.0 * iTime, 0.0);
|
||||||
|
|
||||||
|
vec2 b = fract(5.0 * p);
|
||||||
|
p = floor(5.0 * p);
|
||||||
|
if (fbm(vec2(p.x * p.y)) > 0.996) col += clamp(1.0 - pow(3.0 * length(b + vec2(-0.5)), 0.5), 0.0, 1.0);
|
||||||
|
|
||||||
|
p = save1;
|
||||||
|
vec2 save3;
|
||||||
|
|
||||||
|
float Nb_Capsules = clamp(NBCaps, 0.0, 4.0);
|
||||||
|
for (float i = 0.0; i < Nb_Capsules; i++) {
|
||||||
|
p = save1;
|
||||||
|
p *= r2d(-0.05);
|
||||||
|
p *= 2.5;
|
||||||
|
p *= 1.0 - 0.25 * i;
|
||||||
|
p += vec2(150.0 * fbm(vec2(0.15 * iTime + i * 54.321)) - 75.0,
|
||||||
|
50.0 * sin(0.25 * iTime + i * 54.321) - 25.0);
|
||||||
|
save3 = p;
|
||||||
|
|
||||||
|
p *= 0.04;
|
||||||
|
p.y = abs(p.y);
|
||||||
|
|
||||||
|
if (p.x > 0.0) {
|
||||||
|
col += vec4(0.0, 1.0, 0.5, 1.0) * smoothstep(0.2, 0.0, abs(p.y - 0.05 * fbm(vec2(1.5 * p.x - 40.0 * iTime))) - 0.05) * smoothstep(29.0, 0.0, abs(p.x));
|
||||||
|
col += vec4(1.0, 1.0, 1.0, 1.0) * smoothstep(0.1, 0.0, abs(p.y - 0.05 * fbm(vec2(1.5 * p.x - 40.0 * iTime))) - 0.05) * smoothstep(29.0, 0.0, abs(p.x));
|
||||||
|
}
|
||||||
|
|
||||||
|
p = save3;
|
||||||
|
p.y = abs(p.y);
|
||||||
|
p += vec2(-10.0, 0.0);
|
||||||
|
p *= vec2(0.75, 1.0);
|
||||||
|
|
||||||
|
col += 0.8 * vec4(0.0, 1.0, 0.5, 1.0) * s(20.0, 0.0, length(p) - 25.0 + 7.0 * sin(0.30 * length(p) * atan(p.y, p.x) + 55.0 * iTime));
|
||||||
|
col += 0.8 * vec4(1.0, 1.0, 1.0, 1.0) * s(20.0, 0.0, length(p) - 20.0 + 7.0 * sin(0.30 * length(p) * atan(p.y, p.x) + 55.0 * iTime));
|
||||||
|
|
||||||
|
p = save3;
|
||||||
|
|
||||||
|
col = mix(col, vec4(1.0), 0.5 * s(10.0, 0.0, length(p + vec2(5.0, 0.0)) - 20.0) * abs(sin(50.0 * iTime)));
|
||||||
|
col = mix(col, vec4(1.0), 0.5 * s(20.0, 0.0, length(p + vec2(5.0, 0.0)) - 20.0));
|
||||||
|
|
||||||
|
col = mix(col, vec4(1.0), s(0.01, 0.0, length(p) - 20.0));
|
||||||
|
|
||||||
|
if (length(p) - 20.0 < 0.0) {
|
||||||
|
col = mix(col, vec4(0.65, 0.68, 0.68 + 0.1 * (3.0 - i), 1.0), s(0.5, 0.0, length(p - vec2(2.0, 0.0)) - 17.0));
|
||||||
|
if (s(0.0, 1.0, length(vec2(3.0, 2.0) * p + vec2(33.5, 0.0)) - 23.0) > 0.0)
|
||||||
|
col = mix(col, vec4(0.45, 0.55, 0.55 + 0.1 * (3.0 - i), 1.0),
|
||||||
|
0.75 * s(0.5, 0.0, length(p - vec2(2.0, 0.0) + 0.5 * fbm(vec2(4.5 * atan(p.y, p.x)))) - 9.0));
|
||||||
|
|
||||||
|
col = mix(col, vec4(0.0), s(0.2, 0.0, abs(length(p) - 19.9) - 0.20));
|
||||||
|
col = mix(col, vec4(0.5, 0.2, 0.3, 1.0)
|
||||||
|
- s(5.0, 0.0, length(p + vec2(-6.0, 15.0)) - 20.0)
|
||||||
|
- s(0.25, 0.0, abs(length(p + vec2(0.0, 3.0)) - 15.0) - 0.4)
|
||||||
|
- s(0.0, 1.5, p.y - 8.5)
|
||||||
|
+ 0.25 * vec4(1.0, 0.5, 0.0, 1.0) * s(10.0, 0.0, abs(p.y))
|
||||||
|
,
|
||||||
|
s(0.5, 0.0, length(vec2(3.0, 2.0) * p + vec2(35.0, 0.0)) - 19.9));
|
||||||
|
|
||||||
|
col = mix(col, vec4(0.0, 0.0, 0.0, 1.0), s(1.0, 0.0, abs(length(vec2(3.0, 2.0) * p + vec2(35.0, 0.0)) - 19.9) - 0.1));
|
||||||
|
col = mix(col, vec4(0.0, 0.0, 0.0, 1.0), s(1.0, 0.0, abs(length(vec2(3.0, 2.0) * p + vec2(33.5, 0.0)) - 23.0) - 0.1));
|
||||||
|
|
||||||
|
if (p.y > 0.0) col = mix(col, vec4(0.0, 0.0, 0.0, 1.0), s(1.0, 0.0, abs(length(vec2(3.0, 2.0) * p + vec2(29.0, 0.0)) - 30.0) - 0.1));
|
||||||
|
if (p.y < 0.0) col = mix(col, vec4(0.0, 0.0, 0.0, 1.0), s(1.0, 0.0, abs(length(vec2(3.0, 2.0) * p + vec2(-31.0, 0.0)) - 30.0) - 0.1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fragColor = clamp(col, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
2
shaders/dbz/meta.txt
Normal file
2
shaders/dbz/meta.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Name: New Leaked 3I/Atlas NASA Footage
|
||||||
|
Author: msm01
|
||||||
67
shaders/fractal_pyramid/fractal_pyramid.frag.msl
Normal file
67
shaders/fractal_pyramid/fractal_pyramid.frag.msl
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
// Fractal Pyramid — bradjamesgrant
|
||||||
|
// MSL port of fractal_pyramid.vk.glsl.
|
||||||
|
|
||||||
|
struct ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
float2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassthroughVOut {
|
||||||
|
float4 pos [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
static float3 palette(float d) {
|
||||||
|
return mix(float3(0.2, 0.7, 0.9), float3(1.0, 0.0, 1.0), d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float2 rotate(float2 p, float a) {
|
||||||
|
float c = cos(a);
|
||||||
|
float s = sin(a);
|
||||||
|
return p * float2x2(c, s, -s, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float mapScene(float3 p, float iTime) {
|
||||||
|
for (int i = 0; i < 8; ++i) {
|
||||||
|
float t = iTime * 0.2;
|
||||||
|
p.xz = rotate(p.xz, t);
|
||||||
|
p.xy = rotate(p.xy, t * 1.89);
|
||||||
|
p.xz = abs(p.xz);
|
||||||
|
p.xz -= 0.5;
|
||||||
|
}
|
||||||
|
return dot(sign(p), p) / 5.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float4 rm(float3 ro, float3 rd, float iTime) {
|
||||||
|
float t = 0.0;
|
||||||
|
float3 col = float3(0.0);
|
||||||
|
float d = 1.0;
|
||||||
|
for (int i = 0; i < 64; ++i) {
|
||||||
|
float3 p = ro + rd * t;
|
||||||
|
d = mapScene(p, iTime) * 0.5;
|
||||||
|
if (d < 0.02) break;
|
||||||
|
if (d > 100.0) break;
|
||||||
|
col += palette(length(p) * 0.1) / (400.0 * d);
|
||||||
|
t += d;
|
||||||
|
}
|
||||||
|
return float4(col, 1.0 / (d * 100.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment float4 fractal_pyramid_fs(PassthroughVOut in [[stage_in]],
|
||||||
|
constant ShadertoyUBO& U [[buffer(0)]]) {
|
||||||
|
float2 fragCoord = in.uv * U.iResolution;
|
||||||
|
float2 uv = (fragCoord - (U.iResolution * 0.5)) / U.iResolution.x;
|
||||||
|
float3 ro = float3(0.0, 0.0, -50.0);
|
||||||
|
ro.xz = rotate(ro.xz, U.iTime);
|
||||||
|
float3 cf = normalize(-ro);
|
||||||
|
float3 cs = normalize(cross(cf, float3(0.0, 1.0, 0.0)));
|
||||||
|
float3 cu = normalize(cross(cf, cs));
|
||||||
|
|
||||||
|
float3 uuv = ro + cf * 3.0 + uv.x * cs + uv.y * cu;
|
||||||
|
float3 rd = normalize(uuv - ro);
|
||||||
|
|
||||||
|
return rm(ro, rd, U.iTime);
|
||||||
|
}
|
||||||
BIN
shaders/fractal_pyramid/fractal_pyramid.frag.spv
Normal file
BIN
shaders/fractal_pyramid/fractal_pyramid.frag.spv
Normal file
Binary file not shown.
71
shaders/fractal_pyramid/fractal_pyramid.vk.glsl
Normal file
71
shaders/fractal_pyramid/fractal_pyramid.vk.glsl
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// Name: Fractal Pyramid
|
||||||
|
// Author: bradjamesgrant
|
||||||
|
// URL: https://www.shadertoy.com/view/tsXBzS
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 vUV;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0) uniform ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
vec2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
vec3 palette(float d) {
|
||||||
|
return mix(vec3(0.2, 0.7, 0.9), vec3(1.0, 0.0, 1.0), d);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 rotate(vec2 p, float a) {
|
||||||
|
float c = cos(a);
|
||||||
|
float s = sin(a);
|
||||||
|
return p * mat2(c, s, -s, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
float mapScene(vec3 p) {
|
||||||
|
for (int i = 0; i < 8; ++i) {
|
||||||
|
float t = iTime * 0.2;
|
||||||
|
p.xz = rotate(p.xz, t);
|
||||||
|
p.xy = rotate(p.xy, t * 1.89);
|
||||||
|
p.xz = abs(p.xz);
|
||||||
|
p.xz -= 0.5;
|
||||||
|
}
|
||||||
|
return dot(sign(p), p) / 5.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 rm(vec3 ro, vec3 rd) {
|
||||||
|
float t = 0.0;
|
||||||
|
vec3 col = vec3(0.0);
|
||||||
|
float d = 1.0;
|
||||||
|
for (int i = 0; i < 64; ++i) {
|
||||||
|
vec3 p = ro + rd * t;
|
||||||
|
d = mapScene(p) * 0.5;
|
||||||
|
if (d < 0.02) break;
|
||||||
|
if (d > 100.0) break;
|
||||||
|
col += palette(length(p) * 0.1) / (400.0 * d);
|
||||||
|
t += d;
|
||||||
|
}
|
||||||
|
return vec4(col, 1.0 / (d * 100.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
||||||
|
vec2 uv = (fragCoord - (iResolution.xy * 0.5)) / iResolution.x;
|
||||||
|
vec3 ro = vec3(0.0, 0.0, -50.0);
|
||||||
|
ro.xz = rotate(ro.xz, iTime);
|
||||||
|
vec3 cf = normalize(-ro);
|
||||||
|
vec3 cs = normalize(cross(cf, vec3(0.0, 1.0, 0.0)));
|
||||||
|
vec3 cu = normalize(cross(cf, cs));
|
||||||
|
|
||||||
|
vec3 uuv = ro + cf * 3.0 + uv.x * cs + uv.y * cu;
|
||||||
|
vec3 rd = normalize(uuv - ro);
|
||||||
|
|
||||||
|
vec4 col = rm(ro, rd);
|
||||||
|
fragColor = col;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
2
shaders/fractal_pyramid/meta.txt
Normal file
2
shaders/fractal_pyramid/meta.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Name: Fractal Pyramid
|
||||||
|
Author: bradjamesgrant
|
||||||
89
shaders/just_another_cube/just_another_cube.frag.msl
Normal file
89
shaders/just_another_cube/just_another_cube.frag.msl
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
// Just Another Cube — mrange
|
||||||
|
// MSL port of just_another_cube.vk.glsl. The Shadertoy original uses
|
||||||
|
// mutable file-scope globals; in MSL we pass them by reference.
|
||||||
|
|
||||||
|
struct ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
float2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassthroughVOut {
|
||||||
|
float4 pos [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
constant float M = 1e-3;
|
||||||
|
|
||||||
|
static float D(float3 p,
|
||||||
|
thread float2x2& R,
|
||||||
|
thread float& d,
|
||||||
|
thread float& G) {
|
||||||
|
p.xy = p.xy * R;
|
||||||
|
p.xz = p.xz * R;
|
||||||
|
|
||||||
|
float3 S = sin(123.0 * p);
|
||||||
|
|
||||||
|
float shell = abs(length(p) - 0.6);
|
||||||
|
p *= p * p * p;
|
||||||
|
d = pow(dot(p, p), 0.125) - 0.5
|
||||||
|
- pow(1.0 + S.x * S.y * S.z, 8.0) / 1e5;
|
||||||
|
|
||||||
|
G = min(G, max(shell, d));
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment float4 just_another_cube_fs(PassthroughVOut in [[stage_in]],
|
||||||
|
constant ShadertoyUBO& U [[buffer(0)]]) {
|
||||||
|
float2 C = in.uv * U.iResolution;
|
||||||
|
|
||||||
|
float2x2 R;
|
||||||
|
float d = 1.0, z = 0.0, G = 9.0;
|
||||||
|
|
||||||
|
float3 r = float3(U.iResolution, U.iResolution.y);
|
||||||
|
float3 I = normalize(float3(C - 0.5 * r.xy, r.y));
|
||||||
|
float3 B = float3(1, 2, 9) * M;
|
||||||
|
float3 p = float3(0.0);
|
||||||
|
float3 O = float3(0.0);
|
||||||
|
|
||||||
|
{
|
||||||
|
float4 cs = cos(0.3 * U.iTime + float4(0, 11, 33, 0));
|
||||||
|
R = float2x2(cs.x, cs.y, cs.z, cs.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; z < 9.0 && d > M; z += D(p, R, d, G)) {
|
||||||
|
p = z * I;
|
||||||
|
p.z -= 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (z < 9.0) {
|
||||||
|
for (int i = 0; i < 3; ) {
|
||||||
|
r = float3(0.0);
|
||||||
|
r[i] = M;
|
||||||
|
O[i++] = D(p + r, R, d, G) - D(p - r, R, d, G);
|
||||||
|
}
|
||||||
|
|
||||||
|
O = normalize(O);
|
||||||
|
z = 1.0 + dot(O, I);
|
||||||
|
|
||||||
|
r = reflect(I, O);
|
||||||
|
|
||||||
|
C = (p + r * (5.0 - p.y) / abs(r.y)).xz;
|
||||||
|
|
||||||
|
float3 colorTerm;
|
||||||
|
if (r.y > 0.0) {
|
||||||
|
d = sqrt(length(C * C)) + 1.0;
|
||||||
|
colorTerm = 5e2 * smoothstep(5.0, 4.0, d) * d * B;
|
||||||
|
} else {
|
||||||
|
colorTerm = exp(-2.0 * length(C)) * (B / M - 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
O = z * z * colorTerm + pow(1.0 + O.y, 5.0) * B;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 result = sqrt(float4(O + B / G, O.x + B.x / G));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
BIN
shaders/just_another_cube/just_another_cube.frag.spv
Normal file
BIN
shaders/just_another_cube/just_another_cube.frag.spv
Normal file
Binary file not shown.
88
shaders/just_another_cube/just_another_cube.vk.glsl
Normal file
88
shaders/just_another_cube/just_another_cube.vk.glsl
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// Name: Just Another Cube
|
||||||
|
// Author: mrange
|
||||||
|
// URL: https://www.shadertoy.com/view/3XdXRr
|
||||||
|
// CC0: Just another cube
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 vUV;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0) uniform ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
vec2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
mat2 R;
|
||||||
|
float d = 1.;
|
||||||
|
float z = 0.;
|
||||||
|
float G = 9.;
|
||||||
|
float M = 1e-3;
|
||||||
|
|
||||||
|
float D(vec3 p) {
|
||||||
|
p.xy *= R;
|
||||||
|
p.xz *= R;
|
||||||
|
|
||||||
|
vec3 S = sin(123. * p);
|
||||||
|
|
||||||
|
G = min(
|
||||||
|
G,
|
||||||
|
max(
|
||||||
|
abs(length(p) - .6),
|
||||||
|
d = pow(dot(p *= p * p * p, p), .125) - .5
|
||||||
|
- pow(1. + S.x * S.y * S.z, 8.) / 1e5
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage(out vec4 o, vec2 C) {
|
||||||
|
vec3 p,
|
||||||
|
O,
|
||||||
|
r = vec3(iResolution.xy, iResolution.y),
|
||||||
|
I = normalize(vec3(C - .5 * r.xy, r.y)),
|
||||||
|
B = vec3(1, 2, 9) * M;
|
||||||
|
|
||||||
|
for (
|
||||||
|
R = mat2(cos(.3 * iTime + vec4(0, 11, 33, 0)));
|
||||||
|
z < 9. && d > M;
|
||||||
|
z += D(p)
|
||||||
|
)
|
||||||
|
p = z * I,
|
||||||
|
p.z -= 2.;
|
||||||
|
|
||||||
|
O = vec3(0.0);
|
||||||
|
|
||||||
|
if (z < 9.) {
|
||||||
|
for (int i = 0; i < 3; ) {
|
||||||
|
r -= r;
|
||||||
|
r[i] = M;
|
||||||
|
O[i++] = D(p + r) - D(p - r);
|
||||||
|
}
|
||||||
|
|
||||||
|
z = 1. + dot(O = normalize(O), I);
|
||||||
|
|
||||||
|
r = reflect(I, O);
|
||||||
|
|
||||||
|
C = (p + r * (5. - p.y) / abs(r.y)).xz;
|
||||||
|
|
||||||
|
O =
|
||||||
|
z * z *
|
||||||
|
(
|
||||||
|
r.y > 0.
|
||||||
|
? 5e2 * smoothstep(5., 4., d = sqrt(length(C * C)) + 1.) * d * B
|
||||||
|
: exp(-2. * length(C)) * (B / M - 1.)
|
||||||
|
)
|
||||||
|
+ pow(1. + O.y, 5.) * B;
|
||||||
|
}
|
||||||
|
|
||||||
|
o = sqrt(O + B / G).xyzx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
2
shaders/just_another_cube/meta.txt
Normal file
2
shaders/just_another_cube/meta.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Name: Just Another Cube
|
||||||
|
Author: mrange
|
||||||
2
shaders/octograms/meta.txt
Normal file
2
shaders/octograms/meta.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Name: Octograms
|
||||||
|
Author: whisky_shusuky
|
||||||
95
shaders/octograms/octograms.frag.msl
Normal file
95
shaders/octograms/octograms.frag.msl
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
// Octograms — whisky_shusuky
|
||||||
|
// MSL port of octograms.vk.glsl. The Shadertoy original uses a mutable
|
||||||
|
// file-scope `gTime`; in MSL we pass it as a parameter through the chain.
|
||||||
|
|
||||||
|
struct ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
float2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassthroughVOut {
|
||||||
|
float4 pos [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
static float2x2 rot(float a) {
|
||||||
|
float c = cos(a), s = sin(a);
|
||||||
|
return float2x2(c, s, -s, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float sdBox(float3 p, float3 b) {
|
||||||
|
float3 q = abs(p) - b;
|
||||||
|
return length(max(q, float3(0.0))) + min(max(q.x, max(q.y, q.z)), 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float boxGeom(float3 pos, float scale) {
|
||||||
|
pos *= scale;
|
||||||
|
float base = sdBox(pos, float3(0.4, 0.4, 0.1)) / 1.5;
|
||||||
|
pos.xy = (pos.xy * 5.0 - float2(0.0, 3.5)) * rot(0.75);
|
||||||
|
return -base;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float box_set(float3 pos, float gTime) {
|
||||||
|
float3 pos_origin = pos;
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
pos.y += sin(gTime * 0.4) * 2.5;
|
||||||
|
pos.xy = pos.xy * rot(0.8);
|
||||||
|
float box1 = boxGeom(pos, 2.0 - abs(sin(gTime * 0.4)) * 1.5);
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
pos.y -= sin(gTime * 0.4) * 2.5;
|
||||||
|
pos.xy = pos.xy * rot(0.8);
|
||||||
|
float box2 = boxGeom(pos, 2.0 - abs(sin(gTime * 0.4)) * 1.5);
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
pos.x += sin(gTime * 0.4) * 2.5;
|
||||||
|
pos.xy = pos.xy * rot(0.8);
|
||||||
|
float box3 = boxGeom(pos, 2.0 - abs(sin(gTime * 0.4)) * 1.5);
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
pos.x -= sin(gTime * 0.4) * 2.5;
|
||||||
|
pos.xy = pos.xy * rot(0.8);
|
||||||
|
float box4 = boxGeom(pos, 2.0 - abs(sin(gTime * 0.4)) * 1.5);
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
pos.xy = pos.xy * rot(0.8);
|
||||||
|
float box5 = boxGeom(pos, 0.5) * 6.0;
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
float box6 = boxGeom(pos, 0.5) * 6.0;
|
||||||
|
|
||||||
|
return max(max(max(max(max(box1, box2), box3), box4), box5), box6);
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment float4 octograms_fs(PassthroughVOut in [[stage_in]],
|
||||||
|
constant ShadertoyUBO& U [[buffer(0)]]) {
|
||||||
|
float2 fragCoord = in.uv * U.iResolution;
|
||||||
|
float2 p = (fragCoord * 2.0 - U.iResolution) / min(U.iResolution.x, U.iResolution.y);
|
||||||
|
|
||||||
|
float3 ro = float3(0.0, -0.2, U.iTime * 4.0);
|
||||||
|
float3 ray = normalize(float3(p, 1.5));
|
||||||
|
ray.xy = ray.xy * rot(sin(U.iTime * 0.03) * 5.0);
|
||||||
|
ray.yz = ray.yz * rot(sin(U.iTime * 0.05) * 0.2);
|
||||||
|
float t = 0.1;
|
||||||
|
float ac = 0.0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 99; i++) {
|
||||||
|
float3 pos = ro + ray * t;
|
||||||
|
pos = fract((pos - 2.0) / 4.0) * 4.0 - 2.0;
|
||||||
|
float gTime = U.iTime - float(i) * 0.01;
|
||||||
|
|
||||||
|
float d = box_set(pos, gTime);
|
||||||
|
d = max(abs(d), 0.01);
|
||||||
|
ac += exp(-d * 23.0);
|
||||||
|
t += d * 0.55;
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 col = float3(ac * 0.02);
|
||||||
|
col += float3(0.0, 0.2 * abs(sin(U.iTime)), 0.5 + sin(U.iTime) * 0.2);
|
||||||
|
|
||||||
|
return float4(col, 1.0 - t * (0.02 + 0.02 * sin(U.iTime)));
|
||||||
|
}
|
||||||
BIN
shaders/octograms/octograms.frag.spv
Normal file
BIN
shaders/octograms/octograms.frag.spv
Normal file
Binary file not shown.
109
shaders/octograms/octograms.vk.glsl
Normal file
109
shaders/octograms/octograms.vk.glsl
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// Name: Octograms
|
||||||
|
// Author: whisky_shusuky
|
||||||
|
// URL: https://www.shadertoy.com/view/tlVGDt
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 vUV;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0) uniform ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
vec2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
float gTime = 0.0;
|
||||||
|
const float REPEAT = 5.0;
|
||||||
|
|
||||||
|
mat2 rot(float a) {
|
||||||
|
float c = cos(a), s = sin(a);
|
||||||
|
return mat2(c, s, -s, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
float sdBox(vec3 p, vec3 b) {
|
||||||
|
vec3 q = abs(p) - b;
|
||||||
|
return length(max(q, vec3(0.0))) + min(max(q.x, max(q.y, q.z)), 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float boxGeom(vec3 pos, float scale) {
|
||||||
|
pos *= scale;
|
||||||
|
float base = sdBox(pos, vec3(.4, .4, .1)) / 1.5;
|
||||||
|
pos.xy *= 5.0;
|
||||||
|
pos.y -= 3.5;
|
||||||
|
pos.xy *= rot(.75);
|
||||||
|
float result = -base;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float box_set(vec3 pos, float iTimeLocal) {
|
||||||
|
vec3 pos_origin = pos;
|
||||||
|
pos = pos_origin;
|
||||||
|
pos.y += sin(gTime * 0.4) * 2.5;
|
||||||
|
pos.xy *= rot(.8);
|
||||||
|
float box1 = boxGeom(pos, 2.0 - abs(sin(gTime * 0.4)) * 1.5);
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
pos.y -= sin(gTime * 0.4) * 2.5;
|
||||||
|
pos.xy *= rot(.8);
|
||||||
|
float box2 = boxGeom(pos, 2.0 - abs(sin(gTime * 0.4)) * 1.5);
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
pos.x += sin(gTime * 0.4) * 2.5;
|
||||||
|
pos.xy *= rot(.8);
|
||||||
|
float box3 = boxGeom(pos, 2.0 - abs(sin(gTime * 0.4)) * 1.5);
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
pos.x -= sin(gTime * 0.4) * 2.5;
|
||||||
|
pos.xy *= rot(.8);
|
||||||
|
float box4 = boxGeom(pos, 2.0 - abs(sin(gTime * 0.4)) * 1.5);
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
pos.xy *= rot(.8);
|
||||||
|
float box5 = boxGeom(pos, .5) * 6.0;
|
||||||
|
|
||||||
|
pos = pos_origin;
|
||||||
|
float box6 = boxGeom(pos, .5) * 6.0;
|
||||||
|
|
||||||
|
float result = max(max(max(max(max(box1, box2), box3), box4), box5), box6);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float mapScene(vec3 pos, float iTimeLocal) {
|
||||||
|
return box_set(pos, iTimeLocal);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
||||||
|
vec2 p = (fragCoord.xy * 2.0 - iResolution.xy) / min(iResolution.x, iResolution.y);
|
||||||
|
vec3 ro = vec3(0.0, -0.2, iTime * 4.0);
|
||||||
|
vec3 ray = normalize(vec3(p, 1.5));
|
||||||
|
ray.xy = ray.xy * rot(sin(iTime * .03) * 5.0);
|
||||||
|
ray.yz = ray.yz * rot(sin(iTime * .05) * .2);
|
||||||
|
float t = 0.1;
|
||||||
|
vec3 col = vec3(0.0);
|
||||||
|
float ac = 0.0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 99; i++) {
|
||||||
|
vec3 pos = ro + ray * t;
|
||||||
|
pos = mod(pos - 2.0, 4.0) - 2.0;
|
||||||
|
gTime = iTime - float(i) * 0.01;
|
||||||
|
|
||||||
|
float d = mapScene(pos, iTime);
|
||||||
|
|
||||||
|
d = max(abs(d), 0.01);
|
||||||
|
ac += exp(-d * 23.0);
|
||||||
|
|
||||||
|
t += d * 0.55;
|
||||||
|
}
|
||||||
|
|
||||||
|
col = vec3(ac * 0.02);
|
||||||
|
col += vec3(0.0, 0.2 * abs(sin(iTime)), 0.5 + sin(iTime) * 0.2);
|
||||||
|
|
||||||
|
fragColor = vec4(col, 1.0 - t * (0.02 + 0.02 * sin(iTime)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
2
shaders/remember/meta.txt
Normal file
2
shaders/remember/meta.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Name: Remember
|
||||||
|
Author: diatribes
|
||||||
64
shaders/remember/remember.frag.msl
Normal file
64
shaders/remember/remember.frag.msl
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
// Remember — diatribes
|
||||||
|
// MSL port of remember.vk.glsl.
|
||||||
|
|
||||||
|
struct ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
float2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassthroughVOut {
|
||||||
|
float4 pos [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
static float hash12(float2 p) {
|
||||||
|
float3 p3 = fract(float3(p.xyx) * 0.1031);
|
||||||
|
p3 += dot(p3, p3.yzx + 33.33);
|
||||||
|
return fract((p3.x + p3.y) * p3.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment float4 remember_fs(PassthroughVOut in [[stage_in]],
|
||||||
|
constant ShadertoyUBO& U [[buffer(0)]]) {
|
||||||
|
float2 fragCoord = in.uv * U.iResolution;
|
||||||
|
float2 u = fragCoord;
|
||||||
|
|
||||||
|
float3 q, p = float3(U.iResolution, U.iResolution.x / U.iResolution.y);
|
||||||
|
|
||||||
|
float i = 0.0, s = 0.0;
|
||||||
|
float d = 0.125 * hash12(u);
|
||||||
|
float t = U.iTime * 0.1;
|
||||||
|
|
||||||
|
u = (u + u - p.xy) / p.y;
|
||||||
|
if (abs(u.y) > 0.8) { return float4(0); }
|
||||||
|
|
||||||
|
float4 o = float4(0.0);
|
||||||
|
|
||||||
|
for (; i < 64.0; i++) {
|
||||||
|
|
||||||
|
q = p = float3(u * d, d + t * 5.0);
|
||||||
|
// mat2(cos(.1*p.z+.1*t+vec4(0,33,11,0))) — column-major: (m00,m10,m01,m11)
|
||||||
|
float4 cs = cos(0.1 * p.z + 0.1 * t + float4(0, 33, 11, 0));
|
||||||
|
float2x2 m = float2x2(cs.x, cs.y, cs.z, cs.w);
|
||||||
|
p.xy = p.xy * m;
|
||||||
|
|
||||||
|
q.xz = cos(q.xz);
|
||||||
|
p.z = cos(p.z);
|
||||||
|
|
||||||
|
for (s = 1.0; s++ < 6.0;) {
|
||||||
|
q += sin(0.6 * t + p.zxy * 0.6);
|
||||||
|
p += sin(t + t + p.yzx * s) * 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = 0.02 + abs(min(length(p + 3.0 * sin(p.z * 0.5)) - 4.0, length(q - 2.0 * sin(p.z * 0.4)) - 6.0)) * 0.2;
|
||||||
|
d += s;
|
||||||
|
|
||||||
|
float4 brightTerm = min(0.01 * float4(6, 2, 1, 0) / max(length(u * sin(t + t + t)), 0.001), float4(50.0));
|
||||||
|
o += brightTerm + 1.0 / s * length(u);
|
||||||
|
}
|
||||||
|
|
||||||
|
o = tanh(max(o / 6e2 + dot(u, u) * 0.35, 0.0));
|
||||||
|
return o;
|
||||||
|
}
|
||||||
BIN
shaders/remember/remember.frag.spv
Normal file
BIN
shaders/remember/remember.frag.spv
Normal file
Binary file not shown.
61
shaders/remember/remember.vk.glsl
Normal file
61
shaders/remember/remember.vk.glsl
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// Name: Remember
|
||||||
|
// Author: diatribes
|
||||||
|
// URL: https://www.shadertoy.com/view/tXSBDK
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 vUV;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0) uniform ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
vec2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
// fuzzy brain — Hash function to replace iChannel0 texture noise
|
||||||
|
float hash12(vec2 p) {
|
||||||
|
vec3 p3 = fract(vec3(p.xyx) * .1031);
|
||||||
|
p3 += dot(p3, p3.yzx + 33.33);
|
||||||
|
return fract((p3.x + p3.y) * p3.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage(out vec4 o, vec2 u) {
|
||||||
|
|
||||||
|
vec3 q, p = vec3(iResolution.xy, iResolution.x / iResolution.y);
|
||||||
|
|
||||||
|
float i = 0.0, s,
|
||||||
|
d = .125 * hash12(u),
|
||||||
|
t = iTime * .1;
|
||||||
|
|
||||||
|
u = (u + u - p.xy) / p.y;
|
||||||
|
if (abs(u.y) > .8) { o = vec4(0); return; }
|
||||||
|
|
||||||
|
o = vec4(0.0);
|
||||||
|
|
||||||
|
for (; i < 64.; i++) {
|
||||||
|
|
||||||
|
q = p = vec3(u * d, d + t * 5.);
|
||||||
|
p.xy *= mat2(cos(.1 * p.z + .1 * t + vec4(0, 33, 11, 0)));
|
||||||
|
|
||||||
|
q.xz = cos(q.xz);
|
||||||
|
p.z = cos(p.z);
|
||||||
|
for (s = 1.; s++ < 6.;
|
||||||
|
q += sin(.6 * t + p.zxy * .6),
|
||||||
|
p += sin(t + t + p.yzx * s) * .6);
|
||||||
|
|
||||||
|
d += s = .02 + abs(min(length(p + 3. * sin(p.z * .5)) - 4., length(q - 2. * sin(p.z * .4)) - 6.)) * .2;
|
||||||
|
|
||||||
|
vec4 brightTerm = min(.01 * vec4(6, 2, 1, 0) / max(length(u * sin(t + t + t)), 0.001), vec4(50.0));
|
||||||
|
o += brightTerm + 1. / s * length(u);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
o = tanh(max(o / 6e2 + dot(u, u) * .35, 0.));
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
2
shaders/seascape/meta.txt
Normal file
2
shaders/seascape/meta.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Name: Seascape
|
||||||
|
Author: Alexander Alekseev
|
||||||
181
shaders/seascape/seascape.frag.msl
Normal file
181
shaders/seascape/seascape.frag.msl
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
// Seascape — Alexander Alekseev (TDM, 2014)
|
||||||
|
// MSL port of seascape.vk.glsl. iTime threaded through helpers because
|
||||||
|
// MSL does not allow file-scope mutable globals.
|
||||||
|
|
||||||
|
struct ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
float2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassthroughVOut {
|
||||||
|
float4 pos [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
constant int NUM_STEPS = 32;
|
||||||
|
constant float PI = 3.141592;
|
||||||
|
constant float EPSILON = 1e-3;
|
||||||
|
|
||||||
|
constant int ITER_GEOMETRY = 3;
|
||||||
|
constant int ITER_FRAGMENT = 5;
|
||||||
|
constant float SEA_HEIGHT = 0.6;
|
||||||
|
constant float SEA_CHOPPY = 4.0;
|
||||||
|
constant float SEA_SPEED = 0.8;
|
||||||
|
constant float SEA_FREQ = 0.16;
|
||||||
|
constant float3 SEA_BASE = float3(0.0, 0.09, 0.18);
|
||||||
|
constant float3 SEA_WATER_COLOR = float3(0.8, 0.9, 0.6) * 0.6;
|
||||||
|
constant float2x2 octave_m = float2x2(1.6, 1.2, -1.2, 1.6);
|
||||||
|
|
||||||
|
static float3x3 fromEuler(float3 ang) {
|
||||||
|
float2 a1 = float2(sin(ang.x), cos(ang.x));
|
||||||
|
float2 a2 = float2(sin(ang.y), cos(ang.y));
|
||||||
|
float2 a3 = float2(sin(ang.z), cos(ang.z));
|
||||||
|
float3x3 m;
|
||||||
|
m[0] = float3(a1.y * a3.y + a1.x * a2.x * a3.x, a1.y * a2.x * a3.x + a3.y * a1.x, -a2.y * a3.x);
|
||||||
|
m[1] = float3(-a2.y * a1.x, a1.y * a2.y, a2.x);
|
||||||
|
m[2] = float3(a3.y * a1.x * a2.x + a1.y * a3.x, a1.x * a3.x - a1.y * a3.y * a2.x, a2.y * a3.y);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float hash(float2 p) {
|
||||||
|
float h = dot(p, float2(127.1, 311.7));
|
||||||
|
return fract(sin(h) * 43758.5453123);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float noise(float2 p) {
|
||||||
|
float2 i = floor(p);
|
||||||
|
float2 f = fract(p);
|
||||||
|
float2 u = f * f * (3.0 - 2.0 * f);
|
||||||
|
return -1.0 + 2.0 * mix(mix(hash(i + float2(0.0, 0.0)),
|
||||||
|
hash(i + float2(1.0, 0.0)), u.x),
|
||||||
|
mix(hash(i + float2(0.0, 1.0)),
|
||||||
|
hash(i + float2(1.0, 1.0)), u.x), u.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float diffuseLight(float3 n, float3 l, float p) {
|
||||||
|
return pow(dot(n, l) * 0.4 + 0.6, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float specularLight(float3 n, float3 l, float3 e, float s) {
|
||||||
|
float nrm = (s + 8.0) / (PI * 8.0);
|
||||||
|
return pow(max(dot(reflect(e, n), l), 0.0), s) * nrm;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float3 getSkyColor(float3 e) {
|
||||||
|
e.y = (max(e.y, 0.0) * 0.8 + 0.2) * 0.8;
|
||||||
|
return float3(pow(1.0 - e.y, 2.0), 1.0 - e.y, 0.6 + (1.0 - e.y) * 0.4) * 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float sea_octave(float2 uv, float choppy) {
|
||||||
|
uv += noise(uv);
|
||||||
|
float2 wv = 1.0 - abs(sin(uv));
|
||||||
|
float2 swv = abs(cos(uv));
|
||||||
|
wv = mix(wv, swv, wv);
|
||||||
|
return pow(1.0 - pow(wv.x * wv.y, 0.65), choppy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float seaMap(float3 p, float iTime, int iter) {
|
||||||
|
float SEA_TIME = 1.0 + iTime * SEA_SPEED;
|
||||||
|
float freq = SEA_FREQ;
|
||||||
|
float amp = SEA_HEIGHT;
|
||||||
|
float choppy = SEA_CHOPPY;
|
||||||
|
float2 uv = p.xz; uv.x *= 0.75;
|
||||||
|
|
||||||
|
float d, h = 0.0;
|
||||||
|
for (int i = 0; i < iter; i++) {
|
||||||
|
d = sea_octave((uv + SEA_TIME) * freq, choppy);
|
||||||
|
d += sea_octave((uv - SEA_TIME) * freq, choppy);
|
||||||
|
h += d * amp;
|
||||||
|
uv = uv * octave_m;
|
||||||
|
freq *= 1.9;
|
||||||
|
amp *= 0.22;
|
||||||
|
choppy = mix(choppy, 1.0, 0.2);
|
||||||
|
}
|
||||||
|
return p.y - h;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float3 getSeaColor(float3 p, float3 n, float3 l, float3 eye, float3 dist) {
|
||||||
|
float fresnel = clamp(1.0 - dot(n, -eye), 0.0, 1.0);
|
||||||
|
fresnel = min(fresnel * fresnel * fresnel, 0.5);
|
||||||
|
|
||||||
|
float3 reflected = getSkyColor(reflect(eye, n));
|
||||||
|
float3 refracted = SEA_BASE + diffuseLight(n, l, 80.0) * SEA_WATER_COLOR * 0.12;
|
||||||
|
|
||||||
|
float3 color = mix(refracted, reflected, fresnel);
|
||||||
|
|
||||||
|
float atten = max(1.0 - dot(dist, dist) * 0.001, 0.0);
|
||||||
|
color += SEA_WATER_COLOR * (p.y - SEA_HEIGHT) * 0.18 * atten;
|
||||||
|
|
||||||
|
color += specularLight(n, l, eye, 600.0 * rsqrt(dot(dist, dist)));
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float3 getNormal(float3 p, float eps, float iTime) {
|
||||||
|
float3 n;
|
||||||
|
n.y = seaMap(p, iTime, ITER_FRAGMENT);
|
||||||
|
n.x = seaMap(float3(p.x + eps, p.y, p.z), iTime, ITER_FRAGMENT) - n.y;
|
||||||
|
n.z = seaMap(float3(p.x, p.y, p.z + eps), iTime, ITER_FRAGMENT) - n.y;
|
||||||
|
n.y = eps;
|
||||||
|
return normalize(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float heightMapTracing(float3 ori, float3 dir, thread float3& p, float iTime) {
|
||||||
|
float tm = 0.0;
|
||||||
|
float tx = 1000.0;
|
||||||
|
float hx = seaMap(ori + dir * tx, iTime, ITER_GEOMETRY);
|
||||||
|
if (hx > 0.0) {
|
||||||
|
p = ori + dir * tx;
|
||||||
|
return tx;
|
||||||
|
}
|
||||||
|
float hm = seaMap(ori, iTime, ITER_GEOMETRY);
|
||||||
|
for (int i = 0; i < NUM_STEPS; i++) {
|
||||||
|
float tmid = mix(tm, tx, hm / (hm - hx));
|
||||||
|
p = ori + dir * tmid;
|
||||||
|
float hmid = seaMap(p, iTime, ITER_GEOMETRY);
|
||||||
|
if (hmid < 0.0) {
|
||||||
|
tx = tmid;
|
||||||
|
hx = hmid;
|
||||||
|
} else {
|
||||||
|
tm = tmid;
|
||||||
|
hm = hmid;
|
||||||
|
}
|
||||||
|
if (abs(hmid) < EPSILON) break;
|
||||||
|
}
|
||||||
|
return mix(tm, tx, hm / (hm - hx));
|
||||||
|
}
|
||||||
|
|
||||||
|
static float3 getPixel(float2 coord, float time, float2 iResolution, float iTime) {
|
||||||
|
float2 uv = coord / iResolution;
|
||||||
|
uv = uv * 2.0 - 1.0;
|
||||||
|
uv.x *= iResolution.x / iResolution.y;
|
||||||
|
|
||||||
|
float3 ang = float3(sin(time * 3.0) * 0.1, sin(time) * 0.2 + 0.3, time);
|
||||||
|
float3 ori = float3(0.0, 3.5, time * 5.0);
|
||||||
|
float3 dir = normalize(float3(uv.xy, -2.0));
|
||||||
|
dir.z += length(uv) * 0.14;
|
||||||
|
dir = normalize(dir) * fromEuler(ang);
|
||||||
|
|
||||||
|
float3 p;
|
||||||
|
heightMapTracing(ori, dir, p, iTime);
|
||||||
|
float3 dist = p - ori;
|
||||||
|
float EPSILON_NRM = 0.1 / iResolution.x;
|
||||||
|
float3 n = getNormal(p, dot(dist, dist) * EPSILON_NRM, iTime);
|
||||||
|
float3 light = normalize(float3(0.0, 1.0, 0.8));
|
||||||
|
|
||||||
|
return mix(
|
||||||
|
getSkyColor(dir),
|
||||||
|
getSeaColor(p, n, light, dir, dist),
|
||||||
|
pow(smoothstep(0.0, -0.02, dir.y), 0.2));
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment float4 seascape_fs(PassthroughVOut in [[stage_in]],
|
||||||
|
constant ShadertoyUBO& U [[buffer(0)]]) {
|
||||||
|
float2 fragCoord = in.uv * U.iResolution;
|
||||||
|
float time = U.iTime * 0.3;
|
||||||
|
float3 color = getPixel(fragCoord, time, U.iResolution, U.iTime);
|
||||||
|
return float4(pow(color, float3(0.65)), 1.0);
|
||||||
|
}
|
||||||
BIN
shaders/seascape/seascape.frag.spv
Normal file
BIN
shaders/seascape/seascape.frag.spv
Normal file
Binary file not shown.
200
shaders/seascape/seascape.vk.glsl
Normal file
200
shaders/seascape/seascape.vk.glsl
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// Name: Seascape
|
||||||
|
// Author: Alexander Alekseev
|
||||||
|
// URL: https://www.shadertoy.com/view/Ms2SD1
|
||||||
|
//
|
||||||
|
// "Seascape" by Alexander Alekseev aka TDM - 2014
|
||||||
|
// CC BY-NC-SA 3.0 Unported License.
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 vUV;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0) uniform ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
vec2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
const int NUM_STEPS = 32;
|
||||||
|
const float PI = 3.141592;
|
||||||
|
const float EPSILON = 1e-3;
|
||||||
|
#define EPSILON_NRM (0.1 / iResolution.x)
|
||||||
|
|
||||||
|
const int ITER_GEOMETRY = 3;
|
||||||
|
const int ITER_FRAGMENT = 5;
|
||||||
|
const float SEA_HEIGHT = 0.6;
|
||||||
|
const float SEA_CHOPPY = 4.0;
|
||||||
|
const float SEA_SPEED = 0.8;
|
||||||
|
const float SEA_FREQ = 0.16;
|
||||||
|
const vec3 SEA_BASE = vec3(0.0, 0.09, 0.18);
|
||||||
|
const vec3 SEA_WATER_COLOR = vec3(0.8, 0.9, 0.6) * 0.6;
|
||||||
|
#define SEA_TIME (1.0 + iTime * SEA_SPEED)
|
||||||
|
const mat2 octave_m = mat2(1.6, 1.2, -1.2, 1.6);
|
||||||
|
|
||||||
|
mat3 fromEuler(vec3 ang) {
|
||||||
|
vec2 a1 = vec2(sin(ang.x), cos(ang.x));
|
||||||
|
vec2 a2 = vec2(sin(ang.y), cos(ang.y));
|
||||||
|
vec2 a3 = vec2(sin(ang.z), cos(ang.z));
|
||||||
|
mat3 m;
|
||||||
|
m[0] = vec3(a1.y * a3.y + a1.x * a2.x * a3.x, a1.y * a2.x * a3.x + a3.y * a1.x, -a2.y * a3.x);
|
||||||
|
m[1] = vec3(-a2.y * a1.x, a1.y * a2.y, a2.x);
|
||||||
|
m[2] = vec3(a3.y * a1.x * a2.x + a1.y * a3.x, a1.x * a3.x - a1.y * a3.y * a2.x, a2.y * a3.y);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
float hash(vec2 p) {
|
||||||
|
float h = dot(p, vec2(127.1, 311.7));
|
||||||
|
return fract(sin(h) * 43758.5453123);
|
||||||
|
}
|
||||||
|
|
||||||
|
float noise(in vec2 p) {
|
||||||
|
vec2 i = floor(p);
|
||||||
|
vec2 f = fract(p);
|
||||||
|
vec2 u = f * f * (3.0 - 2.0 * f);
|
||||||
|
return -1.0 + 2.0 * mix(mix(hash(i + vec2(0.0, 0.0)),
|
||||||
|
hash(i + vec2(1.0, 0.0)), u.x),
|
||||||
|
mix(hash(i + vec2(0.0, 1.0)),
|
||||||
|
hash(i + vec2(1.0, 1.0)), u.x), u.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
float diffuse(vec3 n, vec3 l, float p) {
|
||||||
|
return pow(dot(n, l) * 0.4 + 0.6, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
float specular(vec3 n, vec3 l, vec3 e, float s) {
|
||||||
|
float nrm = (s + 8.0) / (PI * 8.0);
|
||||||
|
return pow(max(dot(reflect(e, n), l), 0.0), s) * nrm;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 getSkyColor(vec3 e) {
|
||||||
|
e.y = (max(e.y, 0.0) * 0.8 + 0.2) * 0.8;
|
||||||
|
return vec3(pow(1.0 - e.y, 2.0), 1.0 - e.y, 0.6 + (1.0 - e.y) * 0.4) * 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
float sea_octave(vec2 uv, float choppy) {
|
||||||
|
uv += noise(uv);
|
||||||
|
vec2 wv = 1.0 - abs(sin(uv));
|
||||||
|
vec2 swv = abs(cos(uv));
|
||||||
|
wv = mix(wv, swv, wv);
|
||||||
|
return pow(1.0 - pow(wv.x * wv.y, 0.65), choppy);
|
||||||
|
}
|
||||||
|
|
||||||
|
float map(vec3 p) {
|
||||||
|
float freq = SEA_FREQ;
|
||||||
|
float amp = SEA_HEIGHT;
|
||||||
|
float choppy = SEA_CHOPPY;
|
||||||
|
vec2 uv = p.xz; uv.x *= 0.75;
|
||||||
|
|
||||||
|
float d, h = 0.0;
|
||||||
|
for (int i = 0; i < ITER_GEOMETRY; i++) {
|
||||||
|
d = sea_octave((uv + SEA_TIME) * freq, choppy);
|
||||||
|
d += sea_octave((uv - SEA_TIME) * freq, choppy);
|
||||||
|
h += d * amp;
|
||||||
|
uv *= octave_m; freq *= 1.9; amp *= 0.22;
|
||||||
|
choppy = mix(choppy, 1.0, 0.2);
|
||||||
|
}
|
||||||
|
return p.y - h;
|
||||||
|
}
|
||||||
|
|
||||||
|
float map_detailed(vec3 p) {
|
||||||
|
float freq = SEA_FREQ;
|
||||||
|
float amp = SEA_HEIGHT;
|
||||||
|
float choppy = SEA_CHOPPY;
|
||||||
|
vec2 uv = p.xz; uv.x *= 0.75;
|
||||||
|
|
||||||
|
float d, h = 0.0;
|
||||||
|
for (int i = 0; i < ITER_FRAGMENT; i++) {
|
||||||
|
d = sea_octave((uv + SEA_TIME) * freq, choppy);
|
||||||
|
d += sea_octave((uv - SEA_TIME) * freq, choppy);
|
||||||
|
h += d * amp;
|
||||||
|
uv *= octave_m; freq *= 1.9; amp *= 0.22;
|
||||||
|
choppy = mix(choppy, 1.0, 0.2);
|
||||||
|
}
|
||||||
|
return p.y - h;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 getSeaColor(vec3 p, vec3 n, vec3 l, vec3 eye, vec3 dist) {
|
||||||
|
float fresnel = clamp(1.0 - dot(n, -eye), 0.0, 1.0);
|
||||||
|
fresnel = min(fresnel * fresnel * fresnel, 0.5);
|
||||||
|
|
||||||
|
vec3 reflected = getSkyColor(reflect(eye, n));
|
||||||
|
vec3 refracted = SEA_BASE + diffuse(n, l, 80.0) * SEA_WATER_COLOR * 0.12;
|
||||||
|
|
||||||
|
vec3 color = mix(refracted, reflected, fresnel);
|
||||||
|
|
||||||
|
float atten = max(1.0 - dot(dist, dist) * 0.001, 0.0);
|
||||||
|
color += SEA_WATER_COLOR * (p.y - SEA_HEIGHT) * 0.18 * atten;
|
||||||
|
|
||||||
|
color += specular(n, l, eye, 600.0 * inversesqrt(dot(dist, dist)));
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 getNormal(vec3 p, float eps) {
|
||||||
|
vec3 n;
|
||||||
|
n.y = map_detailed(p);
|
||||||
|
n.x = map_detailed(vec3(p.x + eps, p.y, p.z)) - n.y;
|
||||||
|
n.z = map_detailed(vec3(p.x, p.y, p.z + eps)) - n.y;
|
||||||
|
n.y = eps;
|
||||||
|
return normalize(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
float heightMapTracing(vec3 ori, vec3 dir, out vec3 p) {
|
||||||
|
float tm = 0.0;
|
||||||
|
float tx = 1000.0;
|
||||||
|
float hx = map(ori + dir * tx);
|
||||||
|
if (hx > 0.0) {
|
||||||
|
p = ori + dir * tx;
|
||||||
|
return tx;
|
||||||
|
}
|
||||||
|
float hm = map(ori);
|
||||||
|
for (int i = 0; i < NUM_STEPS; i++) {
|
||||||
|
float tmid = mix(tm, tx, hm / (hm - hx));
|
||||||
|
p = ori + dir * tmid;
|
||||||
|
float hmid = map(p);
|
||||||
|
if (hmid < 0.0) {
|
||||||
|
tx = tmid;
|
||||||
|
hx = hmid;
|
||||||
|
} else {
|
||||||
|
tm = tmid;
|
||||||
|
hm = hmid;
|
||||||
|
}
|
||||||
|
if (abs(hmid) < EPSILON) break;
|
||||||
|
}
|
||||||
|
return mix(tm, tx, hm / (hm - hx));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 getPixel(in vec2 coord, float time) {
|
||||||
|
vec2 uv = coord / iResolution.xy;
|
||||||
|
uv = uv * 2.0 - 1.0;
|
||||||
|
uv.x *= iResolution.x / iResolution.y;
|
||||||
|
|
||||||
|
vec3 ang = vec3(sin(time * 3.0) * 0.1, sin(time) * 0.2 + 0.3, time);
|
||||||
|
vec3 ori = vec3(0.0, 3.5, time * 5.0);
|
||||||
|
vec3 dir = normalize(vec3(uv.xy, -2.0)); dir.z += length(uv) * 0.14;
|
||||||
|
dir = normalize(dir) * fromEuler(ang);
|
||||||
|
|
||||||
|
vec3 p;
|
||||||
|
heightMapTracing(ori, dir, p);
|
||||||
|
vec3 dist = p - ori;
|
||||||
|
vec3 n = getNormal(p, dot(dist, dist) * EPSILON_NRM);
|
||||||
|
vec3 light = normalize(vec3(0.0, 1.0, 0.8));
|
||||||
|
|
||||||
|
return mix(
|
||||||
|
getSkyColor(dir),
|
||||||
|
getSeaColor(p, n, light, dir, dist),
|
||||||
|
pow(smoothstep(0.0, -0.02, dir.y), 0.2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
||||||
|
float time = iTime * 0.3;
|
||||||
|
vec3 color = getPixel(fragCoord, time);
|
||||||
|
fragColor = vec4(pow(color, vec3(0.65)), 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
2
shaders/shader_art_coding_introduction/meta.txt
Normal file
2
shaders/shader_art_coding_introduction/meta.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Name: Shader Art Coding Introduction
|
||||||
|
Author: kishimisu
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
// Shader Art Coding Introduction — kishimisu
|
||||||
|
// MSL port of shader_art_coding_introduction.vk.glsl.
|
||||||
|
|
||||||
|
struct ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
float2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassthroughVOut {
|
||||||
|
float4 pos [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
static float3 palette(float t) {
|
||||||
|
float3 a = float3(0.5, 0.5, 0.5);
|
||||||
|
float3 b = float3(0.5, 0.5, 0.5);
|
||||||
|
float3 c = float3(1.0, 1.0, 1.0);
|
||||||
|
float3 d = float3(0.263, 0.416, 0.557);
|
||||||
|
return a + b * cos(6.28318 * (c * t * d));
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment float4 shader_art_coding_introduction_fs(PassthroughVOut in [[stage_in]],
|
||||||
|
constant ShadertoyUBO& U [[buffer(0)]]) {
|
||||||
|
float2 fragCoord = in.uv * U.iResolution;
|
||||||
|
float2 uv = (fragCoord * 2.0 - U.iResolution) / U.iResolution.y;
|
||||||
|
float2 uv0 = uv;
|
||||||
|
float3 finalColor = float3(0.0);
|
||||||
|
|
||||||
|
for (float i = 0.0; i < 4.0; i++) {
|
||||||
|
uv = fract(uv * 1.5) - 0.5;
|
||||||
|
|
||||||
|
float d = length(uv) * exp(-length(uv0));
|
||||||
|
|
||||||
|
float3 col = palette(length(uv0) + i * 0.4 + U.iTime * 0.4);
|
||||||
|
|
||||||
|
d = sin(d * 8.0 + U.iTime) / 8.0;
|
||||||
|
d = abs(d);
|
||||||
|
d = pow(0.01 / d, 1.2);
|
||||||
|
|
||||||
|
finalColor += col * d;
|
||||||
|
}
|
||||||
|
|
||||||
|
return float4(finalColor, 1.0);
|
||||||
|
}
|
||||||
Binary file not shown.
@@ -0,0 +1,50 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// Name: Shader Art Coding Introduction
|
||||||
|
// Author: kishimisu
|
||||||
|
// URL: https://www.shadertoy.com/view/mtyGWy
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 vUV;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0) uniform ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
vec2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
vec3 palette(float t) {
|
||||||
|
vec3 a = vec3(0.5, 0.5, 0.5);
|
||||||
|
vec3 b = vec3(0.5, 0.5, 0.5);
|
||||||
|
vec3 c = vec3(1.0, 1.0, 1.0);
|
||||||
|
vec3 d = vec3(0.263, 0.416, 0.557);
|
||||||
|
return a + b * cos(6.28318 * (c * t * d));
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
||||||
|
vec2 uv = (fragCoord * 2.0 - iResolution.xy) / iResolution.y;
|
||||||
|
vec2 uv0 = uv;
|
||||||
|
vec3 finalColor = vec3(0.0);
|
||||||
|
|
||||||
|
for (float i = 0.0; i < 4.0; i++) {
|
||||||
|
uv = fract(uv * 1.5) - 0.5;
|
||||||
|
|
||||||
|
float d = length(uv) * exp(-length(uv0));
|
||||||
|
|
||||||
|
vec3 col = palette(length(uv0) + i * 0.4 + iTime * 0.4);
|
||||||
|
|
||||||
|
d = sin(d * 8.0 + iTime) / 8.0;
|
||||||
|
d = abs(d);
|
||||||
|
d = pow(0.01 / d, 1.2);
|
||||||
|
|
||||||
|
finalColor += col * d;
|
||||||
|
}
|
||||||
|
|
||||||
|
fragColor = vec4(finalColor, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
2
shaders/test/meta.txt
Normal file
2
shaders/test/meta.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Name: Test
|
||||||
|
Author: JailDesigner
|
||||||
36
shaders/test/test.frag.msl
Normal file
36
shaders/test/test.frag.msl
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
// Test shader (Metal Shading Language port of test.vk.glsl).
|
||||||
|
// Author: JailDesigner
|
||||||
|
|
||||||
|
struct ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
float2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassthroughVOut {
|
||||||
|
float4 pos [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
static float3 palette(float t) {
|
||||||
|
float3 a = float3(1.0, 0.5, 0.5);
|
||||||
|
float3 b = float3(1.0, 0.5, 0.5);
|
||||||
|
float3 c = float3(1.0, 1.0, 1.0);
|
||||||
|
float3 d = float3(0.263, 0.416, 0.557);
|
||||||
|
return a + b * cos(6.28318 * (c * t * d));
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment float4 test_fs(PassthroughVOut in [[stage_in]],
|
||||||
|
constant ShadertoyUBO& u [[buffer(0)]]) {
|
||||||
|
float2 fragCoord = in.uv * u.iResolution;
|
||||||
|
float2 uv = (fragCoord * 2.0 - u.iResolution) / u.iResolution.y;
|
||||||
|
float d = length(uv);
|
||||||
|
float3 col = palette(d);
|
||||||
|
d = sin(d * 8.0 + u.iTime) / 8.0;
|
||||||
|
d = abs(d);
|
||||||
|
d = 0.02 / d;
|
||||||
|
col *= d;
|
||||||
|
return float4(col, 1.0);
|
||||||
|
}
|
||||||
BIN
shaders/test/test.frag.spv
Normal file
BIN
shaders/test/test.frag.spv
Normal file
Binary file not shown.
42
shaders/test/test.vk.glsl
Normal file
42
shaders/test/test.vk.glsl
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// Name: Test
|
||||||
|
// Author: JailDesigner
|
||||||
|
//
|
||||||
|
// Vulkan port of test.gl.glsl. Bindings follow the SDL3 GPU convention:
|
||||||
|
// set=3, binding=0 — fragment uniform buffer (anonymous block: members
|
||||||
|
// are accessible directly as iTime / iResolution, like Shadertoy).
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 vUV;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0) uniform ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
vec2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
vec3 palette(float t) {
|
||||||
|
vec3 a = vec3(1.0, 0.5, 0.5);
|
||||||
|
vec3 b = vec3(1.0, 0.5, 0.5);
|
||||||
|
vec3 c = vec3(1.0, 1.0, 1.0);
|
||||||
|
vec3 d = vec3(0.263, 0.416, 0.557);
|
||||||
|
return a + b * cos(6.28318 * (c * t * d));
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
|
||||||
|
vec2 uv = (fragCoord * 2.0 - iResolution) / iResolution.y;
|
||||||
|
float d = length(uv);
|
||||||
|
vec3 col = palette(d);
|
||||||
|
d = sin(d * 8.0 + iTime) / 8.0;
|
||||||
|
d = abs(d);
|
||||||
|
d = 0.02 / d;
|
||||||
|
col *= d;
|
||||||
|
fragColor = vec4(col, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
2
shaders/water/meta.txt
Normal file
2
shaders/water/meta.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Name: Water
|
||||||
|
Author: diatribes
|
||||||
40
shaders/water/water.frag.msl
Normal file
40
shaders/water/water.frag.msl
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
// Water — diatribes
|
||||||
|
// MSL port of water.vk.glsl. Entry point is named after the shader (water_fs).
|
||||||
|
|
||||||
|
struct ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
float2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassthroughVOut {
|
||||||
|
float4 pos [[position]];
|
||||||
|
float2 uv;
|
||||||
|
};
|
||||||
|
|
||||||
|
fragment float4 water_fs(PassthroughVOut in [[stage_in]],
|
||||||
|
constant ShadertoyUBO& U [[buffer(0)]]) {
|
||||||
|
float2 fragCoord = in.uv * U.iResolution;
|
||||||
|
float2 u = fragCoord;
|
||||||
|
|
||||||
|
float s = 0.002, i = 0.0, n;
|
||||||
|
float3 r = float3(U.iResolution, U.iResolution.x / U.iResolution.y);
|
||||||
|
float3 p = float3(0);
|
||||||
|
u = (u - r.xy / 2.0) / r.y - 0.3;
|
||||||
|
|
||||||
|
float4 o = float4(0);
|
||||||
|
|
||||||
|
for (; i < 32.0 && s > 0.001; i++) {
|
||||||
|
float4 term = float4(5, 2, 1, 0) / max(length(u - 0.1), 0.001);
|
||||||
|
o += min(term, float4(100.0));
|
||||||
|
p += float3(u * s, s);
|
||||||
|
s = 1.0 + p.y;
|
||||||
|
for (n = 0.01; n < 1.0; n += n) {
|
||||||
|
s += abs(dot(sin(p.z + U.iTime + p / n), float3(1))) * n * 0.1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
o = tanh(o / 5e2);
|
||||||
|
return o;
|
||||||
|
}
|
||||||
BIN
shaders/water/water.frag.spv
Normal file
BIN
shaders/water/water.frag.spv
Normal file
Binary file not shown.
45
shaders/water/water.vk.glsl
Normal file
45
shaders/water/water.vk.glsl
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#version 450
|
||||||
|
|
||||||
|
// Name: Water
|
||||||
|
// Author: diatribes
|
||||||
|
// URL: https://www.shadertoy.com/view/tXjXDy
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 vUV;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
layout(set = 3, binding = 0) uniform ShadertoyUBO {
|
||||||
|
float iTime;
|
||||||
|
vec2 iResolution;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
-2 by @FabriceNeyret2
|
||||||
|
thanks!! :D
|
||||||
|
|
||||||
|
If it doesn't display correctly, change line "r/r" to "vec3(1)"
|
||||||
|
*/
|
||||||
|
|
||||||
|
void mainImage( out vec4 o, vec2 u ) {
|
||||||
|
float s=.002, i=0., n;
|
||||||
|
vec3 r = vec3(iResolution.xy, iResolution.x/iResolution.y);
|
||||||
|
vec3 p = vec3(0);
|
||||||
|
u = (u-r.xy/2.)/r.y-.3;
|
||||||
|
|
||||||
|
o = vec4(0);
|
||||||
|
|
||||||
|
for(; i < 32. && s > .001; i++) {
|
||||||
|
vec4 term = vec4(5,2,1,0)/max(length(u-.1), 0.001);
|
||||||
|
o += min(term, vec4(100.0));
|
||||||
|
for (p += vec3(u*s,s), s = 1. + p.y, n =.01; n < 1.; n+=n) {
|
||||||
|
s += abs(dot(sin(p.z+iTime+p / n), vec3(1))) * n*.1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
o = tanh(o/5e2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 fragCoordPixels = vUV * iResolution;
|
||||||
|
vec4 outColor;
|
||||||
|
mainImage(outColor, fragCoordPixels);
|
||||||
|
FragColor = outColor;
|
||||||
|
}
|
||||||
@@ -6,6 +6,9 @@
|
|||||||
// Nombre de la aplicación
|
// Nombre de la aplicación
|
||||||
constexpr const char* APP_NAME = "Shadertoy";
|
constexpr const char* APP_NAME = "Shadertoy";
|
||||||
|
|
||||||
|
// Prefijo del título de la ventana (estilo aee_2026).
|
||||||
|
constexpr const char* WINDOW_TITLE_PREFIX = "\xC2\xA9 2025 Shadertoy \xE2\x80\x94 JailDesigner";
|
||||||
|
|
||||||
// Tamaño de ventana por defecto
|
// Tamaño de ventana por defecto
|
||||||
constexpr int WINDOW_WIDTH = 800;
|
constexpr int WINDOW_WIDTH = 800;
|
||||||
constexpr int WINDOW_HEIGHT = 800;
|
constexpr int WINDOW_HEIGHT = 800;
|
||||||
|
|||||||
910
src/main.cpp
910
src/main.cpp
File diff suppressed because it is too large
Load Diff
297
src/rendering/opengl_shader_backend.cpp
Normal file
297
src/rendering/opengl_shader_backend.cpp
Normal file
@@ -0,0 +1,297 @@
|
|||||||
|
#include "rendering/opengl_shader_backend.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Rendering {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr const char* VERTEX_SHADER_SRC = R"glsl(
|
||||||
|
#version 330 core
|
||||||
|
layout(location = 0) in vec2 aPos;
|
||||||
|
out vec2 vUV;
|
||||||
|
void main() {
|
||||||
|
vUV = aPos * 0.5 + 0.5;
|
||||||
|
gl_Position = vec4(aPos, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
)glsl";
|
||||||
|
|
||||||
|
void logInfo(const std::string& msg) { std::cout << "[INFO] " << msg << '\n'; }
|
||||||
|
void logError(const std::string& msg) { std::cerr << "[ERROR] " << msg << '\n'; }
|
||||||
|
|
||||||
|
auto compileShader(GLenum type, const char* src) -> GLuint {
|
||||||
|
const GLuint s = glCreateShader(type);
|
||||||
|
glShaderSource(s, 1, &src, nullptr);
|
||||||
|
glCompileShader(s);
|
||||||
|
GLint ok = 0;
|
||||||
|
glGetShaderiv(s, GL_COMPILE_STATUS, &ok);
|
||||||
|
if (ok == 0) {
|
||||||
|
GLint len = 0;
|
||||||
|
glGetShaderiv(s, GL_INFO_LOG_LENGTH, &len);
|
||||||
|
std::string log(len > 0 ? len : 1, ' ');
|
||||||
|
glGetShaderInfoLog(s, len, nullptr, log.data());
|
||||||
|
logError("Shader compile error: " + log);
|
||||||
|
glDeleteShader(s);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto linkProgram(GLuint vs, GLuint fs) -> GLuint {
|
||||||
|
const GLuint p = glCreateProgram();
|
||||||
|
glAttachShader(p, vs);
|
||||||
|
glAttachShader(p, fs);
|
||||||
|
glLinkProgram(p);
|
||||||
|
GLint ok = 0;
|
||||||
|
glGetProgramiv(p, GL_LINK_STATUS, &ok);
|
||||||
|
if (ok == 0) {
|
||||||
|
GLint len = 0;
|
||||||
|
glGetProgramiv(p, GL_INFO_LOG_LENGTH, &len);
|
||||||
|
std::string log(len > 0 ? len : 1, ' ');
|
||||||
|
glGetProgramInfoLog(p, len, nullptr, log.data());
|
||||||
|
logError("Program link error: " + log);
|
||||||
|
glDeleteProgram(p);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto detectFeedbackChannel(const ShaderMetadata& metadata) -> int {
|
||||||
|
if (metadata.iChannel0 == "self") { return 0; }
|
||||||
|
if (metadata.iChannel1 == "self") { return 1; }
|
||||||
|
if (metadata.iChannel2 == "self") { return 2; }
|
||||||
|
if (metadata.iChannel3 == "self") { return 3; }
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
OpenGLShaderBackend::~OpenGLShaderBackend() { cleanup(); }
|
||||||
|
|
||||||
|
auto OpenGLShaderBackend::init(SDL_Window* window) -> bool {
|
||||||
|
window_ = window;
|
||||||
|
|
||||||
|
gl_context_ = SDL_GL_CreateContext(window_);
|
||||||
|
if (gl_context_ == nullptr) {
|
||||||
|
logError(std::string("SDL_GL_CreateContext error: ") + SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gladLoadGLLoader(reinterpret_cast<GLADloadproc>(SDL_GL_GetProcAddress)) == 0) {
|
||||||
|
logError("Failed to initialize GL loader");
|
||||||
|
SDL_GL_DestroyContext(gl_context_);
|
||||||
|
gl_context_ = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr float QUAD_VERTICES[] = {
|
||||||
|
-1.0f, -1.0f,
|
||||||
|
1.0f, -1.0f,
|
||||||
|
-1.0f, 1.0f,
|
||||||
|
1.0f, 1.0f,
|
||||||
|
};
|
||||||
|
|
||||||
|
glGenVertexArrays(1, &vao_);
|
||||||
|
glGenBuffers(1, &vbo_);
|
||||||
|
glBindVertexArray(vao_);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vbo_);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(QUAD_VERTICES), QUAD_VERTICES, GL_STATIC_DRAW);
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), nullptr);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
glBindVertexArray(0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto OpenGLShaderBackend::loadShader(const ShaderProgramSpec& spec) -> bool {
|
||||||
|
const std::filesystem::path source_path = spec.folder / (spec.base_name + ".gl.glsl");
|
||||||
|
|
||||||
|
std::string fragSrc;
|
||||||
|
if (!loadFileToString(source_path, fragSrc)) {
|
||||||
|
logError("Failed to load shader file: " + source_path.string());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int feedback = detectFeedbackChannel(spec.metadata);
|
||||||
|
|
||||||
|
const GLuint vs = compileShader(GL_VERTEX_SHADER, VERTEX_SHADER_SRC);
|
||||||
|
const GLuint fs = compileShader(GL_FRAGMENT_SHADER, fragSrc.c_str());
|
||||||
|
|
||||||
|
if (vs == 0 || fs == 0) {
|
||||||
|
if (vs != 0) { glDeleteShader(vs); }
|
||||||
|
if (fs != 0) { glDeleteShader(fs); }
|
||||||
|
logError("Shader compilation failed for: " + source_path.string());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GLuint program = linkProgram(vs, fs);
|
||||||
|
glDeleteShader(vs);
|
||||||
|
glDeleteShader(fs);
|
||||||
|
|
||||||
|
if (program == 0) {
|
||||||
|
logError("Program linking failed for: " + source_path.string());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_program_ != 0) {
|
||||||
|
glDeleteProgram(current_program_);
|
||||||
|
}
|
||||||
|
current_program_ = program;
|
||||||
|
|
||||||
|
destroyFeedbackFBO();
|
||||||
|
feedback_channel_ = feedback;
|
||||||
|
current_shader_uses_feedback_ = (feedback >= 0);
|
||||||
|
|
||||||
|
if (current_shader_uses_feedback_) {
|
||||||
|
logInfo("Shader uses self-feedback on iChannel" + std::to_string(feedback_channel_));
|
||||||
|
}
|
||||||
|
|
||||||
|
logInfo("Shader loaded successfully: " + spec.base_name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto OpenGLShaderBackend::createFeedbackFBO(int width, int height) -> bool {
|
||||||
|
destroyFeedbackFBO();
|
||||||
|
|
||||||
|
glGenTextures(1, &feedback_texture_);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, feedback_texture_);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
|
||||||
|
std::vector<float> black(static_cast<std::size_t>(width) * static_cast<std::size_t>(height) * 4U, 0.0f);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA, GL_FLOAT, black.data());
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
glGenFramebuffers(1, &feedback_fbo_);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, feedback_fbo_);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, feedback_texture_, 0);
|
||||||
|
|
||||||
|
const GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
|
||||||
|
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||||
|
logError("Feedback FBO creation failed: " + std::to_string(status));
|
||||||
|
destroyFeedbackFBO();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
feedback_width_ = width;
|
||||||
|
feedback_height_ = height;
|
||||||
|
logInfo("Created feedback FBO (" + std::to_string(width) + "x" + std::to_string(height) + ")");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShaderBackend::destroyFeedbackFBO() {
|
||||||
|
if (feedback_fbo_ != 0) {
|
||||||
|
glDeleteFramebuffers(1, &feedback_fbo_);
|
||||||
|
feedback_fbo_ = 0;
|
||||||
|
}
|
||||||
|
if (feedback_texture_ != 0) {
|
||||||
|
glDeleteTextures(1, &feedback_texture_);
|
||||||
|
feedback_texture_ = 0;
|
||||||
|
}
|
||||||
|
feedback_width_ = 0;
|
||||||
|
feedback_height_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShaderBackend::render(const ShaderUniforms& uniforms) {
|
||||||
|
if (current_program_ == 0 || window_ == nullptr) { return; }
|
||||||
|
|
||||||
|
int w = 0;
|
||||||
|
int h = 0;
|
||||||
|
SDL_GetWindowSize(window_, &w, &h);
|
||||||
|
|
||||||
|
if (current_shader_uses_feedback_) {
|
||||||
|
if (feedback_fbo_ == 0 || feedback_width_ != w || feedback_height_ != h) {
|
||||||
|
createFeedbackFBO(w, h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glUseProgram(current_program_);
|
||||||
|
|
||||||
|
const GLint locRes = glGetUniformLocation(current_program_, "iResolution");
|
||||||
|
const GLint locTime = glGetUniformLocation(current_program_, "iTime");
|
||||||
|
|
||||||
|
if (current_shader_uses_feedback_) {
|
||||||
|
const std::string channel_name = "iChannel" + std::to_string(feedback_channel_);
|
||||||
|
const GLint locChannel = glGetUniformLocation(current_program_, channel_name.c_str());
|
||||||
|
|
||||||
|
if (locChannel >= 0) {
|
||||||
|
glActiveTexture(GL_TEXTURE0 + feedback_channel_);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, feedback_texture_);
|
||||||
|
glUniform1i(locChannel, feedback_channel_);
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, feedback_fbo_);
|
||||||
|
glViewport(0, 0, w, h);
|
||||||
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
if (locRes >= 0) { glUniform2f(locRes, static_cast<float>(w), static_cast<float>(h)); }
|
||||||
|
if (locTime >= 0) { glUniform1f(locTime, uniforms.iTime); }
|
||||||
|
|
||||||
|
glBindVertexArray(vao_);
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
glBindVertexArray(0);
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
glViewport(0, 0, w, h);
|
||||||
|
|
||||||
|
if (locRes >= 0) { glUniform2f(locRes, static_cast<float>(w), static_cast<float>(h)); }
|
||||||
|
if (locTime >= 0) { glUniform1f(locTime, uniforms.iTime); }
|
||||||
|
|
||||||
|
glBindVertexArray(vao_);
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
glBindVertexArray(0);
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0 + feedback_channel_);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
} else {
|
||||||
|
glViewport(0, 0, w, h);
|
||||||
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
if (locRes >= 0) { glUniform2f(locRes, static_cast<float>(w), static_cast<float>(h)); }
|
||||||
|
if (locTime >= 0) { glUniform1f(locTime, uniforms.iTime); }
|
||||||
|
|
||||||
|
glBindVertexArray(vao_);
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
glBindVertexArray(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_GL_SwapWindow(window_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShaderBackend::setVSync(bool vsync) {
|
||||||
|
const int result = SDL_GL_SetSwapInterval(vsync ? 1 : 0);
|
||||||
|
if (result == 0) {
|
||||||
|
logInfo(vsync ? "VSync enabled" : "VSync disabled");
|
||||||
|
} else {
|
||||||
|
logError(std::string("Failed to set VSync: ") + SDL_GetError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShaderBackend::cleanup() {
|
||||||
|
if (gl_context_ == nullptr) { return; }
|
||||||
|
|
||||||
|
if (vbo_ != 0) { glDeleteBuffers(1, &vbo_); vbo_ = 0; }
|
||||||
|
if (vao_ != 0) { glDeleteVertexArrays(1, &vao_); vao_ = 0; }
|
||||||
|
if (current_program_ != 0) { glDeleteProgram(current_program_); current_program_ = 0; }
|
||||||
|
destroyFeedbackFBO();
|
||||||
|
current_shader_uses_feedback_ = false;
|
||||||
|
feedback_channel_ = -1;
|
||||||
|
|
||||||
|
SDL_GL_DestroyContext(gl_context_);
|
||||||
|
gl_context_ = nullptr;
|
||||||
|
window_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto makeOpenGLBackend() -> std::unique_ptr<IShaderBackend> {
|
||||||
|
return std::make_unique<OpenGLShaderBackend>();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Rendering
|
||||||
40
src/rendering/opengl_shader_backend.hpp
Normal file
40
src/rendering/opengl_shader_backend.hpp
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glad/glad.h>
|
||||||
|
|
||||||
|
#include "rendering/shader_backend.hpp"
|
||||||
|
|
||||||
|
namespace Rendering {
|
||||||
|
|
||||||
|
class OpenGLShaderBackend final : public IShaderBackend {
|
||||||
|
public:
|
||||||
|
OpenGLShaderBackend() = default;
|
||||||
|
~OpenGLShaderBackend() override;
|
||||||
|
|
||||||
|
auto init(SDL_Window* window) -> bool override;
|
||||||
|
auto loadShader(const ShaderProgramSpec& spec) -> bool override;
|
||||||
|
void render(const ShaderUniforms& uniforms) override;
|
||||||
|
void setVSync(bool vsync) override;
|
||||||
|
void cleanup() override;
|
||||||
|
[[nodiscard]] auto driverName() const -> std::string override { return "OpenGL"; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
auto createFeedbackFBO(int width, int height) -> bool;
|
||||||
|
void destroyFeedbackFBO();
|
||||||
|
|
||||||
|
SDL_Window* window_{nullptr};
|
||||||
|
SDL_GLContext gl_context_{nullptr};
|
||||||
|
|
||||||
|
GLuint vao_{0};
|
||||||
|
GLuint vbo_{0};
|
||||||
|
GLuint current_program_{0};
|
||||||
|
|
||||||
|
GLuint feedback_fbo_{0};
|
||||||
|
GLuint feedback_texture_{0};
|
||||||
|
bool current_shader_uses_feedback_{false};
|
||||||
|
int feedback_channel_{-1};
|
||||||
|
int feedback_width_{0};
|
||||||
|
int feedback_height_{0};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Rendering
|
||||||
238
src/rendering/sdl3gpu/sdl3gpu_shader_backend.cpp
Normal file
238
src/rendering/sdl3gpu/sdl3gpu_shader_backend.cpp
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
#include "rendering/sdl3gpu/sdl3gpu_shader_backend.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "rendering/sdl3gpu/shader_factory.hpp"
|
||||||
|
|
||||||
|
namespace Rendering {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void logInfo(const std::string& msg) { std::cout << "[INFO] " << msg << '\n'; }
|
||||||
|
void logError(const std::string& msg) { std::cerr << "[ERROR] " << msg << '\n'; }
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
constexpr SDL_GPUShaderFormat SHADER_FORMAT = SDL_GPU_SHADERFORMAT_MSL;
|
||||||
|
constexpr const char* VERTEX_ENTRY = "passthrough_vs";
|
||||||
|
constexpr const char* FRAGMENT_ENTRY = "test_fs"; // overridden per-shader (see loadShader)
|
||||||
|
constexpr const char* VERTEX_SUFFIX = ".vert.msl";
|
||||||
|
constexpr const char* FRAGMENT_SUFFIX = ".frag.msl";
|
||||||
|
#else
|
||||||
|
constexpr SDL_GPUShaderFormat SHADER_FORMAT = SDL_GPU_SHADERFORMAT_SPIRV;
|
||||||
|
constexpr const char* VERTEX_ENTRY = "main";
|
||||||
|
constexpr const char* FRAGMENT_ENTRY = "main";
|
||||||
|
constexpr const char* VERTEX_SUFFIX = ".vert.spv";
|
||||||
|
constexpr const char* FRAGMENT_SUFFIX = ".frag.spv";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Sdl3GpuShaderBackend::~Sdl3GpuShaderBackend() { cleanup(); }
|
||||||
|
|
||||||
|
auto Sdl3GpuShaderBackend::init(SDL_Window* window) -> bool {
|
||||||
|
window_ = window;
|
||||||
|
return createDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Sdl3GpuShaderBackend::createDevice() -> bool {
|
||||||
|
device_ = SDL_CreateGPUDevice(SHADER_FORMAT, false, nullptr);
|
||||||
|
if (device_ == nullptr) {
|
||||||
|
logError(std::string("SDL_CreateGPUDevice failed: ") + SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!SDL_ClaimWindowForGPUDevice(device_, window_)) {
|
||||||
|
logError(std::string("SDL_ClaimWindowForGPUDevice failed: ") + SDL_GetError());
|
||||||
|
SDL_DestroyGPUDevice(device_);
|
||||||
|
device_ = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SDL_SetGPUSwapchainParameters(device_, window_, SDL_GPU_SWAPCHAINCOMPOSITION_SDR, bestPresentMode());
|
||||||
|
|
||||||
|
const char* name = SDL_GetGPUDeviceDriver(device_);
|
||||||
|
const std::string raw = (name != nullptr) ? name : "GPU";
|
||||||
|
if (raw == "vulkan") { driver_name_ = "Vulkan"; }
|
||||||
|
else if (raw == "metal") { driver_name_ = "Metal"; }
|
||||||
|
else if (raw == "d3d12") { driver_name_ = "D3D12"; }
|
||||||
|
else if (!raw.empty()) {
|
||||||
|
driver_name_ = raw;
|
||||||
|
driver_name_[0] = static_cast<char>(std::toupper(static_cast<unsigned char>(driver_name_[0])));
|
||||||
|
} else {
|
||||||
|
driver_name_ = "GPU";
|
||||||
|
}
|
||||||
|
logInfo("GPU driver: " + driver_name_);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Sdl3GpuShaderBackend::loadVertexShaderFor(const ShaderProgramSpec& spec) -> bool {
|
||||||
|
if (vertex_shader_ != nullptr) { return true; }
|
||||||
|
|
||||||
|
const std::filesystem::path common_dir = spec.folder.parent_path() / "_common";
|
||||||
|
const std::filesystem::path vertex_path = common_dir / (std::string("passthrough") + VERTEX_SUFFIX);
|
||||||
|
|
||||||
|
vertex_shader_ = Sdl3Gpu::loadShaderFromFile(device_, vertex_path, SHADER_FORMAT,
|
||||||
|
VERTEX_ENTRY, SDL_GPU_SHADERSTAGE_VERTEX, 0, 0);
|
||||||
|
if (vertex_shader_ == nullptr) {
|
||||||
|
logError("Failed to load shared vertex shader: " + vertex_path.string() + " (" + SDL_GetError() + ")");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
logInfo("Loaded shared vertex shader: " + vertex_path.filename().string());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Sdl3GpuShaderBackend::buildPipeline(SDL_GPUShader* fragment) -> SDL_GPUGraphicsPipeline* {
|
||||||
|
const SDL_GPUTextureFormat SWAPCHAIN_FORMAT = SDL_GetGPUSwapchainTextureFormat(device_, window_);
|
||||||
|
|
||||||
|
SDL_GPUColorTargetBlendState no_blend{};
|
||||||
|
SDL_GPUColorTargetDescription color_target{};
|
||||||
|
color_target.format = SWAPCHAIN_FORMAT;
|
||||||
|
color_target.blend_state = no_blend;
|
||||||
|
|
||||||
|
SDL_GPUGraphicsPipelineCreateInfo info{};
|
||||||
|
info.vertex_shader = vertex_shader_;
|
||||||
|
info.fragment_shader = fragment;
|
||||||
|
info.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST;
|
||||||
|
info.target_info.num_color_targets = 1;
|
||||||
|
info.target_info.color_target_descriptions = &color_target;
|
||||||
|
|
||||||
|
SDL_GPUGraphicsPipeline* pipeline = SDL_CreateGPUGraphicsPipeline(device_, &info);
|
||||||
|
if (pipeline == nullptr) {
|
||||||
|
logError(std::string("SDL_CreateGPUGraphicsPipeline failed: ") + SDL_GetError());
|
||||||
|
}
|
||||||
|
return pipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Sdl3GpuShaderBackend::loadShader(const ShaderProgramSpec& spec) -> bool {
|
||||||
|
if (device_ == nullptr) { return false; }
|
||||||
|
|
||||||
|
if (!loadVertexShaderFor(spec)) { return false; }
|
||||||
|
|
||||||
|
const std::filesystem::path frag_path = spec.folder / (spec.base_name + FRAGMENT_SUFFIX);
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
const std::string entry = spec.base_name + "_fs";
|
||||||
|
const char* fragment_entry = entry.c_str();
|
||||||
|
#else
|
||||||
|
const char* fragment_entry = FRAGMENT_ENTRY;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SDL_GPUShader* new_fragment = Sdl3Gpu::loadShaderFromFile(device_, frag_path, SHADER_FORMAT,
|
||||||
|
fragment_entry, SDL_GPU_SHADERSTAGE_FRAGMENT, 0, 1);
|
||||||
|
if (new_fragment == nullptr) {
|
||||||
|
logError("Failed to load fragment shader: " + frag_path.string() + " (" + SDL_GetError() + ")");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_GPUGraphicsPipeline* new_pipeline = buildPipeline(new_fragment);
|
||||||
|
if (new_pipeline == nullptr) {
|
||||||
|
SDL_ReleaseGPUShader(device_, new_fragment);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_WaitForGPUIdle(device_);
|
||||||
|
if (pipeline_ != nullptr) { SDL_ReleaseGPUGraphicsPipeline(device_, pipeline_); }
|
||||||
|
if (fragment_shader_ != nullptr) { SDL_ReleaseGPUShader(device_, fragment_shader_); }
|
||||||
|
|
||||||
|
pipeline_ = new_pipeline;
|
||||||
|
fragment_shader_ = new_fragment;
|
||||||
|
logInfo("Shader loaded successfully: " + spec.base_name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sdl3GpuShaderBackend::render(const ShaderUniforms& uniforms) {
|
||||||
|
if (device_ == nullptr || pipeline_ == nullptr) { return; }
|
||||||
|
|
||||||
|
SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(device_);
|
||||||
|
if (cmd == nullptr) { return; }
|
||||||
|
|
||||||
|
SDL_GPUTexture* swapchain = nullptr;
|
||||||
|
Uint32 sw = 0;
|
||||||
|
Uint32 sh = 0;
|
||||||
|
if (!SDL_AcquireGPUSwapchainTexture(cmd, window_, &swapchain, &sw, &sh) || swapchain == nullptr) {
|
||||||
|
SDL_SubmitGPUCommandBuffer(cmd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_GPUColorTargetInfo color_target{};
|
||||||
|
color_target.texture = swapchain;
|
||||||
|
color_target.load_op = SDL_GPU_LOADOP_CLEAR;
|
||||||
|
color_target.store_op = SDL_GPU_STOREOP_STORE;
|
||||||
|
color_target.clear_color = {.r = 0.0f, .g = 0.0f, .b = 0.0f, .a = 1.0f};
|
||||||
|
|
||||||
|
SDL_GPURenderPass* pass = SDL_BeginGPURenderPass(cmd, &color_target, 1, nullptr);
|
||||||
|
if (pass != nullptr) {
|
||||||
|
SDL_GPUViewport vp{};
|
||||||
|
vp.x = 0.0f;
|
||||||
|
vp.y = 0.0f;
|
||||||
|
vp.w = static_cast<float>(sw);
|
||||||
|
vp.h = static_cast<float>(sh);
|
||||||
|
vp.min_depth = 0.0f;
|
||||||
|
vp.max_depth = 1.0f;
|
||||||
|
SDL_SetGPUViewport(pass, &vp);
|
||||||
|
|
||||||
|
SDL_BindGPUGraphicsPipeline(pass, pipeline_);
|
||||||
|
|
||||||
|
UniformsStd140 ubo{};
|
||||||
|
ubo.iTime = uniforms.iTime;
|
||||||
|
ubo.iResolutionX = uniforms.iResolutionX;
|
||||||
|
ubo.iResolutionY = uniforms.iResolutionY;
|
||||||
|
SDL_PushGPUFragmentUniformData(cmd, 0, &ubo, sizeof(ubo));
|
||||||
|
|
||||||
|
SDL_DrawGPUPrimitives(pass, 3, 1, 0, 0);
|
||||||
|
SDL_EndGPURenderPass(pass);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_SubmitGPUCommandBuffer(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sdl3GpuShaderBackend::setVSync(bool vsync) {
|
||||||
|
vsync_ = vsync;
|
||||||
|
if (device_ != nullptr && window_ != nullptr) {
|
||||||
|
SDL_SetGPUSwapchainParameters(device_, window_, SDL_GPU_SWAPCHAINCOMPOSITION_SDR, bestPresentMode());
|
||||||
|
logInfo(vsync ? "VSync enabled" : "VSync disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Sdl3GpuShaderBackend::bestPresentMode() const -> SDL_GPUPresentMode {
|
||||||
|
if (vsync_) { return SDL_GPU_PRESENTMODE_VSYNC; }
|
||||||
|
if (device_ != nullptr && window_ != nullptr) {
|
||||||
|
if (SDL_WindowSupportsGPUPresentMode(device_, window_, SDL_GPU_PRESENTMODE_IMMEDIATE)) {
|
||||||
|
return SDL_GPU_PRESENTMODE_IMMEDIATE;
|
||||||
|
}
|
||||||
|
if (SDL_WindowSupportsGPUPresentMode(device_, window_, SDL_GPU_PRESENTMODE_MAILBOX)) {
|
||||||
|
return SDL_GPU_PRESENTMODE_MAILBOX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SDL_GPU_PRESENTMODE_VSYNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sdl3GpuShaderBackend::cleanup() {
|
||||||
|
if (device_ == nullptr) { return; }
|
||||||
|
|
||||||
|
SDL_WaitForGPUIdle(device_);
|
||||||
|
|
||||||
|
if (pipeline_ != nullptr) {
|
||||||
|
SDL_ReleaseGPUGraphicsPipeline(device_, pipeline_);
|
||||||
|
pipeline_ = nullptr;
|
||||||
|
}
|
||||||
|
if (fragment_shader_ != nullptr) {
|
||||||
|
SDL_ReleaseGPUShader(device_, fragment_shader_);
|
||||||
|
fragment_shader_ = nullptr;
|
||||||
|
}
|
||||||
|
if (vertex_shader_ != nullptr) {
|
||||||
|
SDL_ReleaseGPUShader(device_, vertex_shader_);
|
||||||
|
vertex_shader_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window_ != nullptr) {
|
||||||
|
SDL_ReleaseWindowFromGPUDevice(device_, window_);
|
||||||
|
}
|
||||||
|
SDL_DestroyGPUDevice(device_);
|
||||||
|
device_ = nullptr;
|
||||||
|
window_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto makeSdl3GpuBackend() -> std::unique_ptr<IShaderBackend> {
|
||||||
|
return std::make_unique<Sdl3GpuShaderBackend>();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Rendering
|
||||||
44
src/rendering/sdl3gpu/sdl3gpu_shader_backend.hpp
Normal file
44
src/rendering/sdl3gpu/sdl3gpu_shader_backend.hpp
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
#include "rendering/shader_backend.hpp"
|
||||||
|
|
||||||
|
namespace Rendering {
|
||||||
|
|
||||||
|
class Sdl3GpuShaderBackend final : public IShaderBackend {
|
||||||
|
public:
|
||||||
|
Sdl3GpuShaderBackend() = default;
|
||||||
|
~Sdl3GpuShaderBackend() override;
|
||||||
|
|
||||||
|
auto init(SDL_Window* window) -> bool override;
|
||||||
|
auto loadShader(const ShaderProgramSpec& spec) -> bool override;
|
||||||
|
void render(const ShaderUniforms& uniforms) override;
|
||||||
|
void setVSync(bool vsync) override;
|
||||||
|
void cleanup() override;
|
||||||
|
[[nodiscard]] auto driverName() const -> std::string override { return driver_name_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct UniformsStd140 {
|
||||||
|
float iTime{0.0f};
|
||||||
|
float pad0{0.0f};
|
||||||
|
float iResolutionX{0.0f};
|
||||||
|
float iResolutionY{0.0f};
|
||||||
|
};
|
||||||
|
|
||||||
|
auto createDevice() -> bool;
|
||||||
|
auto loadVertexShaderFor(const ShaderProgramSpec& spec) -> bool;
|
||||||
|
auto buildPipeline(SDL_GPUShader* fragment) -> SDL_GPUGraphicsPipeline*;
|
||||||
|
[[nodiscard]] auto bestPresentMode() const -> SDL_GPUPresentMode;
|
||||||
|
|
||||||
|
SDL_Window* window_{nullptr};
|
||||||
|
SDL_GPUDevice* device_{nullptr};
|
||||||
|
SDL_GPUShader* vertex_shader_{nullptr};
|
||||||
|
SDL_GPUShader* fragment_shader_{nullptr};
|
||||||
|
SDL_GPUGraphicsPipeline* pipeline_{nullptr};
|
||||||
|
|
||||||
|
bool vsync_{true};
|
||||||
|
std::string driver_name_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Rendering
|
||||||
41
src/rendering/sdl3gpu/shader_factory.hpp
Normal file
41
src/rendering/sdl3gpu/shader_factory.hpp
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
namespace Rendering::Sdl3Gpu {
|
||||||
|
|
||||||
|
// Loads a compiled shader binary or source from disk and creates an SDL_GPUShader.
|
||||||
|
// For SPIR-V: pass the .spv path with format = SDL_GPU_SHADERFORMAT_SPIRV.
|
||||||
|
// For MSL: pass the .msl text path with format = SDL_GPU_SHADERFORMAT_MSL.
|
||||||
|
inline auto loadShaderFromFile(SDL_GPUDevice* device,
|
||||||
|
const std::filesystem::path& path,
|
||||||
|
SDL_GPUShaderFormat format,
|
||||||
|
const char* entrypoint,
|
||||||
|
SDL_GPUShaderStage stage,
|
||||||
|
Uint32 num_samplers,
|
||||||
|
Uint32 num_uniform_buffers) -> SDL_GPUShader* {
|
||||||
|
std::size_t size = 0;
|
||||||
|
void* data = SDL_LoadFile(path.string().c_str(), &size);
|
||||||
|
if (data == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_GPUShaderCreateInfo info{};
|
||||||
|
info.code_size = size;
|
||||||
|
info.code = static_cast<Uint8*>(data);
|
||||||
|
info.entrypoint = entrypoint;
|
||||||
|
info.format = format;
|
||||||
|
info.stage = stage;
|
||||||
|
info.num_samplers = num_samplers;
|
||||||
|
info.num_storage_textures = 0;
|
||||||
|
info.num_storage_buffers = 0;
|
||||||
|
info.num_uniform_buffers = num_uniform_buffers;
|
||||||
|
|
||||||
|
SDL_GPUShader* shader = SDL_CreateGPUShader(device, &info);
|
||||||
|
SDL_free(data);
|
||||||
|
return shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Rendering::Sdl3Gpu
|
||||||
99
src/rendering/shader_backend.cpp
Normal file
99
src/rendering/shader_backend.cpp
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
#include "rendering/shader_backend.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace Rendering {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
auto trimString(const std::string& str) -> std::string {
|
||||||
|
const std::size_t start = str.find_first_not_of(" \t\r\n");
|
||||||
|
const std::size_t end = str.find_last_not_of(" \t\r\n");
|
||||||
|
if (start != std::string::npos && end != std::string::npos) {
|
||||||
|
return str.substr(start, end - start + 1);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
auto loadFileToString(const std::filesystem::path& path, std::string& out) -> bool {
|
||||||
|
std::ifstream ifs(path, std::ios::in | std::ios::binary);
|
||||||
|
if (!ifs) { return false; }
|
||||||
|
std::ostringstream ss;
|
||||||
|
ss << ifs.rdbuf();
|
||||||
|
out = ss.str();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto parseMetaFile(const std::filesystem::path& meta_path) -> ShaderMetadata {
|
||||||
|
ShaderMetadata metadata;
|
||||||
|
std::ifstream ifs(meta_path);
|
||||||
|
if (!ifs) { return metadata; }
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(ifs, line)) {
|
||||||
|
const std::size_t colon = line.find(':');
|
||||||
|
if (colon == std::string::npos) { continue; }
|
||||||
|
|
||||||
|
std::string key = line.substr(0, colon);
|
||||||
|
std::string value = trimString(line.substr(colon + 1));
|
||||||
|
|
||||||
|
std::transform(key.begin(), key.end(), key.begin(),
|
||||||
|
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
|
||||||
|
key = trimString(key);
|
||||||
|
|
||||||
|
if (key == "name") { metadata.name = value; }
|
||||||
|
else if (key == "author") { metadata.author = value; }
|
||||||
|
else if (key == "ichannel0") { metadata.iChannel0 = value; }
|
||||||
|
else if (key == "ichannel1") { metadata.iChannel1 = value; }
|
||||||
|
else if (key == "ichannel2") { metadata.iChannel2 = value; }
|
||||||
|
else if (key == "ichannel3") { metadata.iChannel3 = value; }
|
||||||
|
}
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto extractShaderMetadata(const std::string& source) -> ShaderMetadata {
|
||||||
|
ShaderMetadata metadata;
|
||||||
|
|
||||||
|
std::istringstream stream(source);
|
||||||
|
std::string line;
|
||||||
|
int line_count = 0;
|
||||||
|
constexpr int MAX_LINES_TO_CHECK = 30;
|
||||||
|
|
||||||
|
while (std::getline(stream, line) && line_count < MAX_LINES_TO_CHECK) {
|
||||||
|
line_count++;
|
||||||
|
|
||||||
|
const std::size_t pos = line.find("//");
|
||||||
|
if (pos == std::string::npos) { continue; }
|
||||||
|
|
||||||
|
const std::string comment = line.substr(pos + 2);
|
||||||
|
std::string lower = comment;
|
||||||
|
std::transform(lower.begin(), lower.end(), lower.begin(),
|
||||||
|
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
|
||||||
|
|
||||||
|
auto valueAfterColon = [&]() {
|
||||||
|
return trimString(comment.substr(comment.find(':') + 1));
|
||||||
|
};
|
||||||
|
|
||||||
|
if (lower.find("name:") != std::string::npos) {
|
||||||
|
metadata.name = valueAfterColon();
|
||||||
|
} else if (lower.find("author:") != std::string::npos) {
|
||||||
|
metadata.author = valueAfterColon();
|
||||||
|
} else if (lower.find("ichannel0:") != std::string::npos) {
|
||||||
|
metadata.iChannel0 = valueAfterColon();
|
||||||
|
} else if (lower.find("ichannel1:") != std::string::npos) {
|
||||||
|
metadata.iChannel1 = valueAfterColon();
|
||||||
|
} else if (lower.find("ichannel2:") != std::string::npos) {
|
||||||
|
metadata.iChannel2 = valueAfterColon();
|
||||||
|
} else if (lower.find("ichannel3:") != std::string::npos) {
|
||||||
|
metadata.iChannel3 = valueAfterColon();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Rendering
|
||||||
57
src/rendering/shader_backend.hpp
Normal file
57
src/rendering/shader_backend.hpp
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Rendering {
|
||||||
|
|
||||||
|
struct ShaderMetadata {
|
||||||
|
std::string name;
|
||||||
|
std::string author;
|
||||||
|
std::string iChannel0{"none"};
|
||||||
|
std::string iChannel1{"none"};
|
||||||
|
std::string iChannel2{"none"};
|
||||||
|
std::string iChannel3{"none"};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ShaderUniforms {
|
||||||
|
float iTime{0.0f};
|
||||||
|
float iResolutionX{0.0f};
|
||||||
|
float iResolutionY{0.0f};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ShaderProgramSpec {
|
||||||
|
std::filesystem::path folder;
|
||||||
|
std::string base_name;
|
||||||
|
ShaderMetadata metadata;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IShaderBackend {
|
||||||
|
public:
|
||||||
|
IShaderBackend() = default;
|
||||||
|
virtual ~IShaderBackend() = default;
|
||||||
|
|
||||||
|
IShaderBackend(const IShaderBackend&) = delete;
|
||||||
|
IShaderBackend(IShaderBackend&&) = delete;
|
||||||
|
auto operator=(const IShaderBackend&) -> IShaderBackend& = delete;
|
||||||
|
auto operator=(IShaderBackend&&) -> IShaderBackend& = delete;
|
||||||
|
|
||||||
|
virtual auto init(SDL_Window* window) -> bool = 0;
|
||||||
|
virtual auto loadShader(const ShaderProgramSpec& spec) -> bool = 0;
|
||||||
|
virtual void render(const ShaderUniforms& uniforms) = 0;
|
||||||
|
virtual void setVSync(bool vsync) = 0;
|
||||||
|
virtual void cleanup() = 0;
|
||||||
|
[[nodiscard]] virtual auto driverName() const -> std::string = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] auto makeOpenGLBackend() -> std::unique_ptr<IShaderBackend>;
|
||||||
|
[[nodiscard]] auto makeSdl3GpuBackend() -> std::unique_ptr<IShaderBackend>;
|
||||||
|
|
||||||
|
[[nodiscard]] auto extractShaderMetadata(const std::string& source) -> ShaderMetadata;
|
||||||
|
[[nodiscard]] auto loadFileToString(const std::filesystem::path& path, std::string& out) -> bool;
|
||||||
|
[[nodiscard]] auto parseMetaFile(const std::filesystem::path& meta_path) -> ShaderMetadata;
|
||||||
|
|
||||||
|
} // namespace Rendering
|
||||||
70
tools/shaders/compile_shaders.cmake
Normal file
70
tools/shaders/compile_shaders.cmake
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
# compile_shaders.cmake — invoked via `cmake -P`.
|
||||||
|
#
|
||||||
|
# Required cache vars:
|
||||||
|
# GLSLC — path to the glslc executable.
|
||||||
|
# SHADERS_DIR — path to the shaders/ directory.
|
||||||
|
#
|
||||||
|
# Walks SHADERS_DIR for:
|
||||||
|
# _common/passthrough.vk.glsl -> _common/passthrough.vert.spv
|
||||||
|
# <name>/<name>.vk.glsl -> <name>/<name>.frag.spv
|
||||||
|
#
|
||||||
|
# Shaders are recompiled only if the .spv is missing or older than its source.
|
||||||
|
|
||||||
|
if(NOT GLSLC)
|
||||||
|
message(FATAL_ERROR "compile_shaders.cmake: GLSLC not provided")
|
||||||
|
endif()
|
||||||
|
if(NOT SHADERS_DIR)
|
||||||
|
message(FATAL_ERROR "compile_shaders.cmake: SHADERS_DIR not provided")
|
||||||
|
endif()
|
||||||
|
if(NOT EXISTS "${SHADERS_DIR}")
|
||||||
|
message(FATAL_ERROR "compile_shaders.cmake: SHADERS_DIR does not exist: ${SHADERS_DIR}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
function(_compile_to_spv SOURCE STAGE OUTPUT)
|
||||||
|
if(EXISTS "${OUTPUT}")
|
||||||
|
file(TIMESTAMP "${SOURCE}" SRC_T "%s")
|
||||||
|
file(TIMESTAMP "${OUTPUT}" OUT_T "%s")
|
||||||
|
if(NOT "${SRC_T}" STREQUAL "" AND NOT "${OUT_T}" STREQUAL "")
|
||||||
|
if(SRC_T LESS_EQUAL OUT_T)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
message(STATUS "glslc (${STAGE}) ${SOURCE} -> ${OUTPUT}")
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${GLSLC}" "-fshader-stage=${STAGE}" "${SOURCE}" -o "${OUTPUT}"
|
||||||
|
RESULT_VARIABLE RC
|
||||||
|
OUTPUT_VARIABLE STDOUT
|
||||||
|
ERROR_VARIABLE STDERR
|
||||||
|
)
|
||||||
|
if(NOT RC EQUAL 0)
|
||||||
|
message(FATAL_ERROR "glslc failed for ${SOURCE}:\n${STDERR}")
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
set(VERT_SOURCE "${SHADERS_DIR}/_common/passthrough.vk.glsl")
|
||||||
|
set(VERT_OUTPUT "${SHADERS_DIR}/_common/passthrough.vert.spv")
|
||||||
|
if(EXISTS "${VERT_SOURCE}")
|
||||||
|
_compile_to_spv("${VERT_SOURCE}" "vert" "${VERT_OUTPUT}")
|
||||||
|
else()
|
||||||
|
message(WARNING "Missing shared vertex shader: ${VERT_SOURCE}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
file(GLOB SHADER_DIRS LIST_DIRECTORIES true RELATIVE "${SHADERS_DIR}" "${SHADERS_DIR}/*")
|
||||||
|
foreach(DIR ${SHADER_DIRS})
|
||||||
|
set(ABS_DIR "${SHADERS_DIR}/${DIR}")
|
||||||
|
if(NOT IS_DIRECTORY "${ABS_DIR}")
|
||||||
|
continue()
|
||||||
|
endif()
|
||||||
|
string(SUBSTRING "${DIR}" 0 1 FIRST_CHAR)
|
||||||
|
if(FIRST_CHAR STREQUAL "_" OR FIRST_CHAR STREQUAL ".")
|
||||||
|
continue()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(VK_SOURCE "${ABS_DIR}/${DIR}.vk.glsl")
|
||||||
|
set(SPV_OUTPUT "${ABS_DIR}/${DIR}.frag.spv")
|
||||||
|
|
||||||
|
if(EXISTS "${VK_SOURCE}")
|
||||||
|
_compile_to_spv("${VK_SOURCE}" "frag" "${SPV_OUTPUT}")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
Reference in New Issue
Block a user