Skip to content
This repository has been archived by the owner on Aug 21, 2024. It is now read-only.

Commit

Permalink
Michael/ir 2056 render unit tests (#10374)
Browse files Browse the repository at this point in the history
* added unit test for fog component

* started the unit test for the webglrendersystem

* updated the mock engine renderer
corrected the webGLRendererSystem test for changing the render mode

* added tests for webGL render systems engine render settings reactors

* added tests for webgl render systems camera layer reactors

* added unity test for webGL render system resize

* added test for visible children

* updated the web gl render unit ttest

* removed dev testing code

* implemented PR changes

* changed the background color to white
added assert check that the background color is white

* corrected the npm errors found

* removed globalThis._scene ref and use the local scene ref instead

* removed performanceState assert per the PR request

* removed dev log from portal component
Added fog shader asserts to fog settings components test

* corrected npm found errors

* corrected the npm errors found

---------

Co-authored-by: Josh Field <[email protected]>
  • Loading branch information
MbfloydIR and HexaField authored Jun 19, 2024
1 parent abe0e11 commit a6c2f80
Show file tree
Hide file tree
Showing 4 changed files with 343 additions and 5 deletions.
196 changes: 196 additions & 0 deletions packages/spatial/src/renderer/WebGLRendererSystem.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
// /*
// CPAL-1.0 License

// The contents of this file are subject to the Common Public Attribution License
// Version 1.0. (the "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
// https://github.com/EtherealEngine/etherealengine/blob/dev/LICENSE.
// The License is based on the Mozilla Public License Version 1.1, but Sections 14
// and 15 have been added to cover use of software over a computer network and
// provide for limited attribution for the Original Developer. In addition,
// Exhibit A has been modified to be consistent with Exhibit B.

// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
// specific language governing rights and limitations under the License.

// The Original Code is Ethereal Engine.

// The Original Developer is the Initial Developer. The Initial Developer of the
// Original Code is the Ethereal Engine team.

// All portions of the code written by the Ethereal Engine team are Copyright © 2021-2023
// Ethereal Engine. All Rights Reserved.
// */

import {
Engine,
Entity,
EntityUUID,
SystemDefinitions,
UUIDComponent,
createEntity,
destroyEngine,
getComponent,
getMutableComponent,
setComponent
} from '@etherealengine/ecs'
import { getMutableState } from '@etherealengine/hyperflux'
import { act, render } from '@testing-library/react'
import assert from 'assert'
import { EffectComposer, RenderPass } from 'postprocessing'
import React from 'react'
import { Color, Group, MathUtils, Texture } from 'three'
import { MockEngineRenderer } from '../../tests/util/MockEngineRenderer'
import { CameraComponent } from '../camera/components/CameraComponent'
import { createEngine } from '../initializeEngine'
import { EntityTreeComponent } from '../transform/components/EntityTree'
import { RendererState } from './RendererState'
import {
RendererComponent,
WebGLRendererSystem,
getNestedVisibleChildren,
getSceneParameters
} from './WebGLRendererSystem'
import { FogSettingsComponent, FogType } from './components/FogSettingsComponent'
import { GroupComponent, addObjectToGroup } from './components/GroupComponent'
import { Object3DComponent } from './components/Object3DComponent'
import { BackgroundComponent, EnvironmentMapComponent, SceneComponent } from './components/SceneComponents'
import { VisibleComponent } from './components/VisibleComponent'
import { ObjectLayers } from './constants/ObjectLayers'
import { RenderModes } from './constants/RenderModes'

describe('WebGl Renderer System', () => {
let rootEntity: Entity
let visibleEntity: Entity
let invisibleEntity: Entity
let nestedVisibleEntity: Entity
let nestedInvisibleEntity: Entity

const mockCanvas = () => {
return {
getDrawingBufferSize: () => 0,
getContext: () => {},
parentElement: {
clientWidth: 100,
clientHeight: 100
}
} as any as HTMLCanvasElement
}

beforeEach(() => {
createEngine()

rootEntity = Engine.instance.viewerEntity //createEntity()
setComponent(rootEntity, UUIDComponent, MathUtils.generateUUID() as EntityUUID)
setComponent(rootEntity, EntityTreeComponent)
setComponent(rootEntity, CameraComponent)
setComponent(rootEntity, RendererComponent, { canvas: mockCanvas() })
getMutableComponent(rootEntity, RendererComponent).set(new MockEngineRenderer())
const rendererComp = getMutableComponent(rootEntity, RendererComponent)
rendererComp.canvas.set(mockCanvas())
setComponent(rootEntity, BackgroundComponent, new Color(0xffffff))

setComponent(rootEntity, EnvironmentMapComponent, new Texture())
setComponent(rootEntity, FogSettingsComponent, { type: FogType.Height })

invisibleEntity = createEntity()
setComponent(invisibleEntity, UUIDComponent, MathUtils.generateUUID() as EntityUUID)
setComponent(invisibleEntity, GroupComponent)
const invisibleObject3d = setComponent(invisibleEntity, Object3DComponent, new Group())
addObjectToGroup(invisibleEntity, invisibleObject3d)
setComponent(invisibleEntity, EntityTreeComponent)

visibleEntity = createEntity()
setComponent(visibleEntity, UUIDComponent, MathUtils.generateUUID() as EntityUUID)
setComponent(visibleEntity, VisibleComponent)
const visibleObject3d = setComponent(visibleEntity, Object3DComponent, new Group())
addObjectToGroup(visibleEntity, visibleObject3d)
setComponent(visibleEntity, GroupComponent)
setComponent(visibleEntity, EntityTreeComponent)

setComponent(rootEntity, SceneComponent, { children: [invisibleEntity, visibleEntity] })

nestedInvisibleEntity = createEntity()
setComponent(nestedInvisibleEntity, UUIDComponent, MathUtils.generateUUID() as EntityUUID)
setComponent(nestedInvisibleEntity, GroupComponent)
const nestedInvisibleObject3d = setComponent(nestedInvisibleEntity, Object3DComponent, new Group())
addObjectToGroup(nestedInvisibleEntity, nestedInvisibleObject3d)
setComponent(nestedInvisibleEntity, EntityTreeComponent)
setComponent(visibleEntity, SceneComponent, { children: [nestedInvisibleEntity] })

nestedVisibleEntity = createEntity()
setComponent(nestedVisibleEntity, UUIDComponent, MathUtils.generateUUID() as EntityUUID)
setComponent(nestedVisibleEntity, VisibleComponent)
const nestedVisibleObject3d = setComponent(nestedVisibleEntity, Object3DComponent, new Group())
addObjectToGroup(nestedVisibleEntity, nestedVisibleObject3d)
setComponent(nestedVisibleEntity, GroupComponent)
setComponent(nestedVisibleEntity, EntityTreeComponent)
setComponent(invisibleEntity, SceneComponent, { children: [nestedVisibleEntity] })

//override addpass to test data without dependency on Browser
let addPassCount = 0
EffectComposer.prototype.addPass = () => {
addPassCount++
}
})

afterEach(() => {
return destroyEngine()
})

it('Test Background, Environment, Fog Components', async () => {
const { background, environment, fog, children } = getSceneParameters([rootEntity])
SystemDefinitions.get(WebGLRendererSystem)?.execute()
assert(background, 'background component exists')
const backgroundColor = background as Color
assert(
backgroundColor.r == 1 && backgroundColor.g == 1 && backgroundColor.b == 1,
'backgroud color was set correctly'
)

assert(environment, 'environment component exists')
assert(fog, 'fog component exists')
})

it('Test WebGL Reactors', async () => {
const webGLRendererSystem = SystemDefinitions.get(WebGLRendererSystem)
const RenderSystem = webGLRendererSystem?.reactor!
const tag = <RenderSystem />
const { rerender, unmount } = render(tag)

SystemDefinitions.get(WebGLRendererSystem)?.execute()

const engineRendererSettings = getMutableState(RendererState)
engineRendererSettings.renderMode.set(RenderModes.WIREFRAME)
engineRendererSettings.renderScale.set(2)
engineRendererSettings.qualityLevel.set(3)
engineRendererSettings.automatic.set(false)
engineRendererSettings.physicsDebug.set(true)
engineRendererSettings.avatarDebug.set(true)
engineRendererSettings.gridVisibility.set(true)
engineRendererSettings.nodeHelperVisibility.set(true)

await act(() => rerender(tag))

const camera = getComponent(rootEntity, CameraComponent)
const rendererComp = getComponent(rootEntity, RendererComponent)
const effectComposer = rendererComp.effectComposer
const passes = effectComposer?.passes.filter((p) => p.name === 'RenderPass') as any
const renderPass: RenderPass = passes ? passes[0] : undefined

assert(renderPass.overrideMaterial, 'change render mode')
assert(rendererComp.needsResize, 'change render scale')
assert(camera.layers.isEnabled(ObjectLayers.PhysicsHelper), 'enable physicsDebug')
assert(camera.layers.isEnabled(ObjectLayers.AvatarHelper), 'enable avatarDebug')
assert(camera.layers.isEnabled(ObjectLayers.Gizmos), 'enable gridVisibility')
assert(camera.layers.isEnabled(ObjectLayers.NodeHelper), 'enable nodeHelperVisibility')

webGLRendererSystem?.execute()

assert(!rendererComp.needsResize, 'resize updated')
const scene = getComponent(rootEntity, SceneComponent)
const entitiesToRender = scene.children.map(getNestedVisibleChildren).flat()
assert(entitiesToRender.length == 1 && entitiesToRender[0] == visibleEntity, 'visible children')
})
})
127 changes: 127 additions & 0 deletions packages/spatial/src/renderer/components/FogSettingsComponent.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// /*
// CPAL-1.0 License

// The contents of this file are subject to the Common Public Attribution License
// Version 1.0. (the "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
// https://github.com/EtherealEngine/etherealengine/blob/dev/LICENSE.
// The License is based on the Mozilla Public License Version 1.1, but Sections 14
// and 15 have been added to cover use of software over a computer network and
// provide for limited attribution for the Original Developer. In addition,
// Exhibit A has been modified to be consistent with Exhibit B.

// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
// specific language governing rights and limitations under the License.

// The Original Code is Ethereal Engine.

// The Original Developer is the Initial Developer. The Initial Developer of the
// Original Code is the Ethereal Engine team.

// All portions of the code written by the Ethereal Engine team are Copyright © 2021-2023
// Ethereal Engine. All Rights Reserved.
// */

import {
Entity,
EntityUUID,
UUIDComponent,
createEntity,
destroyEngine,
getComponent,
getMutableComponent,
setComponent
} from '@etherealengine/ecs'
import { act, render } from '@testing-library/react'
import assert from 'assert'
import React from 'react'
import { Fog, FogExp2, MathUtils, ShaderChunk } from 'three'
import { CameraComponent } from '../../camera/components/CameraComponent'
import { createEngine } from '../../initializeEngine'
import { EntityTreeComponent } from '../../transform/components/EntityTree'
import { RendererComponent } from '../WebGLRendererSystem'
import { FogSettingsComponent, FogType } from './FogSettingsComponent'
import { FogShaders } from './FogShaders'
import { FogComponent, SceneComponent } from './SceneComponents'

describe('FogSettingsComponent', () => {
let rootEntity: Entity
let entity: Entity

const mockCanvas = () => {
return {
getDrawingBufferSize: () => 0
} as any as HTMLCanvasElement
}

beforeEach(() => {
createEngine()

rootEntity = createEntity()
setComponent(rootEntity, UUIDComponent, MathUtils.generateUUID() as EntityUUID)
setComponent(rootEntity, EntityTreeComponent)
setComponent(rootEntity, CameraComponent)
setComponent(rootEntity, SceneComponent)
setComponent(rootEntity, RendererComponent, { canvas: mockCanvas() })

entity = createEntity()
setComponent(entity, UUIDComponent, MathUtils.generateUUID() as EntityUUID)
setComponent(entity, FogSettingsComponent)
setComponent(entity, EntityTreeComponent)

//set data to test
setComponent(rootEntity, SceneComponent, { children: [entity] })
})

afterEach(() => {
return destroyEngine()
})

it('Create Fog Setting Component', async () => {
const fogSettingsComponent = getMutableComponent(entity, FogSettingsComponent)
assert(fogSettingsComponent.value, 'fog setting component exists')

fogSettingsComponent.type.set(FogType.Height)
fogSettingsComponent.color.set('#ff0000')
fogSettingsComponent.far.set(2000)
fogSettingsComponent.near.set(2)
fogSettingsComponent.density.set(0.02)
const { rerender, unmount } = render(<></>)

await act(() => {
rerender(<></>)
})
const fogComponent = getComponent(entity, FogComponent)
assert(fogComponent, 'created fog component')
assert(fogComponent.color.r == 1 && fogComponent.color.g == 0 && fogComponent.color.b == 0, 'fog set color')
const fog = fogComponent as Fog
assert(fog.far == 2000, 'fog set far')
assert(fog.near == 2, 'fog set near')
const fogExp2 = fogComponent as FogExp2
assert(fogExp2.density == 0.02, 'fog set density')

assert(ShaderChunk.fog_fragment == FogShaders.fog_fragment.heightFog)
assert(ShaderChunk.fog_pars_fragment == FogShaders.fog_pars_fragment.heightFog)
assert(ShaderChunk.fog_vertex == FogShaders.fog_vertex.heightFog)
assert(ShaderChunk.fog_pars_vertex == FogShaders.fog_pars_vertex.heightFog)

fogSettingsComponent.type.set(FogType.Linear)
await act(() => {
rerender(<></>)
})
assert(ShaderChunk.fog_fragment == FogShaders.fog_fragment.default)
assert(ShaderChunk.fog_pars_fragment == FogShaders.fog_pars_fragment.default)
assert(ShaderChunk.fog_vertex == FogShaders.fog_vertex.default)
assert(ShaderChunk.fog_pars_vertex == FogShaders.fog_pars_vertex.default)

fogSettingsComponent.type.set(FogType.Brownian)
await act(() => {
rerender(<></>)
})
assert(ShaderChunk.fog_fragment == FogShaders.fog_fragment.brownianMotionFog)
assert(ShaderChunk.fog_pars_fragment == FogShaders.fog_pars_fragment.brownianMotionFog)
assert(ShaderChunk.fog_vertex == FogShaders.fog_vertex.brownianMotionFog)
assert(ShaderChunk.fog_pars_vertex == FogShaders.fog_pars_vertex.brownianMotionFog)
})
})
2 changes: 1 addition & 1 deletion packages/spatial/src/renderer/components/FogShaders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ float FBM(vec3 p) {
}
`

const FogShaders = {
export const FogShaders = {
fog_fragment: {
default: ShaderChunk.fog_fragment,
brownianMotionFog: `#ifdef USE_FOG
Expand Down
23 changes: 19 additions & 4 deletions packages/spatial/tests/util/MockEngineRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,32 @@ Ethereal Engine. All Rights Reserved.

import { WebGLRenderer } from 'three/src/renderers/WebGLRenderer'

import { EffectComposer } from 'postprocessing'
import { EngineRenderer } from '../../src/renderer/WebGLRendererSystem'
import { MockEventListener } from './MockEventListener'

class MockRenderer {
setAnimationLoop = () => {}
domElement = new MockEventListener()
setPixelRatio = () => {}
getSize = () => 0
getContext = () => {}
getPixelRatio = () => 1
}

export class MockEngineRenderer extends EngineRenderer {
static instance: EngineRenderer

constructor() {
super()
this.renderer = {
setAnimationLoop: () => {},
domElement: new MockEventListener()
} as unknown as WebGLRenderer
this.renderer = new MockRenderer() as unknown as WebGLRenderer
this.effectComposer = {
setSize: () => {},
passes: [{ name: 'RenderPass', overrideMaterial: null }],
setMainScene: () => {},
setMainCamera: () => {},
render: () => {}
} as unknown as EffectComposer
this.needsResize = false
}
}

0 comments on commit a6c2f80

Please sign in to comment.