diff --git a/next.config.js b/next.config.js
index 1bb819616..78a50013e 100644
--- a/next.config.js
+++ b/next.config.js
@@ -8,6 +8,14 @@ const nextConfig = {
distDir: 'dist/website',
reactStrictMode: false,
+
+ webpack: (config) => {
+ config.module.rules.push({
+ test: /\.glsl$/,
+ type: 'asset/source',
+ });
+ return config;
+ },
};
export default nextConfig;
diff --git a/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor.tsx b/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor.tsx
index f1d5cae89..ca6cb6a4f 100644
--- a/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor.tsx
+++ b/src/app/tools/tankopedia/[id]/components/Model/components/TankArmor.tsx
@@ -94,15 +94,15 @@ export function TankArmor() {
key={node.uuid}
geometry={(node as Mesh).geometry}
thickness={thickness}
- penetration={100}
- ricochet={antagonist.shell.ricochet * (Math.PI / 180)}
+ penetration={225}
+ ricochet={antagonist.shell.ricochet}
caliber={antagonist.shell.caliber}
normalization={antagonist.shell.normalization}
/>
);
})}
- {/*
+
{nodes.map((node) => {
const isCurrentTurret = node.name.startsWith(
`turret_${turretModelDefinition.model
@@ -110,6 +110,9 @@ export function TankArmor() {
.padStart(2, '0')}`,
);
const isVisible = isCurrentTurret;
+ const armorId = parseInt(node.name.match(/.+_armor_(\d+)/)![1]);
+ const thickness =
+ turretModelDefinition.armor.thickness[armorId] ?? 0;
if (!isVisible) return null;
return (
@@ -117,6 +120,11 @@ export function TankArmor() {
key={node.uuid}
position={turretOrigin}
geometry={(node as Mesh).geometry}
+ thickness={thickness}
+ penetration={225}
+ ricochet={antagonist.shell.ricochet}
+ caliber={antagonist.shell.caliber}
+ normalization={antagonist.shell.normalization}
/>
);
})}
@@ -135,6 +143,9 @@ export function TankArmor() {
`gun_${gunModelDefinition.model.toString().padStart(2, '0')}`,
);
const isVisible = isCurrentGun;
+ const armorId = parseInt(node.name.match(/.+_armor_(\d+)/)![1]);
+ const thickness =
+ gunModelDefinition.armor.thickness[armorId] ?? 0;
if (!isVisible) return null;
@@ -143,11 +154,16 @@ export function TankArmor() {
key={node.uuid}
position={turretOrigin.clone().add(gunOrigin)}
geometry={(node as Mesh).geometry}
+ thickness={thickness}
+ penetration={225}
+ ricochet={antagonist.shell.ricochet}
+ caliber={antagonist.shell.caliber}
+ normalization={antagonist.shell.normalization}
/>
);
})}
- */}
+
);
diff --git a/src/components/ArmorMesh.tsx b/src/components/ArmorMesh.tsx
deleted file mode 100644
index e6190284a..000000000
--- a/src/components/ArmorMesh.tsx
+++ /dev/null
@@ -1,130 +0,0 @@
-// // Vertex shader
-// varying vec3 vNormal; // declare a varying variable to pass the normal vector
-// void main() {
-// vNormal = normal; // assign the normal vector to the varying variable
-// gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); // transform the vertex position
-// }
-
-// // Fragment shader
-// varying vec3 vNormal; // declare the same varying variable to receive the normal vector
-// void main() {
-// vec3 cameraDir = -viewPosition; // get the camera direction vector by negating the view position
-// float angle = acos(dot(vNormal, cameraDir)); // calculate the angle of the fragment using the dot product and the acos function
-// vec3 color = mix(vec3(1.0, 0.0, 0.0), vec3(0.0, 0.0, 1.0), angle / PI); // create a gradient color from red to blue based on the angle
-// gl_FragColor = vec4(color, 1.0); // set the fragment color
-// }
-
-import { MeshProps } from '@react-three/fiber';
-import { MeshBasicMaterial } from 'three';
-import CustomShaderMaterial from 'three-custom-shader-material';
-
-interface ArmorMeshProps extends MeshProps {
- thickness: number;
- penetration: number;
- ricochet: number;
- caliber: number;
- normalization: number;
-}
-
-export function ArmorMesh({
- thickness,
- penetration,
- caliber,
- ricochet,
- normalization,
- ...props
-}: ArmorMeshProps) {
- return (
- <>
-
-
-
-
-
- 2.0 * thickness;
- bool threeCaliberRule = caliber > 3.0 * thickness;
- float finalNormalization = normalization;
-
- if (twoCaliberRule) {
- finalNormalization = (normalization * 1.4 * caliber) / (2.0 * thickness);
- }
-
- if (
- angle >= ricochet
- && !threeCaliberRule
- ) {
- penetrationChance = 1.0;
- }
-
- csm_FragColor *= vec4(1.0, 0.0, 0.0, penetrationChance * 0.5);
- }
- `}
- />
-
- {/* */}
- {/* */}
-
- >
- );
-}
diff --git a/src/components/ArmorMesh/index.tsx b/src/components/ArmorMesh/index.tsx
new file mode 100644
index 000000000..0f94ccb61
--- /dev/null
+++ b/src/components/ArmorMesh/index.tsx
@@ -0,0 +1,48 @@
+import { MeshProps } from '@react-three/fiber';
+import { MeshBasicMaterial } from 'three';
+import CustomShaderMaterial from 'three-custom-shader-material';
+import fragment from './shaders/fragment.glsl';
+import vertex from './shaders/vertex.glsl';
+
+interface ArmorMeshProps extends MeshProps {
+ thickness: number;
+ penetration: number;
+ ricochet: number;
+ caliber: number;
+ normalization: number;
+}
+
+export function ArmorMesh({
+ thickness,
+ penetration,
+ caliber,
+ ricochet,
+ normalization,
+ ...props
+}: ArmorMeshProps) {
+ return (
+ <>
+
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/src/components/ArmorMesh/shaders/fragment.glsl b/src/components/ArmorMesh/shaders/fragment.glsl
new file mode 100644
index 000000000..496f6fe31
--- /dev/null
+++ b/src/components/ArmorMesh/shaders/fragment.glsl
@@ -0,0 +1,29 @@
+varying vec3 vViewPosition;
+uniform float thickness;
+uniform float penetration;
+uniform float ricochet;
+uniform float caliber;
+uniform float normalization;
+
+void main() {
+ vec3 normalizedNormal = normalize(vNormal);
+ vec3 normalizedViewPosition = normalize(vViewPosition);
+ float cosAngle = dot(normalizedNormal, -normalizedViewPosition);
+ float angle = acos(cosAngle);
+
+ float penetrationChance = 0.0;
+ bool twoCaliberRule = caliber > 2.0 * thickness;
+ bool threeCaliberRule = caliber > 3.0 * thickness;
+ float finalNormalization = twoCaliberRule ? (normalization * 1.4 * caliber) / (2.0 * thickness) : normalization;
+
+ float effectiveArmor = thickness / cos(angle - finalNormalization);
+
+ if(angle < ricochet) {
+ // no auto-ricochet, resume checks
+ if(effectiveArmor <= penetration || threeCaliberRule) {
+ penetrationChance = 1.0;
+ }
+ }
+
+ csm_FragColor *= vec4(1.0, 0.0, 0.0, (1.0 - penetrationChance) * 0.5);
+}
\ No newline at end of file
diff --git a/src/components/ArmorMesh/shaders/vertex.glsl b/src/components/ArmorMesh/shaders/vertex.glsl
new file mode 100644
index 000000000..829b747fc
--- /dev/null
+++ b/src/components/ArmorMesh/shaders/vertex.glsl
@@ -0,0 +1,8 @@
+varying vec3 vNormal;
+varying vec3 vViewPosition;
+
+void main() {
+ vec4 vViewPosition4 = modelViewMatrix * vec4(position, 1.0);
+ vViewPosition = vViewPosition4.xyz;
+ vNormal = normalMatrix * normal;
+}
\ No newline at end of file
diff --git a/src/types/glsl.d.ts b/src/types/glsl.d.ts
new file mode 100644
index 000000000..77ffce2fc
--- /dev/null
+++ b/src/types/glsl.d.ts
@@ -0,0 +1,4 @@
+declare module '*.glsl' {
+ const value: string;
+ export default value;
+}