Skip to content

Commit

Permalink
feat(godRay): Add feature of GodRay post. (Orillusion#277)
Browse files Browse the repository at this point in the history
Add feature of GodRay post.
import GodRayPost from core
  • Loading branch information
hellmor authored Aug 9, 2023
1 parent 8cd1498 commit 1aa2a85
Show file tree
Hide file tree
Showing 7 changed files with 474 additions and 42 deletions.
126 changes: 126 additions & 0 deletions samples/post/Sample_GodRay.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import {
View3D, DirectLight, Engine3D,
PostProcessingComponent, LitMaterial, HoverCameraController,
KelvinUtil, MeshRenderer, Object3D, PlaneGeometry, Scene3D, SphereGeometry,
CameraUtil, webGPUContext, BoxGeometry, AtmosphericComponent, Time,
HDRBloomPost, GodRayPost
} from '@orillusion/core';
import { GUIHelp } from '@orillusion/debug/GUIHelp';
import { GUIUtil } from '@samples/utils/GUIUtil';

class Sample_GodRay {
lightObj: Object3D;
scene: Scene3D;

async run() {
Engine3D.setting.shadow.shadowSize = 2048
Engine3D.setting.shadow.shadowBound = 400;
Engine3D.setting.shadow.shadowBias = 0.0005;

await Engine3D.init({ renderLoop: () => { this.loop() } });

this.scene = new Scene3D();
let sky = this.scene.addComponent(AtmosphericComponent);
GUIHelp.init();

let mainCamera = CameraUtil.createCamera3DObject(this.scene, 'camera');
mainCamera.perspective(60, webGPUContext.aspect, 1, 5000.0);
let ctrl = mainCamera.object3D.addComponent(HoverCameraController);
ctrl.setCamera(0, -15, 200);
await this.initScene();

sky.relativeTransform = this.lightObj.transform;

let view = new View3D();
view.scene = this.scene;
view.camera = mainCamera;
Engine3D.startRenderView(view);

let postProcessing = this.scene.addComponent(PostProcessingComponent);
postProcessing.addPost(GodRayPost);
postProcessing.addPost(HDRBloomPost);

GUIUtil.renderAtomosphericSky(sky, false);
}
async initScene() {
{
this.lightObj = new Object3D();
this.lightObj.rotationX = 15;
this.lightObj.rotationY = 110;
this.lightObj.rotationZ = 0;
let lc = this.lightObj.addComponent(DirectLight);
lc.lightColor = KelvinUtil.color_temperature_to_rgb(5355);
lc.castShadow = true;
lc.intensity = 20;
this.scene.addChild(this.lightObj);
GUIUtil.renderDirLight(lc);
}

{
let mat = new LitMaterial();

let floor = new Object3D();
let mr = floor.addComponent(MeshRenderer);
mr.geometry = new PlaneGeometry(2000, 2000);
mr.material = mat;
this.scene.addChild(floor);
}

this.createPlane(this.scene);
}

private ball: Object3D;
private createPlane(scene: Scene3D) {
let mat = new LitMaterial();
mat.baseMap = Engine3D.res.whiteTexture;
mat.normalMap = Engine3D.res.normalTexture;
mat.aoMap = Engine3D.res.whiteTexture;
mat.maskMap = Engine3D.res.createTexture(32, 32, 255.0, 10.0, 0.0, 1);
mat.emissiveMap = Engine3D.res.blackTexture;
mat.roughness = 0.5;
mat.roughness_max = 0.1;
mat.metallic = 0.2;
{
let sphereGeometry = new SphereGeometry(20, 50, 50);
let obj: Object3D = new Object3D();
let mr = obj.addComponent(MeshRenderer);
mr.material = mat;
mr.geometry = sphereGeometry;
obj.x = 10;
obj.y = 20;
scene.addChild(obj);
this.ball = obj;
}

const length = 5;
for (let i = 0; i < length; i++) {
let cubeGeometry = new BoxGeometry(10, 160, 10);
for (let j = 0; j < length; j++) {
let obj: Object3D = new Object3D();
let mr = obj.addComponent(MeshRenderer);
mr.material = mat;
mr.geometry = cubeGeometry;
obj.localScale = obj.localScale;
obj.x = (i - 2.5) * 40;
obj.z = (j - 2.5) * 40;
obj.y = 60;
obj.rotationX = (Math.random() - 0.5) * 80;
obj.rotationY = (Math.random() - 0.5) * 90;
scene.addChild(obj);
}
}
}
private loop() {
if (this.ball) {
let position = this.ball.localPosition;
let angle = Time.time * 0.001;
position.x = Math.sin(angle) * 40;
position.z = Math.cos(angle) * 40;
position.y = 80;
this.ball.localPosition = position;
}
}

}

new Sample_GodRay().run();
41 changes: 4 additions & 37 deletions src/assets/shader/compute/DDGILighting_CSShader.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,9 @@
export let DDGILighting_shader = /*wgsl*/`
#include "GlobalUniform"
#include "MathShader"
#include "FastMathShader"
#include "ColorUtil"
struct GlobalUniform {
projMat: mat4x4<f32>,
viewMat: mat4x4<f32>,
cameraWorldMatrix: mat4x4<f32>,
pvMatrixInv : mat4x4<f32>,
shadowMatrix: array<mat4x4<f32>,8>,
CameraPos: vec3<f32>,
frame: f32,
time: f32,
delta: f32,
shadowBias: f32,
skyExposure: f32,
renderPassState:f32,
quadScale: f32,
hdrExposure: f32,
renderState_left: i32,
renderState_right: i32,
renderState_split: f32,
mouseX: f32,
mouseY: f32,
windowWidth: f32,
windowHeight: f32,
near: f32,
far: f32,
pointShadowBias: f32,
shadowMapSize: f32,
shadowSoft: f32,
};
struct ConstUniform{
screenWidth:f32,
Expand Down Expand Up @@ -74,10 +42,9 @@ const PointLightType = 1;
const DirectLightType = 2;
const SpotLightType = 3;
@group(0) @binding(0) var outputBuffer : texture_storage_2d<rgba16float, write>;
@group(0) @binding(1) var prefilterMapSampler: sampler;
@group(0) @binding(2) var prefilterMap: texture_cube<f32>;
@group(0) @binding(3) var<uniform> globalUniform: GlobalUniform;
@group(0) @binding(1) var outputBuffer : texture_storage_2d<rgba16float, write>;
@group(0) @binding(2) var prefilterMapSampler: sampler;
@group(0) @binding(3) var prefilterMap: texture_cube<f32>;
@group(1) @binding(0) var positionMapSampler : sampler;
@group(1) @binding(1) var positionMap : texture_2d<f32>;
Expand Down
4 changes: 1 addition & 3 deletions src/assets/shader/compute/GTAO_cs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ export let GTAO_cs: string = /*wgsl*/ `
slot2: f32,
}
@group(0) @binding(0) var<uniform> standUniform: GlobalUniform;
@group(0) @binding(1) var<uniform> gtaoData: GTAO;
@group(0) @binding(2) var<storage, read_write> directions : array<vec2<f32>>;
@group(0) @binding(3) var<storage, read_write> aoBuffer : array<f32>;
Expand All @@ -41,7 +40,6 @@ export let GTAO_cs: string = /*wgsl*/ `
return;
}
wNormal = textureLoad(normalTex, fragCoord, 0);
wNormal = vec4<f32>(wNormal.rgb,wNormal.w) ;
var oc = textureLoad(inTex, fragCoord, 0);
let index = fragCoord.x + fragCoord.y * i32(texSize.x);
let lastFactor = aoBuffer[index];
Expand All @@ -50,7 +48,7 @@ export let GTAO_cs: string = /*wgsl*/ `
}else{
wPosition = textureLoad(posTex, fragCoord, 0).xyz;
let ndc = standUniform.projMat * standUniform.viewMat * vec4<f32>(wPosition, 1.0);
let ndc = globalUniform.projMat * globalUniform.viewMat * vec4<f32>(wPosition, 1.0);
let ndcZ = ndc.z / ndc.w;
maxPixelScaled = calcPixelByNDC(ndcZ);
newFactor = rayMarch();
Expand Down
180 changes: 180 additions & 0 deletions src/assets/shader/compute/GodRay_cs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
export let GodRay_cs: string = /*wgsl*/ `
#include "GlobalUniform"
struct LightData {
index:f32,
lightType:i32,
radius:f32,
linear:f32,
position:vec3<f32>,
lightMatrixIndex:f32,
direction:vec3<f32>,
quadratic:f32,
lightColor:vec3<f32>,
intensity:f32,
innerCutOff :f32,
outerCutOff:f32,
range :f32,
castShadow:i32,
lightTangent:vec3<f32>,
ies:f32,
};
struct Uniforms {
matrix : array<mat4x4<f32>>
};
struct CacheGodRay {
pos:vec3<f32>,
value:f32,
};
struct GodRayUniform{
intensity: f32,
rayMarchCount: f32,
viewPortWidth: f32,
viewPortHeight: f32,
blendColor: f32,
scatteringExponent: f32,
}
@group(0) @binding(1) var<uniform> godRayUniform: GodRayUniform;
@group(0) @binding(2) var posTex : texture_2d<f32>;
@group(0) @binding(3) var normalTex : texture_2d<f32>;
@group(0) @binding(4) var inTex : texture_2d<f32>;
@group(0) @binding(5) var outTex : texture_storage_2d<rgba16float, write>;
@group(0) @binding(6) var shadowMapSampler : sampler_comparison;
@group(0) @binding(7) var shadowMap : texture_depth_2d_array;
@group(1) @binding(0)
var<storage,read> lightBuffer: array<LightData>;
@group(1) @binding(1)
var<storage, read> models : Uniforms;
@group(2) @binding(0) var<storage, read_write> historyGodRayData: array<CacheGodRay>;
var<private> viewDirection: vec3<f32> ;
var<private> texSize: vec2<u32>;
var<private> fragCoord: vec2<i32>;
var<private> wPosition: vec3<f32>;
var<private> wNormal: vec4<f32>;
var<private> directLight: LightData;
fn directionShadowMapping(worldPos:vec3<f32>, shadowBias:f32) -> f32 {
var shadowPos = globalUniform.shadowMatrix[0] * vec4<f32>(worldPos.xyz, 1.0);
var shadowUV = shadowPos.xy * vec2<f32>(0.5, -0.5) + vec2<f32>(0.5, 0.5) ;
var visibility = textureSampleCompareLevel( shadowMap, shadowMapSampler, shadowUV, 0, shadowPos.z - shadowBias );
return visibility;
}
@compute @workgroup_size( 8 , 8 , 1 )
fn CsMain( @builtin(workgroup_id) workgroup_id : vec3<u32> , @builtin(global_invocation_id) globalInvocation_id : vec3<u32>)
{
fragCoord = vec2<i32>( globalInvocation_id.xy );
texSize = textureDimensions(inTex).xy;
if(fragCoord.x >= i32(texSize.x) || fragCoord.y >= i32(texSize.y)){
return;
}
wNormal = textureLoad(normalTex, fragCoord, 0);
var oc = textureLoad(inTex, fragCoord, 0);
var outColor = oc.xyz;
directLight = lightBuffer[0] ;
if(directLight.castShadow >= 0){
let index = fragCoord.x + fragCoord.y * i32(texSize.x);
var historyData = historyGodRayData[index];
let lightColor = directLight.lightColor;
var godRayFactor = 0.0;
if(wNormal.w > 0.5){
//not sky
let lightPos = models.matrix[u32(directLight.lightMatrixIndex)][3].xyz;
wPosition = textureLoad(posTex, fragCoord, 0).xyz;
viewDirection = normalize(globalUniform.CameraPos - wPosition) ;
godRayFactor = rayMarch();
godRayFactor = updateGodRay(historyData, godRayFactor);
}
historyData.pos = wPosition;
historyData.value = godRayFactor;
historyGodRayData[index] = historyData;
outColor = oc.xyz + vec3<f32>(godRayFactor * godRayUniform.intensity * lightColor);
}
textureStore(outTex, fragCoord , vec4<f32>(outColor, oc.w));
}
fn updateGodRay(historyData:CacheGodRay, newFactor:f32) -> f32 {
var changeFactor = 0.2;
if(length(historyData.pos - wPosition) > 0.01){
changeFactor = 0.4;
}
var factor = mix(historyData.value, newFactor, changeFactor);
let pixelOffset = 1 + i32(globalUniform.frame) % 3;
let coordRange = vec2<i32>(texSize);
let coordIndex0 = getCoordIndex(fragCoord.x + pixelOffset, fragCoord.y - pixelOffset, coordRange);
let coordIndex1 = getCoordIndex(fragCoord.x - pixelOffset, fragCoord.y - pixelOffset, coordRange);
let coordIndex2 = getCoordIndex(fragCoord.x, fragCoord.y + pixelOffset * 2, coordRange);
let oldOC0 = historyGodRayData[coordIndex0].value;
let oldOC1 = historyGodRayData[coordIndex1].value;
let oldOC2 = historyGodRayData[coordIndex2].value;
let opRound = (oldOC0 + oldOC1 + oldOC2) * 0.3333333;
factor = mix(opRound, factor, 0.5);
return factor;
}
fn getCoordIndex(x0:i32, y0:i32, size:vec2<i32>) -> i32{
let x = clamp(x0, 0, size.x - 1);
let y = clamp(y0, 0, size.y - 1);
return y * size.x + x;
}
fn rayMarch() -> f32{
var godRayFactor = 0.0;
let L = normalize(directLight.direction);
let rayMarchCount = godRayUniform.rayMarchCount;
if(godRayUniform.blendColor > 0.5){
let eyePosition = globalUniform.CameraPos;
var samplePosition = eyePosition;
var lastSamplePosition = eyePosition;
var frameOffset = f32(i32(globalUniform.frame) % 4);
frameOffset *= 0.25;
for(var i:f32 = 1.0; i < rayMarchCount; i += 1.0){
var t = (i + frameOffset) / rayMarchCount;
lastSamplePosition = samplePosition;
samplePosition = mix(eyePosition, wPosition, t * t);
var shadowVisibility = directionShadowMapping(samplePosition, globalUniform.shadowBias);
if(shadowVisibility > 0.5){
var stepFactor = calcGodRayValue(samplePosition, L, viewDirection);
stepFactor *= length(lastSamplePosition - samplePosition);
godRayFactor += stepFactor;
}
}
godRayFactor /= length(wPosition - eyePosition);
}
return godRayFactor;
}
fn calcGodRayValue(pos:vec3<f32>, L:vec3<f32>, V:vec3<f32>) -> f32{
var halfLoV = normalize(L + V);
var LoV = saturate(dot(V,halfLoV));
LoV = pow(LoV, godRayUniform.scatteringExponent);
var distance = length(pos - globalUniform.CameraPos) / (globalUniform.far);
distance = 1.0 - saturate(distance);
distance *= distance;
return LoV * distance;
}
`
Loading

0 comments on commit 1aa2a85

Please sign in to comment.