mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
feat: heat shells
This commit is contained in:
1 parent
06c878dd2c
commit
522b40aff1
11 files changed
+183
-90
No files matched your search
Vendored
+3
-1
@@ -54,6 +54,7 @@
|
|||||||
"glsl",
|
"glsl",
|
||||||
"GLTF",
|
"GLTF",
|
||||||
"haha",
|
"haha",
|
||||||
|
"highp",
|
||||||
"iife",
|
"iife",
|
||||||
"immer",
|
"immer",
|
||||||
"Inclusivity",
|
"Inclusivity",
|
||||||
@@ -145,5 +146,6 @@
|
|||||||
"zustand"
|
"zustand"
|
||||||
],
|
],
|
||||||
"deno.enable": false,
|
"deno.enable": false,
|
||||||
"deno.unstable": false
|
"deno.unstable": false,
|
||||||
|
"cSpell.enableFiletypes": ["glsl"]
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useFrame } from '@react-three/fiber';
|
import { useFrame } from '@react-three/fiber';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import {
|
import {
|
||||||
MeshBasicMaterial,
|
MeshBasicMaterial,
|
||||||
Object3D,
|
Object3D,
|
||||||
@@ -7,8 +8,10 @@ import {
|
|||||||
WebGLRenderTarget,
|
WebGLRenderTarget,
|
||||||
} from 'three';
|
} from 'three';
|
||||||
import { degToRad } from 'three/src/math/MathUtils';
|
import { degToRad } from 'three/src/math/MathUtils';
|
||||||
|
import { isExplosive } from '../../../../core/blitz/isExplosive';
|
||||||
import { resolveNearPenetration } from '../../../../core/blitz/resolveNearPenetration';
|
import { resolveNearPenetration } from '../../../../core/blitz/resolveNearPenetration';
|
||||||
import { jsxTree } from '../../../../core/blitzkrieg/jsxTree';
|
import { jsxTree } from '../../../../core/blitzkrieg/jsxTree';
|
||||||
|
import { ShellDefinition } from '../../../../core/blitzkrieg/tankDefinitions';
|
||||||
import { useDuel } from '../../../../stores/duel';
|
import { useDuel } from '../../../../stores/duel';
|
||||||
import fragmentShader from './shaders/fragment.glsl';
|
import fragmentShader from './shaders/fragment.glsl';
|
||||||
import vertexShader from './shaders/vertex.glsl';
|
import vertexShader from './shaders/vertex.glsl';
|
||||||
@@ -25,8 +28,6 @@ const excludeMaterial = new MeshBasicMaterial({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export function CoreArmor({ node, thickness }: CoreArmorProps) {
|
export function CoreArmor({ node, thickness }: CoreArmorProps) {
|
||||||
const { shell } = useDuel.getState().antagonist!;
|
|
||||||
const penetration = resolveNearPenetration(shell.penetration);
|
|
||||||
const material = new ShaderMaterial({
|
const material = new ShaderMaterial({
|
||||||
fragmentShader,
|
fragmentShader,
|
||||||
vertexShader,
|
vertexShader,
|
||||||
@@ -35,10 +36,11 @@ export function CoreArmor({ node, thickness }: CoreArmorProps) {
|
|||||||
|
|
||||||
uniforms: {
|
uniforms: {
|
||||||
thickness: { value: thickness },
|
thickness: { value: thickness },
|
||||||
penetration: { value: penetration },
|
penetration: { value: null },
|
||||||
caliber: { value: shell.caliber },
|
caliber: { value: null },
|
||||||
ricochet: { value: degToRad(shell.ricochet ?? 90) },
|
ricochet: { value: null },
|
||||||
normalization: { value: degToRad(shell.normalization ?? 0) },
|
normalization: { value: null },
|
||||||
|
isExplosive: { value: null },
|
||||||
|
|
||||||
resolution: { value: new Vector2() },
|
resolution: { value: new Vector2() },
|
||||||
spacedArmorBuffer: { value: null },
|
spacedArmorBuffer: { value: null },
|
||||||
@@ -46,6 +48,23 @@ export function CoreArmor({ node, thickness }: CoreArmorProps) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
function handleChange(shell: ShellDefinition) {
|
||||||
|
material.uniforms.penetration.value = resolveNearPenetration(
|
||||||
|
shell.penetration,
|
||||||
|
);
|
||||||
|
material.uniforms.caliber.value = shell.caliber;
|
||||||
|
material.uniforms.ricochet.value = degToRad(shell.ricochet ?? 90);
|
||||||
|
material.uniforms.normalization.value = degToRad(
|
||||||
|
shell.normalization ?? 0,
|
||||||
|
);
|
||||||
|
material.uniforms.isExplosive.value = isExplosive(shell.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChange(useDuel.getState().antagonist!.shell);
|
||||||
|
return useDuel.subscribe((state) => state.antagonist!.shell, handleChange);
|
||||||
|
}, []);
|
||||||
|
|
||||||
useFrame(({ gl }) => {
|
useFrame(({ gl }) => {
|
||||||
gl.getSize(material.uniforms.resolution.value).multiplyScalar(
|
gl.getSize(material.uniforms.resolution.value).multiplyScalar(
|
||||||
gl.getPixelRatio(),
|
gl.getPixelRatio(),
|
||||||
@@ -61,7 +80,6 @@ export function CoreArmor({ node, thickness }: CoreArmorProps) {
|
|||||||
renderOrder: 0,
|
renderOrder: 0,
|
||||||
material: excludeMaterial,
|
material: excludeMaterial,
|
||||||
})}
|
})}
|
||||||
|
|
||||||
{jsxTree(node, {
|
{jsxTree(node, {
|
||||||
renderOrder: 1,
|
renderOrder: 1,
|
||||||
material,
|
material,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
varying vec3 vNormal;
|
varying vec3 vNormal;
|
||||||
varying vec3 vViewPosition;
|
varying vec3 vViewPosition;
|
||||||
|
varying mat4 vProjectionMatrix;
|
||||||
|
|
||||||
uniform float thickness;
|
uniform float thickness;
|
||||||
uniform float penetration;
|
uniform float penetration;
|
||||||
@@ -7,10 +8,17 @@ uniform float caliber;
|
|||||||
uniform float ricochet;
|
uniform float ricochet;
|
||||||
uniform float normalization;
|
uniform float normalization;
|
||||||
uniform vec2 resolution;
|
uniform vec2 resolution;
|
||||||
|
uniform bool isExplosive;
|
||||||
|
|
||||||
uniform sampler2D spacedArmorBuffer;
|
uniform highp sampler2D spacedArmorBuffer;
|
||||||
uniform highp sampler2D spacedArmorDepth;
|
uniform highp sampler2D spacedArmorDepth;
|
||||||
|
|
||||||
|
float depthToDistance(float depth) {
|
||||||
|
vec4 clipPosition = vec4(gl_FragCoord.xy / resolution * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
|
||||||
|
vec4 eyePosition = inverse(vProjectionMatrix) * clipPosition;
|
||||||
|
return length(eyePosition.xyz / eyePosition.w);
|
||||||
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
float penetrationChance = -1.0;
|
float penetrationChance = -1.0;
|
||||||
float splashChance = -1.0;
|
float splashChance = -1.0;
|
||||||
@@ -31,16 +39,30 @@ void main() {
|
|||||||
float remainingPenetration = penetration;
|
float remainingPenetration = penetration;
|
||||||
|
|
||||||
if (isUnderSpacedArmor) {
|
if (isUnderSpacedArmor) {
|
||||||
remainingPenetration -= spacedArmorBufferFragment.r * penetration;
|
float spacedArmorThickness = spacedArmorBufferFragment.r * penetration;
|
||||||
|
remainingPenetration -= spacedArmorThickness;
|
||||||
|
|
||||||
|
if (isExplosive && remainingPenetration > 0.0) {
|
||||||
|
// world space is in meters
|
||||||
|
vec4 spacedArmorDepthFragment = texture2D(spacedArmorDepth, screenCoordinates);
|
||||||
|
float spacedArmorDistance = depthToDistance(spacedArmorDepthFragment.r);
|
||||||
|
float coreArmorDistance = depthToDistance(gl_FragCoord.z);
|
||||||
|
float distanceFromSpacedArmor = coreArmorDistance - spacedArmorDistance;
|
||||||
|
|
||||||
|
// there is a 50% penetration loss per meter for HE based shells
|
||||||
|
remainingPenetration -= 0.5 * remainingPenetration * distanceFromSpacedArmor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
remainingPenetration = max(0.0, remainingPenetration);
|
||||||
float delta = finalThickness - remainingPenetration;
|
float delta = finalThickness - remainingPenetration;
|
||||||
float randomization = remainingPenetration * 0.05;
|
float randomization = remainingPenetration * 0.05;
|
||||||
|
|
||||||
penetrationChance = clamp(1.0 - (delta + randomization) / (2.0 * randomization), 0.0, 1.0);
|
penetrationChance = clamp(1.0 - (delta + randomization) / (2.0 * randomization), 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 color = vec3(1.0, splashChance * 0.392, 0.0);
|
vec3 color = vec3(1.0, splashChance * 0.392, 0.0);
|
||||||
gl_FragColor = vec4(0.0, penetrationChance, 0.0, 1.0);
|
|
||||||
gl_FragColor = vec4(color, (1.0 - penetrationChance) * 0.5);
|
gl_FragColor = vec4(color, (1.0 - penetrationChance) * 0.5);
|
||||||
|
|
||||||
|
// non-trigonometric red-green mixing: https://www.desmos.com/calculator/ceo1oq7l67
|
||||||
|
// gl_FragColor = vec4(-pow(penetrationChance, 2.0) + 1.0, -pow(penetrationChance - 1.0, 2.0) + 1.0, 0.0, 0.5);
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
varying vec3 vNormal;
|
varying vec3 vNormal;
|
||||||
varying vec3 vViewPosition;
|
varying vec3 vViewPosition;
|
||||||
|
varying mat4 vProjectionMatrix;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 vViewPosition4 = modelViewMatrix * vec4(position, 1.0);
|
vec4 vViewPosition4 = modelViewMatrix * vec4(position, 1.0);
|
||||||
|
|
||||||
vViewPosition = vViewPosition4.xyz;
|
vViewPosition = vViewPosition4.xyz;
|
||||||
|
vProjectionMatrix = projectionMatrix;
|
||||||
vNormal = normalMatrix * normal;
|
vNormal = normalMatrix * normal;
|
||||||
|
|
||||||
gl_Position = projectionMatrix * vViewPosition4;
|
gl_Position = projectionMatrix * vViewPosition4;
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ interface CoreArmorSceneProps {
|
|||||||
|
|
||||||
export const CoreArmorScene = memo<CoreArmorSceneProps>(
|
export const CoreArmorScene = memo<CoreArmorSceneProps>(
|
||||||
({ ornamental = false }) => {
|
({ ornamental = false }) => {
|
||||||
const protagonist = useDuel((state) => state.protagonist!);
|
|
||||||
const wrapper = useRef<Group>(null);
|
const wrapper = useRef<Group>(null);
|
||||||
const modelDefinitions = useModelDefinitions();
|
const modelDefinitions = useModelDefinitions();
|
||||||
const turretContainer = useRef<Group>(null);
|
const turretContainer = useRef<Group>(null);
|
||||||
@@ -96,7 +95,7 @@ export const CoreArmorScene = memo<CoreArmorSceneProps>(
|
|||||||
turretContainer.current?.rotation.copy(turretRotation);
|
turretContainer.current?.rotation.copy(turretRotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleModelTransform(protagonist);
|
handleModelTransform(useDuel.getState().protagonist!);
|
||||||
modelTransformEvent.on(handleModelTransform);
|
modelTransformEvent.on(handleModelTransform);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
@@ -115,15 +114,16 @@ export const CoreArmorScene = memo<CoreArmorSceneProps>(
|
|||||||
return unsubscribe;
|
return unsubscribe;
|
||||||
});
|
});
|
||||||
|
|
||||||
const armorGltf = useArmor(protagonist.tank.id);
|
const tank = useDuel((state) => state.protagonist!.tank);
|
||||||
|
const track = useDuel((state) => state.protagonist!.track);
|
||||||
|
const turret = useDuel((state) => state.protagonist!.turret);
|
||||||
|
const gun = useDuel((state) => state.protagonist!.gun);
|
||||||
|
const armorGltf = useArmor(tank.id);
|
||||||
const armorNodes = Object.values(armorGltf.nodes);
|
const armorNodes = Object.values(armorGltf.nodes);
|
||||||
const tankModelDefinition = modelDefinitions[protagonist.tank.id];
|
const tankModelDefinition = modelDefinitions[tank.id];
|
||||||
const trackModelDefinition =
|
const trackModelDefinition = tankModelDefinition.tracks[track.id];
|
||||||
tankModelDefinition.tracks[protagonist.track.id];
|
const turretModelDefinition = tankModelDefinition.turrets[turret.id];
|
||||||
const turretModelDefinition =
|
const gunModelDefinition = turretModelDefinition.guns[gun.id];
|
||||||
tankModelDefinition.turrets[protagonist.turret.id];
|
|
||||||
const gunModelDefinition = turretModelDefinition.guns[protagonist.gun.id];
|
|
||||||
const hullOrigin = new Vector3(
|
const hullOrigin = new Vector3(
|
||||||
trackModelDefinition.origin[0],
|
trackModelDefinition.origin[0],
|
||||||
trackModelDefinition.origin[1],
|
trackModelDefinition.origin[1],
|
||||||
|
|||||||
+27
-15
@@ -1,3 +1,4 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
import {
|
import {
|
||||||
AdditiveBlending,
|
AdditiveBlending,
|
||||||
MeshBasicMaterial,
|
MeshBasicMaterial,
|
||||||
@@ -6,6 +7,7 @@ import {
|
|||||||
} from 'three';
|
} from 'three';
|
||||||
import { resolveNearPenetration } from '../../../../../../core/blitz/resolveNearPenetration';
|
import { resolveNearPenetration } from '../../../../../../core/blitz/resolveNearPenetration';
|
||||||
import { jsxTree } from '../../../../../../core/blitzkrieg/jsxTree';
|
import { jsxTree } from '../../../../../../core/blitzkrieg/jsxTree';
|
||||||
|
import { ShellDefinition } from '../../../../../../core/blitzkrieg/tankDefinitions';
|
||||||
import { useDuel } from '../../../../../../stores/duel';
|
import { useDuel } from '../../../../../../stores/duel';
|
||||||
import fragmentShader from './shaders/fragment.glsl';
|
import fragmentShader from './shaders/fragment.glsl';
|
||||||
import vertexShader from './shaders/vertex.glsl';
|
import vertexShader from './shaders/vertex.glsl';
|
||||||
@@ -19,8 +21,30 @@ export function SpacedArmorSubExternal({
|
|||||||
node,
|
node,
|
||||||
thickness,
|
thickness,
|
||||||
}: SpacedArmorSubExternalProps) {
|
}: SpacedArmorSubExternalProps) {
|
||||||
const shell = useDuel((state) => state.antagonist!.shell);
|
const material = new ShaderMaterial({
|
||||||
const penetration = resolveNearPenetration(shell.penetration);
|
fragmentShader,
|
||||||
|
vertexShader,
|
||||||
|
|
||||||
|
depthTest: true,
|
||||||
|
depthWrite: false,
|
||||||
|
blending: AdditiveBlending,
|
||||||
|
|
||||||
|
uniforms: {
|
||||||
|
thickness: { value: thickness },
|
||||||
|
penetration: { value: null },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
function handleChange(shell: ShellDefinition) {
|
||||||
|
material.uniforms.penetration.value = resolveNearPenetration(
|
||||||
|
shell.penetration,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChange(useDuel.getState().antagonist!.shell);
|
||||||
|
return useDuel.subscribe((state) => state.antagonist!.shell, handleChange);
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -34,19 +58,7 @@ export function SpacedArmorSubExternal({
|
|||||||
})}
|
})}
|
||||||
{jsxTree(node, {
|
{jsxTree(node, {
|
||||||
renderOrder: 4,
|
renderOrder: 4,
|
||||||
material: new ShaderMaterial({
|
material,
|
||||||
fragmentShader,
|
|
||||||
vertexShader,
|
|
||||||
|
|
||||||
depthTest: true,
|
|
||||||
depthWrite: false,
|
|
||||||
blending: AdditiveBlending,
|
|
||||||
|
|
||||||
uniforms: {
|
|
||||||
thickness: { value: thickness },
|
|
||||||
penetration: { value: penetration },
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
})}
|
})}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
import { AdditiveBlending, Object3D, ShaderMaterial } from 'three';
|
|
||||||
import { degToRad } from 'three/src/math/MathUtils';
|
|
||||||
import { resolveNearPenetration } from '../../../../../../core/blitz/resolveNearPenetration';
|
|
||||||
import { jsxTree } from '../../../../../../core/blitzkrieg/jsxTree';
|
|
||||||
import { useDuel } from '../../../../../../stores/duel';
|
|
||||||
import fragmentShader from './shaders/fragment.glsl';
|
|
||||||
import vertexShader from './shaders/vertex.glsl';
|
|
||||||
|
|
||||||
interface SpacedArmorSubSpacedProps {
|
|
||||||
node: Object3D;
|
|
||||||
thickness: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function SpacedArmorSubSpaced({
|
|
||||||
node,
|
|
||||||
thickness,
|
|
||||||
}: SpacedArmorSubSpacedProps) {
|
|
||||||
const shell = useDuel((state) => state.antagonist!.shell);
|
|
||||||
const penetration = resolveNearPenetration(shell.penetration);
|
|
||||||
|
|
||||||
return jsxTree(node, {
|
|
||||||
renderOrder: 2,
|
|
||||||
material: new ShaderMaterial({
|
|
||||||
fragmentShader,
|
|
||||||
vertexShader,
|
|
||||||
|
|
||||||
depthTest: true,
|
|
||||||
depthWrite: false,
|
|
||||||
blending: AdditiveBlending,
|
|
||||||
|
|
||||||
uniforms: {
|
|
||||||
thickness: { value: thickness },
|
|
||||||
penetration: { value: penetration },
|
|
||||||
caliber: { value: shell.caliber },
|
|
||||||
ricochet: { value: degToRad(shell.ricochet ?? 90) },
|
|
||||||
normalization: { value: degToRad(shell.normalization ?? 0) },
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
import {
|
||||||
|
AdditiveBlending,
|
||||||
|
MeshBasicMaterial,
|
||||||
|
Object3D,
|
||||||
|
ShaderMaterial,
|
||||||
|
} from 'three';
|
||||||
|
import { degToRad } from 'three/src/math/MathUtils';
|
||||||
|
import { resolveNearPenetration } from '../../../../../../core/blitz/resolveNearPenetration';
|
||||||
|
import { jsxTree } from '../../../../../../core/blitzkrieg/jsxTree';
|
||||||
|
import { ShellDefinition } from '../../../../../../core/blitzkrieg/tankDefinitions';
|
||||||
|
import { useDuel } from '../../../../../../stores/duel';
|
||||||
|
import fragmentShader from './shaders/fragment.glsl';
|
||||||
|
import vertexShader from './shaders/vertex.glsl';
|
||||||
|
|
||||||
|
interface SpacedArmorSubSpacedProps {
|
||||||
|
node: Object3D;
|
||||||
|
thickness: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const depthWriteMaterial = new MeshBasicMaterial({
|
||||||
|
depthWrite: true,
|
||||||
|
colorWrite: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
export function SpacedArmorSubSpaced({
|
||||||
|
node,
|
||||||
|
thickness,
|
||||||
|
}: SpacedArmorSubSpacedProps) {
|
||||||
|
const material = new ShaderMaterial({
|
||||||
|
fragmentShader,
|
||||||
|
vertexShader,
|
||||||
|
|
||||||
|
depthTest: true,
|
||||||
|
depthWrite: false,
|
||||||
|
blending: AdditiveBlending,
|
||||||
|
|
||||||
|
uniforms: {
|
||||||
|
thickness: { value: thickness },
|
||||||
|
penetration: { value: null },
|
||||||
|
caliber: { value: null },
|
||||||
|
ricochet: { value: null },
|
||||||
|
normalization: { value: null },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
function handleChange(shell: ShellDefinition) {
|
||||||
|
material.uniforms.penetration.value = resolveNearPenetration(
|
||||||
|
shell.penetration,
|
||||||
|
);
|
||||||
|
material.uniforms.caliber.value = shell.caliber;
|
||||||
|
material.uniforms.ricochet.value = degToRad(shell.ricochet ?? 90);
|
||||||
|
material.uniforms.normalization.value = degToRad(
|
||||||
|
shell.normalization ?? 0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChange(useDuel.getState().antagonist!.shell);
|
||||||
|
return useDuel.subscribe((state) => state.antagonist!.shell, handleChange);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{jsxTree(node, {
|
||||||
|
renderOrder: 2,
|
||||||
|
material,
|
||||||
|
})}
|
||||||
|
{jsxTree(node, {
|
||||||
|
renderOrder: 5,
|
||||||
|
material: depthWriteMaterial,
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@ export function SpacedArmor({ node, type, thickness }: SpacedArmorProps) {
|
|||||||
* - 0 : core omission
|
* - 0 : core omission
|
||||||
* - 1-2: spaced without depth buffer write but do test to allow additive blending
|
* - 1-2: spaced without depth buffer write but do test to allow additive blending
|
||||||
* - 3-4: external with depth buffer write in first pass and read in second to simplify geometry
|
* - 3-4: external with depth buffer write in first pass and read in second to simplify geometry
|
||||||
|
* - 5 : spaced depth write
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ interface SpacedArmorSceneProps {
|
|||||||
|
|
||||||
export const SpacedArmorScene = memo<SpacedArmorSceneProps>(
|
export const SpacedArmorScene = memo<SpacedArmorSceneProps>(
|
||||||
({ ornamental = false }) => {
|
({ ornamental = false }) => {
|
||||||
const protagonist = useDuel((state) => state.protagonist!);
|
|
||||||
const wrapper = useRef<Group>(null);
|
const wrapper = useRef<Group>(null);
|
||||||
const modelDefinitions = useModelDefinitions();
|
const modelDefinitions = useModelDefinitions();
|
||||||
const turretContainer = useRef<Group>(null);
|
const turretContainer = useRef<Group>(null);
|
||||||
@@ -103,7 +102,7 @@ export const SpacedArmorScene = memo<SpacedArmorSceneProps>(
|
|||||||
turretContainer.current?.rotation.copy(turretRotation);
|
turretContainer.current?.rotation.copy(turretRotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleModelTransform(protagonist);
|
handleModelTransform(useDuel.getState().protagonist!);
|
||||||
modelTransformEvent.on(handleModelTransform);
|
modelTransformEvent.on(handleModelTransform);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
@@ -122,17 +121,18 @@ export const SpacedArmorScene = memo<SpacedArmorSceneProps>(
|
|||||||
return unsubscribe;
|
return unsubscribe;
|
||||||
});
|
});
|
||||||
|
|
||||||
const armorGltf = useArmor(protagonist.tank.id);
|
const tank = useDuel((state) => state.protagonist!.tank);
|
||||||
const { gltf: modelGltf } = useModel(protagonist.tank.id);
|
const track = useDuel((state) => state.protagonist!.track);
|
||||||
|
const turret = useDuel((state) => state.protagonist!.turret);
|
||||||
|
const gun = useDuel((state) => state.protagonist!.gun);
|
||||||
|
const armorGltf = useArmor(tank.id);
|
||||||
|
const { gltf: modelGltf } = useModel(tank.id);
|
||||||
const armorNodes = Object.values(armorGltf.nodes);
|
const armorNodes = Object.values(armorGltf.nodes);
|
||||||
const modelNodes = Object.values(modelGltf.nodes);
|
const modelNodes = Object.values(modelGltf.nodes);
|
||||||
const tankModelDefinition = modelDefinitions[protagonist.tank.id];
|
const tankModelDefinition = modelDefinitions[tank.id];
|
||||||
const trackModelDefinition =
|
const trackModelDefinition = tankModelDefinition.tracks[track.id];
|
||||||
tankModelDefinition.tracks[protagonist.track.id];
|
const turretModelDefinition = tankModelDefinition.turrets[turret.id];
|
||||||
const turretModelDefinition =
|
const gunModelDefinition = turretModelDefinition.guns[gun.id];
|
||||||
tankModelDefinition.turrets[protagonist.turret.id];
|
|
||||||
const gunModelDefinition = turretModelDefinition.guns[protagonist.gun.id];
|
|
||||||
const hullOrigin = new Vector3(
|
const hullOrigin = new Vector3(
|
||||||
trackModelDefinition.origin[0],
|
trackModelDefinition.origin[0],
|
||||||
trackModelDefinition.origin[1],
|
trackModelDefinition.origin[1],
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { createPortal, useFrame } from '@react-three/fiber';
|
import { createPortal, useFrame } from '@react-three/fiber';
|
||||||
|
import { memo } from 'react';
|
||||||
import { DepthTexture, Scene, Vector2 } from 'three';
|
import { DepthTexture, Scene, Vector2 } from 'three';
|
||||||
import { spacedArmorRenderTarget } from './components/CoreArmor';
|
import { spacedArmorRenderTarget } from './components/CoreArmor';
|
||||||
import { CoreArmorScene } from './components/CoreArmorScene';
|
import { CoreArmorScene } from './components/CoreArmorScene';
|
||||||
import { SpacedArmorScene } from './components/SpacedArmorScene';
|
import { SpacedArmorScene } from './components/SpacedArmorScene';
|
||||||
|
|
||||||
export function Armor() {
|
export const Armor = memo(() => {
|
||||||
const spacedArmorScene = new Scene();
|
const spacedArmorScene = new Scene();
|
||||||
const coreArmorScene = new Scene();
|
const coreArmorScene = new Scene();
|
||||||
const spacedArmorPortal = createPortal(
|
const spacedArmorPortal = createPortal(
|
||||||
@@ -48,4 +49,4 @@ export function Armor() {
|
|||||||
{coreArmorPortal}
|
{coreArmorPortal}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
Reference in new issue
Block a user