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; +}