mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 11:39:50 +02:00
lighting
This commit is contained in:
1 parent
91ac93670f
commit
e3cf2d51cc
5 files changed
+120
-50
No files matched your search
@@ -138,7 +138,10 @@ public partial class GameInterface
|
|||||||
{
|
{
|
||||||
var path = texturePaths[name];
|
var path = texturePaths[name];
|
||||||
var texture = provider.LoadPackageObject<UTexture2D>(path);
|
var texture = provider.LoadPackageObject<UTexture2D>(path);
|
||||||
return provider.Image(texture);
|
var isRMAO = name.EndsWith("_RMAO");
|
||||||
|
var postProcess = isRMAO ? ImagePostProcess.RMAO : ImagePostProcess.None;
|
||||||
|
|
||||||
|
return provider.Image(texture, postProcess);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HashSet<string> Files => files;
|
public HashSet<string> Files => files;
|
||||||
|
|||||||
@@ -17,6 +17,12 @@ using SkiaSharp;
|
|||||||
|
|
||||||
namespace BlitzKit.Game.Models;
|
namespace BlitzKit.Game.Models;
|
||||||
|
|
||||||
|
public enum ImagePostProcess
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
RMAO,
|
||||||
|
}
|
||||||
|
|
||||||
public partial class BlitzFileProvider : DefaultFileProvider
|
public partial class BlitzFileProvider : DefaultFileProvider
|
||||||
{
|
{
|
||||||
[GeneratedRegex(@"\(GameplayTags=\(\(TagName=""(.+)""\)\)\)")]
|
[GeneratedRegex(@"\(GameplayTags=\(\(TagName=""(.+)""\)\)\)")]
|
||||||
@@ -87,13 +93,37 @@ public partial class BlitzFileProvider : DefaultFileProvider
|
|||||||
private readonly SKEncodedImageFormat imageFormat = SKEncodedImageFormat.Webp;
|
private readonly SKEncodedImageFormat imageFormat = SKEncodedImageFormat.Webp;
|
||||||
private readonly int imageQuality = 80;
|
private readonly int imageQuality = 80;
|
||||||
|
|
||||||
public byte[] Image(UTexture2D uTexture)
|
public byte[] Image(UTexture2D uTexture, ImagePostProcess postProcess = ImagePostProcess.None)
|
||||||
{
|
{
|
||||||
var cTexture = uTexture.Decode(ETexturePlatform.DesktopMobile);
|
var cTexture = uTexture.Decode(ETexturePlatform.DesktopMobile);
|
||||||
|
|
||||||
ArgumentNullException.ThrowIfNull(cTexture);
|
ArgumentNullException.ThrowIfNull(cTexture);
|
||||||
|
|
||||||
var bitmap = cTexture.ToSkBitmap();
|
var bitmap = cTexture.ToSkBitmap();
|
||||||
|
|
||||||
|
return Image(bitmap, postProcess);
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] Image(SKBitmap bitmap, ImagePostProcess postProcess)
|
||||||
|
{
|
||||||
|
if (postProcess != ImagePostProcess.None)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < bitmap.Height; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < bitmap.Width; x++)
|
||||||
|
{
|
||||||
|
var color = bitmap.GetPixel(x, y);
|
||||||
|
|
||||||
|
switch (postProcess)
|
||||||
|
{
|
||||||
|
case ImagePostProcess.RMAO:
|
||||||
|
bitmap.SetPixel(x, y, new SKColor(color.Blue, color.Red, color.Green, color.Alpha));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var data = bitmap.Encode(imageFormat, imageQuality);
|
var data = bitmap.Encode(imageFormat, imageQuality);
|
||||||
|
|
||||||
return data.ToArray();
|
return data.ToArray();
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { times } from "lodash-es";
|
||||||
|
import { Quicklime } from "quicklime";
|
||||||
|
import { degToRad, lerp } from "three/src/math/MathUtils.js";
|
||||||
|
|
||||||
|
const ANGLE = Math.PI * 2 ** -2;
|
||||||
|
|
||||||
|
const LIGHTS_COUNT = 5;
|
||||||
|
const THETA_OFFSET = degToRad(-152);
|
||||||
|
const LIGHT_DISTANCE = 13;
|
||||||
|
const LIGHT_HEIGHT_0 = 4;
|
||||||
|
const LIGHT_HEIGHT_1 = 2;
|
||||||
|
const INTENSITY_0 = 3.5;
|
||||||
|
const INTENSITY_1 = 1.5;
|
||||||
|
const HEMISPHERE_INTENSITY = 2;
|
||||||
|
|
||||||
|
export const transitionEvent = new Quicklime<number>(0);
|
||||||
|
|
||||||
|
export function TankopediaLighting() {
|
||||||
|
return (
|
||||||
|
<group>
|
||||||
|
<hemisphereLight
|
||||||
|
intensity={HEMISPHERE_INTENSITY}
|
||||||
|
color="#ffffff"
|
||||||
|
groundColor="#afafaf"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{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),
|
||||||
|
lerp(LIGHT_HEIGHT_0, LIGHT_HEIGHT_1, x),
|
||||||
|
LIGHT_DISTANCE * Math.cos(theta),
|
||||||
|
] as const;
|
||||||
|
const intensity = lerp(INTENSITY_0, INTENSITY_1, x);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<spotLight
|
||||||
|
castShadow
|
||||||
|
userData={{ index }}
|
||||||
|
key={index}
|
||||||
|
position={position}
|
||||||
|
intensity={intensity}
|
||||||
|
penumbra={1}
|
||||||
|
decay={0}
|
||||||
|
color="#ffffff"
|
||||||
|
angle={ANGLE}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</group>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,14 +1,11 @@
|
|||||||
import {
|
import { type StageParameters } from "@protos/blitz_static_tank_upgrade_single_stage";
|
||||||
VisualChanges_TankPart,
|
|
||||||
type StageParameters,
|
|
||||||
} from "@protos/blitz_static_tank_upgrade_single_stage";
|
|
||||||
import { OrbitControls } from "@react-three/drei";
|
import { OrbitControls } from "@react-three/drei";
|
||||||
import { Canvas } from "@react-three/fiber";
|
import { Canvas } from "@react-three/fiber";
|
||||||
import { useProtagonist } from "../../hooks/useProtagonist";
|
|
||||||
import { useTankChassisModel } from "../../hooks/useTankChassisModel";
|
import { useTankChassisModel } from "../../hooks/useTankChassisModel";
|
||||||
import { useTankGunModel } from "../../hooks/useTankGunModel";
|
import { useTankGunModel } from "../../hooks/useTankGunModel";
|
||||||
import { useTankHullModel } from "../../hooks/useTankHullModel";
|
import { useTankHullModel } from "../../hooks/useTankHullModel";
|
||||||
import { useTankTurretModel } from "../../hooks/useTankTurretModel";
|
import { useTankTurretModel } from "../../hooks/useTankTurretModel";
|
||||||
|
import { TankopediaLighting } from "../TankopediaLighting";
|
||||||
import styles from "./index.module.css";
|
import styles from "./index.module.css";
|
||||||
|
|
||||||
interface TankopediaSandboxProps {
|
interface TankopediaSandboxProps {
|
||||||
@@ -33,17 +30,6 @@ export function TankopediaSandbox({ parameters }: TankopediaSandboxProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Content({ parameters }: TankopediaSandboxProps) {
|
function Content({ parameters }: TankopediaSandboxProps) {
|
||||||
const tank = useProtagonist();
|
|
||||||
|
|
||||||
const selectedTurret = parameters.visual_changes.find(
|
|
||||||
({ tank_part }) => tank_part === VisualChanges_TankPart.TANK_PART_TURRET,
|
|
||||||
)!.name;
|
|
||||||
const selectedGun = parameters.visual_changes.find(
|
|
||||||
({ tank_part }) => tank_part === VisualChanges_TankPart.TANK_PART_GUN,
|
|
||||||
)!.name;
|
|
||||||
|
|
||||||
const collision = false;
|
|
||||||
|
|
||||||
const hull = useTankHullModel();
|
const hull = useTankHullModel();
|
||||||
const chassis = useTankChassisModel();
|
const chassis = useTankChassisModel();
|
||||||
const turret = useTankTurretModel(parameters);
|
const turret = useTankTurretModel(parameters);
|
||||||
@@ -64,23 +50,11 @@ function Content({ parameters }: TankopediaSandboxProps) {
|
|||||||
<primitive object={gun} />
|
<primitive object={gun} />
|
||||||
</group>
|
</group>
|
||||||
|
|
||||||
<spotLight
|
<TankopediaLighting />
|
||||||
castShadow
|
|
||||||
position={[3, 10, 5]}
|
|
||||||
intensity={2 ** 10}
|
|
||||||
penumbra={1}
|
|
||||||
/>
|
|
||||||
<spotLight
|
|
||||||
castShadow
|
|
||||||
position={[-3, -10, -5]}
|
|
||||||
intensity={2 ** 10}
|
|
||||||
penumbra={1}
|
|
||||||
/>
|
|
||||||
<ambientLight />
|
|
||||||
|
|
||||||
<mesh receiveShadow rotation={[-Math.PI / 2, 0, 0]}>
|
<mesh receiveShadow rotation={[-Math.PI / 2, 0, 0]}>
|
||||||
<planeGeometry args={[2 ** 8, 2 ** 8]} />
|
<planeGeometry args={[2 ** 9, 2 ** 9]} />
|
||||||
<meshStandardMaterial color="gray" />
|
<meshStandardMaterial color="black" />
|
||||||
</mesh>
|
</mesh>
|
||||||
|
|
||||||
<OrbitControls />
|
<OrbitControls />
|
||||||
|
|||||||
@@ -1,33 +1,43 @@
|
|||||||
import { useLoader } from "@react-three/fiber";
|
import { useLoader } from "@react-three/fiber";
|
||||||
|
import { useEffect } from "react";
|
||||||
import { Mesh, MeshStandardMaterial } from "three";
|
import { Mesh, MeshStandardMaterial } from "three";
|
||||||
import { GLTFLoader } from "three-stdlib";
|
import { GLTFLoader } from "three-stdlib";
|
||||||
|
import { OnObjectUpdate } from "three/src/nodes/utils/EventNode.js";
|
||||||
|
|
||||||
export function useTankModel(url: string, map: Record<string, boolean>) {
|
export function useTankModel(url: string, map: Record<string, boolean>) {
|
||||||
const gltf = useLoader(GLTFLoader, url);
|
const gltf = useLoader(GLTFLoader, url);
|
||||||
const [root] = gltf.scene.children;
|
const [root] = gltf.scene.children;
|
||||||
|
|
||||||
root.traverse((child) => {
|
useEffect(() => {
|
||||||
if (
|
for (const material of Object.values(gltf.materials)) {
|
||||||
child instanceof Mesh &&
|
if (material instanceof MeshStandardMaterial) {
|
||||||
child.material instanceof MeshStandardMaterial
|
// TODO: remove this hack and fix the gltf
|
||||||
) {
|
material.vertexColors = false;
|
||||||
// TODO: remove this hack and fix the gltf
|
material.needsUpdate = true;
|
||||||
child.material.vertexColors = false;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
child.castShadow = true;
|
console.log(gltf.nodes);
|
||||||
child.receiveShadow = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const child of root.children) {
|
for (const node of Object.values(gltf.nodes)) {
|
||||||
if (child.name in map) {
|
if (node instanceof Mesh) {
|
||||||
child.visible = map[child.name];
|
node.castShadow = true;
|
||||||
continue;
|
node.receiveShadow = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}, [url]);
|
||||||
|
|
||||||
child.visible = false;
|
useEffect(() => {
|
||||||
console.warn(`Root child ${child.name} isn't recognized`);
|
for (const child of root.children) {
|
||||||
}
|
if (child.name in map) {
|
||||||
|
child.visible = map[child.name];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
child.visible = false;
|
||||||
|
console.warn(`Root child ${child.name} isn't recognized`);
|
||||||
|
}
|
||||||
|
}, [url, map]);
|
||||||
|
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user