mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 20:19:49 +02:00
feat: improved lighting and grid
This commit is contained in:
1 parent
e65582a432
commit
3ea872c6a4
7 files changed
+174
-21
No files matched your search
Vendored
+1
@@ -26,6 +26,7 @@
|
|||||||
"deburr",
|
"deburr",
|
||||||
"decalmask",
|
"decalmask",
|
||||||
"diacriticless",
|
"diacriticless",
|
||||||
|
"donotremove",
|
||||||
"drei",
|
"drei",
|
||||||
"dvpl",
|
"dvpl",
|
||||||
"DVPLCRC",
|
"DVPLCRC",
|
||||||
|
|||||||
Binary file not shown.
@@ -532,7 +532,8 @@ if (allTargets || targets?.includes('tankModels')) {
|
|||||||
// if (id !== 7297) continue; // 60tp
|
// if (id !== 7297) continue; // 60tp
|
||||||
// if (id !== 1) continue; // t-34
|
// if (id !== 1) continue; // t-34
|
||||||
// if (id !== 6753) continue; // type 71
|
// if (id !== 6753) continue; // type 71
|
||||||
if (id !== 5137) continue; // tiger ii
|
// if (id !== 5137) continue; // tiger ii
|
||||||
|
if (id !== 11633) continue; // tiger ii
|
||||||
// if (id !== 6225) continue; // fv215b
|
// if (id !== 6225) continue; // fv215b
|
||||||
|
|
||||||
console.log(`Building model ${id} @ ${nation}/${tankIndex}`);
|
console.log(`Building model ${id} @ ${nation}/${tankIndex}`);
|
||||||
|
|||||||
@@ -20,16 +20,16 @@ import {
|
|||||||
Theme,
|
Theme,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from '@radix-ui/themes';
|
} from '@radix-ui/themes';
|
||||||
import { Environment, OrbitControls } from '@react-three/drei';
|
import { OrbitControls } from '@react-three/drei';
|
||||||
import { Canvas, ThreeEvent, useLoader } from '@react-three/fiber';
|
import { Canvas, ThreeEvent, useLoader } from '@react-three/fiber';
|
||||||
import { EffectComposer, SSAO } from '@react-three/postprocessing';
|
|
||||||
import { go } from 'fuzzysort';
|
import { go } from 'fuzzysort';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { use, useEffect, useRef, useState } from 'react';
|
import { use, useEffect, useRef, useState } from 'react';
|
||||||
import { Group, Mesh, Vector3 } from 'three';
|
import { Color, Group, Mesh, Vector3 } from 'three';
|
||||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||||
import { Flag } from '../../../../components/Flag';
|
import { Flag } from '../../../../components/Flag';
|
||||||
|
import InfiniteGridHelper from '../../../../components/InfiniteGridHelper';
|
||||||
import { ModuleButtons } from '../../../../components/ModuleButton';
|
import { ModuleButtons } from '../../../../components/ModuleButton';
|
||||||
import PageWrapper from '../../../../components/PageWrapper';
|
import PageWrapper from '../../../../components/PageWrapper';
|
||||||
import { asset } from '../../../../core/blitzkrieg/asset';
|
import { asset } from '../../../../core/blitzkrieg/asset';
|
||||||
@@ -63,7 +63,7 @@ export default function Page({ params }: { params: { id: string } }) {
|
|||||||
const [versusGun, setVersusGun] = useState(versusTurret.guns.at(-1)!);
|
const [versusGun, setVersusGun] = useState(versusTurret.guns.at(-1)!);
|
||||||
const [versusTankTab, setVersusTankTab] = useState('search');
|
const [versusTankTab, setVersusTankTab] = useState('search');
|
||||||
const canvas = useRef<HTMLCanvasElement>(null);
|
const canvas = useRef<HTMLCanvasElement>(null);
|
||||||
const gltf = useLoader(GLTFLoader, '/test/5137.glb');
|
const gltf = useLoader(GLTFLoader, `/test/${id}.glb`);
|
||||||
const turretOrigin = new Vector3(
|
const turretOrigin = new Vector3(
|
||||||
tank.turretOrigin[0],
|
tank.turretOrigin[0],
|
||||||
tank.turretOrigin[1],
|
tank.turretOrigin[1],
|
||||||
@@ -135,32 +135,46 @@ export default function Page({ params }: { params: { id: string } }) {
|
|||||||
|
|
||||||
<div style={{ height: '50vh', maxHeight: 576 }}>
|
<div style={{ height: '50vh', maxHeight: 576 }}>
|
||||||
<Canvas
|
<Canvas
|
||||||
|
shadows
|
||||||
ref={canvas}
|
ref={canvas}
|
||||||
onPointerDown={(event) => event.preventDefault()}
|
onPointerDown={(event) => event.preventDefault()}
|
||||||
camera={{ fov: 20, position: [4, 0, -16] }}
|
camera={{ fov: 20 }}
|
||||||
>
|
>
|
||||||
<TankAlignment model={hullContainer} />
|
<TankAlignment model={hullContainer} />
|
||||||
<OrbitControls enabled={orbitControlsEnabled} />
|
<OrbitControls enabled={orbitControlsEnabled} />
|
||||||
<gridHelper />
|
<InfiniteGridHelper
|
||||||
|
position={[0, 0, 0]}
|
||||||
|
axes="xzy"
|
||||||
|
size1={1 / 5}
|
||||||
|
size2={1}
|
||||||
|
distance={20}
|
||||||
|
color={new Color('#ffffff')}
|
||||||
|
/>
|
||||||
|
<InfiniteGridHelper
|
||||||
|
position={[0, 0, 0]}
|
||||||
|
axes="xzy"
|
||||||
|
size1={0}
|
||||||
|
size2={100}
|
||||||
|
distance={25}
|
||||||
|
color={new Color('red')}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* I really like apartment, dawn, and sunset */}
|
{/* I really like apartment, dawn, and sunset */}
|
||||||
<Environment preset="apartment" />
|
<directionalLight
|
||||||
|
position={[1, 1, -1]}
|
||||||
<EffectComposer enabled={true}>
|
intensity={1}
|
||||||
<SSAO
|
castShadow
|
||||||
worldDistanceFalloff={1.0}
|
/>
|
||||||
worldDistanceThreshold={Infinity}
|
<directionalLight
|
||||||
worldProximityFalloff={0.5}
|
position={[-1, 1, 1]}
|
||||||
worldProximityThreshold={8.0}
|
intensity={2}
|
||||||
samples={10}
|
castShadow
|
||||||
radius={0.25}
|
/>
|
||||||
intensity={10}
|
<ambientLight intensity={0.25} />
|
||||||
/>
|
|
||||||
</EffectComposer>
|
|
||||||
|
|
||||||
<group
|
<group
|
||||||
ref={hullContainer}
|
ref={hullContainer}
|
||||||
rotation={[0 /*-Math.PI / 2*/, 0, hullRotation]}
|
rotation={[-Math.PI / 2, 0, hullRotation]}
|
||||||
>
|
>
|
||||||
{gltf.scene.children[0].children.map((child) => {
|
{gltf.scene.children[0].children.map((child) => {
|
||||||
const isHull = child.name === 'hull';
|
const isHull = child.name === 'hull';
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
import { MeshProps } from '@react-three/fiber';
|
||||||
|
import { forwardRef } from 'react';
|
||||||
|
import { DoubleSide, Mesh } from 'three';
|
||||||
|
|
||||||
|
interface InfiniteGridHelperProps extends MeshProps {
|
||||||
|
size1?: number;
|
||||||
|
size2?: number;
|
||||||
|
color?: THREE.Color;
|
||||||
|
distance?: number;
|
||||||
|
axes?: string;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Thanks, Fyrestar, for [THREE.InfiniteGridHelper](https://github.com/Fyrestar/THREE.InfiniteGridHelper/)!
|
||||||
|
*/
|
||||||
|
const InfiniteGridHelper = forwardRef<Mesh, InfiniteGridHelperProps>(
|
||||||
|
({ size1, size2, color, axes = 'xzy', distance, ...props }, ref) => {
|
||||||
|
const planeAxes = axes.slice(0, 2);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<mesh {...props} ref={ref} frustumCulled={false}>
|
||||||
|
<shaderMaterial
|
||||||
|
args={[
|
||||||
|
{
|
||||||
|
side: DoubleSide,
|
||||||
|
uniforms: {
|
||||||
|
uSize1: { value: size1 },
|
||||||
|
uSize2: { value: size2 },
|
||||||
|
uColor: { value: color },
|
||||||
|
uDistance: { value: distance },
|
||||||
|
},
|
||||||
|
extensions: { derivatives: true },
|
||||||
|
transparent: true,
|
||||||
|
|
||||||
|
vertexShader: `
|
||||||
|
varying vec3 worldPosition;
|
||||||
|
uniform float uDistance;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec3 pos = position.${axes} * uDistance;
|
||||||
|
worldPosition = pos;
|
||||||
|
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
|
||||||
|
fragmentShader: `
|
||||||
|
varying vec3 worldPosition;
|
||||||
|
uniform float uSize1;
|
||||||
|
uniform float uSize2;
|
||||||
|
uniform vec3 uColor;
|
||||||
|
uniform float uDistance;
|
||||||
|
vec2 origin = vec2(0.0, 0.0);
|
||||||
|
|
||||||
|
float getGrid(float size) {
|
||||||
|
vec2 r = worldPosition.${planeAxes} / size;
|
||||||
|
vec2 grid = abs(fract(r - 0.5) - 0.5) / fwidth(r);
|
||||||
|
float line = min(grid.x, grid.y);
|
||||||
|
|
||||||
|
return 1.0 - min(line, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
float d = 1.0 - min(distance(origin, worldPosition.${planeAxes}) / uDistance, 1.0);
|
||||||
|
float g1 = getGrid(uSize1);
|
||||||
|
float g2 = getGrid(uSize2);
|
||||||
|
gl_FragColor = vec4(uColor.rgb, mix(g2, g1, g1) * pow(d, 10.0));
|
||||||
|
gl_FragColor.a = mix(0.5 * gl_FragColor.a, gl_FragColor.a, g2);
|
||||||
|
|
||||||
|
if ( gl_FragColor.a <= 0.0 ) discard;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<planeGeometry />
|
||||||
|
</mesh>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
export default InfiniteGridHelper;
|
||||||
@@ -14,6 +14,10 @@ import { ScgStream, vertexAttributeVectorSizes } from '../streams/scg';
|
|||||||
import { VertexAttribute } from '../streams/scpg';
|
import { VertexAttribute } from '../streams/scpg';
|
||||||
import { readDVPLFile } from './readDVPLFile';
|
import { readDVPLFile } from './readDVPLFile';
|
||||||
|
|
||||||
|
BigInt.prototype.toJSON = function () {
|
||||||
|
return this.toString();
|
||||||
|
};
|
||||||
|
|
||||||
const MAX_FLOAT32 = 2 ** 127 * (2 - 2 ** -23);
|
const MAX_FLOAT32 = 2 ** 127 * (2 - 2 ** -23);
|
||||||
|
|
||||||
const vertexAttributeGLTFName: Partial<Record<VertexAttribute, string>> = {
|
const vertexAttributeGLTFName: Partial<Record<VertexAttribute, string>> = {
|
||||||
@@ -168,9 +172,14 @@ export async function extractModel(
|
|||||||
case 'NewSlotComponent':
|
case 'NewSlotComponent':
|
||||||
case 'StateSwitcherComponent':
|
case 'StateSwitcherComponent':
|
||||||
case 'CustomPropertiesComponent':
|
case 'CustomPropertiesComponent':
|
||||||
|
case 'ActionComponent':
|
||||||
|
case 'ParticleEffectComponent':
|
||||||
case 'SlotComponent':
|
case 'SlotComponent':
|
||||||
|
case 'TankElementComponent':
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// console.log(JSON.stringify(component, null, 2));
|
||||||
|
|
||||||
case 'TransformComponent': {
|
case 'TransformComponent': {
|
||||||
const translation = new Vector3();
|
const translation = new Vector3();
|
||||||
const rotation = new Quaternion();
|
const rotation = new Quaternion();
|
||||||
|
|||||||
@@ -183,6 +183,55 @@ export type Component =
|
|||||||
'cpc.properties.archive': {
|
'cpc.properties.archive': {
|
||||||
'editor.donotremove': number;
|
'editor.donotremove': number;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
| ({
|
||||||
|
'comp.typename': 'ActionComponent';
|
||||||
|
'ac.actionCount': number;
|
||||||
|
} & Record<
|
||||||
|
string, // 0000, 0001, ...
|
||||||
|
{
|
||||||
|
'act.delay': number;
|
||||||
|
'act.delayVariation': number;
|
||||||
|
'act.entityName': string;
|
||||||
|
'act.event': number;
|
||||||
|
'act.eventToTrigger': string;
|
||||||
|
'act.motionFrameTime': number;
|
||||||
|
'act.motionSpeed': number;
|
||||||
|
'act.stateActivated': number;
|
||||||
|
'act.stopAfterNRepeats': number;
|
||||||
|
'act.stopWhenEmpty': boolean;
|
||||||
|
'act.switchIndex': number;
|
||||||
|
'act.type': number;
|
||||||
|
'act.userEventId': string;
|
||||||
|
}
|
||||||
|
>)
|
||||||
|
| {
|
||||||
|
'comp.typename': 'ParticleEffectComponent';
|
||||||
|
'pe.clearOnRestart': boolean;
|
||||||
|
'pe.effectDuration': number;
|
||||||
|
'pe.emitters': {
|
||||||
|
'##name': string;
|
||||||
|
'emitter.data': {
|
||||||
|
'emitter.id': `${number}`;
|
||||||
|
'emitter.quality': string;
|
||||||
|
}[];
|
||||||
|
'emitter.position': Vector3Tuple;
|
||||||
|
'emitter.rotation': Vector4Tuple;
|
||||||
|
'emitter.scale': Vector3Tuple;
|
||||||
|
}[];
|
||||||
|
'pe.inheritScale': boolean;
|
||||||
|
'pe.nestedEmitters': boolean;
|
||||||
|
'pe.repeatsCount': number;
|
||||||
|
'pe.startFromTime': number;
|
||||||
|
'pe.stopWhenEmpty': boolean;
|
||||||
|
'pe.version': number;
|
||||||
|
'ro.flags': number;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
'comp.typename': 'TankElementComponent';
|
||||||
|
isDestructible: boolean;
|
||||||
|
shouldCastShadow: boolean;
|
||||||
|
shouldGenerateSilhouette: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface SceneComponents {
|
interface SceneComponents {
|
||||||
|
|||||||
Reference in new issue
Block a user