Compare commits
60 Commits
2b221338ae
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| fe017dd874 | |||
| 7aeebf2008 | |||
| 0b4184ccc2 | |||
| ddc12e8607 | |||
| 6ad647ae56 | |||
| b77aca926a | |||
| c2bb20f905 | |||
| 14c6a7be03 | |||
| 85d63e8413 | |||
| 78452aaf67 | |||
| 1f72636350 | |||
| 62433ce86a | |||
| 2be36398f7 | |||
| 2675138ddc | |||
| 572665e8e6 | |||
| 0839f39dfa | |||
| 57cf4955a1 | |||
| c52ae2e4f1 | |||
| 48141f23c5 | |||
| cbbcd053fb | |||
| a57923860e | |||
| 160f6bdadf | |||
| 50ad462318 | |||
| 1239145da4 | |||
| 102941b5d2 | |||
| defff993a0 | |||
| e408151295 | |||
| 22159c9f37 | |||
| 9a2779982d | |||
| 2fc7e9880a | |||
| 7e1ac5fa5c | |||
| b2395f30fc | |||
| f4b0bf1e93 | |||
| 31a6a9d7ec | |||
| 7b2f21c499 | |||
| 17c31b4a4b | |||
| 013c8653ff | |||
| bd8b49a416 | |||
| 9d83c318b6 | |||
| cb19c9b5b4 | |||
| f4fe822ef6 | |||
| 6689fbc734 | |||
| 91b6c203e9 | |||
| 2c30554504 | |||
| 37c8779d12 | |||
| 6b704ff469 | |||
| 2a3bff5a18 | |||
| 91482071b8 | |||
| 38151eb233 | |||
| 78ea055aea | |||
| db2482dbe2 | |||
| 5ae6a9e698 | |||
| 6db83e559b | |||
| e7ec872747 | |||
| 31226a3871 | |||
| 9be3240d6c | |||
| 96134404a2 | |||
| 3aac63d255 | |||
| a8d6095204 | |||
| 960095d0d5 |
@ -142,6 +142,8 @@ class Image implements Canvas implements Resource {
|
|||||||
return 5;
|
return 5;
|
||||||
case A16:
|
case A16:
|
||||||
return 7;
|
return 7;
|
||||||
|
case R32UI:
|
||||||
|
return 8;
|
||||||
default:
|
default:
|
||||||
return 1; // Grey8
|
return 1; // Grey8
|
||||||
}
|
}
|
||||||
|
|||||||
@ -266,7 +266,7 @@ class Graphics implements kha.graphics4.Graphics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function beginFace(face: Int): Void {
|
public function beginFace(face: Int): Void {
|
||||||
kinc_graphics_render_to_face(cast(target, CubeMap)._renderTarget, face);
|
kinc_graphics_render_to_face((target is CubeMap) ? cast(target, CubeMap)._renderTarget : cast(target, Image)._renderTarget, face);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function beginEye(eye: Int): Void {}
|
public function beginEye(eye: Int): Void {}
|
||||||
|
|||||||
@ -234,6 +234,8 @@ class Image implements Canvas implements Resource {
|
|||||||
return 5;
|
return 5;
|
||||||
case A16:
|
case A16:
|
||||||
return 7;
|
return 7;
|
||||||
|
case R32UI:
|
||||||
|
return 8;
|
||||||
default:
|
default:
|
||||||
return 1; // Grey8
|
return 1; // Grey8
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,6 +23,7 @@ extern class Krom {
|
|||||||
static function setRenderTarget(stage: kha.graphics4.TextureUnit, renderTarget: Dynamic): Void;
|
static function setRenderTarget(stage: kha.graphics4.TextureUnit, renderTarget: Dynamic): Void;
|
||||||
static function setTextureDepth(unit: kha.graphics4.TextureUnit, texture: Dynamic): Void;
|
static function setTextureDepth(unit: kha.graphics4.TextureUnit, texture: Dynamic): Void;
|
||||||
static function setImageTexture(stage: kha.graphics4.TextureUnit, texture: Dynamic): Void;
|
static function setImageTexture(stage: kha.graphics4.TextureUnit, texture: Dynamic): Void;
|
||||||
|
static function setImageRenderTarget(stage: kha.graphics4.TextureUnit, renderTarget: Dynamic): Void;
|
||||||
static function setTextureParameters(texunit: kha.graphics4.TextureUnit, uAddressing: Int, vAddressing: Int, minificationFilter: Int,
|
static function setTextureParameters(texunit: kha.graphics4.TextureUnit, uAddressing: Int, vAddressing: Int, minificationFilter: Int,
|
||||||
magnificationFilter: Int, mipmapFilter: Int): Void;
|
magnificationFilter: Int, mipmapFilter: Int): Void;
|
||||||
static function setTexture3DParameters(texunit: kha.graphics4.TextureUnit, uAddressing: Int, vAddressing: Int, wAddressing: Int, minificationFilter: Int,
|
static function setTexture3DParameters(texunit: kha.graphics4.TextureUnit, uAddressing: Int, vAddressing: Int, wAddressing: Int, minificationFilter: Int,
|
||||||
@ -114,6 +115,7 @@ extern class Krom {
|
|||||||
static function windowWidth(id: Int): Int;
|
static function windowWidth(id: Int): Int;
|
||||||
static function windowHeight(id: Int): Int;
|
static function windowHeight(id: Int): Int;
|
||||||
static function setWindowTitle(id: Int, title: String): Void;
|
static function setWindowTitle(id: Int, title: String): Void;
|
||||||
|
static function windowSetForeground(id: Int): Void;
|
||||||
static function screenDpi(): Int;
|
static function screenDpi(): Int;
|
||||||
static function systemId(): String;
|
static function systemId(): String;
|
||||||
static function requestShutdown(): Void;
|
static function requestShutdown(): Void;
|
||||||
@ -158,4 +160,45 @@ extern class Krom {
|
|||||||
static function getConstantLocationCompute(shader: Dynamic, name: String): Dynamic;
|
static function getConstantLocationCompute(shader: Dynamic, name: String): Dynamic;
|
||||||
static function getTextureUnitCompute(shader: Dynamic, name: String): Dynamic;
|
static function getTextureUnitCompute(shader: Dynamic, name: String): Dynamic;
|
||||||
static function compute(x: Int, y: Int, z: Int): Void;
|
static function compute(x: Int, y: Int, z: Int): Void;
|
||||||
|
static function webviewCreate(options: Dynamic): Int;
|
||||||
|
static function webviewLoadHTML(id: Int, html: String): Void;
|
||||||
|
static function webviewLoadURL(id: Int, url: String): Void;
|
||||||
|
static function webviewEvalJS(id: Int, js: String): Void;
|
||||||
|
static function webviewEvalJSAsync(id: Int, js: String, callback: String->Void): Void;
|
||||||
|
static function webviewShow(id: Int): Void;
|
||||||
|
static function webviewHide(id: Int): Void;
|
||||||
|
static function webviewDestroy(id: Int): Void;
|
||||||
|
static function webviewResize(id: Int, width: Int, height: Int): Void;
|
||||||
|
static function webviewMove(id: Int, x: Int, y: Int): Void;
|
||||||
|
static function webviewSetBounds(id: Int, x: Int, y: Int, width: Int, height: Int): Void;
|
||||||
|
static function webviewGetX(id: Int): Int;
|
||||||
|
static function webviewGetY(id: Int): Int;
|
||||||
|
static function webviewGetWidth(id: Int): Int;
|
||||||
|
static function webviewGetHeight(id: Int): Int;
|
||||||
|
static function webviewSetTransparent(id: Int, transparent: Bool): Void;
|
||||||
|
static function webviewSetClickThrough(id: Int, enabled: Bool): Void;
|
||||||
|
static function webviewSetTitle(id: Int, title: String): Void;
|
||||||
|
static function webviewSend(id: Int, message: String): Void;
|
||||||
|
static function webviewSetOnMessage(id: Int, callback: String->Void): Void;
|
||||||
|
static function webviewSetOnLoad(id: Int, callback: Void->Void): Void;
|
||||||
|
static function webviewSetOnError(id: Int, callback: String->Void): Void;
|
||||||
|
static function webviewSetOnClose(id: Int, callback: Void->Void): Void;
|
||||||
|
static function webviewCount(): Int;
|
||||||
|
static function webviewIsValid(id: Int): Bool;
|
||||||
|
static function webviewSetActiveDOM(id: Int): Void;
|
||||||
|
static function webviewGetActiveDOM(): Int;
|
||||||
|
static function webviewGoBack(id: Int): Void;
|
||||||
|
static function webviewGoForward(id: Int): Void;
|
||||||
|
static function webviewReload(id: Int): Void;
|
||||||
|
static function webviewCanGoBack(id: Int): Bool;
|
||||||
|
static function webviewCanGoForward(id: Int): Bool;
|
||||||
|
static function webviewGetURL(id: Int): String;
|
||||||
|
static function webviewGetPageTitle(id: Int): String;
|
||||||
|
static function webviewMinimize(id: Int): Void;
|
||||||
|
static function webviewMaximize(id: Int): Void;
|
||||||
|
static function webviewRestore(id: Int): Void;
|
||||||
|
static function webviewSetFullscreen(id: Int, fullscreen: Bool): Void;
|
||||||
|
static function webviewIsFullscreen(id: Int): Bool;
|
||||||
|
static function webviewEnableDevTools(id: Int, enabled: Bool): Void;
|
||||||
|
static function webviewSetContextMenu(id: Int, enabled: Bool): Void;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -75,6 +75,8 @@ class Image implements Canvas implements Resource {
|
|||||||
return 5;
|
return 5;
|
||||||
case A16:
|
case A16:
|
||||||
return 7;
|
return 7;
|
||||||
|
case R32UI:
|
||||||
|
return 8;
|
||||||
default:
|
default:
|
||||||
return 1; // Grey8
|
return 1; // Grey8
|
||||||
}
|
}
|
||||||
@ -200,6 +202,7 @@ class Image implements Canvas implements Resource {
|
|||||||
case RGBA64: 8;
|
case RGBA64: 8;
|
||||||
case A32: 4;
|
case A32: 4;
|
||||||
case A16: 2;
|
case A16: 2;
|
||||||
|
case R32UI: 4;
|
||||||
default: 4;
|
default: 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,15 +30,15 @@ class LoaderImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static function loadSoundFromDescription(desc: Dynamic, done: kha.Sound->Void, failed: AssetError->Void) {
|
public static function loadSoundFromDescription(desc: Dynamic, done: kha.Sound->Void, failed: AssetError->Void) {
|
||||||
var sound = Krom.loadSound(desc.files[0]);
|
var sound = new kha.krom.Sound(desc.files[0]);
|
||||||
if (sound == null) {
|
if (sound.uncompressedData == null) {
|
||||||
failed({
|
failed({
|
||||||
url: desc.files.join(","),
|
url: desc.files.join(","),
|
||||||
error: "Could not load sound(s)",
|
error: "Could not load sound(s)",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
done(new kha.krom.Sound(Bytes.ofData(sound)));
|
done(sound);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -106,7 +106,7 @@ class Compute {
|
|||||||
public static function setSampledDepthTexture(unit: TextureUnit, texture: Image) {
|
public static function setSampledDepthTexture(unit: TextureUnit, texture: Image) {
|
||||||
if (texture == null)
|
if (texture == null)
|
||||||
return;
|
return;
|
||||||
Krom.setSampledDepthTextureCompute(unit, texture);
|
Krom.setSampledDepthTextureCompute(unit, texture.renderTarget_);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function setSampledCubeMap(unit: TextureUnit, cubeMap: CubeMap) {
|
public static function setSampledCubeMap(unit: TextureUnit, cubeMap: CubeMap) {
|
||||||
@ -118,7 +118,7 @@ class Compute {
|
|||||||
public static function setSampledDepthCubeMap(unit: TextureUnit, cubeMap: CubeMap) {
|
public static function setSampledDepthCubeMap(unit: TextureUnit, cubeMap: CubeMap) {
|
||||||
if (cubeMap == null)
|
if (cubeMap == null)
|
||||||
return;
|
return;
|
||||||
Krom.setSampledDepthTextureCompute(unit, cubeMap);
|
Krom.setSampledDepthTextureCompute(unit, cubeMap.renderTarget_);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function setTextureParameters(unit: TextureUnit, uAddressing: TextureAddressing, vAddressing: TextureAddressing,
|
public static function setTextureParameters(unit: TextureUnit, uAddressing: TextureAddressing, vAddressing: TextureAddressing,
|
||||||
|
|||||||
@ -9,14 +9,7 @@ class ShaderStorageBuffer {
|
|||||||
public function new(indexCount: Int, type: VertexData) {
|
public function new(indexCount: Int, type: VertexData) {
|
||||||
myCount = indexCount;
|
myCount = indexCount;
|
||||||
data = new Array<Int>();
|
data = new Array<Int>();
|
||||||
data[myCount - 1] = 0;
|
if (myCount > 0) data[myCount - 1] = 0;
|
||||||
init(indexCount, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
function init(indexCount: Int, type: VertexData) {
|
|
||||||
myCount = indexCount;
|
|
||||||
data = new Array<Int>();
|
|
||||||
data[myCount - 1] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(): Void {}
|
public function delete(): Void {}
|
||||||
|
|||||||
@ -4,19 +4,22 @@ import haxe.io.Bytes;
|
|||||||
import kha.Blob;
|
import kha.Blob;
|
||||||
|
|
||||||
class ComputeShader {
|
class ComputeShader {
|
||||||
public function new(sources: Array<Blob>, files: Array<String>) {
|
public var shader_: Dynamic;
|
||||||
|
|
||||||
|
public function new(sources: Array<Blob>, files: Array<String>) {
|
||||||
|
shader_ = Krom.createShaderCompute(sources[0].toBytes().getData());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function delete(): Void {
|
public function delete(): Void {
|
||||||
|
Krom.deleteShaderCompute(shader_);
|
||||||
|
shader_ = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getConstantLocation(name: String): ConstantLocation {
|
public function getConstantLocation(name: String): ConstantLocation {
|
||||||
return null;
|
return Krom.getConstantLocationCompute(shader_, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTextureUnit(name: String): TextureUnit {
|
public function getTextureUnit(name: String): TextureUnit {
|
||||||
return null;
|
return Krom.getTextureUnitCompute(shader_, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -122,7 +122,12 @@ class Graphics implements kha.graphics4.Graphics {
|
|||||||
public function setImageTexture(unit: kha.graphics4.TextureUnit, texture: kha.Image): Void {
|
public function setImageTexture(unit: kha.graphics4.TextureUnit, texture: kha.Image): Void {
|
||||||
if (texture == null)
|
if (texture == null)
|
||||||
return;
|
return;
|
||||||
Krom.setImageTexture(unit, texture.texture_);
|
if (texture.texture_ != null) {
|
||||||
|
Krom.setImageTexture(unit, texture.texture_);
|
||||||
|
}
|
||||||
|
else if (texture.renderTarget_ != null) {
|
||||||
|
Krom.setImageRenderTarget(unit, texture.renderTarget_);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setTextureParameters(texunit: kha.graphics4.TextureUnit, uAddressing: TextureAddressing, vAddressing: TextureAddressing,
|
public function setTextureParameters(texunit: kha.graphics4.TextureUnit, uAddressing: TextureAddressing, vAddressing: TextureAddressing,
|
||||||
@ -261,10 +266,10 @@ class Graphics implements kha.graphics4.Graphics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function setComputeShader(shader: ComputeShader) {
|
public function setComputeShader(shader: ComputeShader) {
|
||||||
|
Krom.setShaderCompute(shader.shader_);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function compute(x: Int, y: Int, z: Int) {
|
public function compute(x: Int, y: Int, z: Int) {
|
||||||
|
Krom.compute(x, y, z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,24 +2,28 @@ package kha.krom;
|
|||||||
|
|
||||||
import haxe.io.Bytes;
|
import haxe.io.Bytes;
|
||||||
|
|
||||||
|
using StringTools;
|
||||||
|
|
||||||
class Sound extends kha.Sound {
|
class Sound extends kha.Sound {
|
||||||
public function new(bytes: Bytes) {
|
public function new(filename: String) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
var count = Std.int(bytes.length / 4);
|
var sound = Krom.loadSound(filename);
|
||||||
uncompressedData = new kha.arrays.Float32Array(count);
|
if (sound != null) {
|
||||||
for (i in 0...count) {
|
var bytes = Bytes.ofData(sound.buffer);
|
||||||
uncompressedData[i] = bytes.getFloat(i * 4);
|
var count = Std.int(bytes.length / 4);
|
||||||
}
|
uncompressedData = new kha.arrays.Float32Array(count);
|
||||||
|
for (i in 0...count) {
|
||||||
|
uncompressedData[i] = bytes.getFloat(i * 4);
|
||||||
|
}
|
||||||
|
|
||||||
compressedData = null;
|
this.sampleRate = sound.sampleRate;
|
||||||
|
this.channels = sound.channels;
|
||||||
|
this.length = sound.length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override public function uncompress(done: Void->Void): Void {
|
override public function uncompress(done: Void->Void): Void {
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
|
|
||||||
override public function unload(): Void {
|
|
||||||
super.unload();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -821,8 +821,19 @@ int kinc_g4_max_bound_textures(void) {
|
|||||||
return units;
|
return units;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int getUnitStage(kinc_g4_texture_unit_t unit) {
|
||||||
|
for (int i = 0; i < KINC_G4_SHADER_TYPE_COUNT; ++i) {
|
||||||
|
if (unit.stages[i] >= 0) {
|
||||||
|
return unit.stages[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static void setTextureAddressingInternal(GLenum target, kinc_g4_texture_unit_t unit, kinc_g4_texture_direction_t dir, kinc_g4_texture_addressing_t addressing) {
|
static void setTextureAddressingInternal(GLenum target, kinc_g4_texture_unit_t unit, kinc_g4_texture_direction_t dir, kinc_g4_texture_addressing_t addressing) {
|
||||||
glActiveTexture(GL_TEXTURE0 + unit.stages[KINC_G4_SHADER_TYPE_FRAGMENT]);
|
int stage = getUnitStage(unit);
|
||||||
|
if (stage < 0) return;
|
||||||
|
glActiveTexture(GL_TEXTURE0 + stage);
|
||||||
GLenum texDir;
|
GLenum texDir;
|
||||||
switch (dir) {
|
switch (dir) {
|
||||||
case KINC_G4_TEXTURE_DIRECTION_U:
|
case KINC_G4_TEXTURE_DIRECTION_U:
|
||||||
@ -841,39 +852,39 @@ static void setTextureAddressingInternal(GLenum target, kinc_g4_texture_unit_t u
|
|||||||
case KINC_G4_TEXTURE_ADDRESSING_CLAMP:
|
case KINC_G4_TEXTURE_ADDRESSING_CLAMP:
|
||||||
glTexParameteri(target, texDir, GL_CLAMP_TO_EDGE);
|
glTexParameteri(target, texDir, GL_CLAMP_TO_EDGE);
|
||||||
if (dir == KINC_G4_TEXTURE_DIRECTION_U) {
|
if (dir == KINC_G4_TEXTURE_DIRECTION_U) {
|
||||||
texModesU[unit.stages[KINC_G4_SHADER_TYPE_FRAGMENT]] = GL_CLAMP_TO_EDGE;
|
texModesU[stage] = GL_CLAMP_TO_EDGE;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
texModesV[unit.stages[KINC_G4_SHADER_TYPE_FRAGMENT]] = GL_CLAMP_TO_EDGE;
|
texModesV[stage] = GL_CLAMP_TO_EDGE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case KINC_G4_TEXTURE_ADDRESSING_REPEAT:
|
case KINC_G4_TEXTURE_ADDRESSING_REPEAT:
|
||||||
glTexParameteri(target, texDir, GL_REPEAT);
|
glTexParameteri(target, texDir, GL_REPEAT);
|
||||||
if (dir == KINC_G4_TEXTURE_DIRECTION_U) {
|
if (dir == KINC_G4_TEXTURE_DIRECTION_U) {
|
||||||
texModesU[unit.stages[KINC_G4_SHADER_TYPE_FRAGMENT]] = GL_REPEAT;
|
texModesU[stage] = GL_REPEAT;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
texModesV[unit.stages[KINC_G4_SHADER_TYPE_FRAGMENT]] = GL_REPEAT;
|
texModesV[stage] = GL_REPEAT;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case KINC_G4_TEXTURE_ADDRESSING_BORDER:
|
case KINC_G4_TEXTURE_ADDRESSING_BORDER:
|
||||||
// unsupported
|
// unsupported
|
||||||
glTexParameteri(target, texDir, GL_CLAMP_TO_EDGE);
|
glTexParameteri(target, texDir, GL_CLAMP_TO_EDGE);
|
||||||
if (dir == KINC_G4_TEXTURE_DIRECTION_U) {
|
if (dir == KINC_G4_TEXTURE_DIRECTION_U) {
|
||||||
texModesU[unit.stages[KINC_G4_SHADER_TYPE_FRAGMENT]] = GL_CLAMP_TO_EDGE;
|
texModesU[stage] = GL_CLAMP_TO_EDGE;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
texModesV[unit.stages[KINC_G4_SHADER_TYPE_FRAGMENT]] = GL_CLAMP_TO_EDGE;
|
texModesV[stage] = GL_CLAMP_TO_EDGE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case KINC_G4_TEXTURE_ADDRESSING_MIRROR:
|
case KINC_G4_TEXTURE_ADDRESSING_MIRROR:
|
||||||
// unsupported
|
// unsupported
|
||||||
glTexParameteri(target, texDir, GL_REPEAT);
|
glTexParameteri(target, texDir, GL_REPEAT);
|
||||||
if (dir == KINC_G4_TEXTURE_DIRECTION_U) {
|
if (dir == KINC_G4_TEXTURE_DIRECTION_U) {
|
||||||
texModesU[unit.stages[KINC_G4_SHADER_TYPE_FRAGMENT]] = GL_REPEAT;
|
texModesU[stage] = GL_REPEAT;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
texModesV[unit.stages[KINC_G4_SHADER_TYPE_FRAGMENT]] = GL_REPEAT;
|
texModesV[stage] = GL_REPEAT;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -881,11 +892,15 @@ static void setTextureAddressingInternal(GLenum target, kinc_g4_texture_unit_t u
|
|||||||
}
|
}
|
||||||
|
|
||||||
int Kinc_G4_Internal_TextureAddressingU(kinc_g4_texture_unit_t unit) {
|
int Kinc_G4_Internal_TextureAddressingU(kinc_g4_texture_unit_t unit) {
|
||||||
return texModesU[unit.stages[KINC_G4_SHADER_TYPE_FRAGMENT]];
|
int stage = getUnitStage(unit);
|
||||||
|
if (stage < 0) return GL_CLAMP_TO_EDGE;
|
||||||
|
return texModesU[stage];
|
||||||
}
|
}
|
||||||
|
|
||||||
int Kinc_G4_Internal_TextureAddressingV(kinc_g4_texture_unit_t unit) {
|
int Kinc_G4_Internal_TextureAddressingV(kinc_g4_texture_unit_t unit) {
|
||||||
return texModesV[unit.stages[KINC_G4_SHADER_TYPE_FRAGMENT]];
|
int stage = getUnitStage(unit);
|
||||||
|
if (stage < 0) return GL_CLAMP_TO_EDGE;
|
||||||
|
return texModesV[stage];
|
||||||
}
|
}
|
||||||
|
|
||||||
void kinc_g4_set_texture_addressing(kinc_g4_texture_unit_t unit, kinc_g4_texture_direction_t dir, kinc_g4_texture_addressing_t addressing) {
|
void kinc_g4_set_texture_addressing(kinc_g4_texture_unit_t unit, kinc_g4_texture_direction_t dir, kinc_g4_texture_addressing_t addressing) {
|
||||||
@ -899,7 +914,9 @@ void kinc_g4_set_texture3d_addressing(kinc_g4_texture_unit_t unit, kinc_g4_textu
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void setTextureMagnificationFilterInternal(GLenum target, kinc_g4_texture_unit_t texunit, kinc_g4_texture_filter_t filter) {
|
static void setTextureMagnificationFilterInternal(GLenum target, kinc_g4_texture_unit_t texunit, kinc_g4_texture_filter_t filter) {
|
||||||
glActiveTexture(GL_TEXTURE0 + texunit.stages[KINC_G4_SHADER_TYPE_FRAGMENT]);
|
int stage = getUnitStage(texunit);
|
||||||
|
if (stage < 0) return;
|
||||||
|
glActiveTexture(GL_TEXTURE0 + stage);
|
||||||
glCheckErrors();
|
glCheckErrors();
|
||||||
switch (filter) {
|
switch (filter) {
|
||||||
case KINC_G4_TEXTURE_FILTER_POINT:
|
case KINC_G4_TEXTURE_FILTER_POINT:
|
||||||
@ -964,26 +981,34 @@ static void setMinMipFilters(GLenum target, int unit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void kinc_g4_set_texture_minification_filter(kinc_g4_texture_unit_t texunit, kinc_g4_texture_filter_t filter) {
|
void kinc_g4_set_texture_minification_filter(kinc_g4_texture_unit_t texunit, kinc_g4_texture_filter_t filter) {
|
||||||
minFilters[texunit.stages[KINC_G4_SHADER_TYPE_FRAGMENT]] = filter;
|
int stage = getUnitStage(texunit);
|
||||||
setMinMipFilters(GL_TEXTURE_2D, texunit.stages[KINC_G4_SHADER_TYPE_FRAGMENT]);
|
if (stage < 0) return;
|
||||||
|
minFilters[stage] = filter;
|
||||||
|
setMinMipFilters(GL_TEXTURE_2D, stage);
|
||||||
}
|
}
|
||||||
|
|
||||||
void kinc_g4_set_texture3d_minification_filter(kinc_g4_texture_unit_t texunit, kinc_g4_texture_filter_t filter) {
|
void kinc_g4_set_texture3d_minification_filter(kinc_g4_texture_unit_t texunit, kinc_g4_texture_filter_t filter) {
|
||||||
minFilters[texunit.stages[KINC_G4_SHADER_TYPE_FRAGMENT]] = filter;
|
int stage = getUnitStage(texunit);
|
||||||
|
if (stage < 0) return;
|
||||||
|
minFilters[stage] = filter;
|
||||||
#ifndef KINC_OPENGL_ES
|
#ifndef KINC_OPENGL_ES
|
||||||
setMinMipFilters(GL_TEXTURE_3D, texunit.stages[KINC_G4_SHADER_TYPE_FRAGMENT]);
|
setMinMipFilters(GL_TEXTURE_3D, stage);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void kinc_g4_set_texture_mipmap_filter(kinc_g4_texture_unit_t texunit, kinc_g4_mipmap_filter_t filter) {
|
void kinc_g4_set_texture_mipmap_filter(kinc_g4_texture_unit_t texunit, kinc_g4_mipmap_filter_t filter) {
|
||||||
mipFilters[texunit.stages[KINC_G4_SHADER_TYPE_FRAGMENT]] = filter;
|
int stage = getUnitStage(texunit);
|
||||||
setMinMipFilters(GL_TEXTURE_2D, texunit.stages[KINC_G4_SHADER_TYPE_FRAGMENT]);
|
if (stage < 0) return;
|
||||||
|
mipFilters[stage] = filter;
|
||||||
|
setMinMipFilters(GL_TEXTURE_2D, stage);
|
||||||
}
|
}
|
||||||
|
|
||||||
void kinc_g4_set_texture3d_mipmap_filter(kinc_g4_texture_unit_t texunit, kinc_g4_mipmap_filter_t filter) {
|
void kinc_g4_set_texture3d_mipmap_filter(kinc_g4_texture_unit_t texunit, kinc_g4_mipmap_filter_t filter) {
|
||||||
mipFilters[texunit.stages[KINC_G4_SHADER_TYPE_FRAGMENT]] = filter;
|
int stage = getUnitStage(texunit);
|
||||||
|
if (stage < 0) return;
|
||||||
|
mipFilters[stage] = filter;
|
||||||
#ifndef KINC_OPENGL_ES
|
#ifndef KINC_OPENGL_ES
|
||||||
setMinMipFilters(GL_TEXTURE_3D, texunit.stages[KINC_G4_SHADER_TYPE_FRAGMENT]);
|
setMinMipFilters(GL_TEXTURE_3D, stage);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -190,6 +190,17 @@ void kinc_g4_set_compute_shader(kinc_g4_compute_shader *shader) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void kinc_g4_set_image_render_target(kinc_g4_texture_unit_t unit, kinc_g4_render_target_t *render_target) {
|
||||||
|
#if defined(KINC_WINDOWS) || (defined(KINC_LINUX) && defined(GL_VERSION_4_4))
|
||||||
|
for (int i = 0; i < KINC_G4_SHADER_TYPE_COUNT; ++i) {
|
||||||
|
if (unit.stages[i] >= 0) {
|
||||||
|
glBindImageTexture(unit.stages[i], render_target->impl._texture, 0, GL_FALSE, 0, GL_READ_WRITE, convertInternalRTFormat((kinc_g4_render_target_format_t)render_target->impl.format));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glCheckErrors();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void kinc_g4_compute(int x, int y, int z) {
|
void kinc_g4_compute(int x, int y, int z) {
|
||||||
#ifdef HAS_COMPUTE
|
#ifdef HAS_COMPUTE
|
||||||
glDispatchCompute(x, y, z);
|
glDispatchCompute(x, y, z);
|
||||||
|
|||||||
@ -360,17 +360,23 @@ void kinc_g4_render_target_destroy(kinc_g4_render_target_t *renderTarget) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void kinc_g4_render_target_use_color_as_texture(kinc_g4_render_target_t *renderTarget, kinc_g4_texture_unit_t unit) {
|
void kinc_g4_render_target_use_color_as_texture(kinc_g4_render_target_t *renderTarget, kinc_g4_texture_unit_t unit) {
|
||||||
glActiveTexture(GL_TEXTURE0 + unit.stages[KINC_G4_SHADER_TYPE_FRAGMENT]);
|
for (int i = 0; i < KINC_G4_SHADER_TYPE_COUNT; ++i) {
|
||||||
glCheckErrors();
|
if (unit.stages[i] >= 0) {
|
||||||
glBindTexture(renderTarget->isCubeMap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, renderTarget->impl._texture);
|
glActiveTexture(GL_TEXTURE0 + unit.stages[i]);
|
||||||
glCheckErrors();
|
glBindTexture(renderTarget->isCubeMap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, renderTarget->impl._texture);
|
||||||
|
glCheckErrors();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void kinc_g4_render_target_use_depth_as_texture(kinc_g4_render_target_t *renderTarget, kinc_g4_texture_unit_t unit) {
|
void kinc_g4_render_target_use_depth_as_texture(kinc_g4_render_target_t *renderTarget, kinc_g4_texture_unit_t unit) {
|
||||||
glActiveTexture(GL_TEXTURE0 + unit.stages[KINC_G4_SHADER_TYPE_FRAGMENT]);
|
for (int i = 0; i < KINC_G4_SHADER_TYPE_COUNT; ++i) {
|
||||||
glCheckErrors();
|
if (unit.stages[i] >= 0) {
|
||||||
glBindTexture(renderTarget->isCubeMap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, renderTarget->impl._depthTexture);
|
glActiveTexture(GL_TEXTURE0 + unit.stages[i]);
|
||||||
glCheckErrors();
|
glBindTexture(renderTarget->isCubeMap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, renderTarget->impl._depthTexture);
|
||||||
|
glCheckErrors();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void kinc_g4_render_target_set_depth_stencil_from(kinc_g4_render_target_t *renderTarget, kinc_g4_render_target_t *source) {
|
void kinc_g4_render_target_set_depth_stencil_from(kinc_g4_render_target_t *renderTarget, kinc_g4_render_target_t *source) {
|
||||||
|
|||||||
@ -99,6 +99,8 @@ static int convertFormat(kinc_image_format_t format) {
|
|||||||
case KINC_IMAGE_FORMAT_A16:
|
case KINC_IMAGE_FORMAT_A16:
|
||||||
case KINC_IMAGE_FORMAT_GREY8:
|
case KINC_IMAGE_FORMAT_GREY8:
|
||||||
return GL_RED;
|
return GL_RED;
|
||||||
|
case KINC_IMAGE_FORMAT_R32UI:
|
||||||
|
return GL_RED_INTEGER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,6 +134,8 @@ static int convertInternalFormat(kinc_image_format_t format) {
|
|||||||
#else
|
#else
|
||||||
return GL_R8;
|
return GL_R8;
|
||||||
#endif
|
#endif
|
||||||
|
case KINC_IMAGE_FORMAT_R32UI:
|
||||||
|
return GL_R32UI;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,6 +149,8 @@ static int convertType(kinc_image_format_t format) {
|
|||||||
case KINC_IMAGE_FORMAT_RGBA32:
|
case KINC_IMAGE_FORMAT_RGBA32:
|
||||||
default:
|
default:
|
||||||
return GL_UNSIGNED_BYTE;
|
return GL_UNSIGNED_BYTE;
|
||||||
|
case KINC_IMAGE_FORMAT_R32UI:
|
||||||
|
return GL_UNSIGNED_INT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -483,7 +489,7 @@ void kinc_g4_texture_init3d(kinc_g4_texture_t *texture, int width, int height, i
|
|||||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
glCheckErrors();
|
glCheckErrors();
|
||||||
|
|
||||||
glTexImage3D(GL_TEXTURE_3D, 0, convertInternalFormat(format), width, height, depth, 0, convertFormat(format), GL_UNSIGNED_BYTE, NULL);
|
glTexImage3D(GL_TEXTURE_3D, 0, convertInternalFormat(format), width, height, depth, 0, convertFormat(format), convertType(format), NULL);
|
||||||
glCheckErrors();
|
glCheckErrors();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -523,8 +529,8 @@ void Kinc_G4_Internal_TextureSet(kinc_g4_texture_t *texture, kinc_g4_texture_uni
|
|||||||
#else
|
#else
|
||||||
glBindTexture(target, texture->impl.texture);
|
glBindTexture(target, texture->impl.texture);
|
||||||
glCheckErrors();
|
glCheckErrors();
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, Kinc_G4_Internal_TextureAddressingU(unit));
|
glTexParameteri(target, GL_TEXTURE_WRAP_S, Kinc_G4_Internal_TextureAddressingU(unit));
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, Kinc_G4_Internal_TextureAddressingV(unit));
|
glTexParameteri(target, GL_TEXTURE_WRAP_T, Kinc_G4_Internal_TextureAddressingV(unit));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -532,7 +538,7 @@ void Kinc_G4_Internal_TextureImageSet(kinc_g4_texture_t *texture, kinc_g4_textur
|
|||||||
#if defined(KINC_WINDOWS) || (defined(KINC_LINUX) && defined(GL_VERSION_4_4))
|
#if defined(KINC_WINDOWS) || (defined(KINC_LINUX) && defined(GL_VERSION_4_4))
|
||||||
for (int i = 0; i < KINC_G4_SHADER_TYPE_COUNT; ++i) {
|
for (int i = 0; i < KINC_G4_SHADER_TYPE_COUNT; ++i) {
|
||||||
if (unit.stages[i] >= 0) {
|
if (unit.stages[i] >= 0) {
|
||||||
glBindImageTexture(unit.stages[i], texture->impl.texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, convertInternalFormat(texture->format));
|
glBindImageTexture(unit.stages[i], texture->impl.texture, 0, GL_FALSE, 0, GL_READ_WRITE, convertInternalFormat(texture->format));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
glCheckErrors();
|
glCheckErrors();
|
||||||
|
|||||||
@ -392,6 +392,11 @@ void kinc_window_hide(int window_index) {
|
|||||||
UpdateWindow(windows[window_index].handle);
|
UpdateWindow(windows[window_index].handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void kinc_window_set_foreground(int window_index) {
|
||||||
|
SetForegroundWindow(windows[window_index].handle);
|
||||||
|
SetFocus(windows[window_index].handle);
|
||||||
|
}
|
||||||
|
|
||||||
void kinc_window_set_title(int window_index, const char *title) {
|
void kinc_window_set_title(int window_index, const char *title) {
|
||||||
wchar_t buffer[1024];
|
wchar_t buffer[1024];
|
||||||
MultiByteToWideChar(CP_UTF8, 0, title, -1, buffer, 1024);
|
MultiByteToWideChar(CP_UTF8, 0, title, -1, buffer, 1024);
|
||||||
|
|||||||
@ -376,6 +376,8 @@ KINC_FUNC void kinc_g4_set_texture(kinc_g4_texture_unit_t unit, struct kinc_g4_t
|
|||||||
/// <param name="texture">The texture to assign to the unit</param>
|
/// <param name="texture">The texture to assign to the unit</param>
|
||||||
KINC_FUNC void kinc_g4_set_image_texture(kinc_g4_texture_unit_t unit, struct kinc_g4_texture *texture);
|
KINC_FUNC void kinc_g4_set_image_texture(kinc_g4_texture_unit_t unit, struct kinc_g4_texture *texture);
|
||||||
|
|
||||||
|
KINC_FUNC void kinc_g4_set_image_render_target(kinc_g4_texture_unit_t unit, struct kinc_g4_render_target *render_target);
|
||||||
|
|
||||||
KINC_FUNC bool kinc_g4_init_occlusion_query(unsigned *occlusionQuery);
|
KINC_FUNC bool kinc_g4_init_occlusion_query(unsigned *occlusionQuery);
|
||||||
|
|
||||||
KINC_FUNC void kinc_g4_delete_occlusion_query(unsigned occlusionQuery);
|
KINC_FUNC void kinc_g4_delete_occlusion_query(unsigned occlusionQuery);
|
||||||
|
|||||||
@ -30,7 +30,8 @@ typedef enum kinc_image_format {
|
|||||||
KINC_IMAGE_FORMAT_RGBA64,
|
KINC_IMAGE_FORMAT_RGBA64,
|
||||||
KINC_IMAGE_FORMAT_A32,
|
KINC_IMAGE_FORMAT_A32,
|
||||||
KINC_IMAGE_FORMAT_BGRA32,
|
KINC_IMAGE_FORMAT_BGRA32,
|
||||||
KINC_IMAGE_FORMAT_A16
|
KINC_IMAGE_FORMAT_A16,
|
||||||
|
KINC_IMAGE_FORMAT_R32UI
|
||||||
} kinc_image_format_t;
|
} kinc_image_format_t;
|
||||||
|
|
||||||
typedef struct kinc_image {
|
typedef struct kinc_image {
|
||||||
@ -608,6 +609,8 @@ int kinc_image_format_sizeof(kinc_image_format_t format) {
|
|||||||
return 1;
|
return 1;
|
||||||
case KINC_IMAGE_FORMAT_RGB24:
|
case KINC_IMAGE_FORMAT_RGB24:
|
||||||
return 3;
|
return 3;
|
||||||
|
case KINC_IMAGE_FORMAT_R32UI:
|
||||||
|
return 4;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -139,6 +139,11 @@ KINC_FUNC void kinc_window_show(int window);
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
KINC_FUNC void kinc_window_hide(int window);
|
KINC_FUNC void kinc_window_hide(int window);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Brings a window to the foreground and sets focus to it.
|
||||||
|
/// </summary>
|
||||||
|
KINC_FUNC void kinc_window_set_foreground(int window);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the title of a window.
|
/// Sets the title of a window.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 417 KiB After Width: | Height: | Size: 281 KiB |
|
Before Width: | Height: | Size: 417 KiB After Width: | Height: | Size: 281 KiB |
|
Before Width: | Height: | Size: 417 KiB After Width: | Height: | Size: 281 KiB |
|
Before Width: | Height: | Size: 417 KiB After Width: | Height: | Size: 281 KiB |
|
Before Width: | Height: | Size: 417 KiB After Width: | Height: | Size: 281 KiB |
|
Before Width: | Height: | Size: 417 KiB After Width: | Height: | Size: 281 KiB |
|
Before Width: | Height: | Size: 417 KiB After Width: | Height: | Size: 281 KiB |
@ -68,7 +68,7 @@ class Sound implements Resource {
|
|||||||
var soundBytes = output.getBytes();
|
var soundBytes = output.getBytes();
|
||||||
var count = Std.int(soundBytes.length / 4);
|
var count = Std.int(soundBytes.length / 4);
|
||||||
if (header.channel == 1) {
|
if (header.channel == 1) {
|
||||||
length = count / kha.audio2.Audio.samplesPerSecond; // header.sampleRate;
|
length = count / header.sampleRate;
|
||||||
uncompressedData = new kha.arrays.Float32Array(count * 2);
|
uncompressedData = new kha.arrays.Float32Array(count * 2);
|
||||||
for (i in 0...count) {
|
for (i in 0...count) {
|
||||||
uncompressedData[i * 2 + 0] = soundBytes.getFloat(i * 4);
|
uncompressedData[i * 2 + 0] = soundBytes.getFloat(i * 4);
|
||||||
@ -76,7 +76,7 @@ class Sound implements Resource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
length = count / 2 / kha.audio2.Audio.samplesPerSecond; // header.sampleRate;
|
length = count / 2 / header.sampleRate;
|
||||||
uncompressedData = new kha.arrays.Float32Array(count);
|
uncompressedData = new kha.arrays.Float32Array(count);
|
||||||
for (i in 0...count) {
|
for (i in 0...count) {
|
||||||
uncompressedData[i] = soundBytes.getFloat(i * 4);
|
uncompressedData[i] = soundBytes.getFloat(i * 4);
|
||||||
|
|||||||
7
Kha/Sources/kha/compute/Access.hx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package kha.compute;
|
||||||
|
|
||||||
|
enum abstract Access(Int) to Int {
|
||||||
|
var Read = 0;
|
||||||
|
var Write = 1;
|
||||||
|
var ReadWrite = 2;
|
||||||
|
}
|
||||||
41
Kha/Sources/kha/compute/Compute.hx
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package kha.compute;
|
||||||
|
|
||||||
|
import kha.arrays.Float32Array;
|
||||||
|
import kha.Image;
|
||||||
|
import kha.FastFloat;
|
||||||
|
import kha.math.FastMatrix3;
|
||||||
|
import kha.math.FastMatrix4;
|
||||||
|
import kha.math.FastVector2;
|
||||||
|
import kha.math.FastVector3;
|
||||||
|
import kha.math.FastVector4;
|
||||||
|
import kha.graphics4.CubeMap;
|
||||||
|
import kha.graphics4.TextureAddressing;
|
||||||
|
import kha.graphics4.TextureFilter;
|
||||||
|
import kha.graphics4.MipMapFilter;
|
||||||
|
|
||||||
|
extern class Compute {
|
||||||
|
public static function setBool(location: ConstantLocation, value: Bool): Void;
|
||||||
|
public static function setInt(location: ConstantLocation, value: Int): Void;
|
||||||
|
public static function setFloat(location: ConstantLocation, value: FastFloat): Void;
|
||||||
|
public static function setFloat2(location: ConstantLocation, value1: FastFloat, value2: FastFloat): Void;
|
||||||
|
public static function setFloat3(location: ConstantLocation, value1: FastFloat, value2: FastFloat, value3: FastFloat): Void;
|
||||||
|
public static function setFloat4(location: ConstantLocation, value1: FastFloat, value2: FastFloat, value3: FastFloat, value4: FastFloat): Void;
|
||||||
|
public static function setFloats(location: ConstantLocation, values: Float32Array): Void;
|
||||||
|
public static function setVector2(location: ConstantLocation, value: FastVector2): Void;
|
||||||
|
public static function setVector3(location: ConstantLocation, value: FastVector3): Void;
|
||||||
|
public static function setVector4(location: ConstantLocation, value: FastVector4): Void;
|
||||||
|
public static function setMatrix(location: ConstantLocation, value: FastMatrix4): Void;
|
||||||
|
public static function setMatrix3(location: ConstantLocation, value: FastMatrix3): Void;
|
||||||
|
public static function setBuffer(buffer: ShaderStorageBuffer, index: Int): Void;
|
||||||
|
public static function setTexture(unit: TextureUnit, texture: Image, access: Access): Void;
|
||||||
|
public static function setSampledTexture(unit: TextureUnit, texture: Image): Void;
|
||||||
|
public static function setSampledDepthTexture(unit: TextureUnit, texture: Image): Void;
|
||||||
|
public static function setSampledCubeMap(unit: TextureUnit, cubeMap: CubeMap): Void;
|
||||||
|
public static function setSampledDepthCubeMap(unit: TextureUnit, cubeMap: CubeMap): Void;
|
||||||
|
public static function setTextureParameters(unit: TextureUnit, uAddressing: TextureAddressing, vAddressing: TextureAddressing,
|
||||||
|
minificationFilter: TextureFilter, magnificationFilter: TextureFilter, mipmapFilter: MipMapFilter): Void;
|
||||||
|
public static function setTexture3DParameters(unit: TextureUnit, uAddressing: TextureAddressing, vAddressing: TextureAddressing,
|
||||||
|
wAddressing: TextureAddressing, minificationFilter: TextureFilter, magnificationFilter: TextureFilter, mipmapFilter: MipMapFilter): Void;
|
||||||
|
public static function setShader(shader: Shader): Void;
|
||||||
|
public static function compute(x: Int, y: Int, z: Int): Void;
|
||||||
|
}
|
||||||
3
Kha/Sources/kha/compute/ConstantLocation.hx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package kha.compute;
|
||||||
|
|
||||||
|
interface ConstantLocation {}
|
||||||
10
Kha/Sources/kha/compute/Shader.hx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package kha.compute;
|
||||||
|
|
||||||
|
import kha.Blob;
|
||||||
|
|
||||||
|
extern class Shader {
|
||||||
|
public function new(sources: Array<Blob>, files: Array<String>);
|
||||||
|
public function delete(): Void;
|
||||||
|
public function getConstantLocation(name: String): ConstantLocation;
|
||||||
|
public function getTextureUnit(name: String): TextureUnit;
|
||||||
|
}
|
||||||
12
Kha/Sources/kha/compute/ShaderStorageBuffer.hx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package kha.compute;
|
||||||
|
|
||||||
|
import kha.graphics4.VertexData;
|
||||||
|
|
||||||
|
extern class ShaderStorageBuffer {
|
||||||
|
public function new(indexCount: Int, type: VertexData);
|
||||||
|
public function delete(): Void;
|
||||||
|
public function lock(): Array<Int>;
|
||||||
|
public function unlock(): Void;
|
||||||
|
public function set(): Void;
|
||||||
|
public function count(): Int;
|
||||||
|
}
|
||||||
3
Kha/Sources/kha/compute/TextureUnit.hx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package kha.compute;
|
||||||
|
|
||||||
|
interface TextureUnit {}
|
||||||
@ -8,4 +8,5 @@ enum abstract TextureFormat(Int) to Int {
|
|||||||
var RGBA64 = 4; // Half floats
|
var RGBA64 = 4; // Half floats
|
||||||
var A32 = 5; // Float
|
var A32 = 5; // Float
|
||||||
var A16 = 6; // Half float
|
var A16 = 6; // Half float
|
||||||
|
var R32UI = 7; // Unsigned 32-bit integer
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
Krom/Krom.exe
@ -7,7 +7,7 @@ bl_info = {
|
|||||||
"description": "Full Stack SDK",
|
"description": "Full Stack SDK",
|
||||||
"author": "Leenkx.com",
|
"author": "Leenkx.com",
|
||||||
"version": (2026, 5, 0),
|
"version": (2026, 5, 0),
|
||||||
"blender": (4, 5, 0),
|
"blender": (5, 2, 0),
|
||||||
"doc_url": "https://leenkx.com/",
|
"doc_url": "https://leenkx.com/",
|
||||||
"tracker_url": "https://leenkx.com/support"
|
"tracker_url": "https://leenkx.com/support"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
uniform sampler2D tex;
|
uniform sampler2D tex;
|
||||||
uniform sampler2D gbuffer0; // Roughness
|
uniform sampler2D gbuffer0; // Roughness
|
||||||
|
uniform sampler2D gbufferD; // Depth
|
||||||
|
|
||||||
uniform vec2 dirInv;
|
uniform vec2 dirInv;
|
||||||
|
|
||||||
@ -14,19 +15,46 @@ out vec4 fragColor;
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
float roughness = textureLod(gbuffer0, texCoord, 0.0).b;
|
float roughness = textureLod(gbuffer0, texCoord, 0.0).b;
|
||||||
// if (roughness == 0.0) { // Always blur for now, non blured output can produce noise
|
if (roughness >= 0.8) {
|
||||||
// fragColor.rgb = textureLod(tex, texCoord).rgb;
|
fragColor.rgb = textureLod(tex, texCoord, 0.0).rgb;
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
if (roughness >= 0.8) { // No reflections
|
if (roughness < 0.01) {
|
||||||
fragColor.rgb = textureLod(tex, texCoord, 0.0).rgb;
|
fragColor.rgb = textureLod(tex, texCoord, 0.0).rgb;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fragColor.rgb = textureLod(tex, texCoord + dirInv * 2.5, 0.0).rgb;
|
float blurRadius = 1.0 + roughness * 4.0;
|
||||||
fragColor.rgb += textureLod(tex, texCoord + dirInv * 1.5, 0.0).rgb;
|
vec3 center = textureLod(tex, texCoord, 0.0).rgb;
|
||||||
fragColor.rgb += textureLod(tex, texCoord, 0.0).rgb;
|
|
||||||
fragColor.rgb += textureLod(tex, texCoord - dirInv * 1.5, 0.0).rgb;
|
float centerDepth = textureLod(gbufferD, texCoord, 0.0).r;
|
||||||
fragColor.rgb += textureLod(tex, texCoord - dirInv * 2.5, 0.0).rgb;
|
|
||||||
fragColor.rgb /= vec3(5.0);
|
float w0 = 1.0 / (1.0 + roughness * 2.0);
|
||||||
|
float w1 = 1.0 / (1.0 + roughness);
|
||||||
|
float w2 = 1.0 / (1.0 + roughness * 0.5);
|
||||||
|
float totalW = w0;
|
||||||
|
|
||||||
|
fragColor.rgb = center * w0;
|
||||||
|
|
||||||
|
vec2 offsets[4];
|
||||||
|
offsets[0] = dirInv * blurRadius * 2.5;
|
||||||
|
offsets[1] = dirInv * blurRadius * 1.5;
|
||||||
|
offsets[2] = -dirInv * blurRadius * 1.5;
|
||||||
|
offsets[3] = -dirInv * blurRadius * 2.5;
|
||||||
|
float weights[4];
|
||||||
|
weights[0] = w2;
|
||||||
|
weights[1] = w1;
|
||||||
|
weights[2] = w1;
|
||||||
|
weights[3] = w2;
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
vec2 sampleTC = texCoord + offsets[i];
|
||||||
|
float sampleDepth = textureLod(gbufferD, sampleTC, 0.0).r;
|
||||||
|
float depthWeight = exp(-abs(centerDepth - sampleDepth) * 100.0);
|
||||||
|
float w = weights[i] * depthWeight;
|
||||||
|
fragColor.rgb += textureLod(tex, sampleTC, 0.0).rgb * w;
|
||||||
|
totalW += w;
|
||||||
|
}
|
||||||
|
|
||||||
|
fragColor.rgb /= vec3(totalW);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,10 +17,12 @@ in vec3 wnormal;
|
|||||||
+-------------------+-----------------++--------------+--------------+-----------------+--------------------+
|
+-------------------+-----------------++--------------+--------------+-----------------+--------------------+
|
||||||
| GBUF_IDX_1 | || base color (RGB) | occlusion/specular |
|
| GBUF_IDX_1 | || base color (RGB) | occlusion/specular |
|
||||||
+-------------------+-----------------++--------------+--------------+-----------------+--------------------+
|
+-------------------+-----------------++--------------+--------------+-----------------+--------------------+
|
||||||
| GBUF_IDX_2 | _gbuffer2 || velocity (XY) | ignore radiance | unused |
|
| GBUF_IDX_2 | _gbuffer2 || velocity (XY) | ignore radiance | tangent angle |
|
||||||
+-------------------+-----------------++--------------+--------------+-----------------+--------------------+
|
+-------------------+-----------------++--------------+--------------+-----------------+--------------------+
|
||||||
| GBUF_IDX_EMISSION | _EmissionShaded || emission color (RGB) | unused |
|
| GBUF_IDX_EMISSION | _EmissionShaded || emission color (RGB) | unused |
|
||||||
+-------------------+-----------------++--------------+--------------+-----------------+--------------------+
|
+-------------------+-----------------++--------------+--------------+-----------------+--------------------+
|
||||||
|
| GBUF_IDX_REFRACTION | _SSRefraction || packed IOR | transmittance | surfaceDepth | unused |
|
||||||
|
| | _VoxelRefract || (0-1 range) | | | |
|
||||||
|
|
||||||
The indices as well as the GBUF_SIZE define are defined in "compiled.inc".
|
The indices as well as the GBUF_SIZE define are defined in "compiled.inc".
|
||||||
*/
|
*/
|
||||||
@ -52,6 +54,10 @@ void main() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _SSRefraction
|
#ifdef _SSRefraction
|
||||||
fragColor[GBUF_IDX_REFRACTION] = vec4(ior, opacity, 0.0, 0.0);
|
fragColor[GBUF_IDX_REFRACTION] = vec4(packIOR(ior), opacity, 0.0, 1.0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _Anisotropy
|
||||||
|
fragColor[GBUF_IDX_2].a = -1.0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,11 @@ out vec4 fragColor[GBUF_SIZE];
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
fragColor[GBUF_IDX_0] = vec4(1.0, 1.0, 0.0, 1.0);
|
fragColor[GBUF_IDX_0] = vec4(1.0, 1.0, 0.0, 1.0);
|
||||||
|
#if GBUF_SIZE > 1
|
||||||
fragColor[GBUF_IDX_1] = vec4(color, 1.0);
|
fragColor[GBUF_IDX_1] = vec4(color, 1.0);
|
||||||
|
#else
|
||||||
|
fragColor[GBUF_IDX_0] = vec4(color, 1.0);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _EmissionShaded
|
#ifdef _EmissionShaded
|
||||||
fragColor[GBUF_IDX_EMISSION] = vec4(0.0);
|
fragColor[GBUF_IDX_EMISSION] = vec4(0.0);
|
||||||
|
|||||||
@ -8,12 +8,10 @@
|
|||||||
#ifdef _Irr
|
#ifdef _Irr
|
||||||
#include "std/shirr.glsl"
|
#include "std/shirr.glsl"
|
||||||
#endif
|
#endif
|
||||||
#ifdef _SSS
|
|
||||||
#include "std/sss.glsl"
|
|
||||||
#endif
|
|
||||||
#ifdef _SSRS
|
#ifdef _SSRS
|
||||||
#include "std/ssrs.glsl"
|
#include "std/ssrs.glsl"
|
||||||
#endif
|
#endif
|
||||||
|
#include "std/brdf.glsl"
|
||||||
|
|
||||||
uniform sampler2D gbufferD;
|
uniform sampler2D gbufferD;
|
||||||
uniform sampler2D gbuffer0;
|
uniform sampler2D gbuffer0;
|
||||||
@ -25,6 +23,9 @@ uniform sampler2D gbuffer1;
|
|||||||
#ifdef _EmissionShaded
|
#ifdef _EmissionShaded
|
||||||
uniform sampler2D gbufferEmission;
|
uniform sampler2D gbufferEmission;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
uniform sampler2D gbufferCoatNormal;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _VoxelGI
|
#ifdef _VoxelGI
|
||||||
uniform sampler2D voxels_diffuse;
|
uniform sampler2D voxels_diffuse;
|
||||||
@ -91,7 +92,7 @@ uniform mat4 invVP;
|
|||||||
#ifdef _SinglePoint
|
#ifdef _SinglePoint
|
||||||
//!uniform sampler2DShadow shadowMapSpot[1];
|
//!uniform sampler2DShadow shadowMapSpot[1];
|
||||||
//!uniform sampler2D shadowMapSpotTransparent[1];
|
//!uniform sampler2D shadowMapSpotTransparent[1];
|
||||||
//!uniform mat4 LWVPSpot[1];
|
//!uniform mat4 LWVPSpotArray[1];
|
||||||
#endif
|
#endif
|
||||||
#ifdef _Clusters
|
#ifdef _Clusters
|
||||||
//!uniform sampler2DShadow shadowMapSpot[4];
|
//!uniform sampler2DShadow shadowMapSpot[4];
|
||||||
@ -136,7 +137,7 @@ uniform vec2 cameraPlane;
|
|||||||
#ifdef _ShadowMapTransparent
|
#ifdef _ShadowMapTransparent
|
||||||
//!uniform sampler2D shadowMapSpotTransparent[1];
|
//!uniform sampler2D shadowMapSpotTransparent[1];
|
||||||
#endif
|
#endif
|
||||||
//!uniform mat4 LWVPSpot[1];
|
//!uniform mat4 LWVPSpotArray[1];
|
||||||
#else
|
#else
|
||||||
//!uniform samplerCubeShadow shadowMapPoint[1];
|
//!uniform samplerCubeShadow shadowMapPoint[1];
|
||||||
#ifdef _ShadowMapTransparent
|
#ifdef _ShadowMapTransparent
|
||||||
@ -199,6 +200,7 @@ uniform vec3 sunCol;
|
|||||||
uniform sampler2D shadowMapAtlasSunTransparent;
|
uniform sampler2D shadowMapAtlasSunTransparent;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
//!uniform vec4 tileBoundsSunArray[maxLights * shadowmapCascades];
|
||||||
#else
|
#else
|
||||||
uniform sampler2DShadow shadowMap;
|
uniform sampler2DShadow shadowMap;
|
||||||
#ifdef _ShadowMapTransparent
|
#ifdef _ShadowMapTransparent
|
||||||
@ -235,6 +237,9 @@ uniform float time;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "std/light.glsl"
|
#include "std/light.glsl"
|
||||||
|
#ifdef _SSS
|
||||||
|
#include "std/sss.glsl"
|
||||||
|
#endif
|
||||||
|
|
||||||
in vec2 texCoord;
|
in vec2 texCoord;
|
||||||
in vec3 viewRay;
|
in vec3 viewRay;
|
||||||
@ -254,12 +259,40 @@ void main() {
|
|||||||
float metallic;
|
float metallic;
|
||||||
uint matid;
|
uint matid;
|
||||||
unpackFloatInt16(g0.a, metallic, matid);
|
unpackFloatInt16(g0.a, metallic, matid);
|
||||||
|
#ifdef _ExtBRDF
|
||||||
|
matid = min(matid, uint(MAX_MATERIALS - 1));
|
||||||
|
|
||||||
|
//!uniform vec4 materialParams[MAX_MATERIALS * 8];
|
||||||
|
vec4 matp0 = vec4(0.0), matp1 = vec4(0.0), matp2 = vec4(0.0), matp3 = vec4(0.0);
|
||||||
|
vec4 matp4 = vec4(0.0), matp5 = vec4(0.0), matp6 = vec4(0.0), matp7 = vec4(0.0);
|
||||||
|
// TODO: coatIOR=1.5, ior=1.45, thinWall=1.0 move to python make files
|
||||||
|
matp1.z = 1.5;
|
||||||
|
matp3.x = 1.45;
|
||||||
|
matp3.y = 1.0;
|
||||||
|
if (matid >= 3u) {
|
||||||
|
getMaterialParams(matid, matp0, matp1, matp2, matp3, matp4, matp5, matp6, matp7);
|
||||||
|
}
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
vec3 coatTintCol = vec3(matp1.w, matp2.x, matp2.y);
|
||||||
|
#endif
|
||||||
|
#ifdef _Sheen
|
||||||
|
vec3 sheenTintCol = vec3(matp5.z, matp5.w, matp6.x);
|
||||||
|
#endif
|
||||||
|
#ifdef _SSS
|
||||||
|
vec3 sssColorVal = vec3(matp4.w, matp5.x, matp5.y);
|
||||||
|
vec3 sssRadiusBase = vec3(matp4.x, matp4.y, matp4.z);
|
||||||
|
float sssRadiusScalar = max(max(matp4.x, matp4.y), matp4.z) * matp7.x;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
vec2 occspec = unpackFloat2(g1.a);
|
vec2 occspec = unpackFloat2(g1.a);
|
||||||
// re-investigate clamp basecolor to prevent extreme values causing glitches
|
// re-investigate clamp basecolor to prevent extreme values causing glitches
|
||||||
vec3 basecolor = min(g1.rgb, vec3(2.0));
|
vec3 basecolor = min(g1.rgb, vec3(2.0));
|
||||||
vec3 albedo = surfaceAlbedo(basecolor, metallic);
|
vec3 albedo = surfaceAlbedo(basecolor, metallic);
|
||||||
vec3 f0 = surfaceF0(basecolor, metallic);
|
vec3 f0 = surfaceF0(basecolor, metallic);
|
||||||
|
#ifdef _ExtBRDF
|
||||||
|
f0 = mix(f0, basecolor, vec3(matp6.y, matp6.z, matp6.w));
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _VRStereo
|
#ifdef _VRStereo
|
||||||
bool isLeftEye = texCoord.x < 0.5;
|
bool isLeftEye = texCoord.x < 0.5;
|
||||||
@ -279,10 +312,26 @@ void main() {
|
|||||||
#endif
|
#endif
|
||||||
float dotNV = max(dot(n, v), 0.0);
|
float dotNV = max(dot(n, v), 0.0);
|
||||||
|
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
vec4 gCoat = textureLod(gbufferCoatNormal, texCoord, 0.0);
|
||||||
|
vec3 nCoat;
|
||||||
|
nCoat.z = 1.0 - abs(gCoat.x) - abs(gCoat.y);
|
||||||
|
nCoat.xy = nCoat.z >= 0.0 ? gCoat.xy : octahedronWrap(gCoat.xy);
|
||||||
|
nCoat = normalize(nCoat);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _gbuffer2
|
#ifdef _gbuffer2
|
||||||
vec4 g2 = textureLod(gbuffer2, texCoord, 0.0);
|
vec4 g2 = textureLod(gbuffer2, texCoord, 0.0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _Anisotropy
|
||||||
|
#ifdef _gbuffer2
|
||||||
|
vec3 wTangent = decodeTangent(g2.a, n);
|
||||||
|
#else
|
||||||
|
vec3 wTangent = vec3(0.0);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef _MicroShadowing
|
#ifdef _MicroShadowing
|
||||||
occspec.x = mix(1.0, occspec.x, dotNV); // AO Fresnel
|
occspec.x = mix(1.0, occspec.x, dotNV); // AO Fresnel
|
||||||
@ -295,6 +344,44 @@ void main() {
|
|||||||
vec3 F = f0;
|
vec3 F = f0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _ExtBRDF
|
||||||
|
float iblSheenWeight = 1.0;
|
||||||
|
float iblCoatWeight = 1.0;
|
||||||
|
float iblLayerWeight = 1.0;
|
||||||
|
vec3 coatTintAbsorb = vec3(1.0);
|
||||||
|
|
||||||
|
#ifdef _Sheen
|
||||||
|
float sheenAlb = sheenIBLAlbedo(matp0.z, matp0.w, dotNV);
|
||||||
|
iblSheenWeight = max(1.0 - sheenAlb *
|
||||||
|
max(max(sheenTintCol.r, sheenTintCol.g), sheenTintCol.b), 0.0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
float dotNVCoat = max(dot(nCoat, v), 0.0);
|
||||||
|
float coatF = coatIBLFresnel(matp1.x, matp1.z, dotNVCoat);
|
||||||
|
iblCoatWeight = max(1.0 - coatF, 0.0);
|
||||||
|
coatTintAbsorb = mix(vec3(1.0), clamp(coatTintCol, 0.0, 1.0),
|
||||||
|
clamp(1.0 / max(dotNVCoat, 0.3) * 0.2, 0.0, 1.0));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
iblLayerWeight = iblSheenWeight * iblCoatWeight;
|
||||||
|
|
||||||
|
brdf_sheenWeight = iblSheenWeight;
|
||||||
|
brdf_coatWeight = iblCoatWeight;
|
||||||
|
brdf_coatTintAbsorb = coatTintAbsorb;
|
||||||
|
#ifdef _Sheen
|
||||||
|
brdf_sheenAlbedo = sheenAlb;
|
||||||
|
#endif
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
brdf_coatF0 = (matp1.z - 1.0) / (matp1.z + 1.0);
|
||||||
|
brdf_coatF0 = brdf_coatF0 * brdf_coatF0;
|
||||||
|
#endif
|
||||||
|
#ifdef _Transmission
|
||||||
|
brdf_transmissionF0 = (matp3.x - 1.0) / (matp3.x + 1.0);
|
||||||
|
brdf_transmissionF0 = brdf_transmissionF0 * brdf_transmissionF0;
|
||||||
|
#endif
|
||||||
|
#endif // _ExtBRDF
|
||||||
|
|
||||||
#ifndef _VoxelAOvar
|
#ifndef _VoxelAOvar
|
||||||
#ifndef _VoxelGI
|
#ifndef _VoxelGI
|
||||||
// Envmap
|
// Envmap
|
||||||
@ -302,9 +389,7 @@ void main() {
|
|||||||
vec3 envl = shIrradiance(n, shirr);
|
vec3 envl = shIrradiance(n, shirr);
|
||||||
|
|
||||||
#ifdef _gbuffer2
|
#ifdef _gbuffer2
|
||||||
if (g2.b < 0.5) {
|
if (g2.b >= 0.5) {
|
||||||
envl = envl;
|
|
||||||
} else {
|
|
||||||
envl = vec3(0.0);
|
envl = vec3(0.0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -317,16 +402,21 @@ void main() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _Rad
|
#ifdef _Rad
|
||||||
|
#ifdef _Anisotropy
|
||||||
|
vec3 reflectionWorld = anisotropicIBLDirection(n, v, wTangent,
|
||||||
|
matp0.x, roughness);
|
||||||
|
#else
|
||||||
vec3 reflectionWorld = reflect(-v, n);
|
vec3 reflectionWorld = reflect(-v, n);
|
||||||
|
#endif
|
||||||
float lod = getMipFromRoughness(roughness, envmapNumMipmaps);
|
float lod = getMipFromRoughness(roughness, envmapNumMipmaps);
|
||||||
vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb;
|
vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb;
|
||||||
prefilteredColor = min(prefilteredColor, vec3(20.0));
|
prefilteredColor = min(prefilteredColor, vec3(20.0));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _EnvLDR
|
#ifdef _EnvLDR
|
||||||
envl.rgb = pow(envl.rgb, vec3(2.2));
|
envl.rgb = srgbToLinear(envl.rgb);
|
||||||
#ifdef _Rad
|
#ifdef _Rad
|
||||||
prefilteredColor = pow(prefilteredColor, vec3(2.2));
|
prefilteredColor = srgbToLinear(prefilteredColor);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -344,6 +434,68 @@ void main() {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _ExtBRDF
|
||||||
|
envl.rgb *= iblLayerWeight;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _Transmission
|
||||||
|
float transF = transmissionIBLFresnel(matp3.x, dotNV);
|
||||||
|
float transmittance = 1.0 - transF;
|
||||||
|
#ifdef _Rad
|
||||||
|
if (matp2.z > 0.0 && transmittance > 0.0) {
|
||||||
|
vec3 refrDir;
|
||||||
|
if (matp3.y > 0.5) {
|
||||||
|
refrDir = reflect(-v, n);
|
||||||
|
} else {
|
||||||
|
refrDir = transmissionIBLDirection(n, v, matp3.x);
|
||||||
|
}
|
||||||
|
float transLod = getMipFromRoughness(matp2.w, envmapNumMipmaps);
|
||||||
|
vec3 transColor = textureLod(senvmapRadiance,
|
||||||
|
envMapEquirect(refrDir), transLod).rgb;
|
||||||
|
transColor = min(transColor, vec3(20.0));
|
||||||
|
#ifdef _EnvLDR
|
||||||
|
transColor = srgbToLinear(transColor);
|
||||||
|
#endif
|
||||||
|
envl.rgb += albedo * matp2.z * transmittance * transColor * dotNV
|
||||||
|
* iblLayerWeight;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
envl.rgb *= coatTintAbsorb;
|
||||||
|
#ifdef _Rad
|
||||||
|
if (coatF > 0.0) {
|
||||||
|
float coatLod = getMipFromRoughness(matp1.y, envmapNumMipmaps);
|
||||||
|
vec3 coatRefl = reflect(-v, nCoat);
|
||||||
|
vec3 coatColor = textureLod(senvmapRadiance,
|
||||||
|
envMapEquirect(coatRefl), coatLod).rgb;
|
||||||
|
coatColor = min(coatColor, vec3(20.0));
|
||||||
|
#ifdef _EnvLDR
|
||||||
|
coatColor = srgbToLinear(coatColor);
|
||||||
|
#endif
|
||||||
|
envl.rgb += coatColor * coatF * iblSheenWeight;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _Sheen
|
||||||
|
#ifdef _Rad
|
||||||
|
if (sheenAlb > 0.0) {
|
||||||
|
float sheenLod = getMipFromRoughness(matp0.w, envmapNumMipmaps);
|
||||||
|
vec3 sheenRefl = reflect(-v, n);
|
||||||
|
vec3 sheenColor = textureLod(senvmapRadiance,
|
||||||
|
envMapEquirect(sheenRefl), sheenLod).rgb;
|
||||||
|
sheenColor = min(sheenColor, vec3(20.0));
|
||||||
|
#ifdef _EnvLDR
|
||||||
|
sheenColor = srgbToLinear(sheenColor);
|
||||||
|
#endif
|
||||||
|
envl.rgb += sheenColor * sheenTintCol * sheenAlb;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif // _ExtBRDF
|
||||||
|
|
||||||
envl.rgb *= envmapStrength * occspec.x;
|
envl.rgb *= envmapStrength * occspec.x;
|
||||||
|
|
||||||
fragColor.rgb = envl;
|
fragColor.rgb = envl;
|
||||||
@ -352,11 +504,30 @@ void main() {
|
|||||||
|
|
||||||
#ifdef _VoxelGI
|
#ifdef _VoxelGI
|
||||||
fragColor.rgb = textureLod(voxels_diffuse, texCoord, 0.0).rgb * voxelgiDiff;
|
fragColor.rgb = textureLod(voxels_diffuse, texCoord, 0.0).rgb * voxelgiDiff;
|
||||||
if(roughness < 1.0 && occspec.y > 0.0)
|
if(roughness < 1.0) {
|
||||||
fragColor.rgb += textureLod(voxels_specular, texCoord, 0.0).rgb * occspec.y * voxelgiRefl;
|
fragColor.rgb += textureLod(voxels_specular, texCoord, 0.0).rgb * F * voxelgiRefl * occspec.y;
|
||||||
|
}
|
||||||
|
#ifdef _Rad
|
||||||
|
vec3 iblReflection = reflect(-v, n);
|
||||||
|
float iblLod = getMipFromRoughness(roughness, envmapNumMipmaps);
|
||||||
|
vec3 iblPrefiltered = textureLod(senvmapRadiance, envMapEquirect(iblReflection), iblLod).rgb;
|
||||||
|
iblPrefiltered = min(iblPrefiltered, vec3(20.0));
|
||||||
|
#ifdef _EnvLDR
|
||||||
|
iblPrefiltered = srgbToLinear(iblPrefiltered);
|
||||||
|
#endif
|
||||||
|
#ifdef _ExtBRDF
|
||||||
|
iblPrefiltered *= iblLayerWeight;
|
||||||
|
iblPrefiltered *= coatTintAbsorb;
|
||||||
|
#endif
|
||||||
|
fragColor.rgb += iblPrefiltered * F * envmapStrength * occspec.x;
|
||||||
|
#else
|
||||||
|
#ifdef _EnvCol
|
||||||
|
fragColor.rgb += backgroundCol * F * envmapStrength * occspec.x;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
#ifdef _VoxelAOvar
|
#ifdef _VoxelAOvar
|
||||||
fragColor.rgb = textureLod(voxels_ao, texCoord, 0.0).rgb * voxelgiOcc;
|
fragColor.rgb = textureLod(voxels_ao, texCoord, 0.0).rgb;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -379,7 +550,7 @@ void main() {
|
|||||||
|
|
||||||
#ifdef _SSGI
|
#ifdef _SSGI
|
||||||
vec3 ssgiColor = textureLod(ssgitex, texCoord, 0.0).rgb;
|
vec3 ssgiColor = textureLod(ssgitex, texCoord, 0.0).rgb;
|
||||||
fragColor.rgb += ssgiColor * albedo;
|
fragColor.rgb += ssgiColor * basecolor;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _EmissionShadeless
|
#ifdef _EmissionShadeless
|
||||||
@ -406,10 +577,42 @@ void main() {
|
|||||||
float sdotVH = max(0.0, dot(v, sh));
|
float sdotVH = max(0.0, dot(v, sh));
|
||||||
float sdotNL = max(0.0, dot(n, sunDir));
|
float sdotNL = max(0.0, dot(n, sunDir));
|
||||||
vec3 svisibility = vec3(1.0);
|
vec3 svisibility = vec3(1.0);
|
||||||
|
#ifdef _Anisotropy
|
||||||
|
vec3 sdirect;
|
||||||
|
if (abs(matp0.x) > 0.001 && dot(wTangent, wTangent) > 0.001) {
|
||||||
|
vec3 sbitangent = normalize(cross(n, wTangent));
|
||||||
|
sdirect = lambertDiffuseBRDF(albedo, sdotNL) +
|
||||||
|
anisotropicBRDF(f0, roughness, matp0.x, matp0.y,
|
||||||
|
wTangent, sbitangent, n, sunDir, v, sdotNL, dotNV) * occspec.y;
|
||||||
|
} else {
|
||||||
|
sdirect = lambertDiffuseBRDF(albedo, sdotNL) +
|
||||||
|
specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * occspec.y;
|
||||||
|
}
|
||||||
|
#else
|
||||||
vec3 sdirect = lambertDiffuseBRDF(albedo, sdotNL) +
|
vec3 sdirect = lambertDiffuseBRDF(albedo, sdotNL) +
|
||||||
specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * occspec.y;
|
specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * occspec.y;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _ExtBRDF
|
||||||
|
float sunLayerWeight;
|
||||||
|
sdirect = applyExtBRDFLayers(sdirect, albedo, f0, roughness,
|
||||||
|
sdotNL, dotNV, sdotNH, sdotVH, n, sunDir, v, sh
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
, matp1.x, matp1.y, matp1.z, coatTintCol, nCoat
|
||||||
|
#endif
|
||||||
|
#ifdef _Sheen
|
||||||
|
, matp0.z, matp0.w, sheenTintCol
|
||||||
|
#endif
|
||||||
|
#ifdef _Transmission
|
||||||
|
, matp2.z, matp2.w, matp3.x, matp3.y
|
||||||
|
#endif
|
||||||
|
, sunLayerWeight);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _ShadowMap
|
#ifdef _ShadowMap
|
||||||
|
#ifdef _ShadowMapAtlas
|
||||||
|
tileBounds = tileBoundsSunArray[0];
|
||||||
|
#endif
|
||||||
#ifdef _CSM
|
#ifdef _CSM
|
||||||
svisibility = shadowTestCascade(
|
svisibility = shadowTestCascade(
|
||||||
#ifdef _ShadowMapAtlas
|
#ifdef _ShadowMapAtlas
|
||||||
@ -494,23 +697,17 @@ void main() {
|
|||||||
|
|
||||||
fragColor.rgb += sdirect * sunCol * svisibility;
|
fragColor.rgb += sdirect * sunCol * svisibility;
|
||||||
|
|
||||||
// #ifdef _Hair // Aniso
|
|
||||||
// if (matid == 2) {
|
|
||||||
// const float shinyParallel = roughness;
|
|
||||||
// const float shinyPerpendicular = 0.1;
|
|
||||||
// const vec3 v = vec3(0.99146, 0.11664, 0.05832);
|
|
||||||
// vec3 T = abs(dot(n, v)) > 0.99999 ? cross(n, vec3(0.0, 1.0, 0.0)) : cross(n, v);
|
|
||||||
// fragColor.rgb = orenNayarDiffuseBRDF(albedo, roughness, dotNV, dotNL, dotVH) + wardSpecular(n, h, dotNL, dotNV, dotNH, T, shinyParallel, shinyPerpendicular) * spec;
|
|
||||||
// }
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
#ifdef _SSS
|
#ifdef _SSS
|
||||||
if (matid == 2) {
|
#ifdef _ExtBRDF
|
||||||
|
if (matid >= 3u && matp3.z > 0.0) {
|
||||||
#ifdef _CSM
|
#ifdef _CSM
|
||||||
int casi, casindex;
|
int casi, casindex;
|
||||||
mat4 LWVP = getCascadeMat(distance(eye, p), casi, casindex);
|
mat4 LWVP = getCascadeMat(distance(eye, p), casi, casindex);
|
||||||
#endif
|
#endif
|
||||||
fragColor.rgb += fragColor.rgb * SSSSTransmittance(
|
vec3 sssColor = sssColorVal;
|
||||||
|
float sssRadius = sssRadiusScalar;
|
||||||
|
float sssStrength = matp3.z;
|
||||||
|
vec3 sssResult = SSSSTransmittance(
|
||||||
LWVP, p, n, sunDir, lightPlane.y,
|
LWVP, p, n, sunDir, lightPlane.y,
|
||||||
#ifdef _ShadowMapAtlas
|
#ifdef _ShadowMapAtlas
|
||||||
#ifndef _SingleAtlas
|
#ifndef _SingleAtlas
|
||||||
@ -521,12 +718,26 @@ void main() {
|
|||||||
#else
|
#else
|
||||||
shadowMap
|
shadowMap
|
||||||
#endif
|
#endif
|
||||||
);//TODO implement transparent shadowmaps into the SSSSTransmittance()
|
, sssColor, sssRadius
|
||||||
|
#ifdef _ShadowMapAtlas
|
||||||
|
#ifdef _CSM
|
||||||
|
, tileBoundsSunArray[casi]
|
||||||
|
#else
|
||||||
|
, tileBoundsSunArray[0]
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
fragColor.rgb += sunCol * sssStrength * sssResult;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // _Sun
|
#endif // _Sun
|
||||||
|
|
||||||
|
#ifdef _ShadowMapAtlas
|
||||||
|
tileBounds = vec4(0.0, 0.0, 1.0, 1.0);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _SinglePoint
|
#ifdef _SinglePoint
|
||||||
|
|
||||||
#ifdef _VRStereo
|
#ifdef _VRStereo
|
||||||
@ -555,12 +766,53 @@ void main() {
|
|||||||
#ifdef _SSRS
|
#ifdef _SSRS
|
||||||
, gbufferD, invVP, eye
|
, gbufferD, invVP, eye
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
, matp1.x, matp1.y, matp1.z, coatTintCol, nCoat
|
||||||
|
#endif
|
||||||
|
#ifdef _Sheen
|
||||||
|
, matp0.z, matp0.w, sheenTintCol
|
||||||
|
#endif
|
||||||
|
#ifdef _Anisotropy
|
||||||
|
, matp0.x, matp0.y, wTangent
|
||||||
|
#endif
|
||||||
|
#ifdef _SSS
|
||||||
|
, matp3.z, sssColorVal, sssRadiusBase * matp7.x, matp3.w
|
||||||
|
#endif
|
||||||
|
#ifdef _Transmission
|
||||||
|
, matp2.z, matp2.w, matp3.x, matp3.y
|
||||||
|
#endif
|
||||||
);
|
);
|
||||||
|
|
||||||
#ifdef _Spot
|
#ifdef _Spot
|
||||||
#ifdef _SSS
|
#ifdef _SSS
|
||||||
#ifdef _ShadowMap
|
#ifdef _ShadowMap
|
||||||
if (matid == 2) fragColor.rgb += fragColor.rgb * SSSSTransmittance(LWVPSpot[0], p, n, normalize(lightPos - p), lightPlane.y, shadowMapSpot[0]);//TODO implement transparent shadowmaps into the SSSSTransmittance()
|
#ifdef _ExtBRDF
|
||||||
|
if (matid >= 3u && matp3.z > 0.0) {
|
||||||
|
vec3 sssColorSpot = sssColorVal;
|
||||||
|
float sssRadiusSpot = sssRadiusScalar;
|
||||||
|
float sssStrengthSpot = matp3.z;
|
||||||
|
fragColor.rgb += pointCol * sssStrengthSpot * SSSSTransmittance(LWVPSpotArray[0], p, n, normalize(lightPos - p), lightPlane.y, shadowMapSpot[0], sssColorSpot, sssRadiusSpot
|
||||||
|
#ifdef _ShadowMapAtlas
|
||||||
|
, vec4(0.0, 0.0, 1.0, 1.0)
|
||||||
|
#endif
|
||||||
|
);//TODO implement transparent shadowmaps into the SSSSTransmittance()
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _Spot
|
||||||
|
#ifdef _SSS
|
||||||
|
#ifdef _ShadowMap
|
||||||
|
#ifdef _ExtBRDF
|
||||||
|
if (matid >= 3u && matp3.z > 0.0) {
|
||||||
|
vec3 sssColorPoint = sssColorVal;
|
||||||
|
float sssRadiusPoint = sssRadiusScalar;
|
||||||
|
float sssStrengthPoint = matp3.z;
|
||||||
|
fragColor.rgb += pointCol * sssStrengthPoint * SSSSTransmittanceCube(shadowMapPoint[0], lightPos, p, n, normalize(lightPos - p), lightPlane.y, lightProj, sssColorPoint, sssRadiusPoint);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
@ -618,7 +870,96 @@ void main() {
|
|||||||
#ifdef _SSRS
|
#ifdef _SSRS
|
||||||
, gbufferD, invVP, eye
|
, gbufferD, invVP, eye
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
, matp1.x, matp1.y, matp1.z, coatTintCol, nCoat
|
||||||
|
#endif
|
||||||
|
#ifdef _Sheen
|
||||||
|
, matp0.z, matp0.w, sheenTintCol
|
||||||
|
#endif
|
||||||
|
#ifdef _Anisotropy
|
||||||
|
, matp0.x, matp0.y, wTangent
|
||||||
|
#endif
|
||||||
|
#ifdef _SSS
|
||||||
|
, matp3.z, sssColorVal, sssRadiusBase * matp7.x, matp3.w
|
||||||
|
#endif
|
||||||
|
#ifdef _Transmission
|
||||||
|
, matp2.z, matp2.w, matp3.x, matp3.y
|
||||||
|
#endif
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#ifdef _SSS
|
||||||
|
#ifdef _ShadowMap
|
||||||
|
#ifdef _ExtBRDF
|
||||||
|
if (matid >= 3u && matp3.z > 0.0) {
|
||||||
|
vec3 sssColorCL = sssColorVal;
|
||||||
|
float sssRadiusCL = sssRadiusScalar;
|
||||||
|
float sssStrengthCL = matp3.z;
|
||||||
|
vec3 cLightPos = lightsArray[li * 3].xyz;
|
||||||
|
vec3 cLightCol = lightsArray[li * 3 + 1].xyz;
|
||||||
|
vec3 cLightDir = normalize(cLightPos - p);
|
||||||
|
#ifdef _Spot
|
||||||
|
bool isSpotLight = lightsArray[li * 3 + 2].y != 0.0;
|
||||||
|
if (isSpotLight) {
|
||||||
|
#ifdef _ShadowMapAtlas
|
||||||
|
#ifndef _SingleAtlas
|
||||||
|
fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittance(LWVPSpotArray[li], p, n, cLightDir, lightPlane.y, shadowMapAtlasSpot, sssColorCL, sssRadiusCL, tileBoundsSpotArray[li]);
|
||||||
|
#else
|
||||||
|
fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittance(LWVPSpotArray[li], p, n, cLightDir, lightPlane.y, shadowMapAtlas, sssColorCL, sssRadiusCL, tileBoundsSpotArray[li]);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
if (li == 0) fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittance(LWVPSpotArray[0], p, n, cLightDir, lightPlane.y, shadowMapSpot[0], sssColorCL, sssRadiusCL
|
||||||
|
#ifdef _ShadowMapAtlas
|
||||||
|
, vec4(0.0, 0.0, 1.0, 1.0)
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
else if (li == 1) fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittance(LWVPSpotArray[1], p, n, cLightDir, lightPlane.y, shadowMapSpot[1], sssColorCL, sssRadiusCL
|
||||||
|
#ifdef _ShadowMapAtlas
|
||||||
|
, vec4(0.0, 0.0, 1.0, 1.0)
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
else if (li == 2) fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittance(LWVPSpotArray[2], p, n, cLightDir, lightPlane.y, shadowMapSpot[2], sssColorCL, sssRadiusCL
|
||||||
|
#ifdef _ShadowMapAtlas
|
||||||
|
, vec4(0.0, 0.0, 1.0, 1.0)
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
else if (li == 3) fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittance(LWVPSpotArray[3], p, n, cLightDir, lightPlane.y, shadowMapSpot[3], sssColorCL, sssRadiusCL
|
||||||
|
#ifdef _ShadowMapAtlas
|
||||||
|
, vec4(0.0, 0.0, 1.0, 1.0)
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
#ifdef _ShadowMapAtlas
|
||||||
|
#ifndef _SingleAtlas
|
||||||
|
fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittanceCubeAtlas(shadowMapAtlasPoint, cLightPos, p, n, cLightDir, lightPlane.y, lightProj, li, sssColorCL, sssRadiusCL);
|
||||||
|
#else
|
||||||
|
fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittanceCubeAtlas(shadowMapAtlas, cLightPos, p, n, cLightDir, lightPlane.y, lightProj, li, sssColorCL, sssRadiusCL);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
if (li == 0) fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittanceCube(shadowMapPoint[0], cLightPos, p, n, cLightDir, lightPlane.y, lightProj, sssColorCL, sssRadiusCL);
|
||||||
|
else if (li == 1) fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittanceCube(shadowMapPoint[1], cLightPos, p, n, cLightDir, lightPlane.y, lightProj, sssColorCL, sssRadiusCL);
|
||||||
|
else if (li == 2) fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittanceCube(shadowMapPoint[2], cLightPos, p, n, cLightDir, lightPlane.y, lightProj, sssColorCL, sssRadiusCL);
|
||||||
|
else if (li == 3) fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittanceCube(shadowMapPoint[3], cLightPos, p, n, cLightDir, lightPlane.y, lightProj, sssColorCL, sssRadiusCL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#ifdef _ShadowMapAtlas
|
||||||
|
#ifndef _SingleAtlas
|
||||||
|
fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittanceCubeAtlas(shadowMapAtlasPoint, cLightPos, p, n, cLightDir, lightPlane.y, lightProj, li, sssColorCL, sssRadiusCL);
|
||||||
|
#else
|
||||||
|
fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittanceCubeAtlas(shadowMapAtlas, cLightPos, p, n, cLightDir, lightPlane.y, lightProj, li, sssColorCL, sssRadiusCL);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
if (li == 0) fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittanceCube(shadowMapPoint[0], cLightPos, p, n, cLightDir, lightPlane.y, lightProj, sssColorCL, sssRadiusCL);
|
||||||
|
else if (li == 1) fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittanceCube(shadowMapPoint[1], cLightPos, p, n, cLightDir, lightPlane.y, lightProj, sssColorCL, sssRadiusCL);
|
||||||
|
else if (li == 2) fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittanceCube(shadowMapPoint[2], cLightPos, p, n, cLightDir, lightPlane.y, lightProj, sssColorCL, sssRadiusCL);
|
||||||
|
else if (li == 3) fragColor.rgb += cLightCol * sssStrengthCL * SSSSTransmittanceCube(shadowMapPoint[3], cLightPos, p, n, cLightDir, lightPlane.y, lightProj, sssColorCL, sssRadiusCL);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif // _Clusters
|
#endif // _Clusters
|
||||||
|
|
||||||
|
|||||||
@ -138,6 +138,16 @@
|
|||||||
"link": "_cascadeData",
|
"link": "_cascadeData",
|
||||||
"ifdef": ["_Sun", "_ShadowMap", "_CSM"]
|
"ifdef": ["_Sun", "_ShadowMap", "_CSM"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "tileBoundsSunArray",
|
||||||
|
"link": "_tileBoundsSunArray",
|
||||||
|
"ifdef": ["_Sun", "_ShadowMap", "_ShadowMapAtlas"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "tileBoundsSpotArray",
|
||||||
|
"link": "_tileBoundsSpotArray",
|
||||||
|
"ifdef": ["_Clusters", "_Spot", "_ShadowMap", "_ShadowMapAtlas"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "lightPlane",
|
"name": "lightPlane",
|
||||||
"link": "_lightPlane",
|
"link": "_lightPlane",
|
||||||
@ -277,8 +287,15 @@
|
|||||||
"link": "_biasLightWorldViewProjectionMatrixSpot3",
|
"link": "_biasLightWorldViewProjectionMatrixSpot3",
|
||||||
"ifndef": ["_ShadowMapAtlas"],
|
"ifndef": ["_ShadowMapAtlas"],
|
||||||
"ifdef": ["_LTC", "_ShadowMap"]
|
"ifdef": ["_LTC", "_ShadowMap"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "materialParams",
|
||||||
|
"link": "_materialParams",
|
||||||
|
"type": "floats",
|
||||||
|
"ifdef": ["_ExtBRDF"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"texture_units": [],
|
||||||
"vertex_shader": "../include/pass_viewray.vert.glsl",
|
"vertex_shader": "../include/pass_viewray.vert.glsl",
|
||||||
"fragment_shader": "deferred_light.frag.glsl",
|
"fragment_shader": "deferred_light.frag.glsl",
|
||||||
"color_attachments": ["RGBA64"]
|
"color_attachments": ["RGBA64"]
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#include "compiled.inc"
|
#include "compiled.inc"
|
||||||
#include "std/gbuffer.glsl"
|
#include "std/gbuffer.glsl"
|
||||||
#include "std/math.glsl"
|
#include "std/math.glsl"
|
||||||
|
#include "std/brdf.glsl"
|
||||||
#ifdef _Clusters
|
#ifdef _Clusters
|
||||||
#include "std/clusters.glsl"
|
#include "std/clusters.glsl"
|
||||||
#endif
|
#endif
|
||||||
@ -13,6 +14,12 @@
|
|||||||
uniform sampler2D gbufferD;
|
uniform sampler2D gbufferD;
|
||||||
uniform sampler2D gbuffer0;
|
uniform sampler2D gbuffer0;
|
||||||
uniform sampler2D gbuffer1;
|
uniform sampler2D gbuffer1;
|
||||||
|
#ifdef _gbuffer2
|
||||||
|
uniform sampler2D gbuffer2;
|
||||||
|
#endif
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
uniform sampler2D gbufferCoatNormal;
|
||||||
|
#endif
|
||||||
|
|
||||||
uniform float envmapStrength;
|
uniform float envmapStrength;
|
||||||
#ifdef _Irr
|
#ifdef _Irr
|
||||||
@ -49,7 +56,7 @@ uniform vec2 cameraPlane;
|
|||||||
#ifdef _SinglePoint
|
#ifdef _SinglePoint
|
||||||
#ifdef _Spot
|
#ifdef _Spot
|
||||||
//!uniform sampler2DShadow shadowMapSpot[1];
|
//!uniform sampler2DShadow shadowMapSpot[1];
|
||||||
//!uniform mat4 LWVPSpot[1];
|
//!uniform mat4 LWVPSpotArray[1];
|
||||||
#else
|
#else
|
||||||
//!uniform samplerCubeShadow shadowMapPoint[1];
|
//!uniform samplerCubeShadow shadowMapPoint[1];
|
||||||
//!uniform vec2 lightProj;
|
//!uniform vec2 lightProj;
|
||||||
@ -91,6 +98,7 @@ uniform vec3 sunCol;
|
|||||||
#ifndef _SingleAtlas
|
#ifndef _SingleAtlas
|
||||||
uniform sampler2DShadow shadowMapAtlasSun;
|
uniform sampler2DShadow shadowMapAtlasSun;
|
||||||
#endif
|
#endif
|
||||||
|
//!uniform vec4 tileBoundsSunArray[maxLights * shadowmapCascades];
|
||||||
#else
|
#else
|
||||||
uniform sampler2DShadow shadowMap;
|
uniform sampler2DShadow shadowMap;
|
||||||
#endif
|
#endif
|
||||||
@ -132,17 +140,61 @@ void main() {
|
|||||||
float metallic;
|
float metallic;
|
||||||
uint matid;
|
uint matid;
|
||||||
unpackFloatInt16(g0.a, metallic, matid);
|
unpackFloatInt16(g0.a, metallic, matid);
|
||||||
|
#ifdef _ExtBRDF
|
||||||
|
matid = min(matid, uint(MAX_MATERIALS - 1));
|
||||||
|
|
||||||
|
//!uniform vec4 materialParams[MAX_MATERIALS * 8];
|
||||||
|
vec4 matp0 = vec4(0.0), matp1 = vec4(0.0), matp2 = vec4(0.0), matp3 = vec4(0.0);
|
||||||
|
vec4 matp4 = vec4(0.0), matp5 = vec4(0.0), matp6 = vec4(0.0), matp7 = vec4(0.0);
|
||||||
|
// TODO: coatIOR=1.5, ior=1.45, thinWall=1.0 move to python make files
|
||||||
|
matp1.z = 1.5;
|
||||||
|
matp3.x = 1.45;
|
||||||
|
matp3.y = 1.0;
|
||||||
|
if (matid >= 3u) {
|
||||||
|
getMaterialParams(matid, matp0, matp1, matp2, matp3, matp4, matp5, matp6, matp7);
|
||||||
|
}
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
vec3 coatTintCol = vec3(matp1.w, matp2.x, matp2.y);
|
||||||
|
#endif
|
||||||
|
#ifdef _Sheen
|
||||||
|
vec3 sheenTintCol = vec3(matp5.z, matp5.w, matp6.x);
|
||||||
|
#endif
|
||||||
|
#ifdef _SSS
|
||||||
|
vec3 sssColorVal = vec3(matp4.w, matp5.x, matp5.y);
|
||||||
|
vec3 sssRadiusScaled = vec3(matp4.x, matp4.y, matp4.z) * matp7.x;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
vec4 g1 = textureLod(gbuffer1, texCoord, 0.0); // Basecolor.rgb, spec/occ
|
vec4 g1 = textureLod(gbuffer1, texCoord, 0.0); // Basecolor.rgb, spec/occ
|
||||||
vec2 occspec = unpackFloat2(g1.a);
|
vec2 occspec = unpackFloat2(g1.a);
|
||||||
vec3 albedo = surfaceAlbedo(g1.rgb, metallic); // g1.rgb - basecolor
|
vec3 albedo = surfaceAlbedo(g1.rgb, metallic); // g1.rgb - basecolor
|
||||||
vec3 f0 = surfaceF0(g1.rgb, metallic);
|
vec3 f0 = surfaceF0(g1.rgb, metallic);
|
||||||
|
#ifdef _ExtBRDF
|
||||||
|
f0 = mix(f0, min(g1.rgb, vec3(2.0)), vec3(matp6.y, matp6.z, matp6.w));
|
||||||
|
#endif
|
||||||
|
|
||||||
float depth = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
|
float depth = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
|
||||||
vec3 p = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj);
|
vec3 p = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj);
|
||||||
vec3 v = normalize(eye - p);
|
vec3 v = normalize(eye - p);
|
||||||
float dotNV = max(dot(n, v), 0.0);
|
float dotNV = max(dot(n, v), 0.0);
|
||||||
|
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
vec4 gCoat = textureLod(gbufferCoatNormal, texCoord, 0.0);
|
||||||
|
vec3 nCoat;
|
||||||
|
nCoat.z = 1.0 - abs(gCoat.x) - abs(gCoat.y);
|
||||||
|
nCoat.xy = nCoat.z >= 0.0 ? gCoat.xy : octahedronWrap(gCoat.xy);
|
||||||
|
nCoat = normalize(nCoat);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _Anisotropy
|
||||||
|
#ifdef _gbuffer2
|
||||||
|
vec4 g2 = textureLod(gbuffer2, texCoord, 0.0);
|
||||||
|
vec3 wTangent = decodeTangent(g2.a, n);
|
||||||
|
#else
|
||||||
|
vec3 wTangent = vec3(0.0);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _Brdf
|
#ifdef _Brdf
|
||||||
vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(dotNV, 1.0 - roughness) * 256.0), 0).xy;
|
vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(dotNV, 1.0 - roughness) * 256.0), 0).xy;
|
||||||
#endif
|
#endif
|
||||||
@ -158,15 +210,20 @@ void main() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _Rad
|
#ifdef _Rad
|
||||||
|
#ifdef _Anisotropy
|
||||||
|
vec3 reflectionWorld = anisotropicIBLDirection(n, v, wTangent,
|
||||||
|
matp0.x, roughness);
|
||||||
|
#else
|
||||||
vec3 reflectionWorld = reflect(-v, n);
|
vec3 reflectionWorld = reflect(-v, n);
|
||||||
|
#endif
|
||||||
float lod = getMipFromRoughness(roughness, envmapNumMipmaps);
|
float lod = getMipFromRoughness(roughness, envmapNumMipmaps);
|
||||||
vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb;
|
vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _EnvLDR
|
#ifdef _EnvLDR
|
||||||
envl.rgb = pow(envl.rgb, vec3(2.2));
|
envl.rgb = srgbToLinear(envl.rgb);
|
||||||
#ifdef _Rad
|
#ifdef _Rad
|
||||||
prefilteredColor = pow(prefilteredColor, vec3(2.2));
|
prefilteredColor = srgbToLinear(prefilteredColor);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -180,6 +237,98 @@ void main() {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _ExtBRDF
|
||||||
|
float iblSheenWeight = 1.0;
|
||||||
|
float iblCoatWeight = 1.0;
|
||||||
|
vec3 coatTintAbsorb = vec3(1.0);
|
||||||
|
|
||||||
|
#ifdef _Sheen
|
||||||
|
float sheenAlb = sheenIBLAlbedo(matp0.z, matp0.w, dotNV);
|
||||||
|
iblSheenWeight = max(1.0 - sheenAlb *
|
||||||
|
max(max(sheenTintCol.r, sheenTintCol.g), sheenTintCol.b), 0.0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
float dotNVCoat = max(dot(nCoat, v), 0.0);
|
||||||
|
float coatF = coatIBLFresnel(matp1.x, matp1.z, dotNVCoat);
|
||||||
|
iblCoatWeight = max(1.0 - coatF, 0.0);
|
||||||
|
if (matp1.x > 0.0) {
|
||||||
|
coatTintAbsorb = mix(vec3(1.0), clamp(coatTintCol, 0.0, 1.0),
|
||||||
|
clamp(1.0 / max(dotNVCoat, 0.3) * 0.2, 0.0, 1.0));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float iblLayerWeight = iblSheenWeight * iblCoatWeight;
|
||||||
|
envl.rgb *= iblLayerWeight;
|
||||||
|
|
||||||
|
brdf_sheenWeight = iblSheenWeight;
|
||||||
|
brdf_coatWeight = iblCoatWeight;
|
||||||
|
brdf_coatTintAbsorb = coatTintAbsorb;
|
||||||
|
#ifdef _Sheen
|
||||||
|
brdf_sheenAlbedo = sheenAlb;
|
||||||
|
#endif
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
brdf_coatF0 = (matp1.z - 1.0) / (matp1.z + 1.0);
|
||||||
|
brdf_coatF0 = brdf_coatF0 * brdf_coatF0;
|
||||||
|
#endif
|
||||||
|
#ifdef _Transmission
|
||||||
|
brdf_transmissionF0 = (matp3.x - 1.0) / (matp3.x + 1.0);
|
||||||
|
brdf_transmissionF0 = brdf_transmissionF0 * brdf_transmissionF0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _Transmission
|
||||||
|
float transF = transmissionIBLFresnel(matp3.x, dotNV);
|
||||||
|
float transmittance = 1.0 - transF;
|
||||||
|
#ifdef _Rad
|
||||||
|
if (matp2.z > 0.0 && transmittance > 0.0) {
|
||||||
|
vec3 refrDir = transmissionIBLDirection(n, v, matp3.x);
|
||||||
|
float transLod = getMipFromRoughness(matp2.w, envmapNumMipmaps);
|
||||||
|
vec3 transColor = textureLod(senvmapRadiance,
|
||||||
|
envMapEquirect(refrDir), transLod).rgb;
|
||||||
|
transColor = min(transColor, vec3(20.0));
|
||||||
|
#ifdef _EnvLDR
|
||||||
|
transColor = srgbToLinear(transColor);
|
||||||
|
#endif
|
||||||
|
envl.rgb += albedo * matp2.z * transmittance * transColor * dotNV
|
||||||
|
* iblLayerWeight;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
envl.rgb *= coatTintAbsorb;
|
||||||
|
#ifdef _Rad
|
||||||
|
if (coatF > 0.0) {
|
||||||
|
float coatLod = getMipFromRoughness(matp1.y, envmapNumMipmaps);
|
||||||
|
vec3 coatRefl = reflect(-v, nCoat);
|
||||||
|
vec3 coatColor = textureLod(senvmapRadiance,
|
||||||
|
envMapEquirect(coatRefl), coatLod).rgb;
|
||||||
|
coatColor = min(coatColor, vec3(20.0));
|
||||||
|
#ifdef _EnvLDR
|
||||||
|
coatColor = srgbToLinear(coatColor);
|
||||||
|
#endif
|
||||||
|
envl.rgb += coatColor * coatF * iblSheenWeight;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _Sheen
|
||||||
|
#ifdef _Rad
|
||||||
|
if (sheenAlb > 0.0) {
|
||||||
|
float sheenLod = getMipFromRoughness(matp0.w, envmapNumMipmaps);
|
||||||
|
vec3 sheenRefl = reflect(-v, n);
|
||||||
|
vec3 sheenColor = textureLod(senvmapRadiance,
|
||||||
|
envMapEquirect(sheenRefl), sheenLod).rgb;
|
||||||
|
sheenColor = min(sheenColor, vec3(20.0));
|
||||||
|
#ifdef _EnvLDR
|
||||||
|
sheenColor = srgbToLinear(sheenColor);
|
||||||
|
#endif
|
||||||
|
envl.rgb += sheenColor * sheenTintCol * sheenAlb;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif // _ExtBRDF
|
||||||
|
|
||||||
envl.rgb *= envmapStrength * occspec.x;
|
envl.rgb *= envmapStrength * occspec.x;
|
||||||
fragColor.rgb = envl;
|
fragColor.rgb = envl;
|
||||||
|
|
||||||
@ -189,10 +338,50 @@ void main() {
|
|||||||
float sdotVH = max(0.0, dot(v, sh));
|
float sdotVH = max(0.0, dot(v, sh));
|
||||||
float sdotNL = max(0.0, dot(n, sunDir));
|
float sdotNL = max(0.0, dot(n, sunDir));
|
||||||
float svisibility = 1.0;
|
float svisibility = 1.0;
|
||||||
|
#ifdef _Anisotropy
|
||||||
|
vec3 sdirect;
|
||||||
|
if (abs(matp0.x) > 0.001 && dot(wTangent, wTangent) > 0.001) {
|
||||||
|
vec3 sbitangent = normalize(cross(n, wTangent));
|
||||||
|
sdirect = lambertDiffuseBRDF(albedo, sdotNL) +
|
||||||
|
anisotropicBRDF(f0, roughness, matp0.x, matp0.y,
|
||||||
|
wTangent, sbitangent, n, sunDir, v, sdotNL, dotNV) * occspec.y;
|
||||||
|
} else {
|
||||||
|
sdirect = lambertDiffuseBRDF(albedo, sdotNL) +
|
||||||
|
specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * occspec.y;
|
||||||
|
}
|
||||||
|
#else
|
||||||
vec3 sdirect = lambertDiffuseBRDF(albedo, sdotNL) +
|
vec3 sdirect = lambertDiffuseBRDF(albedo, sdotNL) +
|
||||||
specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * occspec.y;
|
specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * occspec.y;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float sunSheenWeight = brdf_sheenWeight;
|
||||||
|
float sunCoatWeight = brdf_coatWeight;
|
||||||
|
|
||||||
|
#ifdef _Sheen
|
||||||
|
vec3 sunSheen = sheenBRDF(matp0.z, matp0.w, sheenTintCol, sdotNL, sdotNH, dotNV);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
vec3 sunCoat = clearcoatBRDF(matp1.x, matp1.y, matp1.z, nCoat, sunDir, v, sh);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float sunLayerWeight = sunSheenWeight * sunCoatWeight;
|
||||||
|
sdirect *= sunLayerWeight;
|
||||||
|
#ifdef _Transmission
|
||||||
|
sdirect += transmissionBRDF(albedo, matp2.z, matp2.w, matp3.x, matp3.y, sdotNL, dotNV, sdotVH) * sunLayerWeight;
|
||||||
|
#endif
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
sdirect *= brdf_coatTintAbsorb;
|
||||||
|
sdirect += sunCoat * sunSheenWeight;
|
||||||
|
#endif
|
||||||
|
#ifdef _Sheen
|
||||||
|
sdirect += sunSheen;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _ShadowMap
|
#ifdef _ShadowMap
|
||||||
|
#ifdef _ShadowMapAtlas
|
||||||
|
tileBounds = tileBoundsSunArray[0];
|
||||||
|
#endif
|
||||||
#ifdef _CSM
|
#ifdef _CSM
|
||||||
svisibility = shadowTestCascade(
|
svisibility = shadowTestCascade(
|
||||||
#ifdef _ShadowMapAtlas
|
#ifdef _ShadowMapAtlas
|
||||||
@ -235,6 +424,21 @@ void main() {
|
|||||||
#ifdef _Spot
|
#ifdef _Spot
|
||||||
, true, spotData.x, spotData.y, spotDir, spotData.zw, spotRight // TODO: Test!
|
, true, spotData.x, spotData.y, spotDir, spotData.zw, spotRight // TODO: Test!
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
, matp1.x, matp1.y, matp1.z, coatTintCol, nCoat
|
||||||
|
#endif
|
||||||
|
#ifdef _Sheen
|
||||||
|
, matp0.z, matp0.w, sheenTintCol
|
||||||
|
#endif
|
||||||
|
#ifdef _Anisotropy
|
||||||
|
, matp0.x, matp0.y, wTangent
|
||||||
|
#endif
|
||||||
|
#ifdef _SSS
|
||||||
|
, matp3.z, sssColorVal, sssRadiusScaled, matp3.w
|
||||||
|
#endif
|
||||||
|
#ifdef _Transmission
|
||||||
|
, matp2.z, matp2.w, matp3.x, matp3.y
|
||||||
|
#endif
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -277,7 +481,29 @@ void main() {
|
|||||||
, vec2(lightsArray[li * 3].w, lightsArray[li * 3 + 1].w) // scale
|
, vec2(lightsArray[li * 3].w, lightsArray[li * 3 + 1].w) // scale
|
||||||
, lightsArraySpot[li * 2 + 1].xyz // right
|
, lightsArraySpot[li * 2 + 1].xyz // right
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
, matp1.x, matp1.y, matp1.z, coatTintCol, nCoat
|
||||||
|
#endif
|
||||||
|
#ifdef _Sheen
|
||||||
|
, matp0.z, matp0.w, sheenTintCol
|
||||||
|
#endif
|
||||||
|
#ifdef _Anisotropy
|
||||||
|
, matp0.x, matp0.y, wTangent
|
||||||
|
#endif
|
||||||
|
#ifdef _SSS
|
||||||
|
, matp3.z, sssColorVal, sssRadiusScaled, matp3.w
|
||||||
|
#endif
|
||||||
|
#ifdef _Transmission
|
||||||
|
, matp2.z, matp2.w, matp3.x, matp3.y
|
||||||
|
#endif
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
#endif // _Clusters
|
#endif // _Clusters
|
||||||
|
|
||||||
|
fragColor.rgb = clamp(fragColor.rgb, vec3(0.0), vec3(65504.0));
|
||||||
|
if (any(isnan(fragColor.rgb)) || any(isinf(fragColor.rgb))) {
|
||||||
|
fragColor.rgb = vec3(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fragColor.a = 1.0; // Mark as opaque
|
||||||
}
|
}
|
||||||
|
|||||||
@ -97,6 +97,16 @@
|
|||||||
"link": "_cascadeData",
|
"link": "_cascadeData",
|
||||||
"ifdef": ["_Sun", "_ShadowMap", "_CSM"]
|
"ifdef": ["_Sun", "_ShadowMap", "_CSM"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "tileBoundsSunArray",
|
||||||
|
"link": "_tileBoundsSunArray",
|
||||||
|
"ifdef": ["_Sun", "_ShadowMap", "_ShadowMapAtlas"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "tileBoundsSpotArray",
|
||||||
|
"link": "_tileBoundsSpotArray",
|
||||||
|
"ifdef": ["_Clusters", "_Spot", "_ShadowMap", "_ShadowMapAtlas"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "eyeLookRight",
|
"name": "eyeLookRight",
|
||||||
"link": "_eyeLookRight",
|
"link": "_eyeLookRight",
|
||||||
@ -214,6 +224,12 @@
|
|||||||
"link": "_biasLightWorldViewProjectionMatrixSpot3",
|
"link": "_biasLightWorldViewProjectionMatrixSpot3",
|
||||||
"ifndef": ["_ShadowMapAtlas"],
|
"ifndef": ["_ShadowMapAtlas"],
|
||||||
"ifdef": ["_LTC", "_ShadowMap"]
|
"ifdef": ["_LTC", "_ShadowMap"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "materialParams",
|
||||||
|
"link": "_materialParams",
|
||||||
|
"type": "floats",
|
||||||
|
"ifdef": ["_ExtBRDF"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"vertex_shader": "../include/pass_viewray.vert.glsl",
|
"vertex_shader": "../include/pass_viewray.vert.glsl",
|
||||||
|
|||||||
@ -28,10 +28,12 @@ in vec2 texCoord;
|
|||||||
out vec4 fragColor;
|
out vec4 fragColor;
|
||||||
|
|
||||||
const float GOLDEN_ANGLE = 2.39996323;
|
const float GOLDEN_ANGLE = 2.39996323;
|
||||||
const int RAY_STEPS = 12;
|
const int RAY_STEPS = 6;
|
||||||
|
const int BINARY_STEPS = 3;
|
||||||
|
|
||||||
vec2 getProjectedCoord(const vec3 viewPos) {
|
vec2 getProjectedCoord(const vec3 viewPos) {
|
||||||
vec4 projectedCoord = P * vec4(viewPos, 1.0);
|
vec4 projectedCoord = P * vec4(viewPos, 1.0);
|
||||||
|
if (projectedCoord.w <= 0.0) return vec2(-1e5);
|
||||||
projectedCoord.xy /= projectedCoord.w;
|
projectedCoord.xy /= projectedCoord.w;
|
||||||
projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
|
projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
|
||||||
#ifdef _InvY
|
#ifdef _InvY
|
||||||
@ -40,16 +42,12 @@ vec2 getProjectedCoord(const vec3 viewPos) {
|
|||||||
return projectedCoord.xy;
|
return projectedCoord.xy;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 cosineSampleHemisphere(vec3 n, vec2 rand) {
|
float linearZ(const float depth) {
|
||||||
float phi = PI * 2.0 * rand.x;
|
return -P[3].z / (depth + P[2].z);
|
||||||
float cosTheta = sqrt(1.0 - rand.y);
|
}
|
||||||
float sinTheta = sqrt(rand.y);
|
|
||||||
|
|
||||||
vec3 h = vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);
|
void buildTBN(vec3 n, out vec3 tangent, out vec3 bitangent) {
|
||||||
|
|
||||||
vec3 tangent, bitangent;
|
|
||||||
vec3 absN = abs(n);
|
vec3 absN = abs(n);
|
||||||
|
|
||||||
if (absN.x <= absN.y && absN.x <= absN.z) {
|
if (absN.x <= absN.y && absN.x <= absN.z) {
|
||||||
tangent = normalize(cross(n, vec3(1.0, 0.0, 0.0)));
|
tangent = normalize(cross(n, vec3(1.0, 0.0, 0.0)));
|
||||||
} else if (absN.y <= absN.z) {
|
} else if (absN.y <= absN.z) {
|
||||||
@ -58,46 +56,70 @@ vec3 cosineSampleHemisphere(vec3 n, vec2 rand) {
|
|||||||
tangent = normalize(cross(n, vec3(0.0, 0.0, 1.0)));
|
tangent = normalize(cross(n, vec3(0.0, 0.0, 1.0)));
|
||||||
}
|
}
|
||||||
bitangent = cross(n, tangent);
|
bitangent = cross(n, tangent);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 sampleHemisphere(vec3 n, vec3 tangent, vec3 bitangent, float phi, float cosTheta) {
|
||||||
|
float sinTheta = sqrt(1.0 - cosTheta * cosTheta);
|
||||||
|
vec3 h = vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);
|
||||||
return normalize(tangent * h.x + bitangent * h.y + n * h.z);
|
return normalize(tangent * h.x + bitangent * h.y + n * h.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 traceRay(vec3 origin, vec3 dir, float maxDist, float minDist) {
|
vec3 traceRay(vec3 origin, vec3 dir, float maxDist, float minDist, float jitter) {
|
||||||
float stepSize = maxDist / float(RAY_STEPS);
|
float stepSize = maxDist / float(RAY_STEPS);
|
||||||
vec3 pos = origin + dir * minDist;
|
float rayDist = minDist + stepSize * (jitter - 1.0);
|
||||||
|
vec3 pos = origin + dir * rayDist;
|
||||||
|
|
||||||
float prevDepthDiff = 0.0;
|
float prevDepthDiff = 0.0;
|
||||||
float hadValidPrev = 0.0;
|
bool hasPrev = false;
|
||||||
|
|
||||||
for (int i = 1; i <= RAY_STEPS; i++) {
|
for (int i = 0; i < RAY_STEPS; i++) {
|
||||||
pos += dir * stepSize;
|
pos += dir * stepSize;
|
||||||
|
rayDist += stepSize;
|
||||||
vec2 uv = getProjectedCoord(pos);
|
vec2 uv = getProjectedCoord(pos);
|
||||||
|
if (uv.x < -100.0) return vec3(-1.0);
|
||||||
|
uv = clamp(uv, vec2(0.001), vec2(0.999));
|
||||||
|
|
||||||
vec2 sampleUV = clamp(uv, vec2(0.001), vec2(0.999));
|
float sampleDepth = textureLod(gbufferD, uv, 0.0).r * 2.0 - 1.0;
|
||||||
|
|
||||||
float sampleDepth = textureLod(gbufferD, sampleUV, 0.0).r * 2.0 - 1.0;
|
|
||||||
if (sampleDepth == 1.0) {
|
if (sampleDepth == 1.0) {
|
||||||
hadValidPrev = 0.0;
|
hasPrev = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 sampleViewPos = getPosView2(invP, sampleDepth, sampleUV);
|
float depthDiff = pos.z - linearZ(sampleDepth);
|
||||||
float depthDiff = pos.z - sampleViewPos.z;
|
float thickness = maxDist * 0.075 + rayDist * 0.125;
|
||||||
float rayDist = length(pos - origin);
|
|
||||||
float thickness = 0.15 + rayDist * 0.25;
|
|
||||||
|
|
||||||
float crossed = hadValidPrev * step(0.0, prevDepthDiff) * step(depthDiff, 0.0);
|
bool crossed = hasPrev && (prevDepthDiff > 0.0) && (depthDiff <= 0.0);
|
||||||
float withinThickness = step(abs(depthDiff), thickness);
|
bool withinThickness = (depthDiff <= 0.0) && (-depthDiff < thickness);
|
||||||
|
|
||||||
if (crossed > 0.5 || withinThickness > 0.5) {
|
if (crossed || withinThickness) {
|
||||||
float distWeight = 1.0 - (rayDist / maxDist);
|
vec3 bPos = pos;
|
||||||
distWeight = max(0.0, distWeight * distWeight);
|
vec3 bDir = dir * stepSize;
|
||||||
|
for (int j = 0; j < BINARY_STEPS; j++) {
|
||||||
|
bDir *= 0.5;
|
||||||
|
bPos -= bDir;
|
||||||
|
vec2 bUV = getProjectedCoord(bPos);
|
||||||
|
bUV = clamp(bUV, vec2(0.001), vec2(0.999));
|
||||||
|
float bDepth = textureLod(gbufferD, bUV, 0.0).r * 2.0 - 1.0;
|
||||||
|
if (bDepth == 1.0) {
|
||||||
|
bPos += bDir;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (bPos.z - linearZ(bDepth) > 0.0) bPos += bDir;
|
||||||
|
}
|
||||||
|
|
||||||
return vec3(sampleUV, distWeight);
|
vec2 bestUV = getProjectedCoord(bPos);
|
||||||
|
if (bestUV.x < -100.0) return vec3(-1.0);
|
||||||
|
bestUV = clamp(bestUV, vec2(0.001), vec2(0.999));
|
||||||
|
|
||||||
|
float hitDist = length(bPos - origin);
|
||||||
|
float distWeight = max(0.0, 1.0 - (hitDist / maxDist));
|
||||||
|
distWeight *= distWeight;
|
||||||
|
|
||||||
|
return vec3(bestUV, distWeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
prevDepthDiff = depthDiff;
|
prevDepthDiff = depthDiff;
|
||||||
hadValidPrev = 1.0;
|
hasPrev = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return vec3(-1.0);
|
return vec3(-1.0);
|
||||||
@ -111,77 +133,77 @@ void main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
|
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
|
||||||
vec2 enc = g0.rg;
|
vec3 n = getNor(g0.rg);
|
||||||
vec3 n;
|
vec3 basecolor = textureLod(gbuffer1, texCoord, 0.0).rgb;
|
||||||
n.z = 1.0 - abs(enc.x) - abs(enc.y);
|
|
||||||
n.xy = n.z >= 0.0 ? enc.xy : octahedronWrap(enc.xy);
|
|
||||||
n = normalize(n);
|
|
||||||
|
|
||||||
vec3 viewNormal = V3 * n;
|
vec3 viewNormal = V3 * n;
|
||||||
vec3 viewPos = getPosView2(invP, depth, texCoord);
|
vec3 viewPos = getPosView2(invP, depth, texCoord);
|
||||||
|
|
||||||
#ifdef _CPostprocess
|
#ifdef _CPostprocess
|
||||||
float radius = PPComp12.y;
|
float radius = PPComp12.y * 2.0;
|
||||||
float strength = PPComp12.x;
|
float strength = PPComp12.x * 0.5;
|
||||||
#else
|
#else
|
||||||
float radius = ssgiRadius;
|
float radius = ssgiRadius * 2.0;
|
||||||
float strength = ssgiStrength;
|
float strength = ssgiStrength * 0.5;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
float noise = fract(52.9829189 * fract(0.06711056 * texCoord.x * 1000.0 + 0.00583715 * texCoord.y * 1000.0));
|
radius = min(radius, max(-viewPos.z / P[1].y, 0.05));
|
||||||
|
|
||||||
|
float noise = fract(52.9829189 * fract(0.06711056 * gl_FragCoord.x + 0.00583715 * gl_FragCoord.y));
|
||||||
|
|
||||||
vec3 gi = vec3(0.0);
|
vec3 gi = vec3(0.0);
|
||||||
int validSamples = 0;
|
float missWeight = 0.0;
|
||||||
|
|
||||||
// min distance to avoid self shadowing artiffacts
|
// min distance to avoid self shadowing artiffacts
|
||||||
float minDist = radius * 0.05;
|
float minDist = radius * 0.05;
|
||||||
|
|
||||||
|
vec3 tangent, bitangent;
|
||||||
|
buildTBN(viewNormal, tangent, bitangent);
|
||||||
|
|
||||||
for (int i = 0; i < ssgiSamples; i++) {
|
for (int i = 0; i < ssgiSamples; i++) {
|
||||||
float fi = float(i) + noise;
|
float phi = float(i) * GOLDEN_ANGLE + noise * PI2;
|
||||||
vec2 rand = vec2(
|
float cosTheta = sqrt(max(0.0, 1.0 - (float(i) + 0.5) / float(ssgiSamples)));
|
||||||
fract(fi * 0.7548776662 + noise),
|
float jitter = fract(noise + float(i) * 0.618034);
|
||||||
fract(fi * 0.5698402909 + noise * 1.5)
|
|
||||||
);
|
|
||||||
|
|
||||||
vec3 rayDir = cosineSampleHemisphere(viewNormal, rand);
|
vec3 rayDir = sampleHemisphere(viewNormal, tangent, bitangent, phi, cosTheta);
|
||||||
vec3 hitResult = traceRay(viewPos, rayDir, radius, minDist);
|
vec3 hitResult = traceRay(viewPos, rayDir, radius, minDist, jitter);
|
||||||
|
|
||||||
if (hitResult.x < 0.0) continue;
|
if (hitResult.x < 0.0) {
|
||||||
|
missWeight += 1.0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
vec2 hitUV = hitResult.xy;
|
vec2 hitUV = hitResult.xy;
|
||||||
float distWeight = hitResult.z;
|
float distWeight = hitResult.z;
|
||||||
|
|
||||||
vec3 hitAlbedo = textureLod(gbuffer1, hitUV, 1.0).rgb;
|
vec3 hitN = getNor(textureLod(gbuffer0, hitUV, 0.0).rg);
|
||||||
|
float emitterCos = max(0.0, dot(V3 * hitN, -rayDir));
|
||||||
|
if (emitterCos <= 0.0) {
|
||||||
|
missWeight += 1.0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 hitAlbedo = textureLod(gbuffer1, hitUV, 0.0).rgb;
|
||||||
|
|
||||||
#ifdef _Sun
|
#ifdef _Sun
|
||||||
vec4 hitG0 = textureLod(gbuffer0, hitUV, 0.0);
|
|
||||||
vec2 hitEnc = hitG0.rg;
|
|
||||||
vec3 hitN;
|
|
||||||
hitN.z = 1.0 - abs(hitEnc.x) - abs(hitEnc.y);
|
|
||||||
hitN.xy = hitN.z >= 0.0 ? hitEnc.xy : octahedronWrap(hitEnc.xy);
|
|
||||||
hitN = normalize(hitN);
|
|
||||||
float hitNdotL = max(0.0, dot(hitN, sunDir));
|
float hitNdotL = max(0.0, dot(hitN, sunDir));
|
||||||
vec3 hitRadiance = hitAlbedo * sunCol * hitNdotL;
|
vec3 hitRadiance = hitAlbedo * (sunCol * hitNdotL + vec3(0.4));
|
||||||
#else
|
#else
|
||||||
vec3 hitRadiance = hitAlbedo * 0.5;
|
vec3 hitRadiance = hitAlbedo * 0.4;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _EmissionShaded
|
#ifdef _EmissionShaded
|
||||||
hitRadiance += textureLod(gbufferEmission, hitUV, 0.0).rgb;
|
hitRadiance += textureLod(gbufferEmission, hitUV, 0.0).rgb;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
gi += hitRadiance * distWeight;
|
gi += hitRadiance * (distWeight * emitterCos);
|
||||||
validSamples++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (validSamples > 0) {
|
gi += basecolor * 0.1 * missWeight;
|
||||||
gi /= float(validSamples);
|
gi *= 2.0 * strength / float(ssgiSamples);
|
||||||
}
|
|
||||||
|
|
||||||
gi *= strength;
|
|
||||||
|
|
||||||
#ifdef _EmissionShaded
|
#ifdef _EmissionShaded
|
||||||
gi += textureLod(gbufferEmission, texCoord, 0.0).rgb * 0.3;
|
gi += textureLod(gbufferEmission, texCoord, 0.0).rgb * 0.3;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fragColor = vec4(min(gi, vec3(2.0)), 1.0);
|
fragColor = vec4(min(gi, vec3(2.0)), 1.0);
|
||||||
|
|||||||
@ -11,6 +11,7 @@ uniform sampler2D gbuffer1; // basecol, spec
|
|||||||
uniform mat4 P;
|
uniform mat4 P;
|
||||||
uniform mat3 V3;
|
uniform mat3 V3;
|
||||||
uniform vec2 cameraProj;
|
uniform vec2 cameraProj;
|
||||||
|
uniform vec2 screenSize;
|
||||||
|
|
||||||
#ifdef _CPostprocess
|
#ifdef _CPostprocess
|
||||||
uniform vec3 PPComp9;
|
uniform vec3 PPComp9;
|
||||||
@ -24,8 +25,8 @@ out vec4 fragColor;
|
|||||||
vec3 hitCoord;
|
vec3 hitCoord;
|
||||||
float depth;
|
float depth;
|
||||||
|
|
||||||
const int numBinarySearchSteps = 7;
|
const int numBinarySearchSteps = 8;
|
||||||
const int maxSteps = int(ceil(1.0 / ssrRayStep) * ssrSearchDist);
|
const int maxSteps = 50;
|
||||||
|
|
||||||
vec2 getProjectedCoord(const vec3 hit) {
|
vec2 getProjectedCoord(const vec3 hit) {
|
||||||
vec4 projectedCoord = P * vec4(hit, 1.0);
|
vec4 projectedCoord = P * vec4(hit, 1.0);
|
||||||
@ -38,44 +39,58 @@ vec2 getProjectedCoord(const vec3 hit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
float getDeltaDepth(const vec3 hit) {
|
float getDeltaDepth(const vec3 hit) {
|
||||||
depth = textureLod(gbufferD, getProjectedCoord(hit), 0.0).r * 2.0 - 1.0;
|
vec2 tc = getProjectedCoord(hit);
|
||||||
|
if (tc.x < 0.0 || tc.x > 1.0 || tc.y < 0.0 || tc.y > 1.0)
|
||||||
|
return -1.0;
|
||||||
|
depth = textureLod(gbufferD, tc, 0.0).r * 2.0 - 1.0;
|
||||||
vec3 viewPos = getPosView(viewRay, depth, cameraProj);
|
vec3 viewPos = getPosView(viewRay, depth, cameraProj);
|
||||||
return viewPos.z - hit.z;
|
return viewPos.z - hit.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 binarySearch(vec3 dir) {
|
vec4 binarySearch(vec3 dir, float stepSize) {
|
||||||
float ddepth;
|
float ddepth;
|
||||||
for (int i = 0; i < numBinarySearchSteps; i++) {
|
for (int i = 0; i < numBinarySearchSteps; i++) {
|
||||||
dir *= 0.5;
|
stepSize *= 0.5;
|
||||||
hitCoord -= dir;
|
hitCoord -= dir * stepSize;
|
||||||
ddepth = getDeltaDepth(hitCoord);
|
ddepth = getDeltaDepth(hitCoord);
|
||||||
if (ddepth < 0.0) hitCoord += dir;
|
if (ddepth < 0.0) hitCoord += dir * stepSize;
|
||||||
}
|
}
|
||||||
// Ugly discard of hits too far away
|
|
||||||
#ifdef _CPostprocess
|
#ifdef _CPostprocess
|
||||||
if (abs(ddepth) > PPComp9.z / 500) return vec4(0.0);
|
float maxDist = PPComp9.z;
|
||||||
#else
|
#else
|
||||||
if (abs(ddepth) > ssrSearchDist / 500) return vec4(0.0);
|
float maxDist = ssrSearchDist;
|
||||||
#endif
|
#endif
|
||||||
return vec4(getProjectedCoord(hitCoord), 0.0, 1.0);
|
if (abs(ddepth) > maxDist * 0.005) return vec4(0.0);
|
||||||
|
vec2 hitTC = getProjectedCoord(hitCoord);
|
||||||
|
if (hitTC.x < 0.0 || hitTC.x > 1.0 || hitTC.y < 0.0 || hitTC.y > 1.0)
|
||||||
|
return vec4(0.0);
|
||||||
|
return vec4(hitTC, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 rayCast(vec3 dir) {
|
vec4 rayCast(vec3 dir) {
|
||||||
#ifdef _CPostprocess
|
#ifdef _CPostprocess
|
||||||
dir *= PPComp9.x;
|
float baseStep = PPComp9.x;
|
||||||
|
float maxDist = PPComp9.z;
|
||||||
#else
|
#else
|
||||||
dir *= ssrRayStep;
|
float baseStep = ssrRayStep;
|
||||||
|
float maxDist = ssrSearchDist;
|
||||||
#endif
|
#endif
|
||||||
|
float stepSize = baseStep * max(1.0, -viewRay.z * 0.1);
|
||||||
|
vec3 startPos = hitCoord;
|
||||||
for (int i = 0; i < maxSteps; i++) {
|
for (int i = 0; i < maxSteps; i++) {
|
||||||
hitCoord += dir;
|
hitCoord += dir * stepSize;
|
||||||
if (getDeltaDepth(hitCoord) > 0.0) return binarySearch(dir);
|
float dist = length(hitCoord - startPos);
|
||||||
|
if (dist > maxDist) break;
|
||||||
|
float ddepth = getDeltaDepth(hitCoord);
|
||||||
|
if (ddepth > 0.0) return binarySearch(dir, stepSize);
|
||||||
|
stepSize *= 1.03;
|
||||||
}
|
}
|
||||||
return vec4(0.0);
|
return vec4(0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
|
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
|
||||||
float roughness = unpackFloat(g0.b).y;
|
float roughness = g0.b;
|
||||||
if (roughness == 1.0) { fragColor.rgb = vec3(0.0); return; }
|
if (roughness == 1.0) { fragColor.rgb = vec3(0.0); return; }
|
||||||
|
|
||||||
float spec = fract(textureLod(gbuffer1, texCoord, 0.0).a);
|
float spec = fract(textureLod(gbuffer1, texCoord, 0.0).a);
|
||||||
@ -92,30 +107,54 @@ void main() {
|
|||||||
|
|
||||||
vec3 viewNormal = V3 * n;
|
vec3 viewNormal = V3 * n;
|
||||||
vec3 viewPos = getPosView(viewRay, d, cameraProj);
|
vec3 viewPos = getPosView(viewRay, d, cameraProj);
|
||||||
vec3 reflected = reflect(viewPos, viewNormal);
|
float NdotV = clamp(dot(viewNormal, -normalize(viewPos)), 0.0, 1.0);
|
||||||
|
vec3 reflected = reflect(normalize(viewPos), viewNormal);
|
||||||
hitCoord = viewPos;
|
hitCoord = viewPos;
|
||||||
|
|
||||||
#ifdef _CPostprocess
|
vec3 dir = reflected;
|
||||||
vec3 dir = reflected * (1.0 - rand(texCoord) * PPComp10.y * roughness) * 2.0;
|
|
||||||
#else
|
|
||||||
vec3 dir = reflected * (1.0 - rand(texCoord) * ssrJitter * roughness) * 2.0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// * max(ssrMinRayStep, -viewPos.z)
|
|
||||||
vec4 coords = rayCast(dir);
|
vec4 coords = rayCast(dir);
|
||||||
|
|
||||||
vec2 deltaCoords = abs(vec2(0.5, 0.5) - coords.xy);
|
if (coords.w <= 0.0) {
|
||||||
float screenEdgeFactor = clamp(1.0 - (deltaCoords.x + deltaCoords.y), 0.0, 1.0);
|
fragColor.rgb = vec3(0.0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 deltaCoords = abs(vec2(0.5, 0.5) - coords.xy);
|
||||||
|
float screenEdgeFactor = smoothstep(0.5, 0.15, deltaCoords.x)
|
||||||
|
* smoothstep(0.5, 0.15, deltaCoords.y);
|
||||||
|
screenEdgeFactor = max(screenEdgeFactor, 0.15);
|
||||||
|
|
||||||
|
float hitDepth = textureLod(gbufferD, coords.xy, 0.0).r * 2.0 - 1.0;
|
||||||
|
vec3 hitViewPos = getPosView(viewRay, hitDepth, cameraProj);
|
||||||
|
vec3 hitDir = normalize(hitViewPos - viewPos);
|
||||||
|
float hitNdotV = clamp(dot(viewNormal, -hitDir), 0.0, 1.0);
|
||||||
|
float hitBackFace = smoothstep(-0.15, 0.3, hitNdotV);
|
||||||
|
|
||||||
float reflectivity = 1.0 - roughness;
|
float reflectivity = 1.0 - roughness;
|
||||||
#ifdef _CPostprocess
|
#ifdef _CPostprocess
|
||||||
float intensity = pow(reflectivity, PPComp10.x) * screenEdgeFactor * clamp(-reflected.z, 0.0, 1.0) * clamp((PPComp9.z - length(viewPos - hitCoord)) * (1.0 / PPComp9.z), 0.0, 1.0) * coords.w;
|
float falloffExp = PPComp10.x;
|
||||||
|
float maxDist = PPComp9.z;
|
||||||
#else
|
#else
|
||||||
float intensity = pow(reflectivity, ssrFalloffExp) * screenEdgeFactor * clamp(-reflected.z, 0.0, 1.0) * clamp((ssrSearchDist - length(viewPos - hitCoord)) * (1.0 / ssrSearchDist), 0.0, 1.0) * coords.w;
|
float falloffExp = ssrFalloffExp;
|
||||||
|
float maxDist = ssrSearchDist;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
float distAttenuation = 1.0 - clamp(length(viewPos - hitCoord) / maxDist, 0.0, 1.0);
|
||||||
|
distAttenuation = pow(distAttenuation, 1.5);
|
||||||
|
|
||||||
|
float fresnel = pow(1.0 - NdotV, 5.0);
|
||||||
|
fresnel = mix(0.04, 1.0, fresnel);
|
||||||
|
|
||||||
|
float intensity = pow(reflectivity, falloffExp) * screenEdgeFactor
|
||||||
|
* smoothstep(0.0, 0.1, -reflected.z)
|
||||||
|
* distAttenuation
|
||||||
|
* hitBackFace
|
||||||
|
* coords.w;
|
||||||
|
|
||||||
intensity = clamp(intensity, 0.0, 1.0);
|
intensity = clamp(intensity, 0.0, 1.0);
|
||||||
|
|
||||||
vec3 reflCol = textureLod(tex, coords.xy, 0.0).rgb;
|
vec3 reflCol = textureLod(tex, coords.xy, 0.0).rgb;
|
||||||
reflCol = clamp(reflCol, 0.0, 1.0);
|
reflCol = clamp(reflCol, 0.0, 1.0);
|
||||||
fragColor.rgb = reflCol * intensity * 0.5;
|
fragColor.rgb = reflCol * intensity * mix(0.5, 1.0, fresnel);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,6 +22,10 @@
|
|||||||
"name": "cameraProj",
|
"name": "cameraProj",
|
||||||
"link": "_cameraPlaneProj"
|
"link": "_cameraPlaneProj"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "screenSize",
|
||||||
|
"link": "_screenSize"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "PPComp9",
|
"name": "PPComp9",
|
||||||
"link": "_PPComp9",
|
"link": "_PPComp9",
|
||||||
|
|||||||
@ -12,6 +12,7 @@ uniform sampler2D tex1;
|
|||||||
uniform sampler2D gbufferD;
|
uniform sampler2D gbufferD;
|
||||||
uniform sampler2D gbuffer0;
|
uniform sampler2D gbuffer0;
|
||||||
uniform sampler2D gbufferD1;
|
uniform sampler2D gbufferD1;
|
||||||
|
uniform sampler2D gbuffer1;
|
||||||
|
|
||||||
uniform sampler2D gbuffer_refraction; // ior\opacity
|
uniform sampler2D gbuffer_refraction; // ior\opacity
|
||||||
uniform mat4 P;
|
uniform mat4 P;
|
||||||
@ -26,7 +27,7 @@ vec3 hitCoord;
|
|||||||
float depth;
|
float depth;
|
||||||
|
|
||||||
const int numBinarySearchSteps = 7;
|
const int numBinarySearchSteps = 7;
|
||||||
const int maxSteps = int(ceil(1.0 / ss_refractionRayStep) * ss_refractionSearchDist);
|
const int maxSteps = 50;
|
||||||
|
|
||||||
vec2 getProjectedCoord(const vec3 hit) {
|
vec2 getProjectedCoord(const vec3 hit) {
|
||||||
vec4 projectedCoord = P * vec4(hit, 1.0);
|
vec4 projectedCoord = P * vec4(hit, 1.0);
|
||||||
@ -39,45 +40,60 @@ vec2 getProjectedCoord(const vec3 hit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
float getDeltaDepth(const vec3 hit) {
|
float getDeltaDepth(const vec3 hit) {
|
||||||
depth = textureLod(gbufferD1, getProjectedCoord(hit), 0.0).r * 2.0 - 1.0;
|
vec2 tc = getProjectedCoord(hit);
|
||||||
|
if (tc.x < 0.0 || tc.x > 1.0 || tc.y < 0.0 || tc.y > 1.0)
|
||||||
|
return -1.0;
|
||||||
|
depth = textureLod(gbufferD1, tc, 0.0).r * 2.0 - 1.0;
|
||||||
vec3 viewPos = getPosView(viewRay, depth, cameraProj);
|
vec3 viewPos = getPosView(viewRay, depth, cameraProj);
|
||||||
return viewPos.z - hit.z;
|
return viewPos.z - hit.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 binarySearch(vec3 dir) {
|
vec4 binarySearch(vec3 dir, float stepSize) {
|
||||||
float ddepth;
|
float ddepth;
|
||||||
for (int i = 0; i < numBinarySearchSteps; i++) {
|
for (int i = 0; i < numBinarySearchSteps; i++) {
|
||||||
dir *= 0.5;
|
stepSize *= 0.5;
|
||||||
hitCoord -= dir;
|
hitCoord -= dir * stepSize;
|
||||||
ddepth = getDeltaDepth(hitCoord);
|
ddepth = getDeltaDepth(hitCoord);
|
||||||
if (ddepth < 0.0) hitCoord += dir;
|
if (ddepth < 0.0) hitCoord += dir * stepSize;
|
||||||
}
|
}
|
||||||
if (abs(ddepth) > ss_refractionSearchDist) return vec4(0.0);
|
if (abs(ddepth) > ss_refractionSearchDist * 0.005) return vec4(0.0);
|
||||||
return vec4(getProjectedCoord(hitCoord), 0.0, 1.0);
|
vec2 hitTC = getProjectedCoord(hitCoord);
|
||||||
|
if (hitTC.x < 0.0 || hitTC.x > 1.0 || hitTC.y < 0.0 || hitTC.y > 1.0)
|
||||||
|
return vec4(0.0);
|
||||||
|
return vec4(hitTC, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 rayCast(vec3 dir) {
|
vec4 rayCast(vec3 dir) {
|
||||||
float ddepth;
|
float stepSize = ss_refractionRayStep * max(1.0, -viewRay.z * 0.1);
|
||||||
dir *= ss_refractionRayStep;
|
vec3 startPos = hitCoord;
|
||||||
for (int i = 0; i < maxSteps; i++) {
|
for (int i = 0; i < maxSteps; i++) {
|
||||||
hitCoord += dir;
|
hitCoord += dir * stepSize;
|
||||||
ddepth = getDeltaDepth(hitCoord);
|
float dist = length(hitCoord - startPos);
|
||||||
if (ddepth > 0.0) return binarySearch(dir);
|
if (dist > ss_refractionSearchDist) break;
|
||||||
|
float ddepth = getDeltaDepth(hitCoord);
|
||||||
|
if (ddepth > 0.0) return binarySearch(dir, stepSize);
|
||||||
|
stepSize *= 1.03;
|
||||||
}
|
}
|
||||||
return vec4(texCoord, 0.0, 0.0);
|
return vec4(texCoord, 0.0, 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 gr = textureLod(gbuffer_refraction, texCoord, 0.0);
|
vec4 gr = textureLod(gbuffer_refraction, texCoord, 0.0);
|
||||||
float ior = gr.x;
|
float ior = unpackIOR(gr.x);
|
||||||
float transmittance = gr.y;
|
float transmittance = gr.y;
|
||||||
float surfaceDepth = gr.z;
|
float surfaceDepth = gr.z;
|
||||||
float d = surfaceDepth * 2.0 - 1.0;
|
float d = surfaceDepth * 2.0 - 1.0;
|
||||||
|
|
||||||
vec4 sceneSample = textureLod(tex, texCoord, 0.0);
|
vec4 sceneSample = textureLod(tex, texCoord, 0.0);
|
||||||
if (surfaceDepth == 0.0 || transmittance == 0.0 || ior == 1.0) {
|
if (surfaceDepth == 0.0 || surfaceDepth == 1.0) {
|
||||||
|
fragColor = sceneSample;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 g1 = textureLod(gbuffer1, texCoord, 0.0);
|
||||||
|
if (transmittance == 0.0 || ior == 1.0) {
|
||||||
vec3 background = textureLod(tex1, texCoord, 0.0).rgb;
|
vec3 background = textureLod(tex1, texCoord, 0.0).rgb;
|
||||||
fragColor.rgb = sceneSample.rgb + background * (1.0 - sceneSample.a);
|
fragColor.rgb = g1.rgb + background * transmittance;
|
||||||
fragColor.a = 1.0;
|
fragColor.a = 1.0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -96,18 +112,18 @@ void main() {
|
|||||||
vec3 refracted = refract(incident, viewNormal, 1.0 / ior);
|
vec3 refracted = refract(incident, viewNormal, 1.0 / ior);
|
||||||
if (length(refracted) < 0.001) {
|
if (length(refracted) < 0.001) {
|
||||||
vec3 background = textureLod(tex1, texCoord, 0.0).rgb;
|
vec3 background = textureLod(tex1, texCoord, 0.0).rgb;
|
||||||
fragColor.rgb = sceneSample.rgb + background * (1.0 - sceneSample.a);
|
fragColor.rgb = g1.rgb + background * transmittance;
|
||||||
fragColor.a = 1.0;
|
fragColor.a = 1.0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
hitCoord = viewPos;
|
hitCoord = viewPos;
|
||||||
|
|
||||||
vec3 dir = refracted * (1.0 - rand(texCoord) * ss_refractionJitter * roughness) * 2.0;
|
vec3 dir = normalize(refracted);
|
||||||
vec4 coords = rayCast(dir);
|
vec4 coords = rayCast(dir);
|
||||||
|
|
||||||
vec2 screenEdge = smoothstep(0.0, 0.1, coords.xy) * smoothstep(0.0, 0.1, 1.0 - coords.xy);
|
vec2 screenEdge = smoothstep(0.0, 0.05, coords.xy) * smoothstep(0.0, 0.05, 1.0 - coords.xy);
|
||||||
float screenEdgeFactor = screenEdge.x * screenEdge.y;
|
float screenEdgeFactor = max(screenEdge.x * screenEdge.y, 0.05);
|
||||||
float refractivity = 1.0 - roughness;
|
float refractivity = 1.0 - roughness;
|
||||||
|
|
||||||
float intensity = pow(refractivity, ss_refractionFalloffExp) * screenEdgeFactor * coords.w;
|
float intensity = pow(refractivity, ss_refractionFalloffExp) * screenEdgeFactor * coords.w;
|
||||||
@ -118,6 +134,6 @@ void main() {
|
|||||||
|
|
||||||
vec3 behindColor = mix(straightBackground, refractedBackground, intensity);
|
vec3 behindColor = mix(straightBackground, refractedBackground, intensity);
|
||||||
|
|
||||||
fragColor.rgb = sceneSample.rgb + behindColor * (1.0 - sceneSample.a);
|
fragColor.rgb = g1.rgb + behindColor * transmittance;
|
||||||
fragColor.a = 1.0;
|
fragColor.a = 1.0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,100 +40,148 @@
|
|||||||
|
|
||||||
uniform sampler2D gbufferD;
|
uniform sampler2D gbufferD;
|
||||||
uniform sampler2D gbuffer0;
|
uniform sampler2D gbuffer0;
|
||||||
|
uniform sampler2D gbuffer1;
|
||||||
uniform sampler2D tex;
|
uniform sampler2D tex;
|
||||||
|
|
||||||
uniform vec2 dir;
|
uniform vec2 dir;
|
||||||
uniform vec2 cameraProj;
|
uniform vec2 cameraProj;
|
||||||
|
uniform mat4 projectionMatrix;
|
||||||
|
|
||||||
|
#ifdef _ExtBRDF
|
||||||
|
//!uniform vec4 materialParams[MAX_MATERIALS * 8];
|
||||||
|
#endif
|
||||||
|
|
||||||
in vec2 texCoord;
|
in vec2 texCoord;
|
||||||
out vec4 fragColor;
|
out vec4 fragColor;
|
||||||
|
|
||||||
const vec3 SKIN_SSS_RADIUS = vec3(4.8, 2.4, 1.5);
|
// TODO: finish the SSS
|
||||||
const float SSS_DISTANCE_SCALE = 0.001;
|
const float SSS_SCALE = 0.05;
|
||||||
|
const float DEPTH_THRESHOLD = 0.05;
|
||||||
|
|
||||||
// Temp hash func -
|
|
||||||
float hash13(vec3 p3) {
|
float hash13(vec3 p3) {
|
||||||
p3 = fract(p3 * vec3(0.1031, 0.1030, 0.0973));
|
p3 = fract(p3 * vec3(0.1031, 0.1030, 0.0973));
|
||||||
p3 += dot(p3, p3.yzx + 33.33);
|
p3 += dot(p3, p3.yzx + 33.33);
|
||||||
return fract((p3.x + p3.y) * p3.z);
|
return fract((p3.x + p3.y) * p3.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 SSSSBlur() {
|
vec4 SSSSBlur(vec3 sssRadius, float sssWeight) {
|
||||||
const int SSSS_N_SAMPLES = 15;
|
const int SSSS_N_SAMPLES = 11;
|
||||||
vec4 kernel[SSSS_N_SAMPLES];
|
vec4 kernel[SSSS_N_SAMPLES];
|
||||||
|
|
||||||
kernel[0] = vec4(0.233, 0.455, 0.649, 0.0); // Center sample
|
kernel[0] = vec4(0.233, 0.455, 0.649, 0.0); // Center sample
|
||||||
kernel[1] = vec4(0.100, 0.336, 0.344, 0.37); // +0.37mm
|
kernel[1] = vec4(0.100, 0.336, 0.344, 0.37); // +0.37
|
||||||
kernel[2] = vec4(0.118, 0.198, 0.0, 0.97); // +0.97mm
|
kernel[2] = vec4(0.118, 0.198, 0.0, 0.97); // +0.97
|
||||||
kernel[3] = vec4(0.113, 0.007, 0.007, 1.93); // +1.93mm
|
kernel[3] = vec4(0.113, 0.007, 0.007, 1.93); // +1.93
|
||||||
kernel[4] = vec4(0.358, 0.004, 0.0, 3.87); // +3.87mm
|
kernel[4] = vec4(0.358, 0.004, 0.0, 3.87); // +3.87
|
||||||
kernel[5] = vec4(0.078, 0.0, 0.0, 6.53); // +6.53mm (red only)
|
kernel[5] = vec4(0.078, 0.0, 0.0, 6.53); // +6.53 (red only)
|
||||||
kernel[6] = vec4(0.0, 0.0, 0.0, 0.0); // Unused
|
kernel[6] = vec4(0.100, 0.336, 0.344, -0.37); // -0.37
|
||||||
kernel[7] = vec4(0.0, 0.0, 0.0, 0.0); // Unused
|
kernel[7] = vec4(0.118, 0.198, 0.0, -0.97); // -0.97
|
||||||
kernel[8] = vec4(0.100, 0.336, 0.344, -0.37); // -0.37mm
|
kernel[8] = vec4(0.113, 0.007, 0.007, -1.93); // -1.93
|
||||||
kernel[9] = vec4(0.118, 0.198, 0.0, -0.97); // -0.97mm
|
kernel[9] = vec4(0.358, 0.004, 0.0, -3.87); // -3.87
|
||||||
kernel[10] = vec4(0.113, 0.007, 0.007, -1.93); // -1.93mm
|
kernel[10] = vec4(0.078, 0.0, 0.0, -6.53); // -6.53 (red only)
|
||||||
kernel[11] = vec4(0.358, 0.004, 0.0, -3.87); // -3.87mm
|
|
||||||
kernel[12] = vec4(0.078, 0.0, 0.0, -6.53); // -6.53mm (red only)
|
|
||||||
kernel[13] = vec4(0.0, 0.0, 0.0, 0.0); // Unused
|
|
||||||
kernel[14] = vec4(0.0, 0.0, 0.0, 0.0); // Unused
|
|
||||||
|
|
||||||
vec4 colorM = textureLod(tex, texCoord, 0.0);
|
vec2 texSize = vec2(textureSize(tex, 0));
|
||||||
|
ivec2 texelCoord = ivec2(texCoord * texSize);
|
||||||
|
|
||||||
float depth = textureLod(gbufferD, texCoord, 0.0).r;
|
vec4 colorM = texelFetch(tex, texelCoord, 0);
|
||||||
|
vec3 albedo = texelFetch(gbuffer1, texelCoord, 0).rgb;
|
||||||
|
|
||||||
|
vec3 irradianceM = colorM.rgb / max(albedo, vec3(0.00001));
|
||||||
|
|
||||||
|
float depth = texelFetch(gbufferD, texelCoord, 0).r;
|
||||||
float depthM = cameraProj.y / (depth - cameraProj.x);
|
float depthM = cameraProj.y / (depth - cameraProj.x);
|
||||||
|
|
||||||
float distanceScale = 1.0 / max(depthM, 0.1);
|
float blurWidth = max(max(sssRadius.r, sssRadius.g), sssRadius.b);
|
||||||
|
float projScale = dot(dir, vec2(projectionMatrix[0][0], projectionMatrix[1][1]));
|
||||||
vec2 finalStep = sssWidth * distanceScale * dir * SSS_DISTANCE_SCALE;
|
vec2 finalStep = blurWidth * (1.0 / depthM) * dir * projScale * SSS_SCALE;
|
||||||
|
|
||||||
|
|
||||||
vec3 jitterSeed = vec3(texCoord.xy * 1000.0, fract(cameraProj.x * 0.0001));
|
vec3 jitterSeed = vec3(texCoord.xy * 1000.0, fract(cameraProj.x * 0.0001));
|
||||||
float jitterOffset = (hash13(jitterSeed) * 2.0 - 1.0) * 0.15;
|
float jitterOffset = (hash13(jitterSeed) * 2.0 - 1.0) * 0.15;
|
||||||
|
|
||||||
finalStep *= (1.0 + jitterOffset);
|
finalStep *= (1.0 + jitterOffset);
|
||||||
vec3 colorBlurred = vec3(0.0);
|
|
||||||
vec3 weightSum = vec3(0.0);
|
vec3 colorBlurred = irradianceM * kernel[0].rgb;
|
||||||
colorBlurred += colorM.rgb * kernel[0].rgb;
|
vec3 weightSum = kernel[0].rgb;
|
||||||
weightSum += kernel[0].rgb;
|
|
||||||
|
|
||||||
for (int i = 1; i < SSSS_N_SAMPLES; i++) {
|
for (int i = 1; i < SSSS_N_SAMPLES; i++) {
|
||||||
float sampleJitter = hash13(vec3(texCoord.xy * 720.0, float(i) * 37.45)) * 0.1 - 0.05;
|
float sampleJitter = hash13(vec3(texCoord.xy * 720.0, float(i) * 37.45)) * 0.1 - 0.05;
|
||||||
vec2 offset = texCoord + (kernel[i].a + sampleJitter) * finalStep;
|
vec2 offset = texCoord + (kernel[i].a + sampleJitter) * finalStep;
|
||||||
vec4 color = textureLod(tex, offset, 0.0);
|
|
||||||
const float DEPTH_THRESHOLD = 0.05;
|
|
||||||
float sampleDepth = textureLod(gbufferD, offset, 0.0).r;
|
|
||||||
float sampleDepthM = cameraProj.y / (sampleDepth - cameraProj.x);
|
|
||||||
|
|
||||||
float depthDiff = abs(depthM - sampleDepthM);
|
vec3 irradiance = irradianceM;
|
||||||
float depthWeight = exp(-depthDiff * 10.0);
|
float s = 0.0;
|
||||||
|
if (all(greaterThanEqual(offset, vec2(0.0))) && all(lessThan(offset, vec2(1.0)))) {
|
||||||
|
ivec2 sampleTexel = ivec2(offset * texSize);
|
||||||
|
|
||||||
if (depthDiff > DEPTH_THRESHOLD) {
|
float sampleDepth = texelFetch(gbufferD, sampleTexel, 0).r;
|
||||||
color.rgb = mix(colorM.rgb, color.rgb, depthWeight);
|
float sampleDepthM = cameraProj.y / (sampleDepth - cameraProj.x);
|
||||||
|
float depthDiff = abs(depthM - sampleDepthM);
|
||||||
|
|
||||||
|
if (depthDiff < 1.0) {
|
||||||
|
vec4 sampleG0 = texelFetch(gbuffer0, sampleTexel, 0);
|
||||||
|
float sampleMetallic;
|
||||||
|
uint sampleMatid;
|
||||||
|
unpackFloatInt16(sampleG0.a, sampleMetallic, sampleMatid);
|
||||||
|
bool sampleIsSSS = false;
|
||||||
|
#ifdef _ExtBRDF
|
||||||
|
if (sampleMatid >= 3u && sampleMatid < uint(MAX_MATERIALS)) {
|
||||||
|
if (materialParams[sampleMatid * 8u + 3u].z > 0.0) sampleIsSSS = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (sampleIsSSS) {
|
||||||
|
vec3 sampleColor = texelFetch(tex, sampleTexel, 0).rgb;
|
||||||
|
vec3 sampleAlbedo = texelFetch(gbuffer1, sampleTexel, 0).rgb;
|
||||||
|
irradiance = sampleColor / max(sampleAlbedo, vec3(0.00001));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (depthDiff <= DEPTH_THRESHOLD) {
|
||||||
|
s = 1.0;
|
||||||
|
} else {
|
||||||
|
s = exp(-depthDiff * 10.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
colorBlurred += color.rgb * kernel[i].rgb;
|
colorBlurred += kernel[i].rgb * mix(irradianceM, irradiance, s);
|
||||||
weightSum += kernel[i].rgb;
|
weightSum += kernel[i].rgb;
|
||||||
}
|
}
|
||||||
vec3 normalizedColor = colorBlurred / max(weightSum, vec3(0.00001));
|
|
||||||
|
vec3 normalizedIrradiance = colorBlurred / max(weightSum, vec3(0.00001));
|
||||||
float dither = hash13(vec3(texCoord * 1333.0, 0.0)) * 0.003 - 0.0015;
|
float dither = hash13(vec3(texCoord * 1333.0, 0.0)) * 0.003 - 0.0015;
|
||||||
normalizedColor = max(normalizedColor + vec3(dither), vec3(0.0));
|
normalizedIrradiance = max(normalizedIrradiance + vec3(dither), vec3(0.0));
|
||||||
return vec4(normalizedColor, colorM.a);
|
vec3 blurredColor = normalizedIrradiance * albedo;
|
||||||
|
vec3 result = mix(colorM.rgb, blurredColor, sssWeight);
|
||||||
|
return vec4(result, colorM.a);
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
|
vec2 texSize0 = vec2(textureSize(gbuffer0, 0));
|
||||||
|
ivec2 texelCoord0 = ivec2(texCoord * texSize0);
|
||||||
|
vec4 g0 = texelFetch(gbuffer0, texelCoord0, 0);
|
||||||
float metallic;
|
float metallic;
|
||||||
uint matid;
|
uint matid;
|
||||||
unpackFloatInt16(g0.a, metallic, matid);
|
unpackFloatInt16(g0.a, metallic, matid);
|
||||||
|
|
||||||
if (matid == 2u) {
|
bool applySSS = false;
|
||||||
vec4 originalColor = textureLod(tex, texCoord, 0.0);
|
vec3 sssRadius = vec3(1.0);
|
||||||
vec4 blurredColor = SSSSBlur();
|
float sssWeight = 1.0;
|
||||||
vec4 sssContribution = blurredColor - originalColor;
|
vec4 matp0, matp1, matp2, matp3, matp4, matp5, matp6, matp7;
|
||||||
vec4 combined = originalColor + max(vec4(0.0), sssContribution) * 0.8;
|
#ifdef _ExtBRDF
|
||||||
fragColor = max(vec4(0.0), min(combined, vec4(10.0)));
|
if (matid >= 3u && matid < uint(MAX_MATERIALS)) {
|
||||||
|
getMaterialParams(matid, matp0, matp1, matp2, matp3, matp4, matp5, matp6, matp7);
|
||||||
|
// matp3.z = subsurface, matp4.xyz = subsurfaceRadiusRGB, matp7.x = subsurfaceScale
|
||||||
|
if (matp3.z > 0.0) {
|
||||||
|
applySSS = true;
|
||||||
|
sssRadius = matp4.xyz * matp7.x;
|
||||||
|
sssWeight = matp3.z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (applySSS) {
|
||||||
|
fragColor = SSSSBlur(sssRadius, sssWeight);
|
||||||
} else {
|
} else {
|
||||||
fragColor = textureLod(tex, texCoord, 0.0);
|
vec2 texSizeMain = vec2(textureSize(tex, 0));
|
||||||
|
ivec2 texelCoordMain = ivec2(texCoord * texSizeMain);
|
||||||
|
fragColor = texelFetch(tex, texelCoordMain, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,16 @@
|
|||||||
{
|
{
|
||||||
"name": "cameraProj",
|
"name": "cameraProj",
|
||||||
"link": "_cameraPlaneProj"
|
"link": "_cameraPlaneProj"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "projectionMatrix",
|
||||||
|
"link": "_projectionMatrix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "materialParams",
|
||||||
|
"link": "_materialParams",
|
||||||
|
"type": "floats",
|
||||||
|
"ifdef": ["_ExtBRDF"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"texture_params": [],
|
"texture_params": [],
|
||||||
@ -32,6 +42,16 @@
|
|||||||
{
|
{
|
||||||
"name": "cameraProj",
|
"name": "cameraProj",
|
||||||
"link": "_cameraPlaneProj"
|
"link": "_cameraPlaneProj"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "projectionMatrix",
|
||||||
|
"link": "_projectionMatrix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "materialParams",
|
||||||
|
"link": "_materialParams",
|
||||||
|
"type": "floats",
|
||||||
|
"ifdef": ["_ExtBRDF"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"texture_params": [],
|
"texture_params": [],
|
||||||
|
|||||||
@ -1,10 +1,30 @@
|
|||||||
#ifndef _BRDF_GLSL_
|
#ifndef _BRDF_GLSL_
|
||||||
#define _BRDF_GLSL_
|
#define _BRDF_GLSL_
|
||||||
|
|
||||||
|
#ifndef PI
|
||||||
|
#define PI 3.1415926535
|
||||||
|
#endif
|
||||||
|
#ifndef INV_PI
|
||||||
|
#define INV_PI 0.3183098861
|
||||||
|
#endif
|
||||||
|
#ifndef INV_TWO_PI
|
||||||
|
#define INV_TWO_PI 0.1591549430
|
||||||
|
#endif
|
||||||
|
#ifndef SCHLICK_A
|
||||||
|
#define SCHLICK_A -5.55473
|
||||||
|
#endif
|
||||||
|
#ifndef SCHLICK_B
|
||||||
|
#define SCHLICK_B -6.98316
|
||||||
|
#endif
|
||||||
|
#ifndef SRGB_GAMMA
|
||||||
|
#define SRGB_GAMMA 2.2
|
||||||
|
#endif
|
||||||
|
#define srgbToLinear(x) pow(x, vec3(SRGB_GAMMA))
|
||||||
|
|
||||||
// http://xlgames-inc.github.io/posts/improvedibl/
|
// http://xlgames-inc.github.io/posts/improvedibl/
|
||||||
// http://blog.selfshadow.com/publications/s2013-shading-course/
|
// http://blog.selfshadow.com/publications/s2013-shading-course/
|
||||||
vec3 f_schlick(const vec3 f0, const float vh) {
|
vec3 f_schlick(const vec3 f0, const float vh) {
|
||||||
return f0 + (1.0 - f0) * exp2((-5.55473 * vh - 6.98316) * vh);
|
return f0 + (1.0 - f0) * exp2((SCHLICK_A * vh + SCHLICK_B) * vh);
|
||||||
}
|
}
|
||||||
|
|
||||||
float v_smithschlick(const float nl, const float nv, const float a) {
|
float v_smithschlick(const float nl, const float nv, const float a) {
|
||||||
@ -31,7 +51,7 @@ float d_ggx(const float nh, const float a) {
|
|||||||
float a2 = a * a;
|
float a2 = a * a;
|
||||||
float denom = nh * nh * (a2 - 1.0) + 1.0;
|
float denom = nh * nh * (a2 - 1.0) + 1.0;
|
||||||
denom = max(denom * denom, 0.00006103515625 /* 2^-14 = smallest possible half float value, prevent div by zero */);
|
denom = max(denom * denom, 0.00006103515625 /* 2^-14 = smallest possible half float value, prevent div by zero */);
|
||||||
return a2 * (1.0 / 3.1415926535) / denom;
|
return a2 * INV_PI / denom;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 specularBRDF(const vec3 f0, const float roughness, const float nl, const float nh, const float nv, const float vh) {
|
vec3 specularBRDF(const vec3 f0, const float roughness, const float nl, const float nh, const float nv, const float vh) {
|
||||||
@ -44,11 +64,10 @@ vec3 specularBRDF(const vec3 f0, const float roughness, const float nl, const fl
|
|||||||
// http://filmicworlds.com/blog/optimizing-ggx-shaders-with-dotlh/
|
// http://filmicworlds.com/blog/optimizing-ggx-shaders-with-dotlh/
|
||||||
vec3 specularBRDFb(const vec3 f0, const float roughness, const float dotNL, const float dotNH, const float dotLH) {
|
vec3 specularBRDFb(const vec3 f0, const float roughness, const float dotNL, const float dotNH, const float dotLH) {
|
||||||
// D
|
// D
|
||||||
const float pi = 3.1415926535;
|
|
||||||
float alpha = roughness * roughness;
|
float alpha = roughness * roughness;
|
||||||
float alphaSqr = alpha * alpha;
|
float alphaSqr = alpha * alpha;
|
||||||
float denom = dotNH * dotNH * (alphaSqr - 1.0) + 1.0;
|
float denom = dotNH * dotNH * (alphaSqr - 1.0) + 1.0;
|
||||||
float D = alphaSqr / (pi * denom * denom);
|
float D = alphaSqr / (PI * denom * denom);
|
||||||
// F
|
// F
|
||||||
const float F_a = 1.0;
|
const float F_a = 1.0;
|
||||||
float F_b = pow(1.0 - dotLH, 5.0);
|
float F_b = pow(1.0 - dotLH, 5.0);
|
||||||
@ -65,21 +84,8 @@ vec3 specularBRDFb(const vec3 f0, const float roughness, const float dotNL, cons
|
|||||||
return specular / 4.0; // TODO: get rid of / 4.0
|
return specular / 4.0; // TODO: get rid of / 4.0
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 orenNayarDiffuseBRDF(const vec3 albedo, const float roughness, const float nv, const float nl, const float vh) {
|
|
||||||
float a = roughness * roughness;
|
|
||||||
float s = a;
|
|
||||||
float s2 = s * s;
|
|
||||||
float vl = 2.0 * vh * vh - 1.0; // Double angle identity
|
|
||||||
float Cosri = vl - nv * nl;
|
|
||||||
float C1 = 1.0 - 0.5 * s2 / (s2 + 0.33);
|
|
||||||
float test = 1.0;
|
|
||||||
if (Cosri >= 0.0) test = (1.0 / (max(nl, nv)));
|
|
||||||
float C2 = 0.45 * s2 / (s2 + 0.09) * Cosri * test;
|
|
||||||
return albedo * max(0.0, nl) * (C1 + C2) * (1.0 + roughness * 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 lambertDiffuseBRDF(const vec3 albedo, const float nl) {
|
vec3 lambertDiffuseBRDF(const vec3 albedo, const float nl) {
|
||||||
return albedo * (1.0 / 3.1415926535) * nl;
|
return albedo * INV_PI * nl;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 surfaceAlbedo(const vec3 baseColor, const float metalness) {
|
vec3 surfaceAlbedo(const vec3 baseColor, const float metalness) {
|
||||||
@ -95,24 +101,6 @@ float getMipFromRoughness(const float roughness, const float numMipmaps) {
|
|||||||
return roughness * numMipmaps;
|
return roughness * numMipmaps;
|
||||||
}
|
}
|
||||||
|
|
||||||
float wardSpecular(vec3 N, vec3 H, float dotNL, float dotNV, float dotNH, vec3 fiberDirection, float shinyParallel, float shinyPerpendicular) {
|
|
||||||
if(dotNL < 0.0 || dotNV < 0.0) {
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
// fiberDirection - parse from rotation
|
|
||||||
// shinyParallel - roughness
|
|
||||||
// shinyPerpendicular - anisotropy
|
|
||||||
|
|
||||||
vec3 fiberParallel = normalize(fiberDirection);
|
|
||||||
vec3 fiberPerpendicular = normalize(cross(N, fiberDirection));
|
|
||||||
float dotXH = dot(fiberParallel, H);
|
|
||||||
float dotYH = dot(fiberPerpendicular, H);
|
|
||||||
const float PI = 3.1415926535;
|
|
||||||
float coeff = sqrt(dotNL/dotNV) / (4.0 * PI * shinyParallel * shinyPerpendicular);
|
|
||||||
float theta = (pow(dotXH/shinyParallel, 2.0) + pow(dotYH/shinyPerpendicular, 2.0)) / (1.0 + dotNH);
|
|
||||||
return clamp(coeff * exp(-2.0 * theta), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile
|
// https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile
|
||||||
// vec3 EnvBRDFApprox(vec3 SpecularColor, float Roughness, float NoV) {
|
// vec3 EnvBRDFApprox(vec3 SpecularColor, float Roughness, float NoV) {
|
||||||
// const vec4 c0 = { -1, -0.0275, -0.572, 0.022 };
|
// const vec4 c0 = { -1, -0.0275, -0.572, 0.022 };
|
||||||
@ -138,4 +126,207 @@ float D_Approx(const float Roughness, const float RoL) {
|
|||||||
return rcp_a2 * exp2( c * RoL - c );
|
return rcp_a2 * exp2( c * RoL - c );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
float brdf_coatF0;
|
||||||
|
vec3 clearcoatBRDF(const float clearcoat, const float clearcoat_rough,
|
||||||
|
const float coat_ior, const vec3 coatN, const vec3 l, const vec3 v, const vec3 h) {
|
||||||
|
if (clearcoat <= 0.0) return vec3(0.0);
|
||||||
|
float cdotNL = max(0.0, dot(coatN, l));
|
||||||
|
float cdotNH = max(0.0, dot(coatN, h));
|
||||||
|
float cdotNV = max(0.0, dot(coatN, v));
|
||||||
|
float cdotVH = max(0.0, dot(v, h));
|
||||||
|
float a = clearcoat_rough * clearcoat_rough;
|
||||||
|
float F = brdf_coatF0 + (1.0 - brdf_coatF0) * exp2((SCHLICK_A * cdotVH + SCHLICK_B) * cdotVH);
|
||||||
|
float D = d_ggx(cdotNH, a);
|
||||||
|
float G = g2_approx(cdotNL, cdotNV, a);
|
||||||
|
return vec3(clearcoat * D * G * F / max(4.0 * cdotNV, 1e-5));
|
||||||
|
}
|
||||||
|
|
||||||
|
float coatAttenuation(const float clearcoat,
|
||||||
|
const float coat_ior, const vec3 coatN, const vec3 v) {
|
||||||
|
if (clearcoat <= 0.0) return 1.0;
|
||||||
|
float cdotNV = max(0.0, dot(coatN, v));
|
||||||
|
float F = brdf_coatF0 + (1.0 - brdf_coatF0) * exp2((SCHLICK_A * cdotNV + SCHLICK_B) * cdotNV);
|
||||||
|
return max(1.0 - F * clearcoat, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 coatTintAttenuation(const float clearcoat, const vec3 coat_tint, const vec3 coatN, const vec3 v) {
|
||||||
|
if (clearcoat <= 0.0) return vec3(1.0);
|
||||||
|
float cdotNV = max(0.0, dot(coatN, v));
|
||||||
|
float absorption = 1.0 / max(cdotNV, 0.3);
|
||||||
|
return mix(vec3(1.0), clamp(coat_tint, 0.0, 1.0), clamp(absorption * 0.2, 0.0, 1.0));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _Sheen
|
||||||
|
float brdf_sheenAlbedo;
|
||||||
|
// based on Blender sheen model/Frostbite PBR
|
||||||
|
vec3 sheenBRDF(const float sheen, const float sheen_rough,
|
||||||
|
const vec3 sheen_tint, const float dotNL, const float dotNH, const float dotNV) {
|
||||||
|
if (sheen <= 0.0) return vec3(0.0);
|
||||||
|
float rough = clamp(sheen_rough, 1e-3, 1.0);
|
||||||
|
float a = rough * rough;
|
||||||
|
float sinNH2 = 1.0 - dotNH * dotNH;
|
||||||
|
float a2 = a * a;
|
||||||
|
float denom = 1.0 + a2 * sinNH2;
|
||||||
|
float D = (2.0 + a2) * sinNH2 * INV_TWO_PI / (denom * denom);
|
||||||
|
float V = 1.0 / (4.0 * dotNL * dotNV + 1e-5);
|
||||||
|
return sheen_tint * sheen * D * V * dotNL * brdf_sheenAlbedo;
|
||||||
|
}
|
||||||
|
|
||||||
|
float sheenAttenuation(const float sheen, const float sheen_rough,
|
||||||
|
const vec3 sheen_tint, const float dotNV) {
|
||||||
|
if (sheen <= 0.0) return 1.0;
|
||||||
|
float maxComp = sheen * max(max(sheen_tint.r, sheen_tint.g), sheen_tint.b) * brdf_sheenAlbedo;
|
||||||
|
return max(1.0 - maxComp, 0.0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _Anisotropy
|
||||||
|
// anisotropic GGX Burley 2012
|
||||||
|
vec3 anisotropicBRDF(const vec3 f0, const float roughness, const float anisotropy,
|
||||||
|
const float aniso_rot, const vec3 tangent, const vec3 bitangent,
|
||||||
|
const vec3 n, const vec3 l, const vec3 v,
|
||||||
|
const float dotNL, const float dotNV) {
|
||||||
|
if (abs(anisotropy) <= 0.001) return vec3(0.0);
|
||||||
|
float rot = aniso_rot * PI * 2.0;
|
||||||
|
float cr = cos(rot);
|
||||||
|
float sr = sin(rot);
|
||||||
|
vec3 t = normalize(tangent * cr + bitangent * sr);
|
||||||
|
vec3 b = normalize(bitangent * cr - tangent * sr);
|
||||||
|
float aniso_abs = abs(anisotropy);
|
||||||
|
float at = max(roughness * (1.0 + aniso_abs), 1e-5);
|
||||||
|
float ab = max(roughness * (1.0 - aniso_abs), 1e-5);
|
||||||
|
if (anisotropy < 0.0) { vec3 tmp = t; t = b; b = tmp; }
|
||||||
|
float at2 = at * at;
|
||||||
|
float ab2 = ab * ab;
|
||||||
|
vec3 h = normalize(l + v);
|
||||||
|
float dotTH = dot(t, h);
|
||||||
|
float dotBH = dot(b, h);
|
||||||
|
float dotTV = dot(t, v);
|
||||||
|
float dotBV = dot(b, v);
|
||||||
|
float dotTL = dot(t, l);
|
||||||
|
float dotBL = dot(b, l);
|
||||||
|
float denom = max(dotTH * dotTH / at2 + dotBH * dotBH / ab2, 1e-7);
|
||||||
|
float D = INV_PI / (at * ab * denom * denom);
|
||||||
|
float V = 1.0 / max(dotNL * (dotTL / at + dotBL / ab) * (dotTV / at + dotBV / ab), 1e-5);
|
||||||
|
float dotVH = max(dot(v, h), 0.0);
|
||||||
|
vec3 F = f_schlick(f0, dotVH);
|
||||||
|
return D * V * F / max(4.0 * dotNV, 1e-5);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _Transmission
|
||||||
|
float brdf_transmissionF0;
|
||||||
|
// Blenders microfacet glass/refraction model
|
||||||
|
vec3 transmissionBRDF(const vec3 albedo, const float transmission,
|
||||||
|
const float trans_rough, const float ior, const float thin_wall,
|
||||||
|
const float dotNL, const float dotNV, const float dotVH) {
|
||||||
|
if (transmission <= 0.0) return vec3(0.0);
|
||||||
|
float F = brdf_transmissionF0 + (1.0 - brdf_transmissionF0) * exp2((SCHLICK_A * dotVH + SCHLICK_B) * dotVH);
|
||||||
|
float transmittance = 1.0 - F;
|
||||||
|
if (thin_wall > 0.5) {
|
||||||
|
return albedo * transmission * transmittance * dotNL;
|
||||||
|
}
|
||||||
|
float a = trans_rough * trans_rough;
|
||||||
|
float rough_atten = min(mix(1.0, 1.0 / max(dotNV, 0.1), a), 4.0);
|
||||||
|
return albedo * transmission * transmittance * rough_atten * dotNL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _ExtBRDF
|
||||||
|
float brdf_sheenWeight = 1.0;
|
||||||
|
float brdf_coatWeight = 1.0;
|
||||||
|
vec3 brdf_coatTintAbsorb = vec3(1.0);
|
||||||
|
|
||||||
|
vec3 applyExtBRDFLayers(
|
||||||
|
const vec3 direct,
|
||||||
|
const vec3 albedo,
|
||||||
|
const vec3 f0,
|
||||||
|
const float roughness,
|
||||||
|
const float dotNL, const float dotNV, const float dotNH, const float dotVH,
|
||||||
|
const vec3 n, const vec3 l, const vec3 v, const vec3 h,
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
const float clearcoat, const float clearcoatRough, const float coatIOR,
|
||||||
|
const vec3 coatTint, const vec3 coatN,
|
||||||
|
#endif
|
||||||
|
#ifdef _Sheen
|
||||||
|
const float sheen, const float sheenRough, const vec3 sheenTint,
|
||||||
|
#endif
|
||||||
|
#ifdef _Transmission
|
||||||
|
const float transmission, const float transRough, const float ior, const float thinWall,
|
||||||
|
#endif
|
||||||
|
out float layerWeight
|
||||||
|
) {
|
||||||
|
float sheenWeight = brdf_sheenWeight;
|
||||||
|
float coatWeight = brdf_coatWeight;
|
||||||
|
#ifdef _Sheen
|
||||||
|
vec3 sheenContrib = sheenBRDF(sheen, sheenRough, sheenTint, dotNL, dotNH, dotNV);
|
||||||
|
#endif
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
vec3 coatContrib = clearcoatBRDF(clearcoat, clearcoatRough, coatIOR, coatN, l, v, h);
|
||||||
|
#endif
|
||||||
|
layerWeight = sheenWeight * coatWeight;
|
||||||
|
vec3 result = direct * layerWeight;
|
||||||
|
#ifdef _Transmission
|
||||||
|
result += transmissionBRDF(albedo, transmission, transRough, ior, thinWall, dotNL, dotNV, dotVH) * layerWeight;
|
||||||
|
#endif
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
result *= brdf_coatTintAbsorb;
|
||||||
|
result += coatContrib * sheenWeight;
|
||||||
|
#endif
|
||||||
|
#ifdef _Sheen
|
||||||
|
result += sheenContrib;
|
||||||
|
#endif
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
float coatIBLFresnel(const float clearcoat, const float coat_ior,
|
||||||
|
const float dotNV_coat) {
|
||||||
|
if (clearcoat <= 0.0) return 0.0;
|
||||||
|
float F = brdf_coatF0 + (1.0 - brdf_coatF0) * exp2((SCHLICK_A * dotNV_coat + SCHLICK_B) * dotNV_coat);
|
||||||
|
return F * clearcoat;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _Sheen
|
||||||
|
float sheenIBLAlbedo(const float sheen, const float sheen_rough,
|
||||||
|
const float dotNV) {
|
||||||
|
if (sheen <= 0.0) return 0.0;
|
||||||
|
float rough = clamp(sheen_rough, 1e-3, 1.0);
|
||||||
|
return sheen * (1.0 - 0.5 * rough) * mix(1.0, dotNV, 0.5);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _Anisotropy
|
||||||
|
vec3 anisotropicIBLDirection(const vec3 n, const vec3 v, const vec3 tangent,
|
||||||
|
const float anisotropy, const float roughness) {
|
||||||
|
if (abs(anisotropy) <= 0.001 || dot(tangent, tangent) < 0.001)
|
||||||
|
return reflect(-v, n);
|
||||||
|
vec3 bitangent = normalize(cross(n, tangent));
|
||||||
|
vec3 r = reflect(-v, n);
|
||||||
|
float aniso_abs = abs(anisotropy);
|
||||||
|
vec3 stretchDir = anisotropy > 0.0 ? tangent : bitangent;
|
||||||
|
float stretchAmt = aniso_abs * roughness;
|
||||||
|
return normalize(r + stretchDir * stretchAmt * dot(r, stretchDir) * 0.5);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _Transmission
|
||||||
|
float transmissionIBLFresnel(const float ior, const float dotNV) {
|
||||||
|
return brdf_transmissionF0 + (1.0 - brdf_transmissionF0) * exp2((SCHLICK_A * dotNV + SCHLICK_B) * dotNV);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 transmissionIBLDirection(const vec3 n, const vec3 v, const float ior) {
|
||||||
|
float eta = 1.0 / ior;
|
||||||
|
vec3 refrDir = refract(-v, n, eta);
|
||||||
|
if (dot(refrDir, refrDir) < 0.001) {
|
||||||
|
refrDir = reflect(-v, n);
|
||||||
|
}
|
||||||
|
return refrDir;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -34,17 +34,19 @@ THE SOFTWARE.
|
|||||||
// https://research.nvidia.com/sites/default/files/publications/GIVoxels-pg2011-authors.pdf
|
// https://research.nvidia.com/sites/default/files/publications/GIVoxels-pg2011-authors.pdf
|
||||||
|
|
||||||
const float MAX_DISTANCE = voxelgiRange;
|
const float MAX_DISTANCE = voxelgiRange;
|
||||||
|
const int MAX_CONE_STEPS = 32;
|
||||||
|
|
||||||
#ifdef _VoxelGI
|
#ifdef _VoxelGI
|
||||||
uniform sampler3D dummy;
|
|
||||||
|
|
||||||
vec4 sampleVoxel(sampler3D voxels, vec3 P, const float clipmaps[voxelgiClipmapCount * 10], const float clipmap_index, const float step_dist, const int precomputed_direction, const vec3 face_offset, const vec3 direction_weight) {
|
vec4 sampleVoxel(sampler3D voxels, vec3 P, const float clipmaps[voxelgiClipmapCount * 10], const float clipmap_index, const float step_dist, const int precomputed_direction, const vec3 face_offset, const vec3 direction_weight) {
|
||||||
vec4 col = vec4(0.0);
|
vec4 col = vec4(0.0);
|
||||||
vec3 tc = (P - vec3(clipmaps[int(clipmap_index * 10 + 4)], clipmaps[int(clipmap_index * 10 + 5)], clipmaps[int(clipmap_index * 10 + 6)])) / (float(clipmaps[int(clipmap_index * 10)]) * voxelgiResolution);
|
int base = int(clipmap_index * 10);
|
||||||
|
float voxelSize = float(clipmaps[base]);
|
||||||
|
vec3 tc = (P - vec3(clipmaps[base + 4], clipmaps[base + 5], clipmaps[base + 6])) / (voxelSize * voxelgiResolution);
|
||||||
vec3 half_texel = vec3(0.5) / voxelgiResolution;
|
vec3 half_texel = vec3(0.5) / voxelgiResolution;
|
||||||
tc = tc * 0.5 + 0.5;
|
tc = tc * 0.5 + 0.5;
|
||||||
tc = clamp(tc, half_texel, 1.0 - half_texel);
|
tc = clamp(tc, half_texel, 1.0 - half_texel);
|
||||||
tc.x = (tc.x + precomputed_direction) / (6 + DIFFUSE_CONE_COUNT);
|
tc.x = (tc.x + precomputed_direction) / (6 + diffuseConeCount);
|
||||||
tc.y = (tc.y + clipmap_index) / voxelgiClipmapCount;
|
tc.y = (tc.y + clipmap_index) / voxelgiClipmapCount;
|
||||||
|
|
||||||
if (precomputed_direction == 0) {
|
if (precomputed_direction == 0) {
|
||||||
@ -55,7 +57,7 @@ vec4 sampleVoxel(sampler3D voxels, vec3 P, const float clipmaps[voxelgiClipmapCo
|
|||||||
else
|
else
|
||||||
col = textureLod(voxels, tc, 0);
|
col = textureLod(voxels, tc, 0);
|
||||||
|
|
||||||
col *= step_dist / float(clipmaps[int(clipmap_index * 10)]);
|
col *= step_dist / voxelSize;
|
||||||
|
|
||||||
return col;
|
return col;
|
||||||
}
|
}
|
||||||
@ -64,11 +66,13 @@ vec4 sampleVoxel(sampler3D voxels, vec3 P, const float clipmaps[voxelgiClipmapCo
|
|||||||
#ifdef _VoxelAOvar
|
#ifdef _VoxelAOvar
|
||||||
float sampleVoxel(sampler3D voxels, vec3 P, const float clipmaps[voxelgiClipmapCount * 10], const float clipmap_index, const float step_dist, const int precomputed_direction, const vec3 face_offset, const vec3 direction_weight) {
|
float sampleVoxel(sampler3D voxels, vec3 P, const float clipmaps[voxelgiClipmapCount * 10], const float clipmap_index, const float step_dist, const int precomputed_direction, const vec3 face_offset, const vec3 direction_weight) {
|
||||||
float opac = 0.0;
|
float opac = 0.0;
|
||||||
vec3 tc = (P - vec3(clipmaps[int(clipmap_index * 10 + 4)], clipmaps[int(clipmap_index * 10 + 5)], clipmaps[int(clipmap_index * 10 + 6)])) / (float(clipmaps[int(clipmap_index * 10)]) * voxelgiResolution);
|
int base = int(clipmap_index * 10);
|
||||||
|
float voxelSize = float(clipmaps[base]);
|
||||||
|
vec3 tc = (P - vec3(clipmaps[base + 4], clipmaps[base + 5], clipmaps[base + 6])) / (voxelSize * voxelgiResolution);
|
||||||
vec3 half_texel = vec3(0.5) / voxelgiResolution;
|
vec3 half_texel = vec3(0.5) / voxelgiResolution;
|
||||||
tc = tc * 0.5 + 0.5;
|
tc = tc * 0.5 + 0.5;
|
||||||
tc = clamp(tc, half_texel, 1.0 - half_texel);
|
tc = clamp(tc, half_texel, 1.0 - half_texel);
|
||||||
tc.x = (tc.x + precomputed_direction) / (6 + DIFFUSE_CONE_COUNT);
|
tc.x = (tc.x + precomputed_direction) / (6 + diffuseConeCount);
|
||||||
tc.y = (tc.y + clipmap_index) / voxelgiClipmapCount;
|
tc.y = (tc.y + clipmap_index) / voxelgiClipmapCount;
|
||||||
|
|
||||||
if (precomputed_direction == 0) {
|
if (precomputed_direction == 0) {
|
||||||
@ -79,7 +83,7 @@ float sampleVoxel(sampler3D voxels, vec3 P, const float clipmaps[voxelgiClipmapC
|
|||||||
else
|
else
|
||||||
opac = textureLod(voxels, tc, 0).r;
|
opac = textureLod(voxels, tc, 0).r;
|
||||||
|
|
||||||
opac *= step_dist / float(clipmaps[int(clipmap_index * 10)]);
|
opac *= step_dist / voxelSize;
|
||||||
|
|
||||||
return opac;
|
return opac;
|
||||||
}
|
}
|
||||||
@ -92,7 +96,7 @@ vec4 traceCone(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 ori
|
|||||||
float dist = voxelSize0;
|
float dist = voxelSize0;
|
||||||
float step_dist = dist;
|
float step_dist = dist;
|
||||||
vec3 samplePos;
|
vec3 samplePos;
|
||||||
vec3 start_pos = origin + n * voxelSize0;
|
vec3 start_pos = origin + n * voxelSize0 * voxelgiOffset;
|
||||||
int clipmap_index0 = 0;
|
int clipmap_index0 = 0;
|
||||||
|
|
||||||
vec3 aniso_direction = -dir;
|
vec3 aniso_direction = -dir;
|
||||||
@ -100,20 +104,24 @@ vec4 traceCone(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 ori
|
|||||||
aniso_direction.x > 0.0 ? 0.0 : 1.0,
|
aniso_direction.x > 0.0 ? 0.0 : 1.0,
|
||||||
aniso_direction.y > 0.0 ? 2.0 : 3.0,
|
aniso_direction.y > 0.0 ? 2.0 : 3.0,
|
||||||
aniso_direction.z > 0.0 ? 4.0 : 5.0
|
aniso_direction.z > 0.0 ? 4.0 : 5.0
|
||||||
) / (6 + DIFFUSE_CONE_COUNT);
|
) / (6 + diffuseConeCount);
|
||||||
vec3 direction_weight = abs(dir);
|
vec3 direction_weight = abs(dir);
|
||||||
|
|
||||||
float coneCoefficient = 2.0 * tan(aperture * 0.5);
|
float coneCoefficient = 2.0 * tan(aperture * 0.5);
|
||||||
|
|
||||||
while (sampleCol.a < 1.0 && dist < MAX_DISTANCE && clipmap_index0 < voxelgiClipmapCount) {
|
const vec3 half_texel = vec3(0.5) / voxelgiResolution;
|
||||||
|
int steps = 0;
|
||||||
|
while (sampleCol.a < 1.0 && dist < MAX_DISTANCE && clipmap_index0 < voxelgiClipmapCount && steps < MAX_CONE_STEPS) {
|
||||||
vec4 mipSample = vec4(0.0);
|
vec4 mipSample = vec4(0.0);
|
||||||
float diam = max(voxelSize0, dist * coneCoefficient);
|
float diam = max(voxelSize0, dist * coneCoefficient);
|
||||||
float lod = clamp(log2(diam / voxelSize0), clipmap_index0, voxelgiClipmapCount - 1);
|
float lod = clamp(log2(diam / voxelSize0), clipmap_index0, voxelgiClipmapCount - 1);
|
||||||
float clipmap_index = floor(lod);
|
float clipmap_index = floor(lod);
|
||||||
float clipmap_blend = fract(lod);
|
float clipmap_blend = smoothstep(0.0, 1.0, fract(lod));
|
||||||
vec3 p0 = start_pos + dir * dist;
|
vec3 p0 = start_pos + dir * dist;
|
||||||
|
|
||||||
samplePos = (p0 - vec3(clipmaps[int(clipmap_index * 10 + 4)], clipmaps[int(clipmap_index * 10 + 5)], clipmaps[int(clipmap_index * 10 + 6)])) / (float(clipmaps[int(clipmap_index * 10)]) * voxelgiResolution);
|
int base = int(clipmap_index * 10);
|
||||||
|
float voxelSize = float(clipmaps[base]);
|
||||||
|
samplePos = (p0 - vec3(clipmaps[base + 4], clipmaps[base + 5], clipmaps[base + 6])) / (voxelSize * voxelgiResolution);
|
||||||
samplePos = samplePos * 0.5 + 0.5;
|
samplePos = samplePos * 0.5 + 0.5;
|
||||||
|
|
||||||
if (any(notEqual(samplePos, clamp(samplePos, 0.0, 1.0)))) {
|
if (any(notEqual(samplePos, clamp(samplePos, 0.0, 1.0)))) {
|
||||||
@ -121,19 +129,26 @@ vec4 traceCone(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 ori
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Edge fade: blend toward coarser clipmap near boundaries
|
||||||
|
vec3 edgeDist = min(samplePos, 1.0 - samplePos);
|
||||||
|
float minEdgeDist = min(min(edgeDist.x, edgeDist.y), edgeDist.z);
|
||||||
|
float edgeBlend = 1.0 - smoothstep(0.0, 0.1, minEdgeDist);
|
||||||
|
float totalBlend = max(clipmap_blend, edgeBlend);
|
||||||
|
|
||||||
mipSample = sampleVoxel(voxels, p0, clipmaps, clipmap_index, step_dist, precomputed_direction, face_offset, direction_weight);
|
mipSample = sampleVoxel(voxels, p0, clipmaps, clipmap_index, step_dist, precomputed_direction, face_offset, direction_weight);
|
||||||
|
|
||||||
if(clipmap_blend > 0.0 && clipmap_index < voxelgiClipmapCount - 1) {
|
if(totalBlend > 0.05 && clipmap_index < voxelgiClipmapCount - 1) {
|
||||||
vec4 mipSampleNext = sampleVoxel(voxels, p0, clipmaps, clipmap_index + 1.0, step_dist, precomputed_direction, face_offset, direction_weight);
|
vec4 mipSampleNext = sampleVoxel(voxels, p0, clipmaps, clipmap_index + 1.0, step_dist, precomputed_direction, face_offset, direction_weight);
|
||||||
mipSample = mix(mipSample, mipSampleNext, clipmap_blend);
|
int baseNext = int((clipmap_index + 1.0) * 10);
|
||||||
|
float voxelSizeCoarse = float(clipmaps[baseNext]);
|
||||||
|
mipSampleNext *= voxelSizeCoarse / voxelSize;
|
||||||
|
mipSample = mix(mipSample, mipSampleNext, totalBlend);
|
||||||
}
|
}
|
||||||
|
|
||||||
sampleCol += (1.0 - sampleCol.a) * mipSample;
|
sampleCol += (1.0 - sampleCol.a) * mipSample;
|
||||||
|
|
||||||
float stepSizeCurrent = step_size;
|
float stepSizeCurrent = step_size;
|
||||||
if (use_sdf) {
|
if (use_sdf) {
|
||||||
// half texel correction is applied to avoid sampling over current clipmap:
|
|
||||||
const vec3 half_texel = vec3(0.5) / voxelgiResolution;
|
|
||||||
vec3 tc0 = clamp(samplePos, half_texel, 1 - half_texel);
|
vec3 tc0 = clamp(samplePos, half_texel, 1 - half_texel);
|
||||||
tc0.y = (tc0.y + clipmap_index) / voxelgiClipmapCount; // remap into clipmap
|
tc0.y = (tc0.y + clipmap_index) / voxelgiClipmapCount; // remap into clipmap
|
||||||
float sdf = textureLod(voxelsSDF, tc0, 0).r;
|
float sdf = textureLod(voxelsSDF, tc0, 0).r;
|
||||||
@ -141,6 +156,7 @@ vec4 traceCone(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 ori
|
|||||||
}
|
}
|
||||||
step_dist = diam * stepSizeCurrent;
|
step_dist = diam * stepSizeCurrent;
|
||||||
dist += step_dist;
|
dist += step_dist;
|
||||||
|
steps++;
|
||||||
}
|
}
|
||||||
return sampleCol;
|
return sampleCol;
|
||||||
}
|
}
|
||||||
@ -148,18 +164,17 @@ vec4 traceCone(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 ori
|
|||||||
vec4 traceDiffuse(const vec3 origin, const vec3 normal, const sampler3D voxels, const float clipmaps[voxelgiClipmapCount * 10]) {
|
vec4 traceDiffuse(const vec3 origin, const vec3 normal, const sampler3D voxels, const float clipmaps[voxelgiClipmapCount * 10]) {
|
||||||
float sum = 0.0;
|
float sum = 0.0;
|
||||||
vec4 amount = vec4(0.0);
|
vec4 amount = vec4(0.0);
|
||||||
mat3 TBN = makeTangentBasis(normal);
|
for (int i = 0; i < diffuseConeCount; ++i) {
|
||||||
for (int i = 0; i < DIFFUSE_CONE_COUNT; ++i) {
|
vec3 coneDir = diffuseConeDirections[i];
|
||||||
vec3 coneDir = TBN * DIFFUSE_CONE_DIRECTIONS[i];
|
|
||||||
const float cosTheta = dot(normal, coneDir);
|
const float cosTheta = dot(normal, coneDir);
|
||||||
if (cosTheta <= 0)
|
if (cosTheta <= 0)
|
||||||
continue;
|
continue;
|
||||||
int precomputed_direction = 6 + i;
|
int precomputed_direction = 6 + i;
|
||||||
amount += traceCone(voxels, dummy, origin, normal, coneDir, precomputed_direction, false, DIFFUSE_CONE_APERTURE, 1.0, clipmaps) * cosTheta;
|
amount += traceCone(voxels, voxels, origin, normal, coneDir, precomputed_direction, false, diffuseConeAperture, 1.0, clipmaps) * cosTheta;
|
||||||
sum += cosTheta;
|
sum += cosTheta;
|
||||||
}
|
}
|
||||||
|
|
||||||
amount /= sum;
|
amount /= max(sum, 0.0001);
|
||||||
amount.rgb = max(amount.rgb, vec3(0.0));
|
amount.rgb = max(amount.rgb, vec3(0.0));
|
||||||
amount.a = clamp(amount.a, 0.0, 1.0);
|
amount.a = clamp(amount.a, 0.0, 1.0);
|
||||||
|
|
||||||
@ -186,7 +201,7 @@ vec4 traceRefraction(const vec3 origin, const vec3 normal, sampler3D voxels, sam
|
|||||||
amount.rgb = max(vec3(0.0), amount.rgb);
|
amount.rgb = max(vec3(0.0), amount.rgb);
|
||||||
amount.a = clamp(amount.a, 0.0, 1.0);
|
amount.a = clamp(amount.a, 0.0, 1.0);
|
||||||
|
|
||||||
return amount * voxelgiOcc;
|
return amount * voxelgiOcc * voxelgiRefr;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -197,7 +212,7 @@ float traceConeAO(const sampler3D voxels, const vec3 origin, const vec3 n, const
|
|||||||
float dist = voxelSize0;
|
float dist = voxelSize0;
|
||||||
float step_dist = dist;
|
float step_dist = dist;
|
||||||
vec3 samplePos;
|
vec3 samplePos;
|
||||||
vec3 start_pos = origin + n * voxelSize0;
|
vec3 start_pos = origin + n * voxelSize0 * voxelgiOffset;
|
||||||
int clipmap_index0 = 0;
|
int clipmap_index0 = 0;
|
||||||
|
|
||||||
vec3 aniso_direction = -dir;
|
vec3 aniso_direction = -dir;
|
||||||
@ -205,20 +220,23 @@ float traceConeAO(const sampler3D voxels, const vec3 origin, const vec3 n, const
|
|||||||
aniso_direction.x > 0.0 ? 0.0 : 1.0,
|
aniso_direction.x > 0.0 ? 0.0 : 1.0,
|
||||||
aniso_direction.y > 0.0 ? 2.0 : 3.0,
|
aniso_direction.y > 0.0 ? 2.0 : 3.0,
|
||||||
aniso_direction.z > 0.0 ? 4.0 : 5.0
|
aniso_direction.z > 0.0 ? 4.0 : 5.0
|
||||||
) / (6 + DIFFUSE_CONE_COUNT);
|
) / (6 + diffuseConeCount);
|
||||||
vec3 direction_weight = abs(dir);
|
vec3 direction_weight = abs(dir);
|
||||||
|
|
||||||
float coneCoefficient = 2.0 * tan(aperture * 0.5);
|
float coneCoefficient = 2.0 * tan(aperture * 0.5);
|
||||||
|
|
||||||
while (sampleCol < 1.0 && dist < MAX_DISTANCE && clipmap_index0 < voxelgiClipmapCount) {
|
int steps = 0;
|
||||||
|
while (sampleCol < 1.0 && dist < MAX_DISTANCE && clipmap_index0 < voxelgiClipmapCount && steps < MAX_CONE_STEPS) {
|
||||||
float mipSample = 0.0;
|
float mipSample = 0.0;
|
||||||
float diam = max(voxelSize0, dist * coneCoefficient);
|
float diam = max(voxelSize0, dist * coneCoefficient);
|
||||||
float lod = clamp(log2(diam / voxelSize0), clipmap_index0, voxelgiClipmapCount - 1);
|
float lod = clamp(log2(diam / voxelSize0), clipmap_index0, voxelgiClipmapCount - 1);
|
||||||
float clipmap_index = floor(lod);
|
float clipmap_index = floor(lod);
|
||||||
float clipmap_blend = fract(lod);
|
float clipmap_blend = smoothstep(0.0, 1.0, fract(lod));
|
||||||
vec3 p0 = start_pos + dir * dist;
|
vec3 p0 = start_pos + dir * dist;
|
||||||
|
|
||||||
samplePos = (p0 - vec3(clipmaps[int(clipmap_index * 10 + 4)], clipmaps[int(clipmap_index * 10 + 5)], clipmaps[int(clipmap_index * 10 + 6)])) / (float(clipmaps[int(clipmap_index * 10)]) * voxelgiResolution.x);
|
int base = int(clipmap_index * 10);
|
||||||
|
float voxelSize = float(clipmaps[base]);
|
||||||
|
samplePos = (p0 - vec3(clipmaps[base + 4], clipmaps[base + 5], clipmaps[base + 6])) / (voxelSize * voxelgiResolution);
|
||||||
samplePos = samplePos * 0.5 + 0.5;
|
samplePos = samplePos * 0.5 + 0.5;
|
||||||
|
|
||||||
if ((any(notEqual(clamp(samplePos, 0.0, 1.0), samplePos)))) {
|
if ((any(notEqual(clamp(samplePos, 0.0, 1.0), samplePos)))) {
|
||||||
@ -226,17 +244,27 @@ float traceConeAO(const sampler3D voxels, const vec3 origin, const vec3 n, const
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Edge fade: blend toward coarser clipmap near boundaries
|
||||||
|
vec3 edgeDist = min(samplePos, 1.0 - samplePos);
|
||||||
|
float minEdgeDist = min(min(edgeDist.x, edgeDist.y), edgeDist.z);
|
||||||
|
float edgeBlend = 1.0 - smoothstep(0.0, 0.1, minEdgeDist);
|
||||||
|
float totalBlend = max(clipmap_blend, edgeBlend);
|
||||||
|
|
||||||
mipSample = sampleVoxel(voxels, p0, clipmaps, clipmap_index, step_dist, precomputed_direction, face_offset, direction_weight);
|
mipSample = sampleVoxel(voxels, p0, clipmaps, clipmap_index, step_dist, precomputed_direction, face_offset, direction_weight);
|
||||||
|
|
||||||
if(clipmap_blend > 0.0 && clipmap_index < voxelgiClipmapCount - 1) {
|
if(totalBlend > 0.05 && clipmap_index < voxelgiClipmapCount - 1) {
|
||||||
float mipSampleNext = sampleVoxel(voxels, p0, clipmaps, clipmap_index + 1.0, step_dist, precomputed_direction, face_offset, direction_weight);
|
float mipSampleNext = sampleVoxel(voxels, p0, clipmaps, clipmap_index + 1.0, step_dist, precomputed_direction, face_offset, direction_weight);
|
||||||
mipSample = mix(mipSample, mipSampleNext, clipmap_blend);
|
int baseNext = int((clipmap_index + 1.0) * 10);
|
||||||
|
float voxelSizeCoarse = float(clipmaps[baseNext]);
|
||||||
|
mipSampleNext *= voxelSizeCoarse / voxelSize;
|
||||||
|
mipSample = mix(mipSample, mipSampleNext, totalBlend);
|
||||||
}
|
}
|
||||||
|
|
||||||
sampleCol += (1.0 - sampleCol) * mipSample;
|
sampleCol += (1.0 - sampleCol) * mipSample;
|
||||||
|
|
||||||
step_dist = diam * step_size;
|
step_dist = diam * step_size;
|
||||||
dist += step_dist;
|
dist += step_dist;
|
||||||
|
steps++;
|
||||||
}
|
}
|
||||||
return sampleCol;
|
return sampleCol;
|
||||||
}
|
}
|
||||||
@ -245,18 +273,18 @@ float traceConeAO(const sampler3D voxels, const vec3 origin, const vec3 n, const
|
|||||||
float traceAO(const vec3 origin, const vec3 normal, const sampler3D voxels, const float clipmaps[voxelgiClipmapCount * 10]) {
|
float traceAO(const vec3 origin, const vec3 normal, const sampler3D voxels, const float clipmaps[voxelgiClipmapCount * 10]) {
|
||||||
float sum = 0.0;
|
float sum = 0.0;
|
||||||
float amount = 0.0;
|
float amount = 0.0;
|
||||||
for (int i = 0; i < DIFFUSE_CONE_COUNT; i++) {
|
for (int i = 0; i < diffuseConeCount; i++) {
|
||||||
vec3 coneDir = DIFFUSE_CONE_DIRECTIONS[i];
|
vec3 coneDir = diffuseConeDirections[i];
|
||||||
int precomputed_direction = 6 + i;
|
int precomputed_direction = 6 + i;
|
||||||
const float cosTheta = dot(normal, coneDir);
|
const float cosTheta = dot(normal, coneDir);
|
||||||
if (cosTheta <= 0)
|
if (cosTheta <= 0)
|
||||||
continue;
|
continue;
|
||||||
amount += traceConeAO(voxels, origin, normal, coneDir, precomputed_direction, DIFFUSE_CONE_APERTURE, 1.0, clipmaps) * cosTheta;
|
amount += traceConeAO(voxels, origin, normal, coneDir, precomputed_direction, diffuseConeAperture, 1.0, clipmaps) * cosTheta;
|
||||||
sum += cosTheta;
|
sum += cosTheta;
|
||||||
}
|
}
|
||||||
amount /= sum;
|
amount /= max(sum, 0.0001);
|
||||||
amount = clamp(amount, 0.0, 1.0);
|
amount = clamp(amount, 0.0, 1.0);
|
||||||
return amount * voxelgiOcc;
|
return amount;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -267,7 +295,7 @@ float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const v
|
|||||||
float dist = voxelSize0;
|
float dist = voxelSize0;
|
||||||
float step_dist = dist;
|
float step_dist = dist;
|
||||||
vec3 samplePos;
|
vec3 samplePos;
|
||||||
vec3 start_pos = origin + n * voxelSize0;
|
vec3 start_pos = origin + n * voxelSize0 * voxelgiOffset;
|
||||||
int clipmap_index0 = 0;
|
int clipmap_index0 = 0;
|
||||||
|
|
||||||
vec3 aniso_direction = -dir;
|
vec3 aniso_direction = -dir;
|
||||||
@ -275,19 +303,23 @@ float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const v
|
|||||||
aniso_direction.x > 0.0 ? 0.0 : 1.0,
|
aniso_direction.x > 0.0 ? 0.0 : 1.0,
|
||||||
aniso_direction.y > 0.0 ? 2.0 : 3.0,
|
aniso_direction.y > 0.0 ? 2.0 : 3.0,
|
||||||
aniso_direction.z > 0.0 ? 4.0 : 5.0
|
aniso_direction.z > 0.0 ? 4.0 : 5.0
|
||||||
) / (6 + DIFFUSE_CONE_COUNT);
|
) / (6 + diffuseConeCount);
|
||||||
vec3 direction_weight = abs(dir);
|
vec3 direction_weight = abs(dir);
|
||||||
float coneCoefficient = 2.0 * tan(aperture * 0.5);
|
float coneCoefficient = 2.0 * tan(aperture * 0.5);
|
||||||
|
|
||||||
while (sampleCol < 1.0 && dist < MAX_DISTANCE && clipmap_index0 < voxelgiClipmapCount) {
|
const vec3 half_texel = vec3(0.5) / voxelgiResolution;
|
||||||
|
int steps = 0;
|
||||||
|
while (sampleCol < 1.0 && dist < MAX_DISTANCE && clipmap_index0 < voxelgiClipmapCount && steps < MAX_CONE_STEPS) {
|
||||||
float mipSample = 0.0;
|
float mipSample = 0.0;
|
||||||
float diam = max(voxelSize0, dist * coneCoefficient);
|
float diam = max(voxelSize0, dist * coneCoefficient);
|
||||||
float lod = clamp(log2(diam / voxelSize0), clipmap_index0, voxelgiClipmapCount - 1);
|
float lod = clamp(log2(diam / voxelSize0), clipmap_index0, voxelgiClipmapCount - 1);
|
||||||
float clipmap_index = floor(lod);
|
float clipmap_index = floor(lod);
|
||||||
float clipmap_blend = fract(lod);
|
float clipmap_blend = smoothstep(0.0, 1.0, fract(lod));
|
||||||
vec3 p0 = start_pos + dir * dist;
|
vec3 p0 = start_pos + dir * dist;
|
||||||
|
|
||||||
samplePos = (p0 - vec3(clipmaps[int(clipmap_index * 10 + 4)], clipmaps[int(clipmap_index * 10 + 5)], clipmaps[int(clipmap_index * 10 + 6)])) / (float(clipmaps[int(clipmap_index * 10)]) * voxelgiResolution);
|
int base = int(clipmap_index * 10);
|
||||||
|
float voxelSize = float(clipmaps[base]);
|
||||||
|
samplePos = (p0 - vec3(clipmaps[base + 4], clipmaps[base + 5], clipmaps[base + 6])) / (voxelSize * voxelgiResolution);
|
||||||
samplePos = samplePos * 0.5 + 0.5;
|
samplePos = samplePos * 0.5 + 0.5;
|
||||||
|
|
||||||
if ((any(notEqual(samplePos, clamp(samplePos, 0.0, 1.0))))) {
|
if ((any(notEqual(samplePos, clamp(samplePos, 0.0, 1.0))))) {
|
||||||
@ -295,27 +327,34 @@ float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const v
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Edge fade: blend toward coarser clipmap near boundaries
|
||||||
|
vec3 edgeDist = min(samplePos, 1.0 - samplePos);
|
||||||
|
float minEdgeDist = min(min(edgeDist.x, edgeDist.y), edgeDist.z);
|
||||||
|
float edgeBlend = 1.0 - smoothstep(0.0, 0.1, minEdgeDist);
|
||||||
|
float totalBlend = max(clipmap_blend, edgeBlend);
|
||||||
|
|
||||||
#ifdef _VoxelAOvar
|
#ifdef _VoxelAOvar
|
||||||
mipSample = sampleVoxel(voxels, p0, clipmaps, clipmap_index, step_dist, 0, face_offset, direction_weight);
|
mipSample = sampleVoxel(voxels, p0, clipmaps, clipmap_index, step_dist, 0, face_offset, direction_weight);
|
||||||
#else
|
#else
|
||||||
mipSample = sampleVoxel(voxels, p0, clipmaps, clipmap_index, step_dist, 0, face_offset, direction_weight).a;
|
mipSample = sampleVoxel(voxels, p0, clipmaps, clipmap_index, step_dist, 0, face_offset, direction_weight).a;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(clipmap_blend > 0.0 && clipmap_index < voxelgiClipmapCount - 1) {
|
if(totalBlend > 0.05 && clipmap_index < voxelgiClipmapCount - 1) {
|
||||||
|
int baseNext = int((clipmap_index + 1.0) * 10);
|
||||||
|
float voxelSizeCoarse = float(clipmaps[baseNext]);
|
||||||
|
float scaleRatio = voxelSizeCoarse / voxelSize;
|
||||||
#ifdef _VoxelAOvar
|
#ifdef _VoxelAOvar
|
||||||
float mipSampleNext = sampleVoxel(voxels, p0, clipmaps, clipmap_index + 1.0, step_dist, 0, face_offset, direction_weight);
|
float mipSampleNext = sampleVoxel(voxels, p0, clipmaps, clipmap_index + 1.0, step_dist, 0, face_offset, direction_weight) * scaleRatio;
|
||||||
#else
|
#else
|
||||||
float mipSampleNext = sampleVoxel(voxels, p0, clipmaps, clipmap_index + 1.0, step_dist, 0, face_offset, direction_weight).a;
|
float mipSampleNext = sampleVoxel(voxels, p0, clipmaps, clipmap_index + 1.0, step_dist, 0, face_offset, direction_weight).a * scaleRatio;
|
||||||
#endif
|
#endif
|
||||||
mipSample = mix(mipSample, mipSampleNext, clipmap_blend);
|
mipSample = mix(mipSample, mipSampleNext, totalBlend);
|
||||||
}
|
}
|
||||||
|
|
||||||
sampleCol += (1.0 - sampleCol) * mipSample;
|
sampleCol += (1.0 - sampleCol) * mipSample;
|
||||||
|
|
||||||
float stepSizeCurrent = step_size;
|
float stepSizeCurrent = step_size;
|
||||||
|
|
||||||
// half texel correction is applied to avoid sampling over current clipmap:
|
|
||||||
const vec3 half_texel = vec3(0.5) / voxelgiResolution;
|
|
||||||
vec3 tc0 = clamp(samplePos, half_texel, 1 - half_texel);
|
vec3 tc0 = clamp(samplePos, half_texel, 1 - half_texel);
|
||||||
tc0.y = (tc0.y + clipmap_index) / voxelgiClipmapCount; // remap into clipmap
|
tc0.y = (tc0.y + clipmap_index) / voxelgiClipmapCount; // remap into clipmap
|
||||||
float sdf = textureLod(voxelsSDF, tc0, 0.0).r;
|
float sdf = textureLod(voxelsSDF, tc0, 0.0).r;
|
||||||
@ -323,6 +362,7 @@ float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const v
|
|||||||
|
|
||||||
step_dist = diam * stepSizeCurrent;
|
step_dist = diam * stepSizeCurrent;
|
||||||
dist += step_dist;
|
dist += step_dist;
|
||||||
|
steps++;
|
||||||
}
|
}
|
||||||
return sampleCol;
|
return sampleCol;
|
||||||
}
|
}
|
||||||
@ -330,7 +370,7 @@ float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const v
|
|||||||
|
|
||||||
float traceShadow(const vec3 origin, const vec3 normal, const sampler3D voxels, const sampler3D voxelsSDF, const vec3 dir, const float clipmaps[voxelgiClipmapCount * 10], const vec2 pixel, const vec2 velocity) {
|
float traceShadow(const vec3 origin, const vec3 normal, const sampler3D voxels, const sampler3D voxelsSDF, const vec3 dir, const float clipmaps[voxelgiClipmapCount * 10], const vec2 pixel, const vec2 velocity) {
|
||||||
vec3 P = origin + dir * (BayerMatrix8[int(pixel.x + velocity.x) % 8][int(pixel.y + velocity.y) % 8] - 0.5) * voxelgiStep;
|
vec3 P = origin + dir * (BayerMatrix8[int(pixel.x + velocity.x) % 8][int(pixel.y + velocity.y) % 8] - 0.5) * voxelgiStep;
|
||||||
float amount = traceConeShadow(voxels, voxelsSDF, P, normal, dir, SHADOW_CONE_APERTURE, voxelgiStep, clipmaps);
|
float amount = traceConeShadow(voxels, voxelsSDF, P, normal, dir, voxelgiAperture, voxelgiStep, clipmaps);
|
||||||
amount = clamp(amount, 0.0, 1.0);
|
amount = clamp(amount, 0.0, 1.0);
|
||||||
return amount * voxelgiOcc;
|
return amount * voxelgiOcc;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,46 +20,25 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const int DIFFUSE_CONE_COUNT = 16;
|
const float diffuseConeAperture = radians(39.0);
|
||||||
|
|
||||||
const float SHADOW_CONE_APERTURE = radians(15.0);
|
const vec3 diffuseConeDirections[16] = vec3[](
|
||||||
|
vec3( 0.3480, 0.0000, 0.9375),
|
||||||
const float DIFFUSE_CONE_APERTURE = 0.872665;
|
vec3(-0.4299, 0.3938, 0.8125),
|
||||||
|
vec3( 0.0635, -0.7234, 0.6875),
|
||||||
mat3 makeTangentBasis(const vec3 normal) {
|
vec3( 0.5031, 0.6561, 0.5625),
|
||||||
// Create a tangent basis from normal vector
|
vec3(-0.8855, -0.1566, 0.4375),
|
||||||
vec3 tangent;
|
vec3( 0.8015, -0.5098, 0.3125),
|
||||||
vec3 bitangent;
|
vec3(-0.2550, 0.9486, 0.1875),
|
||||||
|
vec3(-0.4600, -0.8857, 0.0625),
|
||||||
// Compute tangent (Frisvad's method)
|
vec3( 0.9375, 0.3424, -0.0625),
|
||||||
if (abs(normal.z) < 0.999) {
|
vec3(-0.9080, 0.3748, -0.1875),
|
||||||
tangent = normalize(cross(vec3(0, 1, 0), normal));
|
vec3( 0.4026, -0.8604, -0.3125),
|
||||||
} else {
|
vec3( 0.2691, 0.8580, -0.4375),
|
||||||
tangent = normalize(cross(normal, vec3(1, 0, 0)));
|
vec3(-0.7154, -0.4146, -0.5625),
|
||||||
}
|
vec3( 0.7092, -0.1559, -0.6875),
|
||||||
bitangent = cross(normal, tangent);
|
vec3(-0.3353, 0.4769, -0.8125),
|
||||||
|
vec3(-0.0447, -0.3451, -0.9375)
|
||||||
return mat3(tangent, bitangent, normal);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 16 optimized cone directions for hemisphere sampling (Z-up, normalized)
|
|
||||||
const vec3 DIFFUSE_CONE_DIRECTIONS[16] = vec3[](
|
|
||||||
vec3(0.707107, 0.000000, 0.707107), // Front
|
|
||||||
vec3(-0.707107, 0.000000, 0.707107), // Back
|
|
||||||
vec3(0.000000, 0.707107, 0.707107), // Right
|
|
||||||
vec3(0.000000, -0.707107, 0.707107), // Left
|
|
||||||
vec3(0.500000, 0.500000, 0.707107), // Front-right
|
|
||||||
vec3(-0.500000, 0.500000, 0.707107), // Back-right
|
|
||||||
vec3(0.500000, -0.500000, 0.707107), // Front-left
|
|
||||||
vec3(-0.500000, -0.500000, 0.707107),// Back-left
|
|
||||||
vec3(0.353553, 0.000000, 0.935414), // Narrow front
|
|
||||||
vec3(-0.353553, 0.000000, 0.935414), // Narrow back
|
|
||||||
vec3(0.000000, 0.353553, 0.935414), // Narrow right
|
|
||||||
vec3(0.000000, -0.353553, 0.935414), // Narrow left
|
|
||||||
vec3(0.270598, 0.270598, 0.923880), // Narrow front-right
|
|
||||||
vec3(-0.270598, 0.270598, 0.923880), // Narrow back-right
|
|
||||||
vec3(0.270598, -0.270598, 0.923880), // Narrow front-left
|
|
||||||
vec3(-0.270598, -0.270598, 0.923880) // Narrow back-left
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// TO DO - Disabled momentarily instead of changing formulas
|
// TO DO - Disabled momentarily instead of changing formulas
|
||||||
|
|||||||
@ -170,4 +170,88 @@ void unpackFloatInt16(float val, out float f, out uint i) {
|
|||||||
f = (bitsValue & ~(0xF << numBitFloat)) / maxValFloat;
|
f = (bitsValue & ~(0xF << numBitFloat)) / maxValFloat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _ExtBRDF
|
||||||
|
// extended material parameters by material slot ID returns vec4s (28 floats) of extended BRDF parameters
|
||||||
|
void getMaterialParams(uint matid, out vec4 p0, out vec4 p1, out vec4 p2, out vec4 p3,
|
||||||
|
out vec4 p4, out vec4 p5, out vec4 p6, out vec4 p7) {
|
||||||
|
uint base = matid * 8u;
|
||||||
|
#if defined(_Anisotropy) || defined(_Sheen)
|
||||||
|
p0 = materialParams[base];
|
||||||
|
#else
|
||||||
|
p0 = vec4(0.0);
|
||||||
|
#endif
|
||||||
|
#if defined(_ClearCoat)
|
||||||
|
p1 = materialParams[base + 1u];
|
||||||
|
#else
|
||||||
|
p1 = vec4(0.0);
|
||||||
|
#endif
|
||||||
|
#if defined(_ClearCoat) || defined(_Transmission)
|
||||||
|
p2 = materialParams[base + 2u];
|
||||||
|
#else
|
||||||
|
p2 = vec4(0.0);
|
||||||
|
#endif
|
||||||
|
#if defined(_Transmission) || defined(_SSS)
|
||||||
|
p3 = materialParams[base + 3u];
|
||||||
|
#else
|
||||||
|
p3 = vec4(0.0);
|
||||||
|
#endif
|
||||||
|
#if defined(_SSS)
|
||||||
|
p4 = materialParams[base + 4u];
|
||||||
|
#else
|
||||||
|
p4 = vec4(0.0);
|
||||||
|
#endif
|
||||||
|
#if defined(_Sheen) || defined(_SSS)
|
||||||
|
p5 = materialParams[base + 5u];
|
||||||
|
#else
|
||||||
|
p5 = vec4(0.0);
|
||||||
|
#endif
|
||||||
|
#if defined(_ExtBRDF)
|
||||||
|
p6 = materialParams[base + 6u];
|
||||||
|
#else
|
||||||
|
p6 = vec4(0.0);
|
||||||
|
#endif
|
||||||
|
#if defined(_SSS)
|
||||||
|
p7 = materialParams[base + 7u];
|
||||||
|
#else
|
||||||
|
p7 = vec4(0.0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float packIOR(float ior) {
|
||||||
|
return clamp((ior - 1.0) / 1.5, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float unpackIOR(float packed) {
|
||||||
|
return packed * 1.5 + 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef PI
|
||||||
|
#define PI 3.1415926535
|
||||||
|
#endif
|
||||||
|
#ifndef PI2
|
||||||
|
#define PI2 6.2831853071
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float encodeTangent(vec3 tangent, vec3 normal) {
|
||||||
|
if (length(tangent) < 0.5) return -1.0;
|
||||||
|
vec3 t = normalize(tangent);
|
||||||
|
vec3 n = normalize(normal);
|
||||||
|
vec3 ref = abs(n.y) < 0.999 ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0);
|
||||||
|
vec3 r = normalize(ref - n * dot(ref, n));
|
||||||
|
vec3 b = cross(n, r);
|
||||||
|
float angle = atan(dot(t, b), dot(t, r));
|
||||||
|
return (angle / (2.0 * PI) + 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 decodeTangent(float enc, vec3 normal) {
|
||||||
|
if (enc < 0.0) return vec3(1.0, 0.0, 0.0);
|
||||||
|
vec3 n = normalize(normal);
|
||||||
|
vec3 ref = abs(n.y) < 0.999 ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0);
|
||||||
|
vec3 r = normalize(ref - n * dot(ref, n));
|
||||||
|
vec3 b = cross(n, r);
|
||||||
|
float angle = (enc - 0.5) * 2.0 * PI;
|
||||||
|
return normalize(r * cos(angle) + b * sin(angle));
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -3,7 +3,9 @@ uniform sampler2D texIES;
|
|||||||
|
|
||||||
float iesAttenuation(vec3 l) {
|
float iesAttenuation(vec3 l) {
|
||||||
|
|
||||||
const float PI = 3.1415926535;
|
#ifndef PI
|
||||||
|
#define PI 3.1415926535
|
||||||
|
#endif
|
||||||
// https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
|
// https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
|
||||||
// Sample direction into light space
|
// Sample direction into light space
|
||||||
// vec3 iesSampleDirection = mul(light.worldToLight , -L);
|
// vec3 iesSampleDirection = mul(light.worldToLight , -L);
|
||||||
|
|||||||
@ -51,7 +51,9 @@
|
|||||||
//!uniform sampler2D shadowMapAtlasTransparent;
|
//!uniform sampler2D shadowMapAtlasTransparent;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef _SinglePoint
|
||||||
uniform vec2 lightProj;
|
uniform vec2 lightProj;
|
||||||
|
#endif
|
||||||
#ifdef _ShadowMapAtlas
|
#ifdef _ShadowMapAtlas
|
||||||
#ifndef _SingleAtlas
|
#ifndef _SingleAtlas
|
||||||
uniform sampler2DShadow shadowMapAtlasPoint;
|
uniform sampler2DShadow shadowMapAtlasPoint;
|
||||||
@ -92,7 +94,6 @@ uniform vec3 lightArea3;
|
|||||||
uniform sampler2D sltcMat;
|
uniform sampler2D sltcMat;
|
||||||
uniform sampler2D sltcMag;
|
uniform sampler2D sltcMag;
|
||||||
#ifdef _ShadowMap
|
#ifdef _ShadowMap
|
||||||
#ifndef _Spot
|
|
||||||
#ifdef _SinglePoint
|
#ifdef _SinglePoint
|
||||||
uniform sampler2DShadow shadowMapSpot[1];
|
uniform sampler2DShadow shadowMapSpot[1];
|
||||||
#ifdef _ShadowMapTransparent
|
#ifdef _ShadowMapTransparent
|
||||||
@ -100,18 +101,10 @@ uniform sampler2D sltcMag;
|
|||||||
#endif
|
#endif
|
||||||
uniform mat4 LWVPSpotArray[1];
|
uniform mat4 LWVPSpotArray[1];
|
||||||
#endif
|
#endif
|
||||||
#ifdef _Clusters
|
|
||||||
uniform sampler2DShadow shadowMapSpot[maxLightsCluster];
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
uniform sampler2D shadowMapSpotTransparent[maxLightsCluster];
|
|
||||||
#endif
|
|
||||||
uniform mat4 LWVPSpotArray[maxLightsCluster];
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, const vec3 lp, const vec3 lightCol,
|
vec3 sampleLightCore(const vec3 p, const vec3 n, const vec3 v, const float dotNV, const vec3 lp, const vec3 lightCol,
|
||||||
const vec3 albedo, const float rough, const float spec, const vec3 f0
|
const vec3 albedo, const float rough, const float spec, const vec3 f0
|
||||||
#ifdef _ShadowMap
|
#ifdef _ShadowMap
|
||||||
, int index, float bias, bool receiveShadow
|
, int index, float bias, bool receiveShadow
|
||||||
@ -122,23 +115,34 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
|
|||||||
#ifdef _Spot
|
#ifdef _Spot
|
||||||
, const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
|
, const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
|
||||||
#endif
|
#endif
|
||||||
#ifdef _VoxelShadow
|
#ifdef _ClearCoat
|
||||||
, sampler3D voxels, sampler3D voxelsSDF, float clipmaps[10 * voxelgiClipmapCount], vec2 velocity
|
, float clearcoat, float clearcoatRough, float coatIOR, vec3 coatTint, vec3 coatN
|
||||||
#endif
|
#endif
|
||||||
#ifdef _MicroShadowing
|
#ifdef _Sheen
|
||||||
, float occ
|
, float sheen, float sheenRough, vec3 sheenTint
|
||||||
#endif
|
#endif
|
||||||
#ifdef _SSRS
|
#ifdef _Anisotropy
|
||||||
, sampler2D gbufferD, mat4 invVP, vec3 eye
|
, float anisotropy, float anisoRot, vec3 tangent
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef _SSS
|
||||||
|
, float subsurface, vec3 sssColor, vec3 sssRadius, float sssAnisotropy
|
||||||
|
#endif
|
||||||
|
#ifdef _Transmission
|
||||||
|
, float transmission, float transRough, float ior, float thinWall
|
||||||
|
#endif
|
||||||
|
, out vec3 l_out
|
||||||
) {
|
) {
|
||||||
vec3 ld = lp - p;
|
vec3 ld = lp - p;
|
||||||
vec3 l = normalize(ld);
|
float dist = length(ld);
|
||||||
|
vec3 l = ld / dist;
|
||||||
vec3 h = normalize(v + l);
|
vec3 h = normalize(v + l);
|
||||||
float dotNH = max(0.0, dot(n, h));
|
float dotNH = max(0.0, dot(n, h));
|
||||||
float dotVH = max(0.0, dot(v, h));
|
float dotVH = max(0.0, dot(v, h));
|
||||||
float dotNL = max(0.0, dot(n, l));
|
float dotNL = max(0.0, dot(n, l));
|
||||||
|
|
||||||
|
#ifdef _VoxelPass
|
||||||
|
vec3 direct = vec3(dotNL);
|
||||||
|
#else
|
||||||
#ifdef _LTC
|
#ifdef _LTC
|
||||||
float theta = acos(dotNV);
|
float theta = acos(dotNV);
|
||||||
vec2 tuv = vec2(rough, theta / (0.5 * PI));
|
vec2 tuv = vec2(rough, theta / (0.5 * PI));
|
||||||
@ -153,35 +157,49 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
|
|||||||
float ltcdiff = ltcEvaluate(n, v, dotNV, p, mat3(1.0), lightArea0, lightArea1, lightArea2, lightArea3);
|
float ltcdiff = ltcEvaluate(n, v, dotNV, p, mat3(1.0), lightArea0, lightArea1, lightArea2, lightArea3);
|
||||||
vec3 direct = albedo * ltcdiff + ltcspec * spec * 0.05;
|
vec3 direct = albedo * ltcdiff + ltcspec * spec * 0.05;
|
||||||
#else
|
#else
|
||||||
|
#ifdef _Anisotropy
|
||||||
|
vec3 direct;
|
||||||
|
if (abs(anisotropy) > 0.001 && dot(tangent, tangent) > 0.001) {
|
||||||
|
vec3 bitangent = normalize(cross(n, tangent));
|
||||||
|
direct = lambertDiffuseBRDF(albedo, dotNL) +
|
||||||
|
anisotropicBRDF(f0, rough, anisotropy, anisoRot,
|
||||||
|
tangent, bitangent, n, l, v, dotNL, dotNV) * spec;
|
||||||
|
} else {
|
||||||
|
direct = lambertDiffuseBRDF(albedo, dotNL) +
|
||||||
|
specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec;
|
||||||
|
}
|
||||||
|
#else
|
||||||
vec3 direct = lambertDiffuseBRDF(albedo, dotNL) +
|
vec3 direct = lambertDiffuseBRDF(albedo, dotNL) +
|
||||||
specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec;
|
specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
direct *= attenuate(distance(p, lp));
|
// before attenuate/shadow so everything is properly shadowed in one pass
|
||||||
|
#ifdef _ExtBRDF
|
||||||
|
float layerWeight;
|
||||||
|
direct = applyExtBRDFLayers(direct, albedo, f0, rough,
|
||||||
|
dotNL, dotNV, dotNH, dotVH, n, l, v, h
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
, clearcoat, clearcoatRough, coatIOR, coatTint, coatN
|
||||||
|
#endif
|
||||||
|
#ifdef _Sheen
|
||||||
|
, sheen, sheenRough, sheenTint
|
||||||
|
#endif
|
||||||
|
#ifdef _Transmission
|
||||||
|
, transmission, transRough, ior, thinWall
|
||||||
|
#endif
|
||||||
|
, layerWeight);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
direct *= attenuate(dist);
|
||||||
direct *= min(lightCol, vec3(100.0));
|
direct *= min(lightCol, vec3(100.0));
|
||||||
|
|
||||||
#ifdef _MicroShadowing
|
|
||||||
direct *= clamp(dotNL + 2.0 * occ * occ - 1.0, 0.0, 1.0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _SSRS
|
|
||||||
direct *= traceShadowSS(l, p, gbufferD, invVP, eye);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _VoxelShadow
|
|
||||||
vec3 lightDir = l;
|
|
||||||
#ifdef _Spot
|
|
||||||
if (isSpot)
|
|
||||||
lightDir = spotDir;
|
|
||||||
#endif
|
|
||||||
direct *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, lightDir, clipmaps, gl_FragCoord.xy, velocity).r) * voxelgiShad;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _LTC
|
#ifdef _LTC
|
||||||
#ifdef _ShadowMap
|
#ifdef _ShadowMap
|
||||||
if (receiveShadow) {
|
if (receiveShadow) {
|
||||||
#ifdef _SinglePoint
|
#ifdef _SinglePoint
|
||||||
vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0);
|
vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 10, 1.0);
|
||||||
direct *= shadowTest(shadowMapSpot[0],
|
direct *= shadowTest(shadowMapSpot[0],
|
||||||
#ifdef _ShadowMapTransparent
|
#ifdef _ShadowMapTransparent
|
||||||
shadowMapSpotTransparent[0],
|
shadowMapSpotTransparent[0],
|
||||||
@ -193,7 +211,29 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
|
|||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
#ifdef _Clusters
|
#ifdef _Clusters
|
||||||
vec4 lPos = LWVPSpot[index] * vec4(p + n * bias * 10, 1.0);
|
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
|
||||||
|
#ifdef _ShadowMapAtlas
|
||||||
|
tileBounds = tileBoundsSpotArray[index];
|
||||||
|
direct *= shadowTest(
|
||||||
|
#ifdef _ShadowMapTransparent
|
||||||
|
#ifndef _SingleAtlas
|
||||||
|
shadowMapAtlasSpot, shadowMapAtlasSpotTransparent
|
||||||
|
#else
|
||||||
|
shadowMapAtlas, shadowMapAtlasTransparent
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#ifndef _SingleAtlas
|
||||||
|
shadowMapAtlasSpot
|
||||||
|
#else
|
||||||
|
shadowMapAtlas
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
, lPos.xyz / lPos.w, bias
|
||||||
|
#ifdef _ShadowMapTransparent
|
||||||
|
, transparent
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
#else
|
||||||
if (index == 0) direct *= shadowTest(shadowMapSpot[0],
|
if (index == 0) direct *= shadowTest(shadowMapSpot[0],
|
||||||
#ifdef _ShadowMapTransparent
|
#ifdef _ShadowMapTransparent
|
||||||
shadowMapSpotTransparent[0],
|
shadowMapSpotTransparent[0],
|
||||||
@ -231,8 +271,10 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
|
|||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
l_out = l;
|
||||||
return direct;
|
return direct;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -257,25 +299,26 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
|
|||||||
#ifdef _Clusters
|
#ifdef _Clusters
|
||||||
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
|
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
|
||||||
#ifdef _ShadowMapAtlas
|
#ifdef _ShadowMapAtlas
|
||||||
direct *= shadowTest(
|
tileBounds = tileBoundsSpotArray[index];
|
||||||
#ifdef _ShadowMapTransparent
|
direct *= shadowTest(
|
||||||
#ifndef _SingleAtlas
|
#ifdef _ShadowMapTransparent
|
||||||
shadowMapAtlasSpot, shadowMapAtlasSpotTransparent
|
#ifndef _SingleAtlas
|
||||||
#else
|
shadowMapAtlasSpot, shadowMapAtlasSpotTransparent
|
||||||
shadowMapAtlas, shadowMapAtlasTransparent
|
#else
|
||||||
#endif
|
shadowMapAtlas, shadowMapAtlasTransparent
|
||||||
#else
|
#endif
|
||||||
#ifndef _SingleAtlas
|
#else
|
||||||
shadowMapAtlasSpot
|
#ifndef _SingleAtlas
|
||||||
#else
|
shadowMapAtlasSpot
|
||||||
shadowMapAtlas
|
#else
|
||||||
#endif
|
shadowMapAtlas
|
||||||
#endif
|
#endif
|
||||||
, lPos.xyz / lPos.w, bias
|
#endif
|
||||||
#ifdef _ShadowMapTransparent
|
, lPos.xyz / lPos.w, bias
|
||||||
, transparent
|
#ifdef _ShadowMapTransparent
|
||||||
#endif
|
, transparent
|
||||||
);
|
#endif
|
||||||
|
);
|
||||||
#else
|
#else
|
||||||
if (index == 0) direct *= shadowTest(shadowMapSpot[0],
|
if (index == 0) direct *= shadowTest(shadowMapSpot[0],
|
||||||
#ifdef _ShadowMapTransparent
|
#ifdef _ShadowMapTransparent
|
||||||
@ -317,6 +360,7 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
l_out = l;
|
||||||
return direct;
|
return direct;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -403,9 +447,157 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
l_out = l;
|
||||||
return direct;
|
return direct;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, const vec3 lp, const vec3 lightCol,
|
||||||
|
const vec3 albedo, const float rough, const float spec, const vec3 f0
|
||||||
|
#ifdef _ShadowMap
|
||||||
|
, int index, float bias, bool receiveShadow
|
||||||
|
#ifdef _ShadowMapTransparent
|
||||||
|
, bool transparent
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#ifdef _Spot
|
||||||
|
, const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
|
||||||
|
#endif
|
||||||
|
#ifdef _VoxelShadow
|
||||||
|
, sampler3D voxels, sampler3D voxelsSDF, float clipmaps[10 * voxelgiClipmapCount], vec2 velocity
|
||||||
|
#endif
|
||||||
|
#ifdef _MicroShadowing
|
||||||
|
, float occ
|
||||||
|
#endif
|
||||||
|
#ifdef _SSRS
|
||||||
|
, sampler2D gbufferD, mat4 invVP, vec3 eye
|
||||||
|
#endif
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
, float clearcoat, float clearcoatRough, float coatIOR, vec3 coatTint, vec3 coatN
|
||||||
|
#endif
|
||||||
|
#ifdef _Sheen
|
||||||
|
, float sheen, float sheenRough, vec3 sheenTint
|
||||||
|
#endif
|
||||||
|
#ifdef _Anisotropy
|
||||||
|
, float anisotropy, float anisoRot, vec3 tangent
|
||||||
|
#endif
|
||||||
|
#ifdef _SSS
|
||||||
|
, float subsurface, vec3 sssColor, vec3 sssRadius, float sssAnisotropy
|
||||||
|
#endif
|
||||||
|
#ifdef _Transmission
|
||||||
|
, float transmission, float transRough, float ior, float thinWall
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
vec3 l;
|
||||||
|
vec3 direct = sampleLightCore(p, n, v, dotNV, lp, lightCol, albedo, rough, spec, f0
|
||||||
|
#ifdef _ShadowMap
|
||||||
|
, index, bias, receiveShadow
|
||||||
|
#ifdef _ShadowMapTransparent
|
||||||
|
, transparent
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#ifdef _Spot
|
||||||
|
, isSpot, spotSize, spotBlend, spotDir, scale, right
|
||||||
|
#endif
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
, clearcoat, clearcoatRough, coatIOR, coatTint, coatN
|
||||||
|
#endif
|
||||||
|
#ifdef _Sheen
|
||||||
|
, sheen, sheenRough, sheenTint
|
||||||
|
#endif
|
||||||
|
#ifdef _Anisotropy
|
||||||
|
, anisotropy, anisoRot, tangent
|
||||||
|
#endif
|
||||||
|
#ifdef _SSS
|
||||||
|
, subsurface, sssColor, sssRadius, sssAnisotropy
|
||||||
|
#endif
|
||||||
|
#ifdef _Transmission
|
||||||
|
, transmission, transRough, ior, thinWall
|
||||||
|
#endif
|
||||||
|
, l);
|
||||||
|
|
||||||
|
float dotNL = max(0.0, dot(n, l));
|
||||||
|
|
||||||
|
#ifdef _MicroShadowing
|
||||||
|
direct *= clamp(dotNL + 2.0 * occ * occ - 1.0, 0.0, 1.0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _SSRS
|
||||||
|
direct *= traceShadowSS(l, p, gbufferD, invVP, eye);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _VoxelShadow
|
||||||
|
vec3 lightDir = l;
|
||||||
|
#ifdef _Spot
|
||||||
|
if (isSpot)
|
||||||
|
lightDir = spotDir;
|
||||||
|
#endif
|
||||||
|
direct *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, lightDir, clipmaps, gl_FragCoord.xy, velocity).r) * voxelgiShad;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return direct;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backward-compatible overload for generated shaders that don't pass extended BRDF params
|
||||||
|
#ifdef _ExtBRDF
|
||||||
|
vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, const vec3 lp, const vec3 lightCol,
|
||||||
|
const vec3 albedo, const float rough, const float spec, const vec3 f0
|
||||||
|
#ifdef _ShadowMap
|
||||||
|
, int index, float bias, bool receiveShadow
|
||||||
|
#ifdef _ShadowMapTransparent
|
||||||
|
, bool transparent
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#ifdef _Spot
|
||||||
|
, const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
|
||||||
|
#endif
|
||||||
|
#ifdef _VoxelShadow
|
||||||
|
, sampler3D voxels, sampler3D voxelsSDF, float clipmaps[10 * voxelgiClipmapCount], vec2 velocity
|
||||||
|
#endif
|
||||||
|
#ifdef _MicroShadowing
|
||||||
|
, float occ
|
||||||
|
#endif
|
||||||
|
#ifdef _SSRS
|
||||||
|
, sampler2D gbufferD, mat4 invVP, vec3 eye
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
return sampleLight(p, n, v, dotNV, lp, lightCol, albedo, rough, spec, f0
|
||||||
|
#ifdef _ShadowMap
|
||||||
|
, index, bias, receiveShadow
|
||||||
|
#ifdef _ShadowMapTransparent
|
||||||
|
, transparent
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#ifdef _Spot
|
||||||
|
, isSpot, spotSize, spotBlend, spotDir, scale, right
|
||||||
|
#endif
|
||||||
|
#ifdef _VoxelShadow
|
||||||
|
, voxels, voxelsSDF, clipmaps, velocity
|
||||||
|
#endif
|
||||||
|
#ifdef _MicroShadowing
|
||||||
|
, occ
|
||||||
|
#endif
|
||||||
|
#ifdef _SSRS
|
||||||
|
, gbufferD, invVP, eye
|
||||||
|
#endif
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
, 0.0, 0.0, 1.5, vec3(1.0), n
|
||||||
|
#endif
|
||||||
|
#ifdef _Sheen
|
||||||
|
, 0.0, 0.0, vec3(1.0)
|
||||||
|
#endif
|
||||||
|
#ifdef _Anisotropy
|
||||||
|
, 0.0, 0.0, vec3(0.0)
|
||||||
|
#endif
|
||||||
|
#ifdef _SSS
|
||||||
|
, 0.0, vec3(0.0), vec3(0.0), 0.0
|
||||||
|
#endif
|
||||||
|
#ifdef _Transmission
|
||||||
|
, 0.0, 0.0, 1.45, 1.0
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#endif // _ExtBRDF
|
||||||
|
|
||||||
#ifdef _VoxelGI
|
#ifdef _VoxelGI
|
||||||
vec3 sampleLightVoxels(const vec3 p, const vec3 n, const vec3 v, const float dotNV, const vec3 lp, const vec3 lightCol,
|
vec3 sampleLightVoxels(const vec3 p, const vec3 n, const vec3 v, const float dotNV, const vec3 lp, const vec3 lightCol,
|
||||||
const vec3 albedo, const float rough, const float spec, const vec3 f0
|
const vec3 albedo, const float rough, const float spec, const vec3 f0
|
||||||
@ -418,263 +610,94 @@ vec3 sampleLightVoxels(const vec3 p, const vec3 n, const vec3 v, const float dot
|
|||||||
#ifdef _Spot
|
#ifdef _Spot
|
||||||
, const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
|
, const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
|
||||||
#endif
|
#endif
|
||||||
) {
|
#ifdef _ClearCoat
|
||||||
vec3 ld = lp - p;
|
, float clearcoat, float clearcoatRough, float coatIOR, vec3 coatTint, vec3 coatN
|
||||||
vec3 l = normalize(ld);
|
|
||||||
vec3 h = normalize(v + l);
|
|
||||||
float dotNH = max(0.0, dot(n, h));
|
|
||||||
float dotVH = max(0.0, dot(v, h));
|
|
||||||
float dotNL = max(0.0, dot(n, l));
|
|
||||||
|
|
||||||
#ifdef _LTC
|
|
||||||
float theta = acos(dotNV);
|
|
||||||
vec2 tuv = vec2(rough, theta / (0.5 * PI));
|
|
||||||
tuv = tuv * LUT_SCALE + LUT_BIAS;
|
|
||||||
vec4 t = textureLod(sltcMat, tuv, 0.0);
|
|
||||||
mat3 invM = mat3(
|
|
||||||
vec3(1.0, 0.0, t.y),
|
|
||||||
vec3(0.0, t.z, 0.0),
|
|
||||||
vec3(t.w, 0.0, t.x));
|
|
||||||
float ltcspec = ltcEvaluate(n, v, dotNV, p, invM, lightArea0, lightArea1, lightArea2, lightArea3);
|
|
||||||
ltcspec *= textureLod(sltcMag, tuv, 0.0).a;
|
|
||||||
float ltcdiff = ltcEvaluate(n, v, dotNV, p, mat3(1.0), lightArea0, lightArea1, lightArea2, lightArea3);
|
|
||||||
vec3 direct = albedo * ltcdiff + ltcspec * spec * 0.05;
|
|
||||||
#else
|
|
||||||
vec3 direct = lambertDiffuseBRDF(albedo, dotNL) +
|
|
||||||
specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec;
|
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef _Sheen
|
||||||
direct *= attenuate(distance(p, lp));
|
, float sheen, float sheenRough, vec3 sheenTint
|
||||||
// CRITICAL: Clamp light color to prevent extreme HDR values causing white sphere artifacts
|
|
||||||
direct *= min(lightCol, vec3(100.0));
|
|
||||||
|
|
||||||
#ifdef _LTC
|
|
||||||
#ifdef _ShadowMap
|
|
||||||
if (receiveShadow) {
|
|
||||||
#ifdef _SinglePoint
|
|
||||||
vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0);
|
|
||||||
direct *= shadowTest(shadowMapSpot[0],
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
shadowMapSpotTransparent[0],
|
|
||||||
#endif
|
|
||||||
lPos.xyz / lPos.w, bias
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
, transparent
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
#ifdef _Clusters
|
|
||||||
vec4 lPos = LWVPSpot[index] * vec4(p + n * bias * 10, 1.0);
|
|
||||||
if (index == 0) direct *= shadowTest(shadowMapSpot[0],
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
shadowMapSpotTransparent[0],
|
|
||||||
#endif
|
|
||||||
lPos.xyz / lPos.w, bias
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
, transparent
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
else if (index == 1) direct *= shadowTest(shadowMapSpot[1],
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
shadowMapSpotTransparent[1],
|
|
||||||
#endif
|
|
||||||
lPos.xyz / lPos.w, bias
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
, transparent
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
else if (index == 2) direct *= shadowTest(shadowMapSpot[2],
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
shadowMapSpotTransparent[2],
|
|
||||||
#endif
|
|
||||||
lPos.xyz / lPos.w, bias
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
, transparent
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
else if (index == 3) direct *= shadowTest(shadowMapSpot[3],
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
shadowMapSpotTransparent[3],
|
|
||||||
#endif
|
|
||||||
lPos.xyz / lPos.w, bias
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
, transparent
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
return direct;
|
#ifdef _Anisotropy
|
||||||
|
, float anisotropy, float anisoRot, vec3 tangent
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef _SSS
|
||||||
#ifdef _Spot
|
, float subsurface, vec3 sssColor, vec3 sssRadius, float sssAnisotropy
|
||||||
if (isSpot) {
|
#endif
|
||||||
direct *= spotlightMask(l, spotDir, right, scale, spotSize, spotBlend);
|
#ifdef _Transmission
|
||||||
|
, float transmission, float transRough, float ior, float thinWall
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
vec3 l;
|
||||||
|
return sampleLightCore(p, n, v, dotNV, lp, lightCol, albedo, rough, spec, f0
|
||||||
#ifdef _ShadowMap
|
#ifdef _ShadowMap
|
||||||
if (receiveShadow) {
|
, index, bias, receiveShadow
|
||||||
#ifdef _SinglePoint
|
#ifdef _ShadowMapTransparent
|
||||||
vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 10, 1.0);
|
, transparent
|
||||||
direct *= shadowTest(shadowMapSpot[0],
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
shadowMapSpotTransparent[0],
|
|
||||||
#endif
|
|
||||||
lPos.xyz / lPos.w, bias
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
, transparent
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
#ifdef _Clusters
|
|
||||||
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
|
|
||||||
#ifdef _ShadowMapAtlas
|
|
||||||
direct *= shadowTest(
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
#ifndef _SingleAtlas
|
|
||||||
shadowMapAtlasSpot, shadowMapAtlasSpotTransparent
|
|
||||||
#else
|
|
||||||
shadowMapAtlas, shadowMapAtlasTransparent
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#ifndef _SingleAtlas
|
|
||||||
shadowMapAtlasSpot
|
|
||||||
#else
|
|
||||||
shadowMapAtlas
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
, lPos.xyz / lPos.w, bias
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
, transparent
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
if (index == 0) direct *= shadowTest(shadowMapSpot[0],
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
shadowMapSpotTransparent[0],
|
|
||||||
#endif
|
|
||||||
lPos.xyz / lPos.w, bias
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
, transparent
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
else if (index == 1) direct *= shadowTest(shadowMapSpot[1],
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
shadowMapSpotTransparent[1],
|
|
||||||
#endif
|
|
||||||
lPos.xyz / lPos.w, bias
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
, transparent
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
else if (index == 2) direct *= shadowTest(shadowMapSpot[2],
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
shadowMapSpotTransparent[2],
|
|
||||||
#endif
|
|
||||||
lPos.xyz / lPos.w, bias
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
, transparent
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
else if (index == 3) direct *= shadowTest(shadowMapSpot[3],
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
shadowMapSpotTransparent[3],
|
|
||||||
#endif
|
|
||||||
lPos.xyz / lPos.w, bias
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
, transparent
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
return direct;
|
#endif
|
||||||
}
|
#ifdef _Spot
|
||||||
#endif
|
, isSpot, spotSize, spotBlend, spotDir, scale, right
|
||||||
|
#endif
|
||||||
#ifdef _LightIES
|
#ifdef _ClearCoat
|
||||||
direct *= iesAttenuation(-l);
|
, clearcoat, clearcoatRough, coatIOR, coatTint, coatN
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef _Sheen
|
||||||
#ifdef _ShadowMap
|
, sheen, sheenRough, sheenTint
|
||||||
if (receiveShadow) {
|
#endif
|
||||||
#ifdef _SinglePoint
|
#ifdef _Anisotropy
|
||||||
#ifndef _Spot
|
, anisotropy, anisoRot, tangent
|
||||||
direct *= PCFCube(shadowMapPoint[0],
|
#endif
|
||||||
#ifdef _ShadowMapTransparent
|
#ifdef _SSS
|
||||||
shadowMapPointTransparent[0],
|
, subsurface, sssColor, sssRadius, sssAnisotropy
|
||||||
#endif
|
#endif
|
||||||
ld, -l, bias, lightProj, n
|
#ifdef _Transmission
|
||||||
#ifdef _ShadowMapTransparent
|
, transmission, transRough, ior, thinWall
|
||||||
, transparent
|
#endif
|
||||||
#endif
|
, l);
|
||||||
);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#ifdef _Clusters
|
|
||||||
#ifdef _ShadowMapAtlas
|
|
||||||
direct *= PCFFakeCube(
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
#ifndef _SingleAtlas
|
|
||||||
shadowMapAtlasPoint, shadowMapAtlasPointTransparent
|
|
||||||
#else
|
|
||||||
shadowMapAtlas, shadowMapAtlasTransparent
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#ifndef _SingleAtlas
|
|
||||||
shadowMapAtlasPoint
|
|
||||||
#else
|
|
||||||
shadowMapAtlas
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
, ld, -l, bias, lightProj, n, index
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
, transparent
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
if (index == 0) direct *= PCFCube(shadowMapPoint[0],
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
shadowMapPointTransparent[0],
|
|
||||||
#endif
|
|
||||||
ld, -l, bias, lightProj, n
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
, transparent
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
else if (index == 1) direct *= PCFCube(shadowMapPoint[1],
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
shadowMapPointTransparent[1],
|
|
||||||
#endif
|
|
||||||
ld, -l, bias, lightProj, n
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
, transparent
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
else if (index == 2) direct *= PCFCube(shadowMapPoint[2],
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
shadowMapPointTransparent[2],
|
|
||||||
#endif
|
|
||||||
ld, -l, bias, lightProj, n
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
, transparent
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
else if (index == 3) direct *= PCFCube(shadowMapPoint[3],
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
shadowMapPointTransparent[3],
|
|
||||||
#endif
|
|
||||||
ld, -l, bias, lightProj, n
|
|
||||||
#ifdef _ShadowMapTransparent
|
|
||||||
, transparent
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return direct;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Backward-compatible overload for generated shaders that don't pass extended BRDF params
|
||||||
|
#ifdef _ExtBRDF
|
||||||
|
vec3 sampleLightVoxels(const vec3 p, const vec3 n, const vec3 v, const float dotNV, const vec3 lp, const vec3 lightCol,
|
||||||
|
const vec3 albedo, const float rough, const float spec, const vec3 f0
|
||||||
|
#ifdef _ShadowMap
|
||||||
|
, int index, float bias, bool receiveShadow
|
||||||
|
#ifdef _ShadowMapTransparent
|
||||||
|
, bool transparent
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#ifdef _Spot
|
||||||
|
, const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
vec3 l;
|
||||||
|
return sampleLightCore(p, n, v, dotNV, lp, lightCol, albedo, rough, spec, f0
|
||||||
|
#ifdef _ShadowMap
|
||||||
|
, index, bias, receiveShadow
|
||||||
|
#ifdef _ShadowMapTransparent
|
||||||
|
, transparent
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#ifdef _Spot
|
||||||
|
, isSpot, spotSize, spotBlend, spotDir, scale, right
|
||||||
|
#endif
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
, 0.0, 0.0, 1.5, vec3(1.0), n
|
||||||
|
#endif
|
||||||
|
#ifdef _Sheen
|
||||||
|
, 0.0, 0.0, vec3(1.0)
|
||||||
|
#endif
|
||||||
|
#ifdef _Anisotropy
|
||||||
|
, 0.0, 0.0, vec3(0.0)
|
||||||
|
#endif
|
||||||
|
#ifdef _SSS
|
||||||
|
, 0.0, vec3(0.0), vec3(0.0), 0.0
|
||||||
|
#endif
|
||||||
|
#ifdef _Transmission
|
||||||
|
, 0.0, 0.0, 1.45, 1.0
|
||||||
|
#endif
|
||||||
|
, l);
|
||||||
|
}
|
||||||
|
#endif // _ExtBRDF
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
#ifdef _SinglePoint
|
#ifdef _SinglePoint
|
||||||
#ifdef _Spot
|
#ifdef _Spot
|
||||||
uniform sampler2DShadow shadowMapSpot[1];
|
uniform sampler2DShadow shadowMapSpot[1];
|
||||||
uniform mat4 LWVPSpot[1];
|
uniform mat4 LWVPSpotArray[1];
|
||||||
#else
|
#else
|
||||||
uniform samplerCubeShadow shadowMapPoint[1];
|
uniform samplerCubeShadow shadowMapPoint[1];
|
||||||
uniform vec2 lightProj;
|
uniform vec2 lightProj;
|
||||||
@ -24,7 +24,9 @@
|
|||||||
#ifdef _SingleAtlas
|
#ifdef _SingleAtlas
|
||||||
//!uniform sampler2DShadow shadowMapAtlas;
|
//!uniform sampler2DShadow shadowMapAtlas;
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef _SinglePoint
|
||||||
uniform vec2 lightProj;
|
uniform vec2 lightProj;
|
||||||
|
#endif
|
||||||
#ifdef _ShadowMapAtlas
|
#ifdef _ShadowMapAtlas
|
||||||
#ifndef _SingleAtlas
|
#ifndef _SingleAtlas
|
||||||
uniform sampler2DShadow shadowMapAtlasPoint;
|
uniform sampler2DShadow shadowMapAtlasPoint;
|
||||||
@ -53,19 +55,64 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
|
|||||||
#ifdef _Spot
|
#ifdef _Spot
|
||||||
, bool isSpot, float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
|
, bool isSpot, float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
, float clearcoat, float clearcoatRough, float coatIOR, vec3 coatTint, vec3 coatN
|
||||||
|
#endif
|
||||||
|
#ifdef _Sheen
|
||||||
|
, float sheen, float sheenRough, vec3 sheenTint
|
||||||
|
#endif
|
||||||
|
#ifdef _Anisotropy
|
||||||
|
, float anisotropy, float anisoRot, vec3 tangent
|
||||||
|
#endif
|
||||||
|
#ifdef _SSS
|
||||||
|
, float subsurface, vec3 sssColor, vec3 sssRadius, float sssAnisotropy
|
||||||
|
#endif
|
||||||
|
#ifdef _Transmission
|
||||||
|
, float transmission, float transRough, float ior, float thinWall
|
||||||
|
#endif
|
||||||
) {
|
) {
|
||||||
vec3 ld = lp - p;
|
vec3 ld = lp - p;
|
||||||
vec3 l = normalize(ld);
|
float dist = length(ld);
|
||||||
|
vec3 l = ld / dist;
|
||||||
vec3 h = normalize(v + l);
|
vec3 h = normalize(v + l);
|
||||||
float dotNH = max(0.0, dot(n, h));
|
float dotNH = max(0.0, dot(n, h));
|
||||||
float dotVH = max(0.0, dot(v, h));
|
float dotVH = max(0.0, dot(v, h));
|
||||||
float dotNL = max(0.0, dot(n, l));
|
float dotNL = max(0.0, dot(n, l));
|
||||||
|
|
||||||
|
#ifdef _Anisotropy
|
||||||
|
vec3 direct;
|
||||||
|
if (abs(anisotropy) > 0.001 && dot(tangent, tangent) > 0.001) {
|
||||||
|
vec3 bitangent = normalize(cross(n, tangent));
|
||||||
|
direct = lambertDiffuseBRDF(albedo, dotNL) +
|
||||||
|
anisotropicBRDF(f0, rough, anisotropy, anisoRot,
|
||||||
|
tangent, bitangent, n, l, v, dotNL, dotNV) * spec;
|
||||||
|
} else {
|
||||||
|
direct = lambertDiffuseBRDF(albedo, dotNL) +
|
||||||
|
specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec;
|
||||||
|
}
|
||||||
|
#else
|
||||||
vec3 direct = lambertDiffuseBRDF(albedo, dotNL) +
|
vec3 direct = lambertDiffuseBRDF(albedo, dotNL) +
|
||||||
specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec;
|
specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _ExtBRDF
|
||||||
|
float layerWeight;
|
||||||
|
direct = applyExtBRDFLayers(direct, albedo, f0, rough, dotNL, dotNV, dotNH, dotVH, n, l, v, h
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
, clearcoat, clearcoatRough, coatIOR, coatTint, coatN
|
||||||
|
#endif
|
||||||
|
#ifdef _Sheen
|
||||||
|
, sheen, sheenRough, sheenTint
|
||||||
|
#endif
|
||||||
|
#ifdef _Transmission
|
||||||
|
, transmission, transRough, ior, thinWall
|
||||||
|
#endif
|
||||||
|
, layerWeight
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
direct *= lightCol;
|
direct *= lightCol;
|
||||||
direct *= attenuate(distance(p, lp));
|
direct *= attenuate(dist);
|
||||||
|
|
||||||
#ifdef _Spot
|
#ifdef _Spot
|
||||||
if (isSpot) {
|
if (isSpot) {
|
||||||
@ -74,12 +121,13 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
|
|||||||
#ifdef _ShadowMap
|
#ifdef _ShadowMap
|
||||||
if (receiveShadow) {
|
if (receiveShadow) {
|
||||||
#ifdef _SinglePoint
|
#ifdef _SinglePoint
|
||||||
vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0);
|
vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 10, 1.0);
|
||||||
direct *= shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, bias);
|
direct *= shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, bias);
|
||||||
#endif
|
#endif
|
||||||
#ifdef _Clusters
|
#ifdef _Clusters
|
||||||
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
|
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
|
||||||
#ifdef _ShadowMapAtlas
|
#ifdef _ShadowMapAtlas
|
||||||
|
tileBounds = tileBoundsSpotArray[index];
|
||||||
direct *= shadowTest(
|
direct *= shadowTest(
|
||||||
#ifndef _SingleAtlas
|
#ifndef _SingleAtlas
|
||||||
shadowMapAtlasSpot
|
shadowMapAtlasSpot
|
||||||
@ -132,4 +180,41 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
|
|||||||
return direct;
|
return direct;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Backward-compatible overload for generated shaders that don't pass extended BRDF params
|
||||||
|
#ifdef _ExtBRDF
|
||||||
|
vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, const vec3 lp, const vec3 lightCol,
|
||||||
|
const vec3 albedo, const float rough, const float spec, const vec3 f0
|
||||||
|
#ifdef _ShadowMap
|
||||||
|
, int index, float bias, bool receiveShadow
|
||||||
|
#endif
|
||||||
|
#ifdef _Spot
|
||||||
|
, bool isSpot, float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
return sampleLight(p, n, v, dotNV, lp, lightCol, albedo, rough, spec, f0
|
||||||
|
#ifdef _ShadowMap
|
||||||
|
, index, bias, receiveShadow
|
||||||
|
#endif
|
||||||
|
#ifdef _Spot
|
||||||
|
, isSpot, spotSize, spotBlend, spotDir, scale, right
|
||||||
|
#endif
|
||||||
|
#ifdef _ClearCoat
|
||||||
|
, 0.0, 0.0, 1.5, vec3(1.0), n
|
||||||
|
#endif
|
||||||
|
#ifdef _Sheen
|
||||||
|
, 0.0, 0.0, vec3(1.0)
|
||||||
|
#endif
|
||||||
|
#ifdef _Anisotropy
|
||||||
|
, 0.0, 0.0, vec3(0.0)
|
||||||
|
#endif
|
||||||
|
#ifdef _SSS
|
||||||
|
, 0.0, vec3(0.0), vec3(0.0), 0.0
|
||||||
|
#endif
|
||||||
|
#ifdef _Transmission
|
||||||
|
, 0.0, 0.0, 1.45, 1.0
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#endif // _ExtBRDF
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -8,8 +8,12 @@ float hash(const vec2 p) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
vec2 envMapEquirect(const vec3 normal) {
|
vec2 envMapEquirect(const vec3 normal) {
|
||||||
const float PI = 3.1415926535;
|
#ifndef PI
|
||||||
const float PI2 = PI * 2.0;
|
#define PI 3.1415926535
|
||||||
|
#endif
|
||||||
|
#ifndef PI2
|
||||||
|
#define PI2 6.2831853071
|
||||||
|
#endif
|
||||||
float phi = acos(normal.z);
|
float phi = acos(normal.z);
|
||||||
float theta = atan(-normal.y, normal.x) + PI;
|
float theta = atan(-normal.y, normal.x) + PI;
|
||||||
return vec2(theta / PI2, phi / PI);
|
return vec2(theta / PI2, phi / PI);
|
||||||
|
|||||||
@ -22,6 +22,14 @@ uniform vec2 smSizeUniform;
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _ShadowMapAtlas
|
||||||
|
uniform vec4 tileBoundsSunArray[maxLights * shadowmapCascades];
|
||||||
|
#if defined(_Clusters) && defined(_Spot) && defined(_ShadowMap)
|
||||||
|
uniform vec4 tileBoundsSpotArray[maxLightsCluster];
|
||||||
|
#endif
|
||||||
|
vec4 tileBounds = vec4(0.0, 0.0, 1.0, 1.0);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _ShadowMapAtlas
|
#ifdef _ShadowMapAtlas
|
||||||
// PCF that clamps samples to tile boundaries to prevent bleeding
|
// PCF that clamps samples to tile boundaries to prevent bleeding
|
||||||
vec3 PCFTileAware(sampler2DShadow shadowMap,
|
vec3 PCFTileAware(sampler2DShadow shadowMap,
|
||||||
@ -291,13 +299,13 @@ vec3 PCFFakeCube(sampler2DShadow shadowMap,
|
|||||||
, const bool transparent
|
, const bool transparent
|
||||||
#endif
|
#endif
|
||||||
) {
|
) {
|
||||||
const vec2 smSize = smSizeUniform; // TODO: incorrect...
|
|
||||||
const float compare = lpToDepth(lp, lightProj) - bias * 1.5;
|
const float compare = lpToDepth(lp, lightProj) - bias * 1.5;
|
||||||
ml = ml + n * bias * 20;
|
ml = ml + n * bias * 20;
|
||||||
int faceIndex = 0;
|
int faceIndex = 0;
|
||||||
const int lightIndex = index * 6;
|
const int lightIndex = index * 6;
|
||||||
const vec2 uv = sampleCube(ml, faceIndex);
|
const vec2 uv = sampleCube(ml, faceIndex);
|
||||||
vec4 pointLightTile = pointLightDataArray[lightIndex + faceIndex]; // x: tile X offset, y: tile Y offset, z: tile size relative to atlas
|
vec4 pointLightTile = pointLightDataArray[lightIndex + faceIndex]; // x: tile X offset, y: tile Y offset, z: tile size relative to atlas
|
||||||
|
const vec2 smSize = smSizeUniform; // TODO: incorrect...
|
||||||
vec2 uvtiled = pointLightTile.z * uv + pointLightTile.xy;
|
vec2 uvtiled = pointLightTile.z * uv + pointLightTile.xy;
|
||||||
#ifdef _FlipY
|
#ifdef _FlipY
|
||||||
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
|
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
|
||||||
@ -387,10 +395,6 @@ vec3 PCFFakeCube(sampler2DShadow shadowMap,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _ShadowMapAtlas
|
|
||||||
uniform vec4 tileBounds;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
vec3 shadowTest(sampler2DShadow shadowMap,
|
vec3 shadowTest(sampler2DShadow shadowMap,
|
||||||
#ifdef _ShadowMapTransparent
|
#ifdef _ShadowMapTransparent
|
||||||
sampler2D shadowMapTransparent,
|
sampler2D shadowMapTransparent,
|
||||||
@ -405,9 +409,9 @@ vec3 shadowTest(sampler2DShadow shadowMap,
|
|||||||
#ifdef _ShadowMapAtlas
|
#ifdef _ShadowMapAtlas
|
||||||
// use tile PCF
|
// use tile PCF
|
||||||
#ifdef _SMSizeUniform
|
#ifdef _SMSizeUniform
|
||||||
vec2 smSizeAtlas = smSizeUniform;
|
vec2 smSizeAtlas = smSizeUniform * (tileBounds.zw - tileBounds.xy);
|
||||||
#else
|
#else
|
||||||
const vec2 smSizeAtlas = shadowmapSize;
|
vec2 smSizeAtlas = shadowmapSize * (tileBounds.zw - tileBounds.xy);
|
||||||
#endif
|
#endif
|
||||||
return PCFTileAware(shadowMap,
|
return PCFTileAware(shadowMap,
|
||||||
#ifdef _ShadowMapTransparent
|
#ifdef _ShadowMapTransparent
|
||||||
@ -455,7 +459,7 @@ mat4 getCascadeMat(const float d, out int casi, out int casIndex) {
|
|||||||
float(d > casData[c * 4].y),
|
float(d > casData[c * 4].y),
|
||||||
float(d > casData[c * 4].z),
|
float(d > casData[c * 4].z),
|
||||||
float(d > casData[c * 4].w));
|
float(d > casData[c * 4].w));
|
||||||
casi = int(min(dot(ci, comp), c));
|
casi = int(min(dot(ci, comp), float(c - 1)));
|
||||||
// Get cascade mat
|
// Get cascade mat
|
||||||
casIndex = casi * 4;
|
casIndex = casi * 4;
|
||||||
return mat4(
|
return mat4(
|
||||||
@ -479,8 +483,12 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap,
|
|||||||
#ifdef _SMSizeUniform
|
#ifdef _SMSizeUniform
|
||||||
vec2 smSize = smSizeUniform;
|
vec2 smSize = smSizeUniform;
|
||||||
#else
|
#else
|
||||||
|
#ifdef _ShadowMapAtlas
|
||||||
|
vec2 smSize = shadowmapSize * (tileBoundsSunArray[0].zw - tileBoundsSunArray[0].xy);
|
||||||
|
#else
|
||||||
const vec2 smSize = shadowmapSize * vec2(shadowmapCascades, 1.0);
|
const vec2 smSize = shadowmapSize * vec2(shadowmapCascades, 1.0);
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
const int c = shadowmapCascades;
|
const int c = shadowmapCascades;
|
||||||
float d = distance(eye, p);
|
float d = distance(eye, p);
|
||||||
int casi;
|
int casi;
|
||||||
@ -489,16 +497,35 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap,
|
|||||||
vec4 lPos = LWVP * vec4(p, 1.0);
|
vec4 lPos = LWVP * vec4(p, 1.0);
|
||||||
lPos.xyz /= lPos.w;
|
lPos.xyz /= lPos.w;
|
||||||
|
|
||||||
|
#ifdef _ShadowMapAtlas
|
||||||
|
tileBounds = tileBoundsSunArray[casi];
|
||||||
|
#endif
|
||||||
|
|
||||||
vec3 visibility = vec3(1.0);
|
vec3 visibility = vec3(1.0);
|
||||||
if (lPos.w > 0.0) visibility = PCF(shadowMap,
|
if (lPos.w > 0.0) {
|
||||||
#ifdef _ShadowMapTransparent
|
#ifdef _ShadowMapAtlas
|
||||||
shadowMapTransparent,
|
visibility = PCFTileAware(shadowMap,
|
||||||
#endif
|
#ifdef _ShadowMapTransparent
|
||||||
lPos.xy, lPos.z - shadowsBias, smSize
|
shadowMapTransparent,
|
||||||
#ifdef _ShadowMapTransparent
|
#endif
|
||||||
, transparent
|
lPos.xy, lPos.z - shadowsBias, smSize,
|
||||||
#endif
|
tileBounds.xy, tileBounds.zw
|
||||||
);
|
#ifdef _ShadowMapTransparent
|
||||||
|
, transparent
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
#else
|
||||||
|
visibility = PCF(shadowMap,
|
||||||
|
#ifdef _ShadowMapTransparent
|
||||||
|
shadowMapTransparent,
|
||||||
|
#endif
|
||||||
|
lPos.xy, lPos.z - shadowsBias, smSize
|
||||||
|
#ifdef _ShadowMapTransparent
|
||||||
|
, transparent
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// Blend cascade
|
// Blend cascade
|
||||||
// https://github.com/TheRealMJP/Shadows
|
// https://github.com/TheRealMJP/Shadows
|
||||||
@ -518,15 +545,33 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap,
|
|||||||
lPos2.xyz /= lPos2.w;
|
lPos2.xyz /= lPos2.w;
|
||||||
vec3 visibility2 = vec3(1.0);
|
vec3 visibility2 = vec3(1.0);
|
||||||
// use lPos2 coordinates for second cascade, not lPos
|
// use lPos2 coordinates for second cascade, not lPos
|
||||||
if (lPos2.w > 0.0) visibility2 = PCF(shadowMap,
|
#ifdef _ShadowMapAtlas
|
||||||
#ifdef _ShadowMapTransparent
|
tileBounds = tileBoundsSunArray[casi + 1];
|
||||||
shadowMapTransparent,
|
#endif
|
||||||
#endif
|
if (lPos2.w > 0.0) {
|
||||||
lPos2.xy, lPos2.z - shadowsBias, smSize
|
#ifdef _ShadowMapAtlas
|
||||||
#ifdef _ShadowMapTransparent
|
visibility2 = PCFTileAware(shadowMap,
|
||||||
, transparent
|
#ifdef _ShadowMapTransparent
|
||||||
#endif
|
shadowMapTransparent,
|
||||||
);
|
#endif
|
||||||
|
lPos2.xy, lPos2.z - shadowsBias, smSize,
|
||||||
|
tileBounds.xy, tileBounds.zw
|
||||||
|
#ifdef _ShadowMapTransparent
|
||||||
|
, transparent
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
#else
|
||||||
|
visibility2 = PCF(shadowMap,
|
||||||
|
#ifdef _ShadowMapTransparent
|
||||||
|
shadowMapTransparent,
|
||||||
|
#endif
|
||||||
|
lPos2.xy, lPos2.z - shadowsBias, smSize
|
||||||
|
#ifdef _ShadowMapTransparent
|
||||||
|
, transparent
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
float lerpAmt = smoothstep(0.0, blendThres, splitDist);
|
float lerpAmt = smoothstep(0.0, blendThres, splitDist);
|
||||||
return mix(visibility2, visibility, lerpAmt);
|
return mix(visibility2, visibility, lerpAmt);
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
/* Various sky functions
|
/* Various sky functions
|
||||||
* =====================
|
* =====================
|
||||||
*
|
*
|
||||||
* Nishita model is based on https://github.com/wwwtyro/glsl-atmosphere (Unlicense License)
|
* Single scattering model is based on https://github.com/wwwtyro/glsl-atmosphere (Unlicense License)
|
||||||
*
|
*
|
||||||
* Changes to the original implementation:
|
* Changes to the original implementation:
|
||||||
* - r and pSun parameters of nishita_atmosphere() are already normalized
|
* - r and pSun parameters of single_scatter_atmosphere() are already normalized
|
||||||
* - Some original parameters of nishita_atmosphere() are replaced with pre-defined values
|
* - Some original parameters of single_scatter_atmosphere() are replaced with pre-defined values
|
||||||
* - Implemented air, dust and ozone density node parameters (see Blender source)
|
* - Implemented air, dust and ozone density node parameters (see Blender source)
|
||||||
* - Replaced the inner integral calculation with a LUT lookup
|
* - Replaced the inner integral calculation with a LUT lookup
|
||||||
*
|
*
|
||||||
@ -22,43 +22,43 @@
|
|||||||
|
|
||||||
#include "std/math.glsl"
|
#include "std/math.glsl"
|
||||||
|
|
||||||
uniform sampler2D nishitaLUT;
|
uniform sampler2D singleScatterLUT;
|
||||||
uniform vec2 nishitaDensity;
|
uniform vec2 skyDensity;
|
||||||
|
|
||||||
#ifndef PI
|
#ifndef PI
|
||||||
#define PI 3.141592
|
#define PI 3.1415926535
|
||||||
#endif
|
#endif
|
||||||
#ifndef HALF_PI
|
#ifndef HALF_PI
|
||||||
#define HALF_PI 1.570796
|
#define HALF_PI 1.570796
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define nishita_iSteps 16
|
#define single_scatter_iSteps 16
|
||||||
|
|
||||||
// These values are taken from Cycles code if they
|
// These values are taken from Cycles code if they
|
||||||
// exist there, otherwise they are taken from the example
|
// exist there, otherwise they are taken from the example
|
||||||
// in the glsl-atmosphere repo
|
// in the glsl-atmosphere repo
|
||||||
#define nishita_sun_intensity 22.0
|
#define single_scatter_sun_intensity 22.0
|
||||||
#define nishita_atmo_radius 6420e3
|
#define single_scatter_atmo_radius 6420e3
|
||||||
#define nishita_rayleigh_scale 8e3
|
#define single_scatter_rayleigh_scale 8e3
|
||||||
#define nishita_rayleigh_coeff vec3(5.5e-6, 13.0e-6, 22.4e-6)
|
#define single_scatter_rayleigh_coeff vec3(5.5e-6, 13.0e-6, 22.4e-6)
|
||||||
#define nishita_mie_scale 1.2e3
|
#define single_scatter_mie_scale 1.2e3
|
||||||
#define nishita_mie_coeff 2e-5
|
#define single_scatter_mie_coeff 2e-5
|
||||||
#define nishita_mie_dir 0.76 // Aerosols anisotropy ("direction")
|
#define single_scatter_mie_dir 0.76 // Aerosols anisotropy ("direction")
|
||||||
#define nishita_mie_dir_sq 0.5776 // Squared aerosols anisotropy
|
#define single_scatter_mie_dir_sq 0.5776 // Squared aerosols anisotropy
|
||||||
|
|
||||||
// Values from [Hill: 60]
|
// Values from [Hill: 60]
|
||||||
#define sun_limb_darkening_col vec3(0.397, 0.503, 0.652)
|
#define sun_limb_darkening_col vec3(0.397, 0.503, 0.652)
|
||||||
|
|
||||||
vec3 nishita_lookupLUT(const float height, const float sunTheta) {
|
vec3 single_scatter_lookupLUT(const float height, const float sunTheta) {
|
||||||
vec2 coords = vec2(
|
vec2 coords = vec2(
|
||||||
sqrt(height * (1 / nishita_atmo_radius)),
|
sqrt(height * (1 / single_scatter_atmo_radius)),
|
||||||
0.5 + 0.5 * sign(sunTheta - HALF_PI) * sqrt(abs(sunTheta * (1 / HALF_PI) - 1))
|
0.5 + 0.5 * sign(sunTheta - HALF_PI) * sqrt(abs(sunTheta * (1 / HALF_PI) - 1))
|
||||||
);
|
);
|
||||||
return textureLod(nishitaLUT, coords, 0.0).rgb;
|
return textureLod(singleScatterLUT, coords, 0.0).rgb;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See raySphereIntersection() in leenkx/Sources/renderpath/Nishita.hx */
|
/* See raySphereIntersection() in leenkx/Sources/renderpath/Sky.hx */
|
||||||
vec2 nishita_rsi(const vec3 r0, const vec3 rd, const float sr) {
|
vec2 single_scatter_rsi(const vec3 r0, const vec3 rd, const float sr) {
|
||||||
float a = dot(rd, rd);
|
float a = dot(rd, rd);
|
||||||
float b = 2.0 * dot(rd, r0);
|
float b = 2.0 * dot(rd, r0);
|
||||||
float c = dot(r0, r0) - (sr * sr);
|
float c = dot(r0, r0) - (sr * sr);
|
||||||
@ -74,12 +74,12 @@ vec2 nishita_rsi(const vec3 r0, const vec3 rd, const float sr) {
|
|||||||
* pSun: normalized sun direction
|
* pSun: normalized sun direction
|
||||||
* rPlanet: planet radius
|
* rPlanet: planet radius
|
||||||
*/
|
*/
|
||||||
vec3 nishita_atmosphere(const vec3 r, const vec3 r0, const vec3 pSun, const float rPlanet) {
|
vec3 single_scatter_atmosphere(const vec3 r, const vec3 r0, const vec3 pSun, const float rPlanet) {
|
||||||
// Calculate the step size of the primary ray
|
// Calculate the step size of the primary ray
|
||||||
vec2 p = nishita_rsi(r0, r, nishita_atmo_radius);
|
vec2 p = single_scatter_rsi(r0, r, single_scatter_atmo_radius);
|
||||||
if (p.x > p.y) return vec3(0.0);
|
if (p.x > p.y) return vec3(0.0);
|
||||||
p.y = min(p.y, nishita_rsi(r0, r, rPlanet).x);
|
p.y = min(p.y, single_scatter_rsi(r0, r, rPlanet).x);
|
||||||
float iStepSize = (p.y - p.x) / float(nishita_iSteps);
|
float iStepSize = (p.y - p.x) / float(single_scatter_iSteps);
|
||||||
|
|
||||||
// Primary ray time
|
// Primary ray time
|
||||||
float iTime = 0.0;
|
float iTime = 0.0;
|
||||||
@ -96,18 +96,18 @@ vec3 nishita_atmosphere(const vec3 r, const vec3 r0, const vec3 pSun, const floa
|
|||||||
float mu = dot(r, pSun);
|
float mu = dot(r, pSun);
|
||||||
float mumu = mu * mu;
|
float mumu = mu * mu;
|
||||||
float pRlh = 3.0 / (16.0 * PI) * (1.0 + mumu);
|
float pRlh = 3.0 / (16.0 * PI) * (1.0 + mumu);
|
||||||
float pMie = 3.0 / (8.0 * PI) * ((1.0 - nishita_mie_dir_sq) * (mumu + 1.0)) / (pow(1.0 + nishita_mie_dir_sq - 2.0 * mu * nishita_mie_dir, 1.5) * (2.0 + nishita_mie_dir_sq));
|
float pMie = 3.0 / (8.0 * PI) * ((1.0 - single_scatter_mie_dir_sq) * (mumu + 1.0)) / (pow(1.0 + single_scatter_mie_dir_sq - 2.0 * mu * single_scatter_mie_dir, 1.5) * (2.0 + single_scatter_mie_dir_sq));
|
||||||
|
|
||||||
// Sample the primary ray
|
// Sample the primary ray
|
||||||
for (int i = 0; i < nishita_iSteps; i++) {
|
for (int i = 0; i < single_scatter_iSteps; i++) {
|
||||||
|
|
||||||
// Calculate the primary ray sample position and height
|
// Calculate the primary ray sample position and height
|
||||||
vec3 iPos = r0 + r * (iTime + iStepSize * 0.5);
|
vec3 iPos = r0 + r * (iTime + iStepSize * 0.5);
|
||||||
float iHeight = length(iPos) - rPlanet;
|
float iHeight = length(iPos) - rPlanet;
|
||||||
|
|
||||||
// Calculate the optical depth of the Rayleigh and Mie scattering for this step
|
// Calculate the optical depth of the Rayleigh and Mie scattering for this step
|
||||||
float odStepRlh = exp(-iHeight / nishita_rayleigh_scale) * nishitaDensity.x * iStepSize;
|
float odStepRlh = exp(-iHeight / single_scatter_rayleigh_scale) * skyDensity.x * iStepSize;
|
||||||
float odStepMie = exp(-iHeight / nishita_mie_scale) * nishitaDensity.y * iStepSize;
|
float odStepMie = exp(-iHeight / single_scatter_mie_scale) * skyDensity.y * iStepSize;
|
||||||
|
|
||||||
// Accumulate optical depth
|
// Accumulate optical depth
|
||||||
iOdRlh += odStepRlh;
|
iOdRlh += odStepRlh;
|
||||||
@ -116,12 +116,12 @@ vec3 nishita_atmosphere(const vec3 r, const vec3 r0, const vec3 pSun, const floa
|
|||||||
// Idea behind this: "Rotate" everything by iPos (-> iPos is the new zenith) and then all calculations for the
|
// Idea behind this: "Rotate" everything by iPos (-> iPos is the new zenith) and then all calculations for the
|
||||||
// inner integral only depend on the sample height (iHeight) and sunTheta (angle between sun and new zenith).
|
// inner integral only depend on the sample height (iHeight) and sunTheta (angle between sun and new zenith).
|
||||||
float sunTheta = safe_acos(dot(normalize(iPos), normalize(pSun)));
|
float sunTheta = safe_acos(dot(normalize(iPos), normalize(pSun)));
|
||||||
vec3 jAttn = nishita_lookupLUT(iHeight, sunTheta);
|
vec3 jAttn = single_scatter_lookupLUT(iHeight, sunTheta);
|
||||||
|
|
||||||
// Calculate attenuation
|
// Calculate attenuation
|
||||||
vec3 iAttn = exp(-(
|
vec3 iAttn = exp(-(
|
||||||
nishita_mie_coeff * iOdMie
|
single_scatter_mie_coeff * iOdMie
|
||||||
+ nishita_rayleigh_coeff * iOdRlh
|
+ single_scatter_rayleigh_coeff * iOdRlh
|
||||||
// + 0 for ozone
|
// + 0 for ozone
|
||||||
));
|
));
|
||||||
vec3 attn = iAttn * jAttn;
|
vec3 attn = iAttn * jAttn;
|
||||||
@ -136,7 +136,7 @@ vec3 nishita_atmosphere(const vec3 r, const vec3 r0, const vec3 pSun, const floa
|
|||||||
iTime += iStepSize;
|
iTime += iStepSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nishita_sun_intensity * (pRlh * nishita_rayleigh_coeff * totalRlh + pMie * nishita_mie_coeff * totalMie);
|
return single_scatter_sun_intensity * (pRlh * single_scatter_rayleigh_coeff * totalRlh + pMie * single_scatter_mie_coeff * totalMie);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 sun_disk(const vec3 n, const vec3 light_dir, const float disk_size, const float intensity) {
|
vec3 sun_disk(const vec3 n, const vec3 light_dir, const float disk_size, const float intensity) {
|
||||||
@ -149,7 +149,83 @@ vec3 sun_disk(const vec3 n, const vec3 light_dir, const float disk_size, const f
|
|||||||
float mu = sqrt(invDist * invDist);
|
float mu = sqrt(invDist * invDist);
|
||||||
vec3 limb_darkening = 1.0 - (1.0 - pow(vec3(mu), sun_limb_darkening_col));
|
vec3 limb_darkening = 1.0 - (1.0 - pow(vec3(mu), sun_limb_darkening_col));
|
||||||
|
|
||||||
return 1 + (1.0 - step(1.0, dist)) * nishita_sun_intensity * intensity * limb_darkening;
|
return 1 + (1.0 - step(1.0, dist)) * single_scatter_sun_intensity * intensity * limb_darkening;
|
||||||
|
}
|
||||||
|
|
||||||
|
uniform sampler2D multiScatterLUT;
|
||||||
|
uniform vec4 multiScatterParams; // x=elevation, y=rotation, z=angular_diameter, w=intensity
|
||||||
|
uniform vec4 multiScatterSunBottom; // xyz=sun_bottom, w=earth_intersection_angle
|
||||||
|
uniform vec3 multiScatterSunTop;
|
||||||
|
|
||||||
|
// XYZ to sRGB/Rec.709 conversion (D65 white point)
|
||||||
|
vec3 xyz_to_rgb(vec3 xyz) {
|
||||||
|
return vec3(
|
||||||
|
3.2406 * xyz.x - 1.5372 * xyz.y - 0.4986 * xyz.z,
|
||||||
|
-0.9689 * xyz.x + 1.8758 * xyz.y + 0.0415 * xyz.z,
|
||||||
|
0.0557 * xyz.x - 0.2040 * xyz.y + 1.0570 * xyz.z
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
float sky_elevation_to_v(float elevation) {
|
||||||
|
float abs_el = abs(elevation);
|
||||||
|
float l = sign(elevation) * sqrt(abs_el / 1.5707963);
|
||||||
|
float v = (l + 1.0) * 0.5;
|
||||||
|
return clamp(v, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 multi_scatter_sample_lut(vec3 dir, float sun_rotation) {
|
||||||
|
float azimuth = atan(dir.x, dir.y);
|
||||||
|
float elevation = asin(clamp(dir.z, -1.0, 1.0));
|
||||||
|
|
||||||
|
azimuth -= sun_rotation;
|
||||||
|
float u = fract(azimuth / (2.0 * PI));
|
||||||
|
float v = sky_elevation_to_v(elevation);
|
||||||
|
|
||||||
|
return textureLod(multiScatterLUT, vec2(u, v), 0.0).rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 multi_scatter_sun_disc(vec3 dir, vec3 sun_dir, float angular_diameter, float intensity) {
|
||||||
|
float half_diameter = max(angular_diameter * 0.5, 0.0005);
|
||||||
|
float dist = distance(dir, sun_dir) / half_diameter;
|
||||||
|
float edge = smoothstep(1.0, 0.95, dist);
|
||||||
|
if (edge <= 0.0) return vec3(0.0);
|
||||||
|
|
||||||
|
float horizon = multiScatterSunBottom.w;
|
||||||
|
float dir_elev = asin(clamp(dir.z, -1.0, 1.0));
|
||||||
|
float horizon_fade = smoothstep(horizon - half_diameter * 0.1, horizon + half_diameter * 0.1, dir_elev);
|
||||||
|
edge *= horizon_fade;
|
||||||
|
if (edge <= 0.0) return vec3(0.0);
|
||||||
|
|
||||||
|
float invDist = 1.0 - dist;
|
||||||
|
float mu = sqrt(invDist * invDist);
|
||||||
|
vec3 limb_darkening = 1.0 - (1.0 - pow(vec3(mu), sun_limb_darkening_col));
|
||||||
|
|
||||||
|
float sun_elev = multiScatterParams.x;
|
||||||
|
float t = clamp((dir_elev - (sun_elev - half_diameter)) / (2.0 * half_diameter), 0.0, 1.0);
|
||||||
|
vec3 sun_color = mix(multiScatterSunBottom.rgb, multiScatterSunTop, t) * intensity * limb_darkening;
|
||||||
|
|
||||||
|
return xyz_to_rgb(sun_color) * edge;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 multi_scatter_atmosphere(vec3 dir) {
|
||||||
|
float sun_elevation = multiScatterParams.x;
|
||||||
|
float sun_rotation = multiScatterParams.y;
|
||||||
|
float angular_diameter = multiScatterParams.z;
|
||||||
|
float sun_intensity = multiScatterParams.w;
|
||||||
|
|
||||||
|
vec3 xyz = multi_scatter_sample_lut(dir, sun_rotation);
|
||||||
|
vec3 radiance = xyz_to_rgb(xyz);
|
||||||
|
|
||||||
|
if (sun_intensity > 0.0) {
|
||||||
|
vec3 computed_sun_dir = vec3(
|
||||||
|
sin(sun_rotation) * cos(sun_elevation),
|
||||||
|
cos(sun_rotation) * cos(sun_elevation),
|
||||||
|
sin(sun_elevation)
|
||||||
|
);
|
||||||
|
radiance += multi_scatter_sun_disc(dir, computed_sun_dir, angular_diameter, sun_intensity);
|
||||||
|
}
|
||||||
|
|
||||||
|
return radiance;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -1,15 +1,25 @@
|
|||||||
|
|
||||||
// Separable SSS Transmittance Function, ref to sss_pass
|
// Separable SSS Transmittance Function, ref to sss_pass
|
||||||
vec3 SSSSTransmittance(mat4 LWVP, vec3 p, vec3 n, vec3 l, float lightFar, sampler2DShadow shadowMap) {
|
vec3 SSSSTransmittance(mat4 LWVP, vec3 p, vec3 n, vec3 l, float lightFar, sampler2DShadow shadowMap, vec3 sssColor, float sssRadius
|
||||||
const float translucency = 1.0;
|
#ifdef _ShadowMapAtlas
|
||||||
|
, vec4 tileBounds
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
const float translucency = 0.85;
|
||||||
vec4 shrinkedPos = vec4(p - 0.005 * n, 1.0);
|
vec4 shrinkedPos = vec4(p - 0.005 * n, 1.0);
|
||||||
vec4 shadowPos = LWVP * shrinkedPos;
|
vec4 shadowPos = LWVP * shrinkedPos;
|
||||||
float scale = 8.25 * (1.0 - translucency) / (sssWidth / 10.0);
|
vec2 shadowUV = shadowPos.xy / shadowPos.w;
|
||||||
float d1 = texture(shadowMap, vec3(shadowPos.xy / shadowPos.w, shadowPos.z)).r; // 'd1' has a range of 0..1
|
#ifdef _ShadowMapAtlas
|
||||||
float d2 = shadowPos.z; // 'd2' has a range of 0..'lightFarPlane'
|
shadowUV = clamp(shadowUV, tileBounds.xy, tileBounds.zw);
|
||||||
d1 *= lightFar; // So we scale 'd1' accordingly:
|
#endif
|
||||||
float d = scale * abs(d1 - d2);
|
float scale = 2.5 * (1.0 - translucency) / max(sssRadius, 0.001);
|
||||||
|
float d1 = texture(shadowMap, vec3(shadowUV, shadowPos.z)).r;
|
||||||
|
float d2 = shadowPos.z;
|
||||||
|
d1 *= lightFar;
|
||||||
|
d2 *= lightFar;
|
||||||
|
float d = scale * abs(d1 - d2) * 1000.0;
|
||||||
|
|
||||||
|
if (d > 10.0) return vec3(0.0);
|
||||||
float dd = -d * d;
|
float dd = -d * d;
|
||||||
vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) +
|
vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) +
|
||||||
vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) +
|
vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) +
|
||||||
@ -17,10 +27,70 @@ vec3 SSSSTransmittance(mat4 LWVP, vec3 p, vec3 n, vec3 l, float lightFar, sample
|
|||||||
vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) +
|
vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) +
|
||||||
vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) +
|
vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) +
|
||||||
vec3(0.078, 0.0, 0.0) * exp(dd / 7.41);
|
vec3(0.078, 0.0, 0.0) * exp(dd / 7.41);
|
||||||
return profile * clamp(0.3 + dot(l, -n), 0.0, 1.0);
|
profile *= mix(vec3(1.0), sssColor, 0.8);
|
||||||
|
return profile * clamp(0.5 + dot(l, -n), 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 SSSSTransmittanceCube(float translucency, vec4 shadowPos, vec3 n, vec3 l, float lightFar) {
|
#ifdef _ShadowMapAtlas
|
||||||
// TODO
|
vec3 SSSSTransmittanceCubeAtlas(sampler2DShadow shadowMap, vec3 lightPos, vec3 p, vec3 n, vec3 l, float lightFar, vec2 lightProj, int index, vec3 sssColor, float sssRadius) {
|
||||||
return vec3(0.0);
|
const float translucency = 0.85;
|
||||||
|
vec3 shrinkedPos = p - 0.005 * n;
|
||||||
|
vec3 ld = normalize(shrinkedPos - lightPos);
|
||||||
|
#ifdef _InvY
|
||||||
|
ld.y = -ld.y;
|
||||||
|
#endif
|
||||||
|
float d2 = lpToDepth(ld, lightProj);
|
||||||
|
int faceIndex = 0;
|
||||||
|
int lightIndex = index * 6;
|
||||||
|
vec2 uv = sampleCube(ld, faceIndex);
|
||||||
|
vec4 pointLightTile = pointLightDataArray[lightIndex + faceIndex];
|
||||||
|
vec2 uvtiled = pointLightTile.z * uv + pointLightTile.xy;
|
||||||
|
#ifdef _FlipY
|
||||||
|
uvtiled.y = 1.0 - uvtiled.y;
|
||||||
|
#endif
|
||||||
|
float d1 = texture(shadowMap, vec3(uvtiled, d2)).r;
|
||||||
|
d1 *= lightFar;
|
||||||
|
d2 *= lightFar;
|
||||||
|
float scale = 2.5 * (1.0 - translucency) / max(sssRadius, 0.001);
|
||||||
|
// d1/d2 are in meters, sssRadius is in mm, exponential constants are in mm^2
|
||||||
|
float d = scale * abs(d1 - d2) * 1000.0; // Convert distance to mm
|
||||||
|
|
||||||
|
if (d > 10.0) return vec3(0.0);
|
||||||
|
float dd = -d * d;
|
||||||
|
vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) +
|
||||||
|
vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) +
|
||||||
|
vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) +
|
||||||
|
vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) +
|
||||||
|
vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) +
|
||||||
|
vec3(0.078, 0.0, 0.0) * exp(dd / 7.41);
|
||||||
|
profile *= mix(vec3(1.0), sssColor, 0.8);
|
||||||
|
return profile * clamp(0.5 + dot(l, -n), 0.0, 1.0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
vec3 SSSSTransmittanceCube(samplerCubeShadow shadowMapCube, vec3 lightPos, vec3 p, vec3 n, vec3 l, float lightFar, vec2 lightProj, vec3 sssColor, float sssRadius) {
|
||||||
|
const float translucency = 0.85;
|
||||||
|
vec3 shrinkedPos = p - 0.005 * n;
|
||||||
|
vec3 ld = normalize(shrinkedPos - lightPos);
|
||||||
|
#ifdef _InvY
|
||||||
|
ld.y = -ld.y;
|
||||||
|
#endif
|
||||||
|
float d2 = lpToDepth(ld, lightProj);
|
||||||
|
float d1 = texture(shadowMapCube, vec4(ld, d2)).r;
|
||||||
|
d1 *= lightFar;
|
||||||
|
d2 *= lightFar;
|
||||||
|
float scale = 2.5 * (1.0 - translucency) / max(sssRadius, 0.001);
|
||||||
|
// d1/d2 are in meters, sssRadius is in mm, exponential constants are in mm^2
|
||||||
|
float d = scale * abs(d1 - d2) * 1000.0; // Convert distance to mm
|
||||||
|
|
||||||
|
if (d > 10.0) return vec3(0.0);
|
||||||
|
float dd = -d * d;
|
||||||
|
vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) +
|
||||||
|
vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) +
|
||||||
|
vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) +
|
||||||
|
vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) +
|
||||||
|
vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) +
|
||||||
|
vec3(0.078, 0.0, 0.0) * exp(dd / 7.41);
|
||||||
|
profile *= mix(vec3(1.0), sssColor, 0.8);
|
||||||
|
return profile * clamp(0.5 + dot(l, -n), 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,136 +0,0 @@
|
|||||||
#version 450
|
|
||||||
|
|
||||||
layout (local_size_x = 8, local_size_y = 8, local_size_z = 8) in;
|
|
||||||
|
|
||||||
#include "compiled.inc"
|
|
||||||
#include "std/math.glsl"
|
|
||||||
#include "std/gbuffer.glsl"
|
|
||||||
#include "std/imageatomic.glsl"
|
|
||||||
#ifdef _VoxelShadow
|
|
||||||
#include "std/conetrace.glsl"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uniform vec3 lightPos;
|
|
||||||
uniform vec3 lightColor;
|
|
||||||
uniform int lightType;
|
|
||||||
uniform vec3 lightDir;
|
|
||||||
uniform vec2 spotData;
|
|
||||||
#ifdef _ShadowMap
|
|
||||||
uniform int lightShadow;
|
|
||||||
uniform vec2 lightProj;
|
|
||||||
uniform float shadowsBias;
|
|
||||||
uniform mat4 LVP;
|
|
||||||
#ifdef _ShadowMapAtlas
|
|
||||||
uniform int index;
|
|
||||||
uniform vec4 pointLightDataArray[maxLightsCluster * 6];
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uniform float clipmaps[voxelgiClipmapCount * 10];
|
|
||||||
uniform int clipmapLevel;
|
|
||||||
|
|
||||||
uniform layout(r32ui) uimage3D voxelsLight;
|
|
||||||
|
|
||||||
#ifdef _ShadowMap
|
|
||||||
uniform sampler2DShadow shadowMap;
|
|
||||||
uniform sampler2D shadowMapTransparent;
|
|
||||||
uniform sampler2DShadow shadowMapSpot;
|
|
||||||
#ifdef _ShadowMapAtlas
|
|
||||||
uniform sampler2DShadow shadowMapPoint;
|
|
||||||
#else
|
|
||||||
uniform samplerCubeShadow shadowMapPoint;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _ShadowMapAtlas
|
|
||||||
// https://www.khronos.org/registry/OpenGL/specs/gl/glspec20.pdf // p:168
|
|
||||||
// https://www.gamedev.net/forums/topic/687535-implementing-a-cube-map-lookup-function/5337472/
|
|
||||||
vec2 sampleCube(vec3 dir, out int faceIndex) {
|
|
||||||
vec3 dirAbs = abs(dir);
|
|
||||||
float ma;
|
|
||||||
vec2 uv;
|
|
||||||
if(dirAbs.z >= dirAbs.x && dirAbs.z >= dirAbs.y) {
|
|
||||||
faceIndex = dir.z < 0.0 ? 5 : 4;
|
|
||||||
ma = 0.5 / dirAbs.z;
|
|
||||||
uv = vec2(dir.z < 0.0 ? -dir.x : dir.x, -dir.y);
|
|
||||||
}
|
|
||||||
else if(dirAbs.y >= dirAbs.x) {
|
|
||||||
faceIndex = dir.y < 0.0 ? 3 : 2;
|
|
||||||
ma = 0.5 / dirAbs.y;
|
|
||||||
uv = vec2(dir.x, dir.y < 0.0 ? -dir.z : dir.z);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
faceIndex = dir.x < 0.0 ? 1 : 0;
|
|
||||||
ma = 0.5 / dirAbs.x;
|
|
||||||
uv = vec2(dir.x < 0.0 ? dir.z : -dir.z, -dir.y);
|
|
||||||
}
|
|
||||||
// downscale uv a little to hide seams
|
|
||||||
// transform coordinates from clip space to texture space
|
|
||||||
#ifndef _FlipY
|
|
||||||
return uv * 0.9976 * ma + 0.5;
|
|
||||||
#else
|
|
||||||
#ifdef HLSL
|
|
||||||
return uv * 0.9976 * ma + 0.5;
|
|
||||||
#else
|
|
||||||
return vec2(uv.x * ma, uv.y * -ma) * 0.9976 + 0.5;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
float lpToDepth(vec3 lp, const vec2 lightProj) {
|
|
||||||
lp = abs(lp);
|
|
||||||
float zcomp = max(lp.x, max(lp.y, lp.z));
|
|
||||||
zcomp = lightProj.x - lightProj.y / zcomp;
|
|
||||||
return zcomp * 0.5 + 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
int res = voxelgiResolution.x;
|
|
||||||
ivec3 dst = ivec3(gl_GlobalInvocationID.xyz);
|
|
||||||
|
|
||||||
vec3 wposition = (gl_GlobalInvocationID.xyz + 0.5) / voxelgiResolution.x;
|
|
||||||
wposition = wposition * 2.0 - 1.0;
|
|
||||||
wposition *= float(clipmaps[int(clipmapLevel * 10)]);
|
|
||||||
wposition *= voxelgiResolution.x;
|
|
||||||
wposition += vec3(clipmaps[clipmapLevel * 10 + 4], clipmaps[clipmapLevel * 10 + 5], clipmaps[clipmapLevel * 10 + 6]);
|
|
||||||
|
|
||||||
float visibility;
|
|
||||||
vec3 lp = lightPos - wposition;
|
|
||||||
vec3 l;
|
|
||||||
if (lightType == 0) { l = lightDir; visibility = 1.0; }
|
|
||||||
else { l = normalize(lp); visibility = attenuate(distance(wposition, lightPos)); }
|
|
||||||
|
|
||||||
#ifdef _ShadowMap
|
|
||||||
if (lightShadow == 1) {
|
|
||||||
vec4 lightPosition = LVP * vec4(wposition, 1.0);
|
|
||||||
vec3 lPos = lightPosition.xyz / lightPosition.w;
|
|
||||||
visibility *= texture(shadowMap, vec3(lPos.xy, lPos.z - shadowsBias)).r;
|
|
||||||
}
|
|
||||||
else if (lightShadow == 2) {
|
|
||||||
vec4 lightPosition = LVP * vec4(wposition, 1.0);
|
|
||||||
vec3 lPos = lightPosition.xyz / lightPosition.w;
|
|
||||||
visibility *= texture(shadowMapSpot, vec3(lPos.xy, lPos.z - shadowsBias)).r;
|
|
||||||
}
|
|
||||||
else if (lightShadow == 3) {
|
|
||||||
#ifdef _ShadowMapAtlas
|
|
||||||
int faceIndex = 0;
|
|
||||||
const int lightIndex = index * 6;
|
|
||||||
const vec2 uv = sampleCube(-l, faceIndex);
|
|
||||||
vec4 pointLightTile = pointLightDataArray[lightIndex + faceIndex]; // x: tile X offset, y: tile Y offset, z: tile size relative to atlas
|
|
||||||
vec2 uvtiled = pointLightTile.z * uv + pointLightTile.xy;
|
|
||||||
#ifdef _FlipY
|
|
||||||
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
|
|
||||||
#endif
|
|
||||||
visibility *= texture(shadowMapPoint, vec3(uvtiled, lpToDepth(lp, lightProj) - shadowsBias)).r;
|
|
||||||
#else
|
|
||||||
visibility *= texture(shadowMapPoint, vec4(-l, lpToDepth(lp, lightProj) - shadowsBias)).r;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
vec3 light = visibility * lightColor;
|
|
||||||
imageAtomicAdd(voxelsLight, dst, uint(light.r * 255));
|
|
||||||
imageAtomicAdd(voxelsLight, dst + ivec3(0, 0, voxelgiResolution.x), uint(light.g * 255));
|
|
||||||
imageAtomicAdd(voxelsLight, dst + ivec3(0, 0, voxelgiResolution.x * 2), uint(light.b * 255));
|
|
||||||
}
|
|
||||||
@ -38,7 +38,6 @@ uniform layout(r8) image3D voxelsOut;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
uniform int clipmapLevel;
|
uniform int clipmapLevel;
|
||||||
uniform float voxelBlend;
|
|
||||||
|
|
||||||
uniform float clipmaps[voxelgiClipmapCount * 10];
|
uniform float clipmaps[voxelgiClipmapCount * 10];
|
||||||
|
|
||||||
@ -47,7 +46,7 @@ void main() {
|
|||||||
ivec3 src = ivec3(gl_GlobalInvocationID.xyz);
|
ivec3 src = ivec3(gl_GlobalInvocationID.xyz);
|
||||||
src.y += clipmapLevel * res;
|
src.y += clipmapLevel * res;
|
||||||
|
|
||||||
for (int i = 0; i < 6 + DIFFUSE_CONE_COUNT; i++)
|
for (int i = 0; i < 6 + diffuseConeCount; i++)
|
||||||
{
|
{
|
||||||
vec4 col = vec4(0.0);
|
vec4 col = vec4(0.0);
|
||||||
|
|
||||||
|
|||||||
@ -165,7 +165,7 @@ void main() {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
envl.rgb *= envmapStrength * occspec.x;
|
envl.rgb *= envmapStrength * voxelgiEnv * occspec.x;
|
||||||
|
|
||||||
vec3 occ = envl * (1.0 - traceAO(P, n, voxels, clipmaps));
|
vec3 occ = envl * (1.0 - traceAO(P, n, voxels, clipmaps));
|
||||||
|
|
||||||
|
|||||||
@ -53,13 +53,6 @@ uniform float shirr[7 * 4];
|
|||||||
#ifdef _Brdf
|
#ifdef _Brdf
|
||||||
uniform sampler2D senvmapBrdf;
|
uniform sampler2D senvmapBrdf;
|
||||||
#endif
|
#endif
|
||||||
#ifdef _Rad
|
|
||||||
uniform sampler2D senvmapRadiance;
|
|
||||||
uniform int envmapNumMipmaps;
|
|
||||||
#endif
|
|
||||||
#ifdef _EnvCol
|
|
||||||
uniform vec3 backgroundCol;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
const vec2 pixel = gl_GlobalInvocationID.xy;
|
const vec2 pixel = gl_GlobalInvocationID.xy;
|
||||||
@ -140,17 +133,8 @@ void main() {
|
|||||||
vec3 envl = vec3(0.0);
|
vec3 envl = vec3(0.0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _Rad
|
|
||||||
vec3 reflectionWorld = reflect(-v, n);
|
|
||||||
float lod = getMipFromRoughness(roughness, envmapNumMipmaps);
|
|
||||||
vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _EnvLDR
|
#ifdef _EnvLDR
|
||||||
envl.rgb = pow(envl.rgb, vec3(2.2));
|
envl.rgb = pow(envl.rgb, vec3(2.2));
|
||||||
#ifdef _Rad
|
|
||||||
prefilteredColor = pow(prefilteredColor, vec3(2.2));
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
envl.rgb *= albedo;
|
envl.rgb *= albedo;
|
||||||
@ -159,15 +143,7 @@ void main() {
|
|||||||
envl.rgb *= 1.0 - F; //LV: We should take refracted light into account
|
envl.rgb *= 1.0 - F; //LV: We should take refracted light into account
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _Rad // Indirect specular
|
envl.rgb *= envmapStrength * voxelgiEnv * occspec.x;
|
||||||
envl.rgb += prefilteredColor * F; //LV: Removed "1.5 * occspec.y". Specular should be weighted only by FV LUT
|
|
||||||
#else
|
|
||||||
#ifdef _EnvCol
|
|
||||||
envl.rgb += backgroundCol * F; //LV: Eh, what's the point of weighting it only by F0?
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
envl.rgb *= envmapStrength * occspec.x;
|
|
||||||
|
|
||||||
vec4 trace = traceDiffuse(P, n, voxels, clipmaps);
|
vec4 trace = traceDiffuse(P, n, voxels, clipmaps);
|
||||||
vec3 color = trace.rgb * albedo * (1.0 - F);
|
vec3 color = trace.rgb * albedo * (1.0 - F);
|
||||||
|
|||||||
@ -48,13 +48,15 @@ void main() {
|
|||||||
const vec2 pixel = gl_GlobalInvocationID.xy;
|
const vec2 pixel = gl_GlobalInvocationID.xy;
|
||||||
vec2 uv = (pixel + 0.5) / postprocess_resolution;
|
vec2 uv = (pixel + 0.5) / postprocess_resolution;
|
||||||
#ifdef _InvY
|
#ifdef _InvY
|
||||||
uv.y = 1.0 - uv.y
|
uv.y = 1.0 - uv.y;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
float depth = textureLod(gbufferD, uv, 0.0).r * 2.0 - 1.0;
|
float depth = textureLod(gbufferD, uv, 0.0).r * 2.0 - 1.0;
|
||||||
if (depth == 0) return;
|
if (depth == 0) return;
|
||||||
|
|
||||||
vec2 ior_opac = textureLod(gbuffer_refraction, uv, 0.0).xy;
|
vec2 ior_opac = textureLod(gbuffer_refraction, uv, 0.0).xy;
|
||||||
|
float ior = unpackIOR(ior_opac.x);
|
||||||
|
float opacity = ior_opac.y;
|
||||||
|
|
||||||
float x = uv.x * 2 - 1;
|
float x = uv.x * 2 - 1;
|
||||||
float y = uv.y * 2 - 1;
|
float y = uv.y * 2 - 1;
|
||||||
@ -72,8 +74,8 @@ void main() {
|
|||||||
n = normalize(n);
|
n = normalize(n);
|
||||||
|
|
||||||
vec3 color = vec3(0.0);
|
vec3 color = vec3(0.0);
|
||||||
if(ior_opac.y < 1.0)
|
if(opacity < 1.0)
|
||||||
color = traceRefraction(P, n, voxels, voxelsSDF, normalize(eye - P), ior_opac.x, g0.b, clipmaps, pixel).rgb;
|
color = traceRefraction(P, n, voxels, voxelsSDF, normalize(eye - P), ior, g0.b, clipmaps, pixel).rgb;
|
||||||
|
|
||||||
imageStore(voxels_refraction, ivec2(pixel), vec4(color, 1.0));
|
imageStore(voxels_refraction, ivec2(pixel), vec4(color, 1.0));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -66,9 +66,13 @@ void main() {
|
|||||||
n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);
|
n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);
|
||||||
n = normalize(n);
|
n = normalize(n);
|
||||||
|
|
||||||
|
float roughness = g0.b;
|
||||||
|
|
||||||
|
vec3 v = normalize(eye - P);
|
||||||
|
|
||||||
vec2 velocity = -textureLod(sveloc, uv, 0.0).rg;
|
vec2 velocity = -textureLod(sveloc, uv, 0.0).rg;
|
||||||
|
|
||||||
vec3 color = traceSpecular(P, n, voxels, voxelsSDF, normalize(eye - P), g0.z * g0.z, clipmaps, pixel, velocity).rgb;
|
vec3 color = traceSpecular(P, n, voxels, voxelsSDF, v, roughness * roughness, clipmaps, pixel, velocity).rgb;
|
||||||
|
|
||||||
imageStore(voxels_specular, ivec2(pixel), vec4(color, 1.0));
|
imageStore(voxels_specular, ivec2(pixel), vec4(color, 1.0));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,7 +43,6 @@ uniform mat4 LVP;
|
|||||||
#endif
|
#endif
|
||||||
uniform sampler3D voxelsSampler;
|
uniform sampler3D voxelsSampler;
|
||||||
uniform layout(r32ui) uimage3D voxels;
|
uniform layout(r32ui) uimage3D voxels;
|
||||||
uniform layout(r32ui) uimage3D voxelsLight;
|
|
||||||
uniform layout(rgba8) image3D voxelsB;
|
uniform layout(rgba8) image3D voxelsB;
|
||||||
uniform layout(rgba8) image3D voxelsOut;
|
uniform layout(rgba8) image3D voxelsOut;
|
||||||
uniform layout(r8) image3D SDF;
|
uniform layout(r8) image3D SDF;
|
||||||
@ -75,21 +74,13 @@ void main() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _VoxelGI
|
#ifdef _VoxelGI
|
||||||
vec3 light = vec3(0.0);
|
vec4 aniso_colors[6];
|
||||||
light.r = float(imageLoad(voxelsLight, ivec3(gl_GlobalInvocationID.xyz)).r) / 255;
|
#else
|
||||||
light.g = float(imageLoad(voxelsLight, ivec3(gl_GlobalInvocationID.xyz) + ivec3(0, 0, voxelgiResolution.x)).r) / 255;
|
float aniso_colors[6];
|
||||||
light.b = float(imageLoad(voxelsLight, ivec3(gl_GlobalInvocationID.xyz) + ivec3(0, 0, voxelgiResolution.x * 2)).r) / 255;
|
|
||||||
light /= 3;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (int i = 0; i < 6 + DIFFUSE_CONE_COUNT; i++)
|
for (int i = 0; i < 6 + diffuseConeCount; i++)
|
||||||
{
|
{
|
||||||
#ifdef _VoxelGI
|
|
||||||
vec4 aniso_colors[6];
|
|
||||||
#else
|
|
||||||
float aniso_colors[6];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ivec3 src = ivec3(gl_GlobalInvocationID.xyz);
|
ivec3 src = ivec3(gl_GlobalInvocationID.xyz);
|
||||||
src.x += i * res;
|
src.x += i * res;
|
||||||
ivec3 dst = src;
|
ivec3 dst = src;
|
||||||
@ -103,30 +94,37 @@ void main() {
|
|||||||
|
|
||||||
if (i < 6) {
|
if (i < 6) {
|
||||||
#ifdef _VoxelGI
|
#ifdef _VoxelGI
|
||||||
|
uint count = imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 15)).r;
|
||||||
|
if (count > 0) {
|
||||||
vec4 basecol = vec4(0.0);
|
vec4 basecol = vec4(0.0);
|
||||||
basecol.r = float(imageLoad(voxels, src)) / 255;
|
basecol.r = float(imageLoad(voxels, src)) / 255;
|
||||||
basecol.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x))) / 255;
|
basecol.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x))) / 255;
|
||||||
basecol.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 2))) / 255;
|
basecol.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 2))) / 255;
|
||||||
basecol.a = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 3))) / 255;
|
basecol.a = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 3))) / 255;
|
||||||
basecol /= 4;
|
basecol /= count;
|
||||||
vec3 emission = vec3(0.0);
|
vec3 emission = vec3(0.0);
|
||||||
emission.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 4))) / 255;
|
emission.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 4))) / 255;
|
||||||
emission.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 5))) / 255;
|
emission.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 5))) / 255;
|
||||||
emission.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 6))) / 255;
|
emission.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 6))) / 255;
|
||||||
emission /= 3;
|
emission /= count;
|
||||||
vec3 N = vec3(0.0);
|
vec3 N = vec3(0.0);
|
||||||
N.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 7))) / 255;
|
N.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 7))) / 255;
|
||||||
N.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 8))) / 255;
|
N.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 8))) / 255;
|
||||||
N /= 2;
|
N /= count;
|
||||||
vec3 wnormal = decode_oct(N.rg * 2 - 1);
|
vec3 wnormal = decode_oct(N.rg * 2 - 1);
|
||||||
vec3 envl = vec3(0.0);
|
vec3 envl = vec3(0.0);
|
||||||
envl.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 9))) / 255;
|
envl.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 9))) / 255;
|
||||||
envl.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 10))) / 255;
|
envl.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 10))) / 255;
|
||||||
envl.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 11))) / 255;
|
envl.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 11))) / 255;
|
||||||
envl /= 3;
|
envl /= count;
|
||||||
#ifdef _HOSEK
|
#ifdef _HOSEK
|
||||||
envl *= 100;
|
envl *= 100;
|
||||||
#endif
|
#endif
|
||||||
|
vec3 light = vec3(0.0);
|
||||||
|
light.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 12))) / 255;
|
||||||
|
light.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 13))) / 255;
|
||||||
|
light.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 14))) / 255;
|
||||||
|
light /= count;
|
||||||
|
|
||||||
//clipmap to world
|
//clipmap to world
|
||||||
vec3 wposition = (gl_GlobalInvocationID.xyz + 0.5) / voxelgiResolution.x;
|
vec3 wposition = (gl_GlobalInvocationID.xyz + 0.5) / voxelgiResolution.x;
|
||||||
@ -138,8 +136,9 @@ void main() {
|
|||||||
radiance = basecol;
|
radiance = basecol;
|
||||||
vec4 trace = traceDiffuse(wposition, wnormal, voxelsSampler, clipmaps);
|
vec4 trace = traceDiffuse(wposition, wnormal, voxelsSampler, clipmaps);
|
||||||
vec3 indirect = trace.rgb + envl.rgb * (1.0 - trace.a);
|
vec3 indirect = trace.rgb + envl.rgb * (1.0 - trace.a);
|
||||||
radiance.rgb *= light.rgb + indirect.rgb;
|
radiance.rgb *= light.rgb * INV_PI + indirect.rgb;
|
||||||
radiance.rgb += emission.rgb;
|
radiance.rgb += emission.rgb;
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
opac = float(imageLoad(voxels, src)) / 255;
|
opac = float(imageLoad(voxels, src)) / 255;
|
||||||
@ -196,7 +195,7 @@ void main() {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// precompute cone sampling:
|
// precompute cone sampling:
|
||||||
vec3 coneDirection = DIFFUSE_CONE_DIRECTIONS[i - 6];
|
vec3 coneDirection = diffuseConeDirections[i - 6];
|
||||||
vec3 aniso_direction = -coneDirection;
|
vec3 aniso_direction = -coneDirection;
|
||||||
uvec3 face_offsets = uvec3(
|
uvec3 face_offsets = uvec3(
|
||||||
aniso_direction.x > 0 ? 0 : 1,
|
aniso_direction.x > 0 ? 0 : 1,
|
||||||
|
|||||||
@ -88,53 +88,98 @@ vec4 rayCast(vec3 dir) {
|
|||||||
}
|
}
|
||||||
#endif //SSR
|
#endif //SSR
|
||||||
|
|
||||||
|
vec3 sampleWaterNormals(vec2 hitXY, float speed, out vec2 tcnor0, out vec2 tcnor1) {
|
||||||
|
tcnor0 = hitXY / 3.0;
|
||||||
|
vec3 n0 = textureLod(sdetail, tcnor0 + vec2(speed / 60.0, speed / 120.0), 0.0).rgb;
|
||||||
|
tcnor1 = hitXY / 6.0 + n0.xy / 20.0;
|
||||||
|
vec3 n1 = textureLod(sbase, tcnor1 + vec2(speed / 40.0, speed / 80.0), 0.0).rgb;
|
||||||
|
return normalize(n0 + n1 - 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
float gdepth = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
|
float gdepth = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
|
||||||
if (gdepth == 1.0) {
|
|
||||||
fragColor = vec4(0.0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Eye below water
|
|
||||||
if (eye.z < waterLevel) {
|
|
||||||
fragColor = vec4(0.0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Displace surface
|
|
||||||
vec3 vray = normalize(viewRay);
|
vec3 vray = normalize(viewRay);
|
||||||
vec3 p = getPos(eye, eyeLook, vray, gdepth, cameraProj);
|
|
||||||
float speed = time * 2.0 * waterSpeed;
|
float speed = time * 2.0 * waterSpeed;
|
||||||
p.z += sin(p.x * 10.0 / waterDisplace + speed) * cos(p.y * 10.0 / waterDisplace + speed) / 50.0 * waterDisplace;
|
bool isSky = (gdepth == 1.0);
|
||||||
|
|
||||||
|
// Ray-plane intersection with water surface (z = waterLevel)
|
||||||
|
float denom = dot(vray, vec3(0.0, 0.0, 1.0));
|
||||||
|
float tWater = (waterLevel - eye.z) / denom;
|
||||||
|
bool hasWaterHit = (abs(denom) > 0.0001) && (tWater > 0.0);
|
||||||
|
|
||||||
|
if (eye.z < waterLevel) {
|
||||||
|
vec2 tc = texCoord;
|
||||||
|
float fogFactor;
|
||||||
|
|
||||||
|
if (hasWaterHit && denom > 0.0) {
|
||||||
|
// Looking up at water surface - apply normal distortion
|
||||||
|
vec3 hit = eye + tWater * vray;
|
||||||
|
vec2 tc0, tc1;
|
||||||
|
vec3 n2 = sampleWaterNormals(hit.xy * waterFreq, speed, tc0, tc1);
|
||||||
|
tc = texCoord + (n2.xy * n2.z) / 30.0 * waterRefract;
|
||||||
|
fogFactor = clamp(tWater * waterDensity, 0.0, 0.95);
|
||||||
|
} else {
|
||||||
|
// Looking forward/down - distort via water surface above fragment
|
||||||
|
vec3 p = getPos(eye, eyeLook, vray, gdepth, cameraProj);
|
||||||
|
vec2 wxy = isSky ? (eye.xy + vray.xy * 50.0) : p.xy;
|
||||||
|
vec2 tc0, tc1;
|
||||||
|
vec3 n2 = sampleWaterNormals(wxy * waterFreq, speed, tc0, tc1);
|
||||||
|
tc = texCoord + (n2.xy * n2.z) / 30.0 * waterRefract;
|
||||||
|
float waterDist = isSky ? 50.0 : length(p - eye);
|
||||||
|
fogFactor = clamp(waterDist * waterDensity, 0.0, 0.95);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 refracted = textureLod(tex, tc, 0.0).rgb;
|
||||||
|
fragColor.rgb = mix(refracted, waterColor, fogFactor);
|
||||||
|
fragColor.a = 1.0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Above water
|
// Above water
|
||||||
if (p.z > waterLevel) {
|
if (!hasWaterHit || denom >= 0.0) {
|
||||||
fragColor = vec4(0.0);
|
fragColor = vec4(0.0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isSky) tWater = min(tWater, 100.0); // Clamp to prevent aliasing at horizon
|
||||||
|
vec3 p = isSky ? (eye + tWater * vray) : getPos(eye, eyeLook, vray, gdepth, cameraProj);
|
||||||
|
|
||||||
|
float horizonFactor = clamp(1.0 - tWater / 60.0, 0.0, 1.0);
|
||||||
|
if (!isSky && p.z > waterLevel) {
|
||||||
|
fragColor = vec4(0.0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Displace surface
|
||||||
|
p.z += (sin(p.x * 10.0 / waterDisplace + speed) * cos(p.y * 10.0 / waterDisplace + speed)
|
||||||
|
+ sin(p.x * 20.0 / waterDisplace + speed * 1.3) * cos(p.y * 20.0 / waterDisplace + speed * 1.3) * 0.5)
|
||||||
|
/ 50.0 * waterDisplace;
|
||||||
|
|
||||||
// Hit plane to determine uvs
|
// Hit plane to determine uvs
|
||||||
vec3 v = normalize(eye - p.xyz);
|
vec3 v = normalize(eye - p);
|
||||||
float t = -(dot(eye, vec3(0.0, 0.0, 1.0)) - waterLevel) / dot(v, vec3(0.0, 0.0, 1.0));
|
float t = (waterLevel - eye.z) / dot(v, vec3(0.0, 0.0, 1.0));
|
||||||
vec3 hit = eye + t * v;
|
vec3 hit = eye + t * v;
|
||||||
hit.xy *= waterFreq;
|
|
||||||
hit.z += waterLevel;
|
|
||||||
|
|
||||||
// Sample normal maps
|
// Sample normal maps
|
||||||
vec2 tcnor0 = hit.xy / 3.0;
|
vec2 tcnor0, tcnor1;
|
||||||
vec3 n0 = textureLod(sdetail, tcnor0 + vec2(speed / 60.0, speed / 120.0), 0.0).rgb;
|
vec3 n2 = sampleWaterNormals(hit.xy * waterFreq, speed, tcnor0, tcnor1);
|
||||||
|
|
||||||
vec2 tcnor1 = hit.xy / 6.0 + n0.xy / 20.0;
|
// Refraction
|
||||||
vec3 n1 = textureLod(sbase, tcnor1 + vec2(speed / 40.0, speed / 80.0), 0.0).rgb;
|
vec2 tc;
|
||||||
vec3 n2 = normalize(((n1 + n0) / 2.0) * 2.0 - 1.0);
|
if (isSky) {
|
||||||
|
tc = texCoord + (n2.xy * n2.z) / 30.0 * waterRefract;
|
||||||
float ddepth = textureLod(gbufferD, texCoord + (n2.xy * n2.z) / 40.0, 0.0).r * 2.0 - 1.0;
|
} else {
|
||||||
vec3 p2 = getPos(eye, eyeLook, vray, ddepth, cameraProj);
|
float ddepth = textureLod(gbufferD, texCoord + (n2.xy * n2.z) / 40.0, 0.0).r * 2.0 - 1.0;
|
||||||
vec2 tc = p2.z > waterLevel ? texCoord : texCoord + (n2.xy * n2.z) / 30.0 * waterRefract;
|
vec3 p2 = getPos(eye, eyeLook, vray, ddepth, cameraProj);
|
||||||
|
tc = p2.z > waterLevel ? texCoord : texCoord + (n2.xy * n2.z) / 30.0 * waterRefract;
|
||||||
|
}
|
||||||
|
|
||||||
// Light
|
// Light
|
||||||
float fresnel = 1.0 - max(dot(n2, v), 0.0);
|
float fresnel = 1.0 - max(dot(n2, v), 0.0);
|
||||||
fresnel = pow(fresnel, 30.0) * 0.45;
|
fresnel = 0.02 + 0.98 * pow(fresnel, 5.0);
|
||||||
vec3 r = reflect(-v, n2);
|
vec3 r = reflect(-v, n2);
|
||||||
#ifdef _Rad
|
#ifdef _Rad
|
||||||
vec3 reflectedEnv = textureLod(senvmapRadiance, envMapEquirect(r), 0).rgb;
|
vec3 reflectedEnv = textureLod(senvmapRadiance, envMapEquirect(r), 0).rgb;
|
||||||
#else
|
#else
|
||||||
const vec3 reflectedEnv = vec3(0.5);
|
const vec3 reflectedEnv = vec3(0.5);
|
||||||
#endif
|
#endif
|
||||||
@ -147,8 +192,8 @@ void main() {
|
|||||||
float spec = 0.9;//fract(textureLod(gbuffer1, texCoord, 0.0).a);
|
float spec = 0.9;//fract(textureLod(gbuffer1, texCoord, 0.0).a);
|
||||||
//if (spec == 0.0) { fragColor.rgb = vec3(0.0); return; }
|
//if (spec == 0.0) { fragColor.rgb = vec3(0.0); return; }
|
||||||
|
|
||||||
vec3 viewNormal = n2;
|
vec3 viewNormal = V3 * n2;
|
||||||
vec3 viewPos = getPosView(viewRay, gdepth, cameraProj);
|
vec3 viewPos = isSky ? vec3(0.0) : getPosView(viewRay, gdepth, cameraProj);
|
||||||
vec3 reflected = reflect(normalize(viewPos), viewNormal);
|
vec3 reflected = reflect(normalize(viewPos), viewNormal);
|
||||||
hitCoord = viewPos;
|
hitCoord = viewPos;
|
||||||
|
|
||||||
@ -158,7 +203,6 @@ void main() {
|
|||||||
vec3 dir = reflected * (1.0 - rand(texCoord) * ssrJitter * roughness) * 2.0;
|
vec3 dir = reflected * (1.0 - rand(texCoord) * ssrJitter * roughness) * 2.0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// * max(ssrMinRayStep, -viewPos.z)
|
|
||||||
vec4 coords = rayCast(dir);
|
vec4 coords = rayCast(dir);
|
||||||
|
|
||||||
vec2 deltaCoords = abs(vec2(0.5, 0.5) - coords.xy);
|
vec2 deltaCoords = abs(vec2(0.5, 0.5) - coords.xy);
|
||||||
@ -177,20 +221,32 @@ void main() {
|
|||||||
#else
|
#else
|
||||||
fragColor.rgb = mix(refracted, reflectedEnv, waterReflect * fresnel);
|
fragColor.rgb = mix(refracted, reflectedEnv, waterReflect * fresnel);
|
||||||
#endif
|
#endif
|
||||||
fragColor.rgb *= waterColor;
|
// Water color tint - blend rather than multiply to preserve brightness
|
||||||
fragColor.rgb += clamp(pow(max(dot(r, ld), 0.0), 200.0) * (200.0 + 8.0) / (PI * 8.0), 0.0, 2.0);
|
float colorMix = isSky ? 0.7 : 0.5;
|
||||||
fragColor.rgb *= 1.0 - (clamp(-(p.z - waterLevel) * waterDensity, 0.0, 0.9));
|
fragColor.rgb = mix(fragColor.rgb, fragColor.rgb * waterColor, colorMix * horizonFactor);
|
||||||
fragColor.a = clamp(abs(p.z - waterLevel) * 5.0, 0.0, 1.0);
|
// Blinn-Phong specular using half-vector, faded at horizon
|
||||||
|
vec3 h = normalize(v + ld);
|
||||||
|
float specAmount = pow(max(dot(n2, h), 0.0), 200.0) * (200.0 + 8.0) / (PI * 8.0);
|
||||||
|
fragColor.rgb += specAmount * (isSky ? 0.3 : 1.0) * horizonFactor;
|
||||||
|
// Depth fog - blend toward waterColor with depth, faded at horizon
|
||||||
|
float depthFog = clamp(-(p.z - waterLevel) * waterDensity, 0.0, 0.9);
|
||||||
|
fragColor.rgb = mix(fragColor.rgb, waterColor, depthFog * horizonFactor);
|
||||||
|
// Alpha fades smoothly at horizon instead of hard cut
|
||||||
|
fragColor.a = isSky ? horizonFactor : clamp(abs(p.z - waterLevel) * 5.0, 0.0, 1.0);
|
||||||
|
|
||||||
// Foam
|
// Foam - based on actual geometry depth below water surface
|
||||||
float fd = abs(p.z - waterLevel);
|
float fd = isSky ? 1.0 : abs(p.z - waterLevel);
|
||||||
if (fd < 0.1) {
|
if (fd < 0.1) {
|
||||||
// Based on foam by Owen Deery
|
// Based on foam by Owen Deery
|
||||||
// http://fire-face.com/personal/water
|
// http://fire-face.com/personal/water
|
||||||
vec3 foamMask0 = textureLod(sfoam, tcnor0 * 10, 0.0).rgb;
|
// Distance-based LOD blurs foam at range to reduce noise
|
||||||
vec3 foamMask1 = textureLod(sfoam, tcnor1 * 11, 0.0).rgb;
|
float foamLod = clamp(tWater / 15.0, 0.0, 5.0);
|
||||||
vec3 foam = vec3(1.0) - foamMask0.rrr - foamMask1.bbb;
|
vec2 foamUV0 = tcnor0 * 3.0 + vec2(speed / 30.0, speed / 50.0);
|
||||||
float fac = 1.0 - (fd * (1.0 / 0.1));
|
vec2 foamUV1 = tcnor1 * 4.0 + vec2(-speed / 35.0, speed / 45.0);
|
||||||
fragColor.rgb = mix(fragColor.rgb, clamp(foam, 0.0, 1.0), clamp(fac, 0.0, 1.0));
|
vec3 foamMask0 = textureLod(sfoam, foamUV0, foamLod).rgb;
|
||||||
|
vec3 foamMask1 = textureLod(sfoam, foamUV1, foamLod).rgb;
|
||||||
|
float foamStrength = clamp(1.0 - foamMask0.r * 0.5 - foamMask1.b * 0.5, 0.0, 1.0);
|
||||||
|
float fac = (1.0 - (fd * (1.0 / 0.1))) * horizonFactor;
|
||||||
|
fragColor.rgb = mix(fragColor.rgb, mix(fragColor.rgb, waterColor + 0.2, foamStrength), clamp(fac, 0.0, 1.0) * 0.5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -304,10 +304,13 @@ class RenderPath {
|
|||||||
currentD = 1;
|
currentD = 1;
|
||||||
currentFace = -1;
|
currentFace = -1;
|
||||||
meshesSorted = false;
|
meshesSorted = false;
|
||||||
|
sun = null;
|
||||||
|
|
||||||
for (l in Scene.active.lights) {
|
for (l in Scene.active.lights) {
|
||||||
if (l.visible) l.buildMatrix(Scene.active.camera);
|
if (l.visible) l.buildMatrix(Scene.active.camera);
|
||||||
if (l.data.raw.type == "sun") sun = l;
|
if (l.data.raw.type == "sun") {
|
||||||
|
if (sun == null || (!sun.data.raw.cast_shadow && l.data.raw.cast_shadow)) sun = l;
|
||||||
|
}
|
||||||
else point = l;
|
else point = l;
|
||||||
}
|
}
|
||||||
light = Scene.active.lights[0];
|
light = Scene.active.lights[0];
|
||||||
@ -500,7 +503,7 @@ class RenderPath {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function drawMeshes(context: String) {
|
public function drawMeshes(context: String) {
|
||||||
var isShadows = context == "shadowmap";
|
var isShadows = context == "shadowmap" || context == "shadowmap_transparent";
|
||||||
if (isShadows) {
|
if (isShadows) {
|
||||||
// Disabled shadow casting for this light
|
// Disabled shadow casting for this light
|
||||||
if (light == null || !light.data.raw.cast_shadow || !light.visible || light.data.raw.strength == 0) return;
|
if (light == null || !light.data.raw.cast_shadow || !light.visible || light.data.raw.strength == 0) return;
|
||||||
@ -672,7 +675,7 @@ class RenderPath {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if (rp_voxels != "Off")
|
#if (rp_voxels != "Off")
|
||||||
public function getComputeShader(handle: String): kha.compute.Shader {
|
public function getComputeShader(handle: String): kha.graphics4.ComputeShader {
|
||||||
return Reflect.field(kha.Shaders, handle + "_comp");
|
return Reflect.field(kha.Shaders, handle + "_comp");
|
||||||
}
|
}
|
||||||
#end
|
#end
|
||||||
|
|||||||
@ -71,6 +71,13 @@ class Scene {
|
|||||||
|
|
||||||
public var embedded: Map<String, kha.Image>;
|
public var embedded: Map<String, kha.Image>;
|
||||||
|
|
||||||
|
#if (rp_renderer == "Deferred")
|
||||||
|
public static inline var MAX_MATERIALS = 16;
|
||||||
|
public static inline var FLOATS_PER_MATERIAL_PARAM = 32; // 8 vec4s per material
|
||||||
|
public var materialParamsBuffer: kha.arrays.Float32Array;
|
||||||
|
public var materialParamsDirty: Bool = true;
|
||||||
|
#end
|
||||||
|
|
||||||
public var ready: Bool; // Async in progress
|
public var ready: Bool; // Async in progress
|
||||||
|
|
||||||
public var traitInits: Array<Void->Void> = [];
|
public var traitInits: Array<Void->Void> = [];
|
||||||
@ -107,6 +114,9 @@ class Scene {
|
|||||||
armatures = [];
|
armatures = [];
|
||||||
#end
|
#end
|
||||||
embedded = new Map();
|
embedded = new Map();
|
||||||
|
#if (rp_renderer == "Deferred")
|
||||||
|
materialParamsBuffer = new kha.arrays.Float32Array(MAX_MATERIALS * FLOATS_PER_MATERIAL_PARAM);
|
||||||
|
#end
|
||||||
root = new Object();
|
root = new Object();
|
||||||
root.name = "Root";
|
root.name = "Root";
|
||||||
traitInits = [];
|
traitInits = [];
|
||||||
@ -204,6 +214,89 @@ class Scene {
|
|||||||
root.remove();
|
root.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if (rp_renderer == "Deferred")
|
||||||
|
public function markMaterialParamsDirty() {
|
||||||
|
materialParamsDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateMaterialParams() {
|
||||||
|
if (!materialParamsDirty) return;
|
||||||
|
materialParamsDirty = false;
|
||||||
|
var buf = materialParamsBuffer;
|
||||||
|
for (m in meshes) {
|
||||||
|
if (m.materials == null) continue;
|
||||||
|
for (mat in m.materials) {
|
||||||
|
if (mat == null) continue;
|
||||||
|
if (mat.contexts == null) continue;
|
||||||
|
var slot = -1;
|
||||||
|
var bc = null;
|
||||||
|
for (ctx in mat.contexts) {
|
||||||
|
if (ctx == null || ctx.raw == null) continue;
|
||||||
|
if (ctx.raw.name == "mesh" && ctx.raw.bind_constants != null) {
|
||||||
|
bc = ctx.raw.bind_constants;
|
||||||
|
for (c in bc) {
|
||||||
|
if (c != null && c.name == "materialID" && c.intValue != null) {
|
||||||
|
slot = c.intValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (slot < 0 || slot >= MAX_MATERIALS) continue;
|
||||||
|
var base = slot * FLOATS_PER_MATERIAL_PARAM;
|
||||||
|
if (base + FLOATS_PER_MATERIAL_PARAM - 1 >= buf.length) continue;
|
||||||
|
if (bc == null) continue;
|
||||||
|
for (i in 0...FLOATS_PER_MATERIAL_PARAM) buf[base + i] = 0.0;
|
||||||
|
buf[base + 6] = 1.5; // coatIOR
|
||||||
|
buf[base + 12] = 1.45; // ior
|
||||||
|
buf[base + 13] = 1.0; // thinWall
|
||||||
|
for (c in bc) {
|
||||||
|
if (c == null || c.name == null || c.floatValue == null) continue;
|
||||||
|
switch (c.name) {
|
||||||
|
// matp0: vec4(anisotropy, anisoRot, sheen, sheenRough)
|
||||||
|
case "anisotropy": buf[base + 0] = c.floatValue;
|
||||||
|
case "anisoRot": buf[base + 1] = c.floatValue;
|
||||||
|
case "sheen": buf[base + 2] = c.floatValue;
|
||||||
|
case "sheenRough": buf[base + 3] = c.floatValue;
|
||||||
|
// matp1: vec4(clearcoat, clearcoatRough, coatIOR, coatTintR)
|
||||||
|
case "clearcoat": buf[base + 4] = c.floatValue;
|
||||||
|
case "clearcoatRough": buf[base + 5] = c.floatValue;
|
||||||
|
case "coatIOR": buf[base + 6] = c.floatValue;
|
||||||
|
case "coatTintR": buf[base + 7] = c.floatValue;
|
||||||
|
// matp2: vec4(coatTintG, coatTintB, transmission, transRough)
|
||||||
|
case "coatTintG": buf[base + 8] = c.floatValue;
|
||||||
|
case "coatTintB": buf[base + 9] = c.floatValue;
|
||||||
|
case "transmission": buf[base + 10] = c.floatValue;
|
||||||
|
case "transmissionRough": buf[base + 11] = c.floatValue;
|
||||||
|
// matp3: vec4(ior, thinWall, subsurface, subsurfaceAnisotropy)
|
||||||
|
case "ior": buf[base + 12] = c.floatValue;
|
||||||
|
case "thinWall": buf[base + 13] = c.floatValue;
|
||||||
|
case "subsurface": buf[base + 14] = c.floatValue;
|
||||||
|
case "subsurfaceAnisotropy": buf[base + 15] = c.floatValue;
|
||||||
|
// matp4: vec4(subsurfaceRadiusR, subsurfaceRadiusG, subsurfaceRadiusB, subsurfaceColorR)
|
||||||
|
case "subsurfaceRadiusR": buf[base + 16] = c.floatValue;
|
||||||
|
case "subsurfaceRadiusG": buf[base + 17] = c.floatValue;
|
||||||
|
case "subsurfaceRadiusB": buf[base + 18] = c.floatValue;
|
||||||
|
case "subsurfaceColorR": buf[base + 19] = c.floatValue;
|
||||||
|
// matp5: vec4(subsurfaceColorG, subsurfaceColorB, sheenTintR, sheenTintG)
|
||||||
|
case "subsurfaceColorG": buf[base + 20] = c.floatValue;
|
||||||
|
case "subsurfaceColorB": buf[base + 21] = c.floatValue;
|
||||||
|
case "sheenTintR": buf[base + 22] = c.floatValue;
|
||||||
|
case "sheenTintG": buf[base + 23] = c.floatValue;
|
||||||
|
// matp6: vec4(sheenTintB, specularTintR, specularTintG, specularTintB)
|
||||||
|
case "sheenTintB": buf[base + 24] = c.floatValue;
|
||||||
|
case "specularTintR": buf[base + 25] = c.floatValue;
|
||||||
|
case "specularTintG": buf[base + 26] = c.floatValue;
|
||||||
|
case "specularTintB": buf[base + 27] = c.floatValue;
|
||||||
|
// matp7: vec4(subsurfaceScale, 0, 0, 0)
|
||||||
|
case "subsurfaceScale": buf[base + 28] = c.floatValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#end
|
||||||
|
|
||||||
static var framePassed = true;
|
static var framePassed = true;
|
||||||
public static function setActive(sceneName: String, done: Object->Void = null) {
|
public static function setActive(sceneName: String, done: Object->Void = null) {
|
||||||
if (!framePassed) return;
|
if (!framePassed) return;
|
||||||
@ -351,6 +444,9 @@ class Scene {
|
|||||||
public function addMeshObject(data: MeshData, materials: Vector<MaterialData>, parent: Object = null): MeshObject {
|
public function addMeshObject(data: MeshData, materials: Vector<MaterialData>, parent: Object = null): MeshObject {
|
||||||
var object = new MeshObject(data, materials);
|
var object = new MeshObject(data, materials);
|
||||||
parent != null ? object.setParent(parent) : object.setParent(root);
|
parent != null ? object.setParent(parent) : object.setParent(root);
|
||||||
|
#if (rp_renderer == "Deferred")
|
||||||
|
markMaterialParamsDirty();
|
||||||
|
#end
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -55,6 +55,8 @@ class Geometry {
|
|||||||
// Skinned
|
// Skinned
|
||||||
#if lnx_skin
|
#if lnx_skin
|
||||||
public var skeletonTransformsI: Array<Mat4> = null;
|
public var skeletonTransformsI: Array<Mat4> = null;
|
||||||
|
public var actions: Map<String, Array<iron.data.SceneFormat.TObj>> = new Map();
|
||||||
|
public var mats: Map<String, Array<Mat4>> = new Map();
|
||||||
#end
|
#end
|
||||||
|
|
||||||
public function new(data: MeshData, indices: Array<Uint32Array>, materialIndices: Array<Int>, usage: Usage = null) {
|
public function new(data: MeshData, indices: Array<Uint32Array>, materialIndices: Array<Int>, usage: Usage = null) {
|
||||||
|
|||||||
@ -348,7 +348,13 @@ typedef TWorldData = {
|
|||||||
@:optional public var turbidity: Null<FastFloat>;
|
@:optional public var turbidity: Null<FastFloat>;
|
||||||
@:optional public var ground_albedo: Null<FastFloat>;
|
@:optional public var ground_albedo: Null<FastFloat>;
|
||||||
@:optional public var envmap: String;
|
@:optional public var envmap: String;
|
||||||
@:optional public var nishita_density: Float32Array; // Rayleigh, Mie, ozone
|
@:optional public var sky_density: Float32Array; // Air, dust/aerosol, ozone density
|
||||||
|
@:optional public var sky_sun_elevation: Null<FastFloat>;
|
||||||
|
@:optional public var sky_sun_rotation: Null<FastFloat>;
|
||||||
|
@:optional public var sky_sun_size: Null<FastFloat>;
|
||||||
|
@:optional public var sky_sun_intensity: Null<FastFloat>;
|
||||||
|
@:optional public var sky_altitude: Null<FastFloat>;
|
||||||
|
@:optional public var sky_sun_disc: Null<Int>; // 0 or 1
|
||||||
}
|
}
|
||||||
|
|
||||||
#if js
|
#if js
|
||||||
|
|||||||
@ -245,7 +245,12 @@ class LightObject extends Object {
|
|||||||
// Snap to texel coords - fix translation swim
|
// Snap to texel coords - fix translation swim
|
||||||
var smsize = data.raw.shadowmap_size;
|
var smsize = data.raw.shadowmap_size;
|
||||||
#if lnx_csm // Cascades
|
#if lnx_csm // Cascades
|
||||||
smsize = Std.int(smsize / 4);
|
#if lnx_shadowmap_atlas
|
||||||
|
var ts = cascade < tileScale.length ? tileScale[cascade] : 1.0;
|
||||||
|
smsize = Std.int(Math.max(ts * data.raw.shadowmap_size, 1.0));
|
||||||
|
#else
|
||||||
|
smsize = Std.int(smsize / cascadeCount);
|
||||||
|
#end
|
||||||
#end
|
#end
|
||||||
var worldPerTexelX = (maxx - minx) / smsize;
|
var worldPerTexelX = (maxx - minx) / smsize;
|
||||||
var worldPerTexelY = (maxy - miny) / smsize;
|
var worldPerTexelY = (maxy - miny) / smsize;
|
||||||
@ -685,22 +690,6 @@ class LightObject extends Object {
|
|||||||
return LWVPMatrixArray;
|
return LWVPMatrixArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static inline function getMaxLights(): Int {
|
|
||||||
#if (rp_max_lights == 8)
|
|
||||||
return 8;
|
|
||||||
#elseif (rp_max_lights == 16)
|
|
||||||
return 16;
|
|
||||||
#elseif (rp_max_lights == 24)
|
|
||||||
return 24;
|
|
||||||
#elseif (rp_max_lights == 32)
|
|
||||||
return 32;
|
|
||||||
#elseif (rp_max_lights == 64)
|
|
||||||
return 64;
|
|
||||||
#else
|
|
||||||
return 4;
|
|
||||||
#end
|
|
||||||
}
|
|
||||||
|
|
||||||
public static inline function getMaxLightsCluster(): Int {
|
public static inline function getMaxLightsCluster(): Int {
|
||||||
#if (rp_max_lights_cluster == 8)
|
#if (rp_max_lights_cluster == 8)
|
||||||
return 8;
|
return 8;
|
||||||
@ -718,6 +707,90 @@ class LightObject extends Object {
|
|||||||
}
|
}
|
||||||
#end // lnx_clusters
|
#end // lnx_clusters
|
||||||
|
|
||||||
|
public static inline function getMaxLights(): Int {
|
||||||
|
#if (rp_max_lights == 8)
|
||||||
|
return 8;
|
||||||
|
#elseif (rp_max_lights == 16)
|
||||||
|
return 16;
|
||||||
|
#elseif (rp_max_lights == 24)
|
||||||
|
return 24;
|
||||||
|
#elseif (rp_max_lights == 32)
|
||||||
|
return 32;
|
||||||
|
#elseif (rp_max_lights == 64)
|
||||||
|
return 64;
|
||||||
|
#else
|
||||||
|
return 4;
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (rp_shadowmap && lnx_shadowmap_atlas)
|
||||||
|
public static var sunTileBoundsArray: Float32Array = null;
|
||||||
|
public static var tileBoundsDirty: Bool = true;
|
||||||
|
|
||||||
|
public static function updateSunTileBoundsArray(): Float32Array {
|
||||||
|
if (!tileBoundsDirty && sunTileBoundsArray != null) return sunTileBoundsArray;
|
||||||
|
tileBoundsDirty = false;
|
||||||
|
var maxLights = getMaxLights();
|
||||||
|
var numTiles = maxLights * cascadeCount;
|
||||||
|
if (sunTileBoundsArray == null) {
|
||||||
|
sunTileBoundsArray = new Float32Array(numTiles * 4);
|
||||||
|
}
|
||||||
|
for (k in 0...sunTileBoundsArray.length) sunTileBoundsArray[k] = 0;
|
||||||
|
var i = 0;
|
||||||
|
for (light in Scene.active.lights) {
|
||||||
|
if (i >= maxLights) break;
|
||||||
|
if (!light.visible || light.data.raw.type != "sun") continue;
|
||||||
|
if (!light.data.raw.cast_shadow || light.data.raw.strength == 0.0) continue;
|
||||||
|
for (c in 0...cascadeCount) {
|
||||||
|
var idx = (i * cascadeCount + c) * 4;
|
||||||
|
sunTileBoundsArray[idx ] = light.tileOffsetX[c];
|
||||||
|
sunTileBoundsArray[idx + 2] = light.tileOffsetX[c] + light.tileScale[c];
|
||||||
|
#if (!kha_opengl)
|
||||||
|
// flip bounds to match
|
||||||
|
sunTileBoundsArray[idx + 1] = 1.0 - (light.tileOffsetY[c] + light.tileScale[c]);
|
||||||
|
sunTileBoundsArray[idx + 3] = 1.0 - light.tileOffsetY[c];
|
||||||
|
#else
|
||||||
|
sunTileBoundsArray[idx + 1] = light.tileOffsetY[c];
|
||||||
|
sunTileBoundsArray[idx + 3] = light.tileOffsetY[c] + light.tileScale[c];
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return sunTileBoundsArray;
|
||||||
|
}
|
||||||
|
#end
|
||||||
|
|
||||||
|
#if (rp_shadowmap && lnx_shadowmap_atlas)
|
||||||
|
public static var spotTileBoundsArray: Float32Array = null;
|
||||||
|
|
||||||
|
public static function updateSpotTileBoundsArray(): Float32Array {
|
||||||
|
var maxLights = getMaxLights();
|
||||||
|
if (spotTileBoundsArray == null) {
|
||||||
|
spotTileBoundsArray = new Float32Array(maxLights * 4);
|
||||||
|
}
|
||||||
|
for (k in 0...spotTileBoundsArray.length) spotTileBoundsArray[k] = 0;
|
||||||
|
var i = 0;
|
||||||
|
for (light in Scene.active.lights) {
|
||||||
|
if (i >= maxLights) break;
|
||||||
|
if (!light.visible || light.data.raw.type != "spot") continue;
|
||||||
|
if (!light.data.raw.cast_shadow || light.data.raw.strength == 0.0) continue;
|
||||||
|
var idx = i * 4;
|
||||||
|
spotTileBoundsArray[idx ] = light.tileOffsetX[0];
|
||||||
|
spotTileBoundsArray[idx + 2] = light.tileOffsetX[0] + light.tileScale[0];
|
||||||
|
#if (!kha_opengl)
|
||||||
|
// flip bounds
|
||||||
|
spotTileBoundsArray[idx + 1] = 1.0 - (light.tileOffsetY[0] + light.tileScale[0]);
|
||||||
|
spotTileBoundsArray[idx + 3] = 1.0 - light.tileOffsetY[0];
|
||||||
|
#else
|
||||||
|
spotTileBoundsArray[idx + 1] = light.tileOffsetY[0];
|
||||||
|
spotTileBoundsArray[idx + 3] = light.tileOffsetY[0] + light.tileScale[0];
|
||||||
|
#end
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return spotTileBoundsArray;
|
||||||
|
}
|
||||||
|
#end
|
||||||
|
|
||||||
public inline function right(): Vec4 {
|
public inline function right(): Vec4 {
|
||||||
return new Vec4(V._00, V._10, V._20);
|
return new Vec4(V._00, V._10, V._20);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -89,6 +89,9 @@ class MeshObject extends Object {
|
|||||||
#end
|
#end
|
||||||
if (tilesheet != null) tilesheet.remove();
|
if (tilesheet != null) tilesheet.remove();
|
||||||
if (Scene.active != null) Scene.active.meshes.remove(this);
|
if (Scene.active != null) Scene.active.meshes.remove(this);
|
||||||
|
#if (rp_renderer == "Deferred")
|
||||||
|
if (Scene.active != null) Scene.active.markMaterialParamsDirty();
|
||||||
|
#end
|
||||||
data.refcount--;
|
data.refcount--;
|
||||||
super.remove();
|
super.remove();
|
||||||
}
|
}
|
||||||
@ -318,9 +321,9 @@ class MeshObject extends Object {
|
|||||||
if (scontext.pipeState != lastPipeline) {
|
if (scontext.pipeState != lastPipeline) {
|
||||||
g.setPipeline(scontext.pipeState);
|
g.setPipeline(scontext.pipeState);
|
||||||
lastPipeline = scontext.pipeState;
|
lastPipeline = scontext.pipeState;
|
||||||
// Uniforms.setContextConstants(g, scontext, bindParams);
|
Uniforms.setContextConstants(g, scontext, bindParams);
|
||||||
}
|
}
|
||||||
Uniforms.setContextConstants(g, scontext, bindParams); //
|
//Uniforms.setContextConstants(g, scontext, bindParams); //
|
||||||
Uniforms.setObjectConstants(g, scontext, this);
|
Uniforms.setObjectConstants(g, scontext, this);
|
||||||
if (materialContexts.length > mi) {
|
if (materialContexts.length > mi) {
|
||||||
Uniforms.setMaterialConstants(g, scontext, materialContexts[mi]);
|
Uniforms.setMaterialConstants(g, scontext, materialContexts[mi]);
|
||||||
|
|||||||
@ -394,7 +394,7 @@ class ParticleSystemCPU {
|
|||||||
if (physics.hasScaleRamp && physics.rampPositions.length > 1) {
|
if (physics.hasScaleRamp && physics.rampPositions.length > 1) {
|
||||||
var normalizedAge: FastFloat = physics.age / physics.lifetime;
|
var normalizedAge: FastFloat = physics.age / physics.lifetime;
|
||||||
var scaleMultiplier: FastFloat = interpolateRampValue(normalizedAge, physics.rampPositions, physics.rampColors);
|
var scaleMultiplier: FastFloat = interpolateRampValue(normalizedAge, physics.rampPositions, physics.rampColors);
|
||||||
var finalScale: FastFloat = scale * (particleScale * (1 - physics.scaleRampSizeFactor) + scaleMultiplier * physics.scaleRampSizeFactor);
|
var finalScale: FastFloat = 1 + (scaleMultiplier - 1) * physics.scaleRampSizeFactor;
|
||||||
particle.transform.scale.setFrom(physics.baseScale.clone().mult(finalScale));
|
particle.transform.scale.setFrom(physics.baseScale.clone().mult(finalScale));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -827,9 +827,20 @@ class Uniforms {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case "_shadowMapSize": {
|
case "_shadowMapSize": {
|
||||||
if (light != null && light.data.raw.cast_shadow) {
|
var shadowLight = light;
|
||||||
|
if (shadowLight == null || !shadowLight.data.raw.cast_shadow) {
|
||||||
|
shadowLight = RenderPath.active.sun;
|
||||||
|
}
|
||||||
|
if (shadowLight != null && shadowLight.data.raw.cast_shadow) {
|
||||||
v = helpVec;
|
v = helpVec;
|
||||||
v.x = v.y = light.data.raw.shadowmap_size;
|
v.x = v.y = shadowLight.data.raw.shadowmap_size;
|
||||||
|
#if lnx_csm
|
||||||
|
#if (!lnx_shadowmap_atlas)
|
||||||
|
if (shadowLight.data.raw.type == "sun") {
|
||||||
|
v.x = shadowLight.data.raw.shadowmap_size * LightObject.cascadeCount;
|
||||||
|
}
|
||||||
|
#end
|
||||||
|
#end
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -887,6 +898,11 @@ class Uniforms {
|
|||||||
case "_envmapIrradiance": {
|
case "_envmapIrradiance": {
|
||||||
fa = Scene.active.world == null ? WorldData.getEmptyIrradiance() : Scene.active.world.probe.irradiance;
|
fa = Scene.active.world == null ? WorldData.getEmptyIrradiance() : Scene.active.world.probe.irradiance;
|
||||||
}
|
}
|
||||||
|
#if (rp_renderer == "Deferred")
|
||||||
|
case "_materialParams": {
|
||||||
|
fa = Scene.active.materialParamsBuffer;
|
||||||
|
}
|
||||||
|
#end
|
||||||
#if lnx_clusters
|
#if lnx_clusters
|
||||||
case "_lightsArray": {
|
case "_lightsArray": {
|
||||||
fa = LightObject.lightsArray;
|
fa = LightObject.lightsArray;
|
||||||
@ -903,15 +919,18 @@ class Uniforms {
|
|||||||
#end
|
#end
|
||||||
#end // lnx_clusters
|
#end // lnx_clusters
|
||||||
#if lnx_csm
|
#if lnx_csm
|
||||||
case "_cascadeData": {
|
case "_cascadeData": {
|
||||||
for (l in Scene.active.lights) {
|
var sun = RenderPath.active.sun;
|
||||||
if (l.data.raw.type == "sun") {
|
if (sun != null && sun.data.raw.type == "sun") {
|
||||||
fa = l.getCascadeData();
|
fa = sun.getCascadeData();
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#end
|
}
|
||||||
|
#end
|
||||||
|
#if lnx_shadowmap_atlas
|
||||||
|
case "_tileBoundsSunArray": {
|
||||||
|
fa = LightObject.updateSunTileBoundsArray();
|
||||||
|
}
|
||||||
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fa != null) {
|
if (fa != null) {
|
||||||
@ -1064,32 +1083,30 @@ class Uniforms {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case "_biasLightWorldViewProjectionMatrixSun": {
|
case "_biasLightWorldViewProjectionMatrixSun": {
|
||||||
for (l in iron.Scene.active.lights) {
|
var sun = RenderPath.active.sun;
|
||||||
if (l.data.raw.type == "sun") {
|
if (sun != null && sun.data.raw.type == "sun") {
|
||||||
// object is null for DrawQuad
|
// object is null for DrawQuad
|
||||||
object == null ? helpMat.setIdentity() : helpMat.setFrom(object.transform.worldUnpack);
|
object == null ? helpMat.setIdentity() : helpMat.setFrom(object.transform.worldUnpack);
|
||||||
helpMat.multmat(l.VP);
|
helpMat.multmat(sun.VP);
|
||||||
helpMat.multmat(biasMat);
|
helpMat.multmat(biasMat);
|
||||||
#if lnx_shadowmap_atlas
|
#if lnx_shadowmap_atlas
|
||||||
// tile matrix
|
// tile matrix
|
||||||
helpMat2.setIdentity();
|
helpMat2.setIdentity();
|
||||||
// scale [0-1] coords to [0-tilescale]
|
// scale [0-1] coords to [0-tilescale]
|
||||||
helpMat2._00 = l.tileScale[0];
|
helpMat2._00 = sun.tileScale[0];
|
||||||
helpMat2._11 = l.tileScale[0];
|
helpMat2._11 = sun.tileScale[0];
|
||||||
// offset coordinate start from [0, 0] to [tile-start-x, tile-start-y]
|
// offset coordinate start from [0, 0] to [tile-start-x, tile-start-y]
|
||||||
helpMat2._30 = l.tileOffsetX[0];
|
helpMat2._30 = sun.tileOffsetX[0];
|
||||||
helpMat2._31 = l.tileOffsetY[0];
|
helpMat2._31 = sun.tileOffsetY[0];
|
||||||
helpMat.multmat(helpMat2);
|
helpMat.multmat(helpMat2);
|
||||||
#if (!kha_opengl)
|
#if (!kha_opengl)
|
||||||
helpMat2.setIdentity();
|
helpMat2.setIdentity();
|
||||||
helpMat2._11 = -1.0;
|
helpMat2._11 = -1.0;
|
||||||
helpMat2._31 = 1.0;
|
helpMat2._31 = 1.0;
|
||||||
helpMat.multmat(helpMat2);
|
helpMat.multmat(helpMat2);
|
||||||
#end
|
#end
|
||||||
#end
|
#end
|
||||||
m = helpMat;
|
m = helpMat;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if rp_probes
|
#if rp_probes
|
||||||
@ -1373,7 +1390,7 @@ class Uniforms {
|
|||||||
if (fa == null) return;
|
if (fa == null) return;
|
||||||
g.setFloats(location, fa);
|
g.setFloats(location, fa);
|
||||||
}
|
}
|
||||||
else if (c.type == "int") {
|
else if (c.type == "int" || c.type == "uint") {
|
||||||
var i: Null<Int> = null;
|
var i: Null<Int> = null;
|
||||||
switch (c.link) {
|
switch (c.link) {
|
||||||
case "_uid": {
|
case "_uid": {
|
||||||
|
|||||||
@ -8,7 +8,7 @@ class AlertNode extends LogicNode {
|
|||||||
|
|
||||||
override function run(from: Int) {
|
override function run(from: Int) {
|
||||||
|
|
||||||
#if kha_html5
|
#if js
|
||||||
js.Browser.window.alert(inputs[1].get());
|
js.Browser.window.alert(inputs[1].get());
|
||||||
#end
|
#end
|
||||||
|
|
||||||
|
|||||||
@ -2,19 +2,31 @@ package leenkx.logicnode;
|
|||||||
|
|
||||||
class ConfirmNode extends LogicNode {
|
class ConfirmNode extends LogicNode {
|
||||||
|
|
||||||
|
var result: Dynamic;
|
||||||
|
|
||||||
public function new(tree: LogicTree) {
|
public function new(tree: LogicTree) {
|
||||||
super(tree);
|
super(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
override function run(from: Int) {
|
override function run(from: Int) {
|
||||||
|
#if js
|
||||||
#if kha_html5
|
result = js.Browser.window.confirm(inputs[1].get());
|
||||||
var answer: Bool = js.Browser.window.confirm(inputs[1].get());
|
if (Reflect.field(result, "loaded") != null) {
|
||||||
if(answer)
|
tree.notifyOnUpdate(poll);
|
||||||
return runOutput(0);
|
} else {
|
||||||
else
|
if (result) runOutput(0);
|
||||||
return runOutput(1);
|
else runOutput(1);
|
||||||
|
}
|
||||||
#end
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
function poll() {
|
||||||
|
#if js
|
||||||
|
if (result.loaded) {
|
||||||
|
tree.removeUpdate(poll);
|
||||||
|
if (result.data) runOutput(0);
|
||||||
|
else runOutput(1);
|
||||||
|
}
|
||||||
|
#end
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,12 +11,11 @@ class GetElementPropertyNode extends LogicNode {
|
|||||||
override function get(from: Int): Dynamic {
|
override function get(from: Int): Dynamic {
|
||||||
return switch (from) {
|
return switch (from) {
|
||||||
case 0:
|
case 0:
|
||||||
var object: Dynamic = inputs[0].get();
|
#if js
|
||||||
var property = inputs[1].get();
|
var element: Dynamic = inputs[0].get();
|
||||||
|
var property = inputs[1].get();
|
||||||
value = Reflect.field(object, property);
|
value = Reflect.field(element, property);
|
||||||
|
#end
|
||||||
//value = object.getAttribute(property.toString());
|
|
||||||
default: throw "Unreachable";
|
default: throw "Unreachable";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,27 +0,0 @@
|
|||||||
package leenkx.logicnode;
|
|
||||||
|
|
||||||
import iron.math.Vec4;
|
|
||||||
|
|
||||||
class GetHosekWilkiePropertiesNode extends LogicNode {
|
|
||||||
|
|
||||||
public function new(tree: LogicTree) {
|
|
||||||
super(tree);
|
|
||||||
}
|
|
||||||
|
|
||||||
override function get(from: Int): Dynamic {
|
|
||||||
|
|
||||||
var world = iron.Scene.active.world.raw;
|
|
||||||
|
|
||||||
return switch (from) {
|
|
||||||
case 0:
|
|
||||||
world.turbidity;
|
|
||||||
case 1:
|
|
||||||
world.ground_albedo;
|
|
||||||
case 2:
|
|
||||||
new Vec4(world.sun_direction[0], world.sun_direction[1], world.sun_direction[2]);
|
|
||||||
default:
|
|
||||||
null;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
package leenkx.logicnode;
|
|
||||||
|
|
||||||
import iron.math.Vec4;
|
|
||||||
|
|
||||||
class GetNishitaPropertiesNode extends LogicNode {
|
|
||||||
|
|
||||||
public function new(tree: LogicTree) {
|
|
||||||
super(tree);
|
|
||||||
}
|
|
||||||
|
|
||||||
override function get(from: Int): Dynamic {
|
|
||||||
|
|
||||||
var world = iron.Scene.active.world.raw;
|
|
||||||
|
|
||||||
return switch (from) {
|
|
||||||
case 0:
|
|
||||||
world.nishita_density[0];
|
|
||||||
case 1:
|
|
||||||
world.nishita_density[1];
|
|
||||||
case 2:
|
|
||||||
world.nishita_density[2];
|
|
||||||
case 3:
|
|
||||||
new Vec4(world.sun_direction[0], world.sun_direction[1], world.sun_direction[2]);
|
|
||||||
default:
|
|
||||||
null;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
15
leenkx/Sources/leenkx/logicnode/GetWorldColorNode.hx
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package leenkx.logicnode;
|
||||||
|
|
||||||
|
import iron.math.Vec4;
|
||||||
|
|
||||||
|
class GetWorldColorNode extends LogicNode {
|
||||||
|
|
||||||
|
public function new(tree: LogicTree) {
|
||||||
|
super(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function get(from: Int): Dynamic {
|
||||||
|
var col = iron.Scene.active.world.raw.background_color;
|
||||||
|
return new Vec4(((col >> 16) & 0xff) / 255, ((col >> 8) & 0xff) / 255, (col & 0xff) / 255, 1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
50
leenkx/Sources/leenkx/logicnode/GetWorldSkyNode.hx
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package leenkx.logicnode;
|
||||||
|
|
||||||
|
import iron.math.Vec4;
|
||||||
|
|
||||||
|
class GetWorldSkyNode extends LogicNode {
|
||||||
|
|
||||||
|
public var property0:String;
|
||||||
|
|
||||||
|
public function new(tree: LogicTree) {
|
||||||
|
super(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function get(from: Int): Dynamic {
|
||||||
|
var world = iron.Scene.active.world.raw;
|
||||||
|
|
||||||
|
if (property0 == 'hosek') {
|
||||||
|
return switch (from) {
|
||||||
|
case 0: world.turbidity != null ? world.turbidity : 1.0;
|
||||||
|
case 1: world.ground_albedo != null ? world.ground_albedo : 0.0;
|
||||||
|
case 2: world.sun_direction != null ? new Vec4(world.sun_direction[0], world.sun_direction[1], world.sun_direction[2]) : new Vec4(0, 0, 1);
|
||||||
|
default: null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (property0 == 'single') {
|
||||||
|
return switch (from) {
|
||||||
|
case 0: world.sky_density != null ? world.sky_density[0] : 1.0;
|
||||||
|
case 1: world.sky_density != null ? world.sky_density[1] : 1.0;
|
||||||
|
case 2: world.sky_density != null ? world.sky_density[2] : 1.0;
|
||||||
|
case 3: world.sky_altitude != null ? world.sky_altitude : 0.0;
|
||||||
|
case 4: world.sun_direction != null ? new Vec4(world.sun_direction[0], world.sun_direction[1], world.sun_direction[2]) : new Vec4(0, 0, 1);
|
||||||
|
default: null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { // multi
|
||||||
|
return switch (from) {
|
||||||
|
case 0: world.sky_density != null ? world.sky_density[0] : 1.0;
|
||||||
|
case 1: world.sky_density != null ? world.sky_density[1] : 1.0;
|
||||||
|
case 2: world.sky_density != null ? world.sky_density[2] : 1.0;
|
||||||
|
case 3: world.sky_sun_elevation != null ? world.sky_sun_elevation : 0.0;
|
||||||
|
case 4: world.sky_sun_rotation != null ? world.sky_sun_rotation : 0.0;
|
||||||
|
case 5: world.sky_sun_size != null ? world.sky_sun_size : 0.545;
|
||||||
|
case 6: world.sky_sun_intensity != null ? world.sky_sun_intensity : 1.0;
|
||||||
|
case 7: world.sky_altitude != null ? world.sky_altitude : 0.0;
|
||||||
|
case 8: world.sky_sun_disc != null ? world.sky_sun_disc : 1;
|
||||||
|
case 9: world.sun_direction != null ? new Vec4(world.sun_direction[0], world.sun_direction[1], world.sun_direction[2]) : new Vec4(0, 0, 1);
|
||||||
|
default: null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
17
leenkx/Sources/leenkx/logicnode/GetWorldTextureNode.hx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package leenkx.logicnode;
|
||||||
|
|
||||||
|
class GetWorldTextureNode extends LogicNode {
|
||||||
|
|
||||||
|
public function new(tree: LogicTree) {
|
||||||
|
super(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function get(from: Int): Dynamic {
|
||||||
|
var world = iron.Scene.active.world;
|
||||||
|
return switch (from) {
|
||||||
|
case 0: world.probe != null ? world.probe.raw.strength : 1.0;
|
||||||
|
case 1: world.raw.envmap != null ? world.raw.envmap : '';
|
||||||
|
default: null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
leenkx/Sources/leenkx/logicnode/KromCopyToClipboardNode.hx
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package leenkx.logicnode;
|
||||||
|
|
||||||
|
class KromCopyToClipboardNode extends LogicNode {
|
||||||
|
|
||||||
|
public function new(tree: LogicTree) {
|
||||||
|
super(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function run(from: Int) {
|
||||||
|
#if kha_krom
|
||||||
|
var text: String = inputs[1].get();
|
||||||
|
js.Syntax.code("Krom.copyToClipboard({0})", text);
|
||||||
|
#end
|
||||||
|
runOutput(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
15
leenkx/Sources/leenkx/logicnode/KromDelayIdleSleepNode.hx
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package leenkx.logicnode;
|
||||||
|
|
||||||
|
class KromDelayIdleSleepNode extends LogicNode {
|
||||||
|
|
||||||
|
public function new(tree: LogicTree) {
|
||||||
|
super(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function run(from: Int) {
|
||||||
|
#if kha_krom
|
||||||
|
js.Syntax.code("Krom.delayIdleSleep()");
|
||||||
|
#end
|
||||||
|
runOutput(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
16
leenkx/Sources/leenkx/logicnode/KromDeleteFileNode.hx
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package leenkx.logicnode;
|
||||||
|
|
||||||
|
class KromDeleteFileNode extends LogicNode {
|
||||||
|
|
||||||
|
public function new(tree: LogicTree) {
|
||||||
|
super(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function run(from: Int) {
|
||||||
|
#if kha_krom
|
||||||
|
var path: String = inputs[1].get();
|
||||||
|
js.Syntax.code("Krom.deleteFile({0})", path);
|
||||||
|
#end
|
||||||
|
runOutput(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
17
leenkx/Sources/leenkx/logicnode/KromFileExistsNode.hx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package leenkx.logicnode;
|
||||||
|
|
||||||
|
class KromFileExistsNode extends LogicNode {
|
||||||
|
|
||||||
|
public function new(tree: LogicTree) {
|
||||||
|
super(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function get(from: Int): Dynamic {
|
||||||
|
#if kha_krom
|
||||||
|
var path: String = inputs[0].get();
|
||||||
|
return js.Syntax.code("Krom.fileExists({0})", path);
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
}
|
||||||
16
leenkx/Sources/leenkx/logicnode/KromGetArgCountNode.hx
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package leenkx.logicnode;
|
||||||
|
|
||||||
|
class KromGetArgCountNode extends LogicNode {
|
||||||
|
|
||||||
|
public function new(tree: LogicTree) {
|
||||||
|
super(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function get(from: Int): Dynamic {
|
||||||
|
#if kha_krom
|
||||||
|
return Krom.getArgCount();
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
}
|
||||||
17
leenkx/Sources/leenkx/logicnode/KromGetArgNode.hx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package leenkx.logicnode;
|
||||||
|
|
||||||
|
class KromGetArgNode extends LogicNode {
|
||||||
|
|
||||||
|
public function new(tree: LogicTree) {
|
||||||
|
super(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function get(from: Int): Dynamic {
|
||||||
|
#if kha_krom
|
||||||
|
var index: Int = inputs[0].get();
|
||||||
|
return Krom.getArg(index);
|
||||||
|
#else
|
||||||
|
return "";
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
}
|
||||||
16
leenkx/Sources/leenkx/logicnode/KromGetFilesLocationNode.hx
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package leenkx.logicnode;
|
||||||
|
|
||||||
|
class KromGetFilesLocationNode extends LogicNode {
|
||||||
|
|
||||||
|
public function new(tree: LogicTree) {
|
||||||
|
super(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function get(from: Int): Dynamic {
|
||||||
|
#if kha_krom
|
||||||
|
return Krom.getFilesLocation();
|
||||||
|
#else
|
||||||
|
return "";
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
}
|
||||||
16
leenkx/Sources/leenkx/logicnode/KromSavePathNode.hx
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package leenkx.logicnode;
|
||||||
|
|
||||||
|
class KromSavePathNode extends LogicNode {
|
||||||
|
|
||||||
|
public function new(tree: LogicTree) {
|
||||||
|
super(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function get(from: Int): Dynamic {
|
||||||
|
#if kha_krom
|
||||||
|
return Krom.savePath();
|
||||||
|
#else
|
||||||
|
return "";
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
package leenkx.logicnode;
|
||||||
|
|
||||||
|
class KromSetApplicationNameNode extends LogicNode {
|
||||||
|
|
||||||
|
public function new(tree: LogicTree) {
|
||||||
|
super(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function run(from: Int) {
|
||||||
|
#if kha_krom
|
||||||
|
var name: String = inputs[1].get();
|
||||||
|
js.Syntax.code("Krom.setApplicationName({0})", name);
|
||||||
|
#end
|
||||||
|
runOutput(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
16
leenkx/Sources/leenkx/logicnode/KromShowKeyboardNode.hx
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package leenkx.logicnode;
|
||||||
|
|
||||||
|
class KromShowKeyboardNode extends LogicNode {
|
||||||
|
|
||||||
|
public function new(tree: LogicTree) {
|
||||||
|
super(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function run(from: Int) {
|
||||||
|
#if kha_krom
|
||||||
|
var show: Bool = inputs[1].get();
|
||||||
|
js.Syntax.code("Krom.showKeyboard({0})", show);
|
||||||
|
#end
|
||||||
|
runOutput(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
28
leenkx/Sources/leenkx/logicnode/KromSysCommandNode.hx
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package leenkx.logicnode;
|
||||||
|
|
||||||
|
class KromSysCommandNode extends LogicNode {
|
||||||
|
|
||||||
|
var exitCode: Int = 0;
|
||||||
|
|
||||||
|
public function new(tree: LogicTree) {
|
||||||
|
super(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function run(from: Int) {
|
||||||
|
#if kha_krom
|
||||||
|
var cmd: String = inputs[1].get();
|
||||||
|
var args: Dynamic = inputs[2].get();
|
||||||
|
if (args != null) {
|
||||||
|
exitCode = Krom.sysCommand(cmd, args);
|
||||||
|
} else {
|
||||||
|
exitCode = Krom.sysCommand(cmd);
|
||||||
|
}
|
||||||
|
#end
|
||||||
|
runOutput(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
override function get(from: Int): Dynamic {
|
||||||
|
if (from == 1) return exitCode;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -20,6 +20,7 @@ class LeenkxSendMessageNode extends LogicNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override function run(from:Int) {
|
override function run(from:Int) {
|
||||||
|
#if js
|
||||||
var connection = inputs[1].get();
|
var connection = inputs[1].get();
|
||||||
if (connection == null) return;
|
if (connection == null) return;
|
||||||
var api: String = inputs[2].get();
|
var api: String = inputs[2].get();
|
||||||
@ -348,6 +349,7 @@ class LeenkxSendMessageNode extends LogicNode {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,7 @@ class LoadUrlNode extends LogicNode {
|
|||||||
override function run(from: Int) {
|
override function run(from: Int) {
|
||||||
//System.loadUrl(inputs[1].get());
|
//System.loadUrl(inputs[1].get());
|
||||||
|
|
||||||
#if kha_html5
|
#if js
|
||||||
if (inputs[2].get()){
|
if (inputs[2].get()){
|
||||||
var window = inputs[3].get() ? js.Browser.window.open(inputs[1].get(), "_blank", "width="+inputs[4].get()+",height="+inputs[5].get()+",left="+inputs[6].get()+",top="+inputs[7].get())
|
var window = inputs[3].get() ? js.Browser.window.open(inputs[1].get(), "_blank", "width="+inputs[4].get()+",height="+inputs[5].get()+",left="+inputs[6].get()+",top="+inputs[7].get())
|
||||||
: js.Browser.window.open(inputs[1].get(), "_blank");
|
: js.Browser.window.open(inputs[1].get(), "_blank");
|
||||||
|
|||||||