mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-22 11:17:05 +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",
|
||||
"decalmask",
|
||||
"diacriticless",
|
||||
"donotremove",
|
||||
"drei",
|
||||
"dvpl",
|
||||
"DVPLCRC",
|
||||
|
||||
Binary file not shown.
@@ -532,7 +532,8 @@ if (allTargets || targets?.includes('tankModels')) {
|
||||
// if (id !== 7297) continue; // 60tp
|
||||
// if (id !== 1) continue; // t-34
|
||||
// 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
|
||||
|
||||
console.log(`Building model ${id} @ ${nation}/${tankIndex}`);
|
||||
|
||||
@@ -20,16 +20,16 @@ import {
|
||||
Theme,
|
||||
Tooltip,
|
||||
} 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 { EffectComposer, SSAO } from '@react-three/postprocessing';
|
||||
import { go } from 'fuzzysort';
|
||||
import { debounce } from 'lodash';
|
||||
import Link from 'next/link';
|
||||
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 { Flag } from '../../../../components/Flag';
|
||||
import InfiniteGridHelper from '../../../../components/InfiniteGridHelper';
|
||||
import { ModuleButtons } from '../../../../components/ModuleButton';
|
||||
import PageWrapper from '../../../../components/PageWrapper';
|
||||
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 [versusTankTab, setVersusTankTab] = useState('search');
|
||||
const canvas = useRef<HTMLCanvasElement>(null);
|
||||
const gltf = useLoader(GLTFLoader, '/test/5137.glb');
|
||||
const gltf = useLoader(GLTFLoader, `/test/${id}.glb`);
|
||||
const turretOrigin = new Vector3(
|
||||
tank.turretOrigin[0],
|
||||
tank.turretOrigin[1],
|
||||
@@ -135,32 +135,46 @@ export default function Page({ params }: { params: { id: string } }) {
|
||||
|
||||
<div style={{ height: '50vh', maxHeight: 576 }}>
|
||||
<Canvas
|
||||
shadows
|
||||
ref={canvas}
|
||||
onPointerDown={(event) => event.preventDefault()}
|
||||
camera={{ fov: 20, position: [4, 0, -16] }}
|
||||
camera={{ fov: 20 }}
|
||||
>
|
||||
<TankAlignment model={hullContainer} />
|
||||
<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 */}
|
||||
<Environment preset="apartment" />
|
||||
|
||||
<EffectComposer enabled={true}>
|
||||
<SSAO
|
||||
worldDistanceFalloff={1.0}
|
||||
worldDistanceThreshold={Infinity}
|
||||
worldProximityFalloff={0.5}
|
||||
worldProximityThreshold={8.0}
|
||||
samples={10}
|
||||
radius={0.25}
|
||||
intensity={10}
|
||||
/>
|
||||
</EffectComposer>
|
||||
<directionalLight
|
||||
position={[1, 1, -1]}
|
||||
intensity={1}
|
||||
castShadow
|
||||
/>
|
||||
<directionalLight
|
||||
position={[-1, 1, 1]}
|
||||
intensity={2}
|
||||
castShadow
|
||||
/>
|
||||
<ambientLight intensity={0.25} />
|
||||
|
||||
<group
|
||||
ref={hullContainer}
|
||||
rotation={[0 /*-Math.PI / 2*/, 0, hullRotation]}
|
||||
rotation={[-Math.PI / 2, 0, hullRotation]}
|
||||
>
|
||||
{gltf.scene.children[0].children.map((child) => {
|
||||
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 { readDVPLFile } from './readDVPLFile';
|
||||
|
||||
BigInt.prototype.toJSON = function () {
|
||||
return this.toString();
|
||||
};
|
||||
|
||||
const MAX_FLOAT32 = 2 ** 127 * (2 - 2 ** -23);
|
||||
|
||||
const vertexAttributeGLTFName: Partial<Record<VertexAttribute, string>> = {
|
||||
@@ -168,9 +172,14 @@ export async function extractModel(
|
||||
case 'NewSlotComponent':
|
||||
case 'StateSwitcherComponent':
|
||||
case 'CustomPropertiesComponent':
|
||||
case 'ActionComponent':
|
||||
case 'ParticleEffectComponent':
|
||||
case 'SlotComponent':
|
||||
case 'TankElementComponent':
|
||||
break;
|
||||
|
||||
// console.log(JSON.stringify(component, null, 2));
|
||||
|
||||
case 'TransformComponent': {
|
||||
const translation = new Vector3();
|
||||
const rotation = new Quaternion();
|
||||
|
||||
@@ -183,6 +183,55 @@ export type Component =
|
||||
'cpc.properties.archive': {
|
||||
'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 {
|
||||
|
||||
Reference in new issue
Block a user