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

Repair shadow matrix for 3d-v1.2 #7223

Merged
merged 10 commits into from Aug 28, 2020
24 changes: 12 additions & 12 deletions cocos/core/3d/builtin/effects.ts

Large diffs are not rendered by default.

43 changes: 42 additions & 1 deletion cocos/core/geometry/sphere.ts
Expand Up @@ -4,8 +4,12 @@

import { Mat4, Quat, Vec3 } from '../math';
import enums from './enums';
import aabb from './aabb';

const _v3_tmp = new Vec3();
const _offset = new Vec3();
const _min = new Vec3();
const _max = new Vec3();
function maxComponent (v: Vec3) { return Math.max(Math.max(v.x, v.y), v.z); }

/**
Expand Down Expand Up @@ -79,7 +83,7 @@ export default class sphere {
/**
* @en
* Set the components of a sphere to the given values
* @zh
* @zh
* 将球体的属性设置为给定的值。
* @param {sphere} out 接受操作的 sphere。
* @param cx 形状的相对于原点的 X 坐标。
Expand All @@ -98,6 +102,43 @@ export default class sphere {
return out;
}

/**
* @zh
* 球跟点合并
*/
public static mergePoint (out: sphere, s: sphere, point: Vec3) {
if (s.radius < 0.0) {
out.center = point;
out.radius = 0.0;
return out;
}

Vec3.subtract(_offset, point, s.center);
const dist = _offset.length();

if (dist > s.radius) {
const half = (dist - s.radius) * 0.5;
out.radius += half;
Vec3.multiplyScalar(_offset, _offset, half / dist);
Vec3.add(out.center, out.center, _offset);
}

return out;
}

/**
* @zh
* 球跟立方体合并
*/
public static mergeAABB (out: sphere, s:sphere, a: aabb) {
a.getBoundary(_min, _max);

sphere.mergePoint(out, s, _min);
sphere.mergePoint(out, s, _max);

return out;
}

/**
* @en
* The center of this sphere.
Expand Down
6 changes: 5 additions & 1 deletion cocos/core/pipeline/define.ts
Expand Up @@ -198,7 +198,9 @@ export class UBOShadow {
public static MAT_LIGHT_PLANE_PROJ_OFFSET: number = 0;
public static MAT_LIGHT_VIEW_PROJ_OFFSET: number = UBOShadow.MAT_LIGHT_PLANE_PROJ_OFFSET + 16;
public static SHADOW_COLOR_OFFSET: number = UBOShadow.MAT_LIGHT_VIEW_PROJ_OFFSET + 16;
public static COUNT: number = UBOShadow.SHADOW_COLOR_OFFSET + 4;
public static SHADOW_PCF_OFFSET: number = UBOShadow.SHADOW_COLOR_OFFSET + 4;
public static SHADOW_SIZE_OFFSET: number = UBOShadow.SHADOW_PCF_OFFSET + 4;
public static COUNT: number = UBOShadow.SHADOW_SIZE_OFFSET + 4;
public static SIZE: number = UBOShadow.COUNT * 4;

public static BLOCK: IBlockInfo = {
Expand All @@ -207,6 +209,8 @@ export class UBOShadow {
{ name: 'cc_matLightPlaneProj', type: GFXType.MAT4, count: 1 },
{ name: 'cc_matLightViewProj', type: GFXType.MAT4, count: 1 },
{ name: 'cc_shadowColor', type: GFXType.FLOAT4, count: 1 },
{ name: 'cc_shadowPCF', type: GFXType.FLOAT4, count: 1 },
{ name: 'cc_shadowSize', type: GFXType.FLOAT4, count: 1 },
],
};
}
Expand Down
22 changes: 19 additions & 3 deletions cocos/core/pipeline/forward/forward-pipeline.ts
Expand Up @@ -26,6 +26,7 @@ import { Shadows, ShadowType } from '../../renderer/scene/shadows';

const matShadowView = new Mat4();
const matShadowViewProj = new Mat4();
const vec4 = new Vec4();

/**
* @en The forward render pipeline
Expand Down Expand Up @@ -167,11 +168,20 @@ export class ForwardPipeline extends RenderPipeline {

if (mainLight && shadowInfo.type === ShadowType.ShadowMap) {
// light view
Mat4.invert(matShadowView, mainLight!.node!.worldMatrix);
const shadowCameraView = shadowInfo.getWorldMatrix(mainLight!.node!.worldRotation, mainLight!.direction);
Mat4.invert(matShadowView, shadowCameraView);

// light proj
const x = shadowInfo.orthoSize * shadowInfo.aspect;
const y = shadowInfo.orthoSize;
let x: number = 0;
let y: number = 0;
if (shadowInfo.orthoSize > shadowInfo.sphere.radius) {
x = shadowInfo.orthoSize * shadowInfo.aspect;
y = shadowInfo.orthoSize;
} else {
// if orthoSize is the smallest, auto calculate orthoSize.
x = shadowInfo.sphere.radius * shadowInfo.aspect;
y = shadowInfo.sphere.radius;
}
const projectionSignY = device.screenSpaceSignY * device.UVSpaceSignY;
Mat4.ortho(matShadowViewProj, -x, x, -y, y, shadowInfo.near, shadowInfo.far,
device.clipSpaceMinZ, projectionSignY);
Expand All @@ -180,6 +190,12 @@ export class ForwardPipeline extends RenderPipeline {
Mat4.multiply(matShadowViewProj, matShadowViewProj, matShadowView);

Mat4.toArray(this._shadowUBO, matShadowViewProj, UBOShadow.MAT_LIGHT_VIEW_PROJ_OFFSET);

vec4.set(shadowInfo.pcf);
Vec4.toArray(this._shadowUBO, vec4, UBOShadow.SHADOW_PCF_OFFSET);

vec4.set(shadowInfo.size.x, shadowInfo.size.y);
Vec4.toArray(this._shadowUBO, vec4, UBOShadow.SHADOW_SIZE_OFFSET);
}

// update ubos
Expand Down
6 changes: 5 additions & 1 deletion cocos/core/pipeline/forward/scene-culling.ts
@@ -1,4 +1,4 @@
import { intersect } from '../../geometry';
import { intersect, sphere } from '../../geometry';
import { Model, Camera } from '../../renderer';
import { Layers } from '../../scene-graph';
import { Vec3} from '../../math';
Expand Down Expand Up @@ -49,6 +49,9 @@ export function sceneCulling (pipeline: ForwardPipeline, view: RenderView) {

const mainLight = scene.mainLight;
const shadows = pipeline.shadows;
const shadowSphere = shadows.sphere;
shadowSphere.center.set(0.0, 0.0, 0.0);
shadowSphere.radius = 0.01;
if (mainLight) {
mainLight.update();
if (shadows.type === ShadowType.Planar) {
Expand Down Expand Up @@ -84,6 +87,7 @@ export function sceneCulling (pipeline: ForwardPipeline, view: RenderView) {
// shadow render Object
if (model.castShadow) {
model.updateUBOs(stamp);
sphere.mergeAABB(shadowSphere, shadowSphere, model.worldBounds!);
shadowObjects.push(getCastShadowRenderObject(model, camera));
}

Expand Down
63 changes: 60 additions & 3 deletions cocos/core/renderer/scene/shadows.ts
@@ -1,8 +1,8 @@

import { Material } from '../../assets/material';
import { aabb, frustum, intersect } from '../../geometry';
import { aabb, frustum, intersect, sphere } from '../../geometry';
import { GFXPipelineState } from '../../gfx/pipeline-state';
import { Color, Mat4, Quat, Vec3, Vec2 } from '../../math';
import { Color, Mat4, Quat, Vec3, Vec2, Vec4 } from '../../math';
import { UBOShadow, SetIndex} from '../../pipeline/define';
import { DirectionalLight } from './directional-light';
import { Model } from './model';
Expand All @@ -21,6 +21,9 @@ const _v3 = new Vec3();
const _ab = new aabb();
const _qt = new Quat();
const _up = new Vec3(0, 1, 0);
const _dir_negate = new Vec3();
const _vec3_p = new Vec3();
const _mat4_trans = new Mat4();

/**
* @zh 阴影类型。
Expand All @@ -46,6 +49,35 @@ export const ShadowType = Enum({
ShadowMap: 1,
})

/**
* @zh pcf阴影等级。
* @en The pcf type
* @static
* @enum Shadows.ShadowType
*/
export const PCFType = Enum({
/**
* @zh x1 次采样
* @en x1 times
* @readonly
*/
HARD: 0,

/**
* @zh x5 次采样
* @en x5 times
* @readonly
*/
FILTER_X5: 1,

/**
* @zh x9 次采样
* @en x9 times
* @readonly
*/
FILTER_X9: 2,
})

interface IShadowRenderData {
model: Model;
shaders: GFXShader[];
Expand Down Expand Up @@ -134,6 +166,9 @@ export class Shadows {
get data () {
return this._data;
}
get sphere () {
return this._sphere;
}
protected _enabled: boolean = false;
protected _type = ShadowType.Planar;
protected _normal = new Vec3(0, 1, 0);
Expand All @@ -151,6 +186,11 @@ export class Shadows {
protected _device: GFXDevice|null = null;
protected _globalDescriptorSet: GFXDescriptorSet | null = null;
protected _dirty: boolean = true;
/**
* @zh
* 场景包围球
*/
protected _sphere: sphere = new sphere(0.0, 0.0, 0.0, 0.01);
/**
* @en get or set shadow camera near
* @zh 获取或者设置阴影相机近裁剪面
Expand All @@ -170,13 +210,19 @@ export class Shadows {
* @en get or set shadow camera orthoSize
* @zh 获取或者设置阴影相机正交大小
*/
public orthoSize: number = 5;
public orthoSize: number = 1;
/**
* @en get or set shadow camera orthoSize
* @zh 获取或者设置阴影纹理大小
*/
public size: Vec2 = new Vec2(512, 512);

/**
* @en get or set shadow pcf
* @zh 获取或者设置阴影pcf等级
*/
public pcf = PCFType.HARD;

public activate () {
const pipeline = legacyCC.director.root.pipeline;
this._globalDescriptorSet = pipeline.descriptorSet;
Expand All @@ -190,6 +236,17 @@ export class Shadows {
}
}

public getWorldMatrix (rotation: Quat, dir: Vec3) {
Vec3.negate(_dir_negate, dir);
const distance: number = Math.sqrt(2) * this._sphere.radius;
Vec3.multiplyScalar(_vec3_p, _dir_negate, distance);
Vec3.add(_vec3_p, _vec3_p, this._sphere.center);

Mat4.fromRT(_mat4_trans, rotation, _vec3_p);

return _mat4_trans;
}

protected _updatePlanarInfo () {
this._dirty = true;
if (!this._material) {
Expand Down
18 changes: 17 additions & 1 deletion cocos/core/scene-graph/scene-globals.ts
Expand Up @@ -28,7 +28,7 @@ import { ccclass, property, visible, type, displayOrder, slide, range, rangeStep
import { CCBoolean, CCFloat } from '../data/utils/attribute';
import { Color, Quat, Vec3, Vec2 } from '../math';
import { Ambient } from '../renderer/scene/ambient';
import { Shadows, ShadowType } from '../renderer/scene/shadows';
import { Shadows, ShadowType, PCFType } from '../renderer/scene/shadows';
import { Skybox } from '../renderer/scene/skybox';
import { Fog, FogType } from '../renderer/scene/fog';
import { Node } from './node';
Expand Down Expand Up @@ -386,6 +386,8 @@ export class ShadowsInfo {
@property
protected _shadowColor = new Color(0, 0, 0, 76);
@property
protected _pcf = PCFType.HARD;
@property
protected _near: number = 1;
@property
protected _far: number = 30;
Expand Down Expand Up @@ -461,6 +463,20 @@ export class ShadowsInfo {
return this._distance;
}

/**
* @en The normal of the plane which receives shadow
* @zh 阴影接收平面的法线
*/
@type(PCFType)
@visible(function (this: ShadowsInfo) { return this._type === ShadowType.ShadowMap; })
set pcf (val) {
this._pcf = val;
if (this._resource) { this._resource.pcf = val; }
}
get pcf () {
return this._pcf;
}

/**
* @en get or set shadow camera near
* @zh 获取或者设置阴影相机近裁剪面
Expand Down
36 changes: 35 additions & 1 deletion editor/assets/chunks/cc-shadow-map-fs.chunk
Expand Up @@ -7,9 +7,43 @@ in vec4 v_shadowPos;
#pragma builtin(global)
layout(set = 0, binding = 4) uniform sampler2D cc_shadowMap;

vec4 CCGetShadowFactor () {
vec4 CCGetShadowFactorX1 () {
vec3 clipPos = v_shadowPos.xyz / v_shadowPos.w * 0.5 + 0.5;
float depth = unpackRGBAToDepth(texture(cc_shadowMap, clipPos.xy));
if (depth < (clipPos.z - 0.001)) return cc_shadowColor;
else return vec4(0);
}

vec4 CCGetShadowFactorX5 () {
vec3 clipPos = v_shadowPos.xyz / v_shadowPos.w * 0.5 + 0.5;
float offsetx = 1.0 / cc_shadowSize.x;
float offsety = 1.0 / cc_shadowSize.y;
float depth = 0.0;
depth += unpackRGBAToDepth(texture(cc_shadowMap, vec2(clipPos.x - offsetx, clipPos.y - offsety)));
depth += unpackRGBAToDepth(texture(cc_shadowMap, vec2(clipPos.x - offsetx, clipPos.y + offsety)));
depth += unpackRGBAToDepth(texture(cc_shadowMap, vec2(clipPos.x, clipPos.y)));
depth += unpackRGBAToDepth(texture(cc_shadowMap, vec2(clipPos.x + offsetx, clipPos.y - offsety)));
depth += unpackRGBAToDepth(texture(cc_shadowMap, vec2(clipPos.x + offsetx, clipPos.y + offsety)));
depth /= 5.0;
if (depth < (clipPos.z - 0.001)) return cc_shadowColor;
else return vec4(0);
}

vec4 CCGetShadowFactorX9 () {
vec3 clipPos = v_shadowPos.xyz / v_shadowPos.w * 0.5 + 0.5;
float offsetx = 1.0 / cc_shadowSize.x;
float offsety = 1.0 / cc_shadowSize.y;
float depth = 0.0;
depth += unpackRGBAToDepth(texture(cc_shadowMap, vec2(clipPos.x - offsetx, clipPos.y - offsety)));
depth += unpackRGBAToDepth(texture(cc_shadowMap, vec2(clipPos.x, clipPos.y - offsety)));
depth += unpackRGBAToDepth(texture(cc_shadowMap, vec2(clipPos.x + offsetx, clipPos.y - offsety)));
depth += unpackRGBAToDepth(texture(cc_shadowMap, vec2(clipPos.x - offsetx, clipPos.y)));
depth += unpackRGBAToDepth(texture(cc_shadowMap, vec2(clipPos.x, clipPos.y)));
depth += unpackRGBAToDepth(texture(cc_shadowMap, vec2(clipPos.x + offsetx, clipPos.y)));
depth += unpackRGBAToDepth(texture(cc_shadowMap, vec2(clipPos.x - offsetx, clipPos.y + offsety)));
depth += unpackRGBAToDepth(texture(cc_shadowMap, vec2(clipPos.x, clipPos.y + offsety)));
depth += unpackRGBAToDepth(texture(cc_shadowMap, vec2(clipPos.x + offsetx, clipPos.y + offsety)));
depth /= 9.0;
if (depth < (clipPos.z - 0.001)) return cc_shadowColor;
else return vec4(0);
}
2 changes: 2 additions & 0 deletions editor/assets/chunks/cc-shadow.chunk
Expand Up @@ -5,4 +5,6 @@ layout(set = 0, binding = 1) uniform CCShadow {
highp mat4 cc_matLightPlaneProj;
highp mat4 cc_matLightViewProj;
lowp vec4 cc_shadowColor;
lowp vec4 cc_shadowPCF;
lowp vec4 cc_shadowSize;
};
8 changes: 7 additions & 1 deletion editor/assets/chunks/shading-standard.chunk
Expand Up @@ -2,6 +2,7 @@
// reference: 'moving frostbite to pbr' & UE4 BRDF.usf

#include <cc-global>
#include <cc-shadow>

#if CC_USE_IBL
#include <cc-environment>
Expand Down Expand Up @@ -154,7 +155,12 @@ struct StandardSurface {
finalColor += s.emissive;

#if CC_RECEIVE_SHADOW
vec4 shadow = CCGetShadowFactor();
vec4 shadow = vec4(1.0);
float pcf = cc_shadowPCF.x + 0.001;
if (pcf > 2.0) {shadow = CCGetShadowFactorX9();}
if (2.0 > pcf && pcf > 1.0) {shadow = CCGetShadowFactorX5();}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这应该是 else if 吧

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

之前有语法错误 所以分开写了 现在纠正了语法错误,改成if else的分支判断了

if (1.0 > pcf && pcf > 0.0) {shadow = CCGetShadowFactorX1();}

finalColor = shadow.rgb * shadow.a + finalColor * (1.0 - shadow.a);
#endif

Expand Down