Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(godRay): Add feature of GodRay post. #277

Merged
merged 2 commits into from
Aug 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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