This commit is contained in:
Lubos Lenco 2017-05-23 15:01:56 +02:00
parent da5f18c97c
commit 52efec23da
18 changed files with 133 additions and 107 deletions

View file

@ -49,7 +49,7 @@ in vec2 texCoord;
out vec4 fragColor;
void main() {
vec4 g0 = texture(gbuffer0, texCoord); // Normal.xy, metallic/roughness, occlusion
vec4 g0 = texture(gbuffer0, texCoord); // Normal.xy, metallic/roughness, depth
vec3 n;
n.z = 1.0 - abs(g0.x) - abs(g0.y);
@ -119,7 +119,11 @@ void main() {
envl.rgb += prefilteredColor * (f0 * envBRDF.x + envBRDF.y);
#endif
#ifdef _SSS
envl.rgb *= envmapStrength * fract(g1.a);
#else
envl.rgb *= envmapStrength * g1.a; // Occlusion
#endif
#ifdef _SSAO
envl.rgb *= texture(ssaotex, texCoord).r; // SSAO

View file

@ -20,6 +20,9 @@ precision mediump float;
#include "../std/shadows.glsl"
#endif
#endif
#ifdef _SSS
#include "../std/sss.glsl"
#endif
#include "../std/gbuffer.glsl"
// #ifdef _VoxelGI
@ -70,29 +73,6 @@ uniform vec3 eye;
in vec4 wvpposition;
out vec4 fragColor;
// Separable SSS Transmittance Function, ref to sss_pass
#ifdef _SSS
vec3 SSSSTransmittance(float translucency, float sssWidth, vec3 worldPosition, vec3 worldNormal, vec3 lightDir) {
float scale = 8.25 * (1.0 - translucency) / sssWidth;
vec4 shrinkedPos = vec4(worldPosition - 0.005 * worldNormal, 1.0);
vec4 shadowPosition = LWVP * shrinkedPos;
float d1 = texture(shadowMap, shadowPosition.xy / shadowPosition.w).r; // 'd1' has a range of 0..1
float d2 = shadowPosition.z; // 'd2' has a range of 0..'lightFarPlane'
const float lightFarPlane = 120 / 3.5;
d1 *= lightFarPlane; // So we scale 'd1' accordingly:
float d = scale * abs(d1 - d2);
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);
return profile * clamp(0.3 + dot(lightDir, -worldNormal), 0.0, 1.0);
}
#endif
#ifndef _NoShadows
float shadowTest(const vec3 lPos) {
@ -260,9 +240,9 @@ void main() {
#endif
#ifdef _SSS
float mask = g0.a;
if (mask == 2.0) {
fragColor.rgb *= SSSSTransmittance(1.0, 0.005, p, n, l);
if (floor(g1.a) == 2) {
if (lightShadow == 1) fragColor.rgb += fragColor.rgb * SSSSTransmittance(1.0, 0.005, p, n, l, shadowMap, LWVP);
else fragColor.rgb += fragColor.rgb * SSSSTransmittanceCube(1.0, 0.005, p, n, l, shadowMapCube, LWVP);
}
#endif

View file

@ -14,6 +14,9 @@ precision mediump float;
#include "../std/shadows.glsl"
#endif
#endif
#ifdef _SSS
#include "../std/sss.glsl"
#endif
#include "../std/gbuffer.glsl"
uniform sampler2D gbufferD;
@ -47,29 +50,6 @@ in vec2 texCoord;
in vec3 viewRay;
out vec4 fragColor;
// Separable SSS Transmittance Function, ref to sss_pass
#ifdef _SSS
vec3 SSSSTransmittance(float translucency, float sssWidth, vec3 worldPosition, vec3 worldNormal, vec3 lightDir) {
float scale = 8.25 * (1.0 - translucency) / sssWidth;
vec4 shrinkedPos = vec4(worldPosition - 0.005 * worldNormal, 1.0);
vec4 shadowPosition = LWVP * shrinkedPos;
float d1 = texture(shadowMap, shadowPosition.xy / shadowPosition.w).r; // 'd1' has a range of 0..1
float d2 = shadowPosition.z; // 'd2' has a range of 0..'lightFarPlane'
const float lightFarPlane = 120 / 3.5;
d1 *= lightFarPlane; // So we scale 'd1' accordingly:
float d = scale * abs(d1 - d2);
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);
return profile * clamp(0.3 + dot(lightDir, -worldNormal), 0.0, 1.0);
}
#endif
#ifndef _NoShadows
float shadowTest(const vec3 lPos) {
@ -187,9 +167,8 @@ void main() {
#endif
#ifdef _SSS
float mask = g0.a;
if (mask == 2.0) {
fragColor.rgb *= SSSSTransmittance(1.0, 0.005, p, n, l);
if (floor(g1.a) == 2) {
fragColor.rgb += fragColor.rgb * SSSSTransmittance(1.0, 0.005, p, n, l, shadowMap, LWVP);
}
#endif

View file

@ -1,37 +1,37 @@
/**
* Copyright (C) 2012 Jorge Jimenez (jorge@iryoku.com)
* Copyright (C) 2012 Diego Gutierrez (diegog@unizar.es)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the following disclaimer
* in the documentation and/or other materials provided with the
* distribution:
*
* "Uses Separable SSS. Copyright (C) 2012 by Jorge Jimenez and Diego
* Gutierrez."
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
* IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are
* those of the authors and should not be interpreted as representing official
* policies, either expressed or implied, of the copyright holders.
*/
//
// Copyright (C) 2012 Jorge Jimenez (jorge@iryoku.com)
// Copyright (C) 2012 Diego Gutierrez (diegog@unizar.es)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the following disclaimer
// in the documentation and/or other materials provided with the
// distribution:
//
// "Uses Separable SSS. Copyright (C) 2012 by Jorge Jimenez and Diego
// Gutierrez."
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
// IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS OR CONTRIBUTORS
// BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// The views and conclusions contained in the software and documentation are
// those of the authors and should not be interpreted as representing official
// policies, either expressed or implied, of the copyright holders.
//
#version 450
@ -42,7 +42,7 @@ precision mediump float;
#include "../compiled.glsl"
uniform sampler2D gbufferD;
uniform sampler2D gbuffer0;
uniform sampler2D gbuffer1;
uniform sampler2D tex;
uniform vec2 dir;
@ -53,7 +53,8 @@ out vec4 fragColor;
const float SSSS_FOVY = 45.0;
// Separable SSS Reflectance
vec4 SSSSBlur(float sssWidth) {
// const float sssWidth = 0.005;
vec4 SSSSBlur() {
// Quality = 0
const int SSSS_N_SAMPLES = 11;
vec4 kernel[SSSS_N_SAMPLES];
@ -76,12 +77,10 @@ vec4 SSSSBlur(float sssWidth) {
// if (SSSS_STREGTH_SOURCE == 0.0) discard;
// Fetch linear depth of current pixel
// vec4 g0 = texture(gbuffer0, texCoord);
// float depth = 1.0 - g0.a;
float depth = texture(gbufferD, texCoord).r * 2.0 - 1.0;
float depth = texture(gbufferD, texCoord).r;
const float projectionA = cameraPlane.y / (cameraPlane.y - cameraPlane.x);
const float projectionB = (-cameraPlane.y * cameraPlane.x) / (cameraPlane.y - cameraPlane.x);
float depthM = projectionB / (depth * 0.5 + 0.5 - projectionA);
float depthM = projectionB / (depth - projectionA);
// Calculate the sssWidth scale (1.0 for a unit plane sitting on the projection window)
float distanceToProjectionWindow = 1.0 / tan(0.5 * radians(SSSS_FOVY));
@ -89,7 +88,7 @@ vec4 SSSSBlur(float sssWidth) {
// Calculate the final step to fetch the surrounding pixels
vec2 finalStep = sssWidth * scale * dir;
finalStep *= 1.0;//SSSS_STREGTH_SOURCE; // Modulate it using the alpha channel.
// finalStep *= 1.0;//SSSS_STREGTH_SOURCE; // Modulate it using the alpha channel.
finalStep *= 1.0 / 3.0; // Divide by 3 as the kernels range from -3 to 3.
// Accumulate the center sample:
@ -154,8 +153,8 @@ vec4 SSSSBlur(float sssWidth) {
void main() {
// SSS only masked objects
if (texture(gbuffer0, texCoord).a == 2.0) {
fragColor = SSSSBlur(0.005);
if (floor(texture(gbuffer1, texCoord).a) == 2) {
fragColor = clamp(SSSSBlur(), 0.0, 1.0);
}
else {
fragColor = texture(tex, texCoord);

View file

@ -18,7 +18,7 @@
},
{
"name": "sss_pass_y",
"depth_write": true,
"depth_write": false,
"compare_mode": "always",
"cull_mode": "none",
"links": [

25
Shaders/std/sss.glsl Normal file
View file

@ -0,0 +1,25 @@
// Separable SSS Transmittance Function, ref to sss_pass
vec3 SSSSTransmittance(float translucency, float sssWidth, vec3 worldPosition, vec3 worldNormal, vec3 lightDir, sampler2D shadowMap, mat4 LWVP) {
float scale = 8.25 * (1.0 - translucency) / sssWidth;
vec4 shrinkedPos = vec4(worldPosition - 0.005 * worldNormal, 1.0);
vec4 shadowPosition = LWVP * shrinkedPos;
float d1 = texture(shadowMap, shadowPosition.xy / shadowPosition.w).r; // 'd1' has a range of 0..1
float d2 = shadowPosition.z; // 'd2' has a range of 0..'lightFarPlane'
const float lightFarPlane = 50.0; // TODO
d1 *= lightFarPlane; // So we scale 'd1' accordingly:
float d = scale * abs(d1 - d2);
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);
return profile * clamp(0.3 + dot(lightDir, -worldNormal), 0.0, 1.0);
}
vec3 SSSSTransmittanceCube(float translucency, float sssWidth, vec3 worldPosition, vec3 worldNormal, vec3 lightDir, samplerCube shadowMapCube, mat4 LWVP) {
// TODO
return vec3(0.2);
}

View file

@ -697,9 +697,13 @@ class Cycles {
// # write_normal(node.inputs[3])
// pass
// elif node.type == 'SUBSURFACE_SCATTERING':
// # write_normal(node.inputs[4])
// pass
else if (node.type == 'SUBSURFACE_SCATTERING') {
//if parse_surface:
write_normal(node.inputs[4]);
parsing_basecol = true;
sout.out_basecol = parse_vector_input(node.inputs[0]);
parsing_basecol = false;
}
// elif node.type == 'BSDF_TOON':
// # write_normal(node.inputs[3])

View file

@ -156,7 +156,10 @@ def make_deferred(cam):
relink('Set Target Accum', 'Bloom')
# if not cam.rp_bloom:
relink('Bloom', 'SSR')
relink('Bloom', 'SSS')
if not cam.rp_sss_state == 'On':
relink('SSS', 'SSR')
if not cam.rp_ssr:
relink('SSR', 'Draw Compositor')

View file

@ -448,8 +448,8 @@ def make_taa_pass(stages, node_group, node):
make_quad_pass(stages, node_group, node, target_index=1, bind_target_indices=[2, 3, 4], bind_target_constants=['tex', 'tex2', 'sveloc'], shader_context='taa_pass/taa_pass/taa_pass')
def make_sss_pass(stages, node_group, node):
make_quad_pass(stages, node_group, node, target_index=1, bind_target_indices=[3, 4, 5], bind_target_constants=['tex', 'gbufferD', 'gbuffer0'], shader_context='sss_pass/sss_pass/sss_pass_x')
make_quad_pass(stages, node_group, node, target_index=2, bind_target_indices=[3, 4, 5], bind_target_constants=['tex', 'gbufferD', 'gbuffer0'], shader_context='sss_pass/sss_pass/sss_pass_y')
make_quad_pass(stages, node_group, node, target_index=1, bind_target_indices=[3, 4, 5], bind_target_constants=['tex', 'gbufferD', 'gbuffer1'], shader_context='sss_pass/sss_pass/sss_pass_x')
make_quad_pass(stages, node_group, node, target_index=2, bind_target_indices=[3, 4, 5], bind_target_constants=['tex', 'gbufferD', 'gbuffer1'], shader_context='sss_pass/sss_pass/sss_pass_y')
def make_water_pass(stages, node_group, node):
make_quad_pass(stages, node_group, node, target_index=1, bind_target_indices=[2, 3], bind_target_constants=['tex', 'gbufferD'], shader_context='water_pass/water_pass/water_pass')
@ -770,6 +770,9 @@ def traverse_renderpath(node, node_group, render_targets, depth_buffers):
elif node.bl_idname == 'SMAAPassNodeType':
bpy.data.worlds['Arm'].rp_defs += '_SMAA'
elif node.bl_idname == 'SSSPassNodeType':
bpy.data.worlds['Arm'].rp_defs += '_SSS'
elif node.bl_idname == 'SSAOPassNodeType' or node.bl_idname == 'ApplySSAOPassNodeType' or node.bl_idname == 'SSAOReprojectPassNodeType':
if bpy.data.worlds['Arm'].generate_ssao: # SSAO enabled
bpy.data.worlds['Arm'].rp_defs += '_SSAO'

View file

@ -289,8 +289,11 @@ def parse_shader(node, socket):
pass
elif node.type == 'SUBSURFACE_SCATTERING':
# write_normal(node.inputs[4])
pass
if parse_surface:
write_normal(node.inputs[4])
parsing_basecolor(True)
out_basecol = parse_vector_input(node.inputs[0])
parsing_basecolor(False)
elif node.type == 'BSDF_TOON':
# write_normal(node.inputs[3])

View file

@ -1,5 +1,6 @@
import bpy
import arm.utils
import arm.nodes
import arm.material.make_shader as make_shader
import arm.material.mat_batch as mat_batch
import arm.material.mat_state as mat_state
@ -44,6 +45,14 @@ def parse(material, mat_data, mat_users, mat_armusers, rid):
const['bool'] = material.receive_shadow
c['bind_constants'].append(const)
if bpy.data.cameras[0].rp_sss_state == 'On':
sss_node = arm.nodes.get_node_by_type(material.node_tree, 'SUBSURFACE_SCATTERING')
if sss_node != None and sss_node.outputs[0].is_linked: # Check linked node
const = {}
const['name'] = 'materialID'
const['int'] = 2
c['bind_constants'].append(const)
# TODO: Mesh only material batching
if wrd.arm_batch_materials:
# Set textures uniforms

View file

@ -237,7 +237,11 @@ def make_deferred(con_mesh):
frag.write('n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy);')
# TODO: store_depth
frag.write('fragColor[0] = vec4(n.xy, packFloat(metallic, roughness), 1.0 - gl_FragCoord.z);')
frag.write('fragColor[1] = vec4(basecol.rgb, occlusion);')
if '_SSS' in wrd.rp_defs:
frag.add_uniform('int materialID')
frag.write('fragColor[1] = vec4(basecol.rgb, materialID + clamp(occlusion, 0.0, 1.0 - 0.001));')
else:
frag.write('fragColor[1] = vec4(basecol.rgb, occlusion);')
if '_Veloc' in wrd.rp_defs:
frag.write('vec2 posa = (wvpposition.xy / wvpposition.w) * 0.5 + 0.5;')

View file

@ -290,7 +290,7 @@ class SSSPassNode(Node, CGPipelineTreeNode):
self.inputs.new('NodeSocketShader', "Target Out")
self.inputs.new('NodeSocketShader', "Color")
self.inputs.new('NodeSocketShader', "GBufferD")
self.inputs.new('NodeSocketShader', "GBuffer0")
self.inputs.new('NodeSocketShader', "GBuffer1")
self.outputs.new('NodeSocketShader', "Stage")

View file

@ -357,6 +357,10 @@ def init_properties():
('Off', 'Off', 'Off'),
('Auto', 'Auto', 'Auto')],
name="Overlays", description="X-Ray pass", default='Auto', update=update_overlays_state)
bpy.types.Camera.rp_sss_state = bpy.props.EnumProperty(
items=[('On', 'On', 'On'),
('Off', 'Off', 'Off')],
name="SSS", description="Sub-surface scattering pass", default='Off', update=update_renderpath)
bpy.types.Camera.rp_stereo = bpy.props.BoolProperty(name="Stereo", description="Stereo rendering", default=False, update=update_renderpath)
bpy.types.Camera.rp_greasepencil = bpy.props.BoolProperty(name="Grease Pencil", description="Render Grease Pencil data", default=False, update=update_renderpath)
bpy.types.Camera.rp_voxelgi = bpy.props.BoolProperty(name="Voxel GI", description="Voxel-based Global Illumination", default=False, update=update_renderpath)
@ -370,6 +374,7 @@ def init_properties():
bpy.types.World.voxelgi_env = bpy.props.FloatProperty(name="Env Map", description="Contribute light from environment map", default=0.0, update=assets.invalidate_shader_cache)
bpy.types.World.voxelgi_step = bpy.props.FloatProperty(name="Step", description="Step size", default=1.0, update=assets.invalidate_shader_cache)
bpy.types.World.voxelgi_range = bpy.props.FloatProperty(name="Range", description="Maximum range", default=1.0, update=assets.invalidate_shader_cache)
bpy.types.World.sss_width = bpy.props.FloatProperty(name="SSS Width", description="SSS blur strength", default=1.0, update=assets.invalidate_shader_cache)
# For world
bpy.types.World.world_envtex_name = bpy.props.StringProperty(name="Environment Texture", default='')

View file

@ -245,6 +245,9 @@ class GenRPDataPropsPanel(bpy.types.Panel):
layout.prop(dat, "rp_translucency_state")
layout.prop(dat, "rp_overlays_state")
layout.prop(dat, "rp_decals_state")
layout.prop(dat, "rp_sss_state")
if dat.rp_sss_state == 'On':
layout.prop(wrd, 'sss_width')
layout.prop(dat, "rp_hdr")
layout.prop(dat, "rp_worldnodes")
if not dat.rp_worldnodes:

View file

@ -381,6 +381,11 @@ const float voxelgiOcc = """ + str(round(wrd.voxelgi_occ * 100) / 100) + """;
const float voxelgiEnv = """ + str(round(wrd.voxelgi_env * 100) / 100) + """;
const float voxelgiStep = """ + str(round(wrd.voxelgi_step * 100) / 100) + """;
const float voxelgiRange = """ + str(round(wrd.voxelgi_range * 100) / 100) + """;
""")
if bpy.data.cameras[0].rp_sss_state == 'On':
f.write(
"""const float sssWidth = """ + str(wrd.sss_width / 10.0) + """;
""")
# Skinning

Binary file not shown.

Binary file not shown.