From ad8c57de82bd28280cf58f565f2f20ef3f87d491 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 24 Apr 2025 05:47:58 +0300 Subject: [PATCH 1/3] init --- renderer/viewer/three/shadersThree.ts | 82 +++++++++++++++++++++ renderer/viewer/three/worldrendererThree.ts | 68 +++++++++++++---- 2 files changed, 135 insertions(+), 15 deletions(-) create mode 100644 renderer/viewer/three/shadersThree.ts diff --git a/renderer/viewer/three/shadersThree.ts b/renderer/viewer/three/shadersThree.ts new file mode 100644 index 00000000..7ed30bd8 --- /dev/null +++ b/renderer/viewer/three/shadersThree.ts @@ -0,0 +1,82 @@ +import { ShaderChunk } from 'three' + +// Original simple shader for non-animated blocks +export const BLOCK_VERTEX_SHADER = ` +// Three.js already provides position and uv attributes +attribute vec3 color; + +varying vec2 vUv; +varying vec3 vColor; + +void main() { + vUv = uv; + vColor = color; + gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); +} +` + +export const BLOCK_FRAGMENT_SHADER = ` +uniform sampler2D map; +varying vec2 vUv; +varying vec3 vColor; + +void main() { + vec4 texColor = texture2D(map, vUv); + gl_FragColor = vec4(vColor * texColor.rgb, texColor.a); +} +` + +// New shader for animated blocks +export const ANIMATED_BLOCK_VERTEX_SHADER = ` +#include +${ShaderChunk.logdepthbuf_pars_vertex} + +uniform float animationFrameHeight; +uniform float animationFrameIndex; +uniform float animationInterpolationFrameIndex; +uniform float animationInterpolation; + +attribute vec3 color; +varying vec2 vUv; +varying vec3 vColor; +varying float vAnimationInterpolation; + +void main() { + vUv = uv; + vColor = color; + vAnimationInterpolation = animationInterpolation; + gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); + + ${ShaderChunk.logdepthbuf_vertex} +} +` + +export const ANIMATED_BLOCK_FRAGMENT_SHADER = ` +${ShaderChunk.logdepthbuf_pars_fragment} + +uniform sampler2D map; +uniform float animationFrameHeight; +uniform float animationFrameIndex; +uniform float animationInterpolationFrameIndex; + +varying vec2 vUv; +varying vec3 vColor; +varying float vAnimationInterpolation; + +void main() { + // Calculate UV coordinates for current frame + vec2 currentFrameUv = vec2(vUv.x, animationFrameHeight * (vUv.y + animationFrameIndex)); + vec4 currentFrame = texture2D(map, currentFrameUv); + + // If interpolation is enabled, calculate UV for next frame and mix + if (vAnimationInterpolation > 0.0) { + vec2 nextFrameUv = vec2(vUv.x, animationFrameHeight * (vUv.y + animationInterpolationFrameIndex)); + vec4 nextFrame = texture2D(map, nextFrameUv); + currentFrame = mix(currentFrame, nextFrame, vAnimationInterpolation); + } + + gl_FragColor = vec4(vColor * currentFrame.rgb, currentFrame.a); + + ${ShaderChunk.logdepthbuf_fragment} +} +` diff --git a/renderer/viewer/three/worldrendererThree.ts b/renderer/viewer/three/worldrendererThree.ts index ac31d686..f6465641 100644 --- a/renderer/viewer/three/worldrendererThree.ts +++ b/renderer/viewer/three/worldrendererThree.ts @@ -25,9 +25,42 @@ import { Entities } from './entities' import { ThreeJsSound } from './threeJsSound' import { CameraShake } from './cameraShake' import { ThreeJsMedia } from './threeJsMedia' +import { BLOCK_VERTEX_SHADER, BLOCK_FRAGMENT_SHADER, ANIMATED_BLOCK_VERTEX_SHADER, ANIMATED_BLOCK_FRAGMENT_SHADER } from './shadersThree' type SectionKey = string +class CustomBlockMaterial extends THREE.ShaderMaterial { + constructor () { + super({ + uniforms: { + map: { value: null } + }, + vertexShader: BLOCK_VERTEX_SHADER, + fragmentShader: BLOCK_FRAGMENT_SHADER, + transparent: true, + alphaTest: 0.1 + }) + } +} + +class AnimatedBlockMaterial extends THREE.ShaderMaterial { + constructor () { + super({ + uniforms: { + map: { value: null }, + animationFrameHeight: { value: 1 }, + animationFrameIndex: { value: 0 }, + animationInterpolationFrameIndex: { value: 0 }, + animationInterpolation: { value: 0 } + }, + vertexShader: ANIMATED_BLOCK_VERTEX_SHADER, + fragmentShader: ANIMATED_BLOCK_FRAGMENT_SHADER, + transparent: true, + alphaTest: 0.1 + }) + } +} + export class WorldRendererThree extends WorldRendererCommon { outputFormat = 'threeJs' as const sectionObjects: Record = {} @@ -35,14 +68,15 @@ export class WorldRendererThree extends WorldRendererCommon { signsCache = new Map() starField: StarField cameraSectionPos: Vec3 = new Vec3(0, 0, 0) - holdingBlock: HoldingBlock - holdingBlockLeft: HoldingBlock + holdingBlock: HoldingBlock | undefined + holdingBlockLeft: HoldingBlock | undefined scene = new THREE.Scene() ambientLight = new THREE.AmbientLight(0xcc_cc_cc) directionalLight = new THREE.DirectionalLight(0xff_ff_ff, 0.5) entities = new Entities(this) cameraObjectOverride?: THREE.Object3D // for xr - material = new THREE.MeshLambertMaterial({ vertexColors: true, transparent: true, alphaTest: 0.1 }) + material = new CustomBlockMaterial() + animatedMaterial = new AnimatedBlockMaterial() itemsTexture: THREE.Texture cursorBlock = new CursorBlock(this) onRender: Array<() => void> = [] @@ -66,8 +100,8 @@ export class WorldRendererThree extends WorldRendererCommon { displayOptions.rendererState.renderer = WorldRendererThree.getRendererInfo(renderer) ?? '...' this.starField = new StarField(this.scene) - this.holdingBlock = new HoldingBlock(this) - this.holdingBlockLeft = new HoldingBlock(this, true) + // this.holdingBlock = new HoldingBlock(this) + // this.holdingBlockLeft = new HoldingBlock(this, true) this.addDebugOverlay() this.resetScene() @@ -137,23 +171,23 @@ export class WorldRendererThree extends WorldRendererCommon { changeHandSwingingState (isAnimationPlaying: boolean, isLeft = false) { const holdingBlock = isLeft ? this.holdingBlockLeft : this.holdingBlock if (isAnimationPlaying) { - holdingBlock.startSwing() + holdingBlock?.startSwing() } else { - holdingBlock.stopSwing() + holdingBlock?.stopSwing() } } async updateAssetsData (): Promise { const resources = this.resourcesManager.currentResources! - const oldTexture = this.material.map + const oldTexture = this.material.uniforms.map.value const oldItemsTexture = this.itemsTexture const texture = await new THREE.TextureLoader().loadAsync(resources.blocksAtlasParser.latestImage) texture.magFilter = THREE.NearestFilter texture.minFilter = THREE.NearestFilter texture.flipY = false - this.material.map = texture + this.material.uniforms.map.value = texture const itemsTexture = await new THREE.TextureLoader().loadAsync(resources.itemsAtlasParser.latestImage) itemsTexture.magFilter = THREE.NearestFilter @@ -177,10 +211,14 @@ export class WorldRendererThree extends WorldRendererCommon { } onAllTexturesLoaded () { - this.holdingBlock.ready = true - this.holdingBlock.updateItem() - this.holdingBlockLeft.ready = true - this.holdingBlockLeft.updateItem() + if (this.holdingBlock) { + this.holdingBlock.ready = true + this.holdingBlock.updateItem() + } + if (this.holdingBlockLeft) { + this.holdingBlockLeft.ready = true + this.holdingBlockLeft.updateItem() + } } changeBackgroundColor (color: [number, number, number]): void { @@ -432,8 +470,8 @@ export class WorldRendererThree extends WorldRendererCommon { this.renderer.render(this.scene, cam) if (this.displayOptions.inWorldRenderingConfig.showHand/* && !this.freeFlyMode */) { - this.holdingBlock.render(this.camera, this.renderer, this.ambientLight, this.directionalLight) - this.holdingBlockLeft.render(this.camera, this.renderer, this.ambientLight, this.directionalLight) + this.holdingBlock?.render(this.camera, this.renderer, this.ambientLight, this.directionalLight) + this.holdingBlockLeft?.render(this.camera, this.renderer, this.ambientLight, this.directionalLight) } for (const onRender of this.onRender) { From d4cc305baae6a99b20844534276a2cf909f3f20c Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Fri, 25 Apr 2025 04:16:45 +0300 Subject: [PATCH 2/3] sprm --- renderer/viewer/three/worldrendererThree.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/renderer/viewer/three/worldrendererThree.ts b/renderer/viewer/three/worldrendererThree.ts index e5fd5e9d..44618ab0 100644 --- a/renderer/viewer/three/worldrendererThree.ts +++ b/renderer/viewer/three/worldrendererThree.ts @@ -514,14 +514,6 @@ export class WorldRendererThree extends WorldRendererCommon { fountain.render() } - for (const fountain of this.fountains) { - if (this.sectionObjects[fountain.sectionId] && !this.sectionObjects[fountain.sectionId].foutain) { - fountain.createParticles(this.sectionObjects[fountain.sectionId]) - this.sectionObjects[fountain.sectionId].foutain = true - } - fountain.render() - } - for (const onRender of this.onRender) { onRender() } From 60a39bbaf544310b7d13b3358cc8e4382d7850b0 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Fri, 25 Apr 2025 04:29:26 +0300 Subject: [PATCH 3/3] fix depth --- renderer/viewer/three/shadersThree.ts | 14 +++++++++++++- renderer/viewer/three/worldrendererThree.ts | 14 ++++++++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/renderer/viewer/three/shadersThree.ts b/renderer/viewer/three/shadersThree.ts index 7ed30bd8..052b9009 100644 --- a/renderer/viewer/three/shadersThree.ts +++ b/renderer/viewer/three/shadersThree.ts @@ -2,7 +2,9 @@ import { ShaderChunk } from 'three' // Original simple shader for non-animated blocks export const BLOCK_VERTEX_SHADER = ` -// Three.js already provides position and uv attributes +#include +${ShaderChunk.logdepthbuf_pars_vertex} + attribute vec3 color; varying vec2 vUv; @@ -12,17 +14,25 @@ void main() { vUv = uv; vColor = color; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); + + ${ShaderChunk.logdepthbuf_vertex} } ` export const BLOCK_FRAGMENT_SHADER = ` +#include +${ShaderChunk.logdepthbuf_pars_fragment} + uniform sampler2D map; varying vec2 vUv; varying vec3 vColor; void main() { vec4 texColor = texture2D(map, vUv); + if (texColor.a < 0.1) discard; gl_FragColor = vec4(vColor * texColor.rgb, texColor.a); + + ${ShaderChunk.logdepthbuf_fragment} } ` @@ -52,6 +62,7 @@ void main() { ` export const ANIMATED_BLOCK_FRAGMENT_SHADER = ` +#include ${ShaderChunk.logdepthbuf_pars_fragment} uniform sampler2D map; @@ -75,6 +86,7 @@ void main() { currentFrame = mix(currentFrame, nextFrame, vAnimationInterpolation); } + if (currentFrame.a < 0.1) discard; gl_FragColor = vec4(vColor * currentFrame.rgb, currentFrame.a); ${ShaderChunk.logdepthbuf_fragment} diff --git a/renderer/viewer/three/worldrendererThree.ts b/renderer/viewer/three/worldrendererThree.ts index 44618ab0..117d631d 100644 --- a/renderer/viewer/three/worldrendererThree.ts +++ b/renderer/viewer/three/worldrendererThree.ts @@ -39,7 +39,10 @@ class CustomBlockMaterial extends THREE.ShaderMaterial { vertexShader: BLOCK_VERTEX_SHADER, fragmentShader: BLOCK_FRAGMENT_SHADER, transparent: true, - alphaTest: 0.1 + alphaTest: 0.1, + depthWrite: true, + depthTest: true, + side: THREE.FrontSide }) } } @@ -57,7 +60,10 @@ class AnimatedBlockMaterial extends THREE.ShaderMaterial { vertexShader: ANIMATED_BLOCK_VERTEX_SHADER, fragmentShader: ANIMATED_BLOCK_FRAGMENT_SHADER, transparent: true, - alphaTest: 0.1 + alphaTest: 0.1, + depthWrite: true, + depthTest: true, + side: THREE.FrontSide }) } } @@ -119,8 +125,8 @@ export class WorldRendererThree extends WorldRendererCommon { displayOptions.rendererState.renderer = WorldRendererThree.getRendererInfo(renderer) ?? '...' this.starField = new StarField(this.scene) - // this.holdingBlock = new HoldingBlock(this) - // this.holdingBlockLeft = new HoldingBlock(this, true) + this.holdingBlock = new HoldingBlock(this) + this.holdingBlockLeft = new HoldingBlock(this, true) this.addDebugOverlay() this.resetScene()