mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 03:59:50 +02:00
Compare commits
3
Commits
84ecaec5d3
...
e2df4d35b8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e2df4d35b8 | ||
|
|
7739dbd0a3 | ||
|
|
9b7aa13d61 |
No files matched your search
+14
-11
@@ -1,3 +1,4 @@
|
||||
import { ContactShadows } from "@react-three/drei";
|
||||
import { useFrame } from "@react-three/fiber";
|
||||
import { clamp, times } from "lodash-es";
|
||||
import { Quicklime } from "quicklime";
|
||||
@@ -12,25 +13,24 @@ import { HemisphereLight, SpotLight, type Group } from "three";
|
||||
import { degToRad, lerp } from "three/src/math/MathUtils.js";
|
||||
import { Tankopedia } from "../../../../../../stores/tankopedia";
|
||||
import { TankopediaPersistent } from "../../../../../../stores/tankopediaPersistent";
|
||||
import { HelpingSpotLight } from "../../../../../HelpingSpotLight";
|
||||
|
||||
const ANGLE = degToRad(12);
|
||||
const REVEAL_ANIMATION_TIME = 3;
|
||||
const TRANSITION_ANIMATION_TIME = 0.5;
|
||||
|
||||
const LIGHTS_COUNT = 4;
|
||||
const LIGHTS_COUNT = 3;
|
||||
const THETA_OFFSET = degToRad(180 - 45);
|
||||
const LIGHT_DISTANCE = 20;
|
||||
const LIGHT_HEIGHT_0 = 4;
|
||||
const LIGHT_HEIGHT_1 = 6;
|
||||
const INTENSITY_0 = 6 * 9;
|
||||
const INTENSITY_1 = 3 * 9;
|
||||
const HEMISPHERE_INTENSITY = 2;
|
||||
const INTENSITY_0 = 2 ** 6.5;
|
||||
const INTENSITY_1 = 2 ** 3.5;
|
||||
const HEMISPHERE_INTENSITY = 2 ** 1.2;
|
||||
|
||||
export const transitionEvent = new Quicklime<number>(0);
|
||||
|
||||
export function Lighting() {
|
||||
const wrapper = useRef<Group>(null!);
|
||||
const wrapper = useRef<Group>(null);
|
||||
|
||||
const highGraphics = TankopediaPersistent.use((state) => state.highGraphics);
|
||||
const requestedDisplay = Tankopedia.use((state) => state.requestedDisplay);
|
||||
@@ -61,6 +61,8 @@ export function Lighting() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<ContactShadows blur={2 ** 1} opacity={2 ** 1} />
|
||||
|
||||
{animate && (
|
||||
<Animator
|
||||
t0={t0}
|
||||
@@ -73,21 +75,20 @@ export function Lighting() {
|
||||
)}
|
||||
|
||||
<group ref={wrapper}>
|
||||
<hemisphereLight intensity={0} color="#ffffff" groundColor="#afafaf" />
|
||||
<hemisphereLight intensity={0} color="#d2e9ff" groundColor="#85490c" />
|
||||
|
||||
{times(LIGHTS_COUNT, (index) => {
|
||||
const x = index / (LIGHTS_COUNT - 1);
|
||||
const theta = 2 * Math.PI * (index / LIGHTS_COUNT) + THETA_OFFSET;
|
||||
const position = [
|
||||
LIGHT_DISTANCE * Math.sin(theta),
|
||||
-LIGHT_DISTANCE * Math.sin(theta),
|
||||
lerp(LIGHT_HEIGHT_0, LIGHT_HEIGHT_1, x),
|
||||
LIGHT_DISTANCE * Math.cos(theta),
|
||||
] as const;
|
||||
const intensity = lerp(INTENSITY_0, INTENSITY_1, x);
|
||||
|
||||
return (
|
||||
<HelpingSpotLight
|
||||
userData={{ index }}
|
||||
<spotLight
|
||||
key={index}
|
||||
position={position}
|
||||
intensity={intensity}
|
||||
@@ -109,13 +110,15 @@ interface AnimatorProps {
|
||||
|
||||
t0: RefObject<number>;
|
||||
animationTime: RefObject<number>;
|
||||
wrapper: RefObject<Group>;
|
||||
wrapper: RefObject<Group | null>;
|
||||
}
|
||||
|
||||
function Animator({ stop, t0, animationTime, wrapper }: AnimatorProps) {
|
||||
const requestedDisplay = Tankopedia.use((state) => state.requestedDisplay);
|
||||
|
||||
const apply = useCallback((t: number) => {
|
||||
if (wrapper.current === null) return;
|
||||
|
||||
for (const child of wrapper.current.children) {
|
||||
if (child instanceof SpotLight) {
|
||||
child.angle = ANGLE * t;
|
||||
|
||||
+2
-1
@@ -3,7 +3,7 @@ import { Quicklime, type QuicklimeEvent } from "quicklime";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { Mesh, MeshStandardMaterial } from "three";
|
||||
|
||||
const SIZE = 2 ** 4;
|
||||
const SIZE = 2 ** 5;
|
||||
|
||||
export const screenshotReadyEvent = new Quicklime(false);
|
||||
|
||||
@@ -26,6 +26,7 @@ export function SceneProps() {
|
||||
|
||||
return (
|
||||
<mesh
|
||||
position={[0, -(2 ** -8), 0]}
|
||||
rotation={[-Math.PI / 2, 0, 0]}
|
||||
receiveShadow
|
||||
visible={!screenshotReadyEvent.last!}
|
||||
|
||||
-2
@@ -5,7 +5,6 @@ import {
|
||||
useImperativeHandle,
|
||||
useRef,
|
||||
} from "react";
|
||||
import { Fog } from "three";
|
||||
import { applyPitchYawLimits } from "../../../../../core/blitz/applyPitchYawLimits";
|
||||
import { modelTransformEvent } from "../../../../../core/blitzkit/modelTransform";
|
||||
import { Pose, poseEvent } from "../../../../../core/blitzkit/pose";
|
||||
@@ -150,7 +149,6 @@ export const TankSandbox = forwardRef<HTMLCanvasElement, TankSandboxProps>(
|
||||
<SmartCanvas
|
||||
resize={{ debounce: 0 }}
|
||||
ref={canvas}
|
||||
scene={{ fog: new Fog("black", 30, 50) }}
|
||||
gl={{
|
||||
clippingPlanes: [],
|
||||
localClippingEnabled: true,
|
||||
|
||||
@@ -107,9 +107,6 @@ async function extractModel(vfs: AbstractVFS, path: string) {
|
||||
if (textures) {
|
||||
const baseColor = await readBaseColor(
|
||||
`Data/3d/${dirname(path)}/${textures.baseColorMap ?? textures.albedo}`,
|
||||
textures.miscMap
|
||||
? `Data/3d/${dirname(path)}/${textures.miscMap}`
|
||||
: undefined,
|
||||
);
|
||||
material.setBaseColorTexture(
|
||||
document
|
||||
@@ -180,6 +177,19 @@ async function extractModel(vfs: AbstractVFS, path: string) {
|
||||
}
|
||||
}
|
||||
|
||||
if (textures.miscMap) {
|
||||
material.setOcclusionTexture(
|
||||
document
|
||||
.createTexture(node.materialName)
|
||||
.setMimeType("image/webp")
|
||||
.setImage(
|
||||
await readOcclusion(
|
||||
`Data/3d/${dirname(path)}/${textures.miscMap}`,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (textures.baseRMMap) {
|
||||
material.setMetallicRoughnessTexture(
|
||||
document
|
||||
@@ -368,46 +378,18 @@ async function extractModel(vfs: AbstractVFS, path: string) {
|
||||
return document;
|
||||
}
|
||||
|
||||
async function readBaseColor(path: string, occlusionPath?: string) {
|
||||
const baseRaw = await readTexture(path);
|
||||
const occlusionRaw = occlusionPath
|
||||
? await readTexture(occlusionPath)
|
||||
: undefined;
|
||||
const base = await sharp(baseRaw.data, { raw: baseRaw }).raw().toBuffer();
|
||||
const occlusion = occlusionRaw
|
||||
? await sharp(occlusionRaw.data, { raw: occlusionRaw })
|
||||
.extractChannel(3)
|
||||
.raw()
|
||||
.toBuffer()
|
||||
: undefined;
|
||||
async function readBaseColor(path: string) {
|
||||
const raw = await readTexture(path);
|
||||
const image = await sharp(raw.data, { raw }).webp().toBuffer();
|
||||
|
||||
const combined = Buffer.alloc(baseRaw.width * baseRaw.height * 4);
|
||||
return image;
|
||||
}
|
||||
|
||||
for (let i = 0; i < baseRaw.width * baseRaw.height; i++) {
|
||||
let c = 1;
|
||||
async function readOcclusion(path: string) {
|
||||
const raw = await readTexture(path);
|
||||
|
||||
if (occlusionRaw) {
|
||||
const x = i % baseRaw.width;
|
||||
const y = Math.floor(i / baseRaw.width);
|
||||
const u = Math.floor(x * (occlusionRaw.width / baseRaw.width));
|
||||
const v = Math.floor(y * (occlusionRaw.height / baseRaw.height));
|
||||
|
||||
const occlusionI = u + v * occlusionRaw.width;
|
||||
|
||||
c = occlusion![occlusionI] / 255;
|
||||
}
|
||||
|
||||
const alpha = base[i * 4 + 3];
|
||||
|
||||
combined[i * 4 + 0] = Math.round(base[i * 4 + 0] * c);
|
||||
combined[i * 4 + 1] = Math.round(base[i * 4 + 1] * c);
|
||||
combined[i * 4 + 2] = Math.round(base[i * 4 + 2] * c);
|
||||
combined[i * 4 + 3] = alpha;
|
||||
}
|
||||
|
||||
const image = await sharp(combined, {
|
||||
raw: { width: baseRaw.width, height: baseRaw.height, channels: 4 },
|
||||
})
|
||||
const image = await sharp(raw.data, { raw })
|
||||
.extractChannel(3)
|
||||
.webp()
|
||||
.toBuffer();
|
||||
|
||||
@@ -416,7 +398,7 @@ async function readBaseColor(path: string, occlusionPath?: string) {
|
||||
|
||||
async function readRoughnessMetallic(path: string) {
|
||||
const raw = await readTexture(path);
|
||||
const blitz = sharp(raw.data, { raw: raw });
|
||||
const blitz = sharp(raw.data, { raw });
|
||||
const metallicness = await blitz?.extractChannel(1).raw().toBuffer();
|
||||
const roughness = await blitz?.extractChannel(3).raw().toBuffer();
|
||||
|
||||
|
||||
Reference in new issue
Block a user