Skip to content

Commit

Permalink
Source Engine: Implement eyeballs
Browse files Browse the repository at this point in the history
* View target vector is forced to the camera position right now
* No max deflection yet
* No glint yet
* No lighting on eyeballs yet
  • Loading branch information
magcius committed Nov 22, 2024
1 parent 1495729 commit da2d1ff
Show file tree
Hide file tree
Showing 4 changed files with 286 additions and 39 deletions.
2 changes: 1 addition & 1 deletion src/SourceEngine/Materials/MaterialBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ export abstract class BaseMaterial {
return (this.param[name] as P.ParameterVector);
}

protected paramGetMatrix(name: string): ReadonlyMat4 {
public paramGetMatrix(name: string): mat4 {
return (this.param[name] as P.ParameterMatrix).matrix;
}

Expand Down
5 changes: 5 additions & 0 deletions src/SourceEngine/Materials/MaterialCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { ParticleSystemCache } from "../ParticleSystem.js";
import { VMT, parseVMT } from "../VMT.js";
import { VTF } from "../VTF.js";
import { MaterialShaderTemplateBase, LateBindingTexture, BaseMaterial } from "./MaterialBase.js";
import { Material_Eyes, ShaderTemplate_Eyes } from "./Material_Eyes.js";
import { Material_Generic, ShaderTemplate_Generic } from "./Material_Generic.js";
import { Material_Modulate, ShaderTemplate_Modulate } from "./Material_Modulate.js";
import { Material_Refract, ShaderTemplate_Refract } from "./Material_Refract.js";
Expand Down Expand Up @@ -151,6 +152,7 @@ class ShaderTemplates {
public Sky = new ShaderTemplate_Sky();
public SkyHDRCompressed = new ShaderTemplate_SkyHDRCompressed();
public SpriteCard = new ShaderTemplate_SpriteCard();
public Eyes = new ShaderTemplate_Eyes();

public destroy(device: GfxDevice): void {
this.Generic.destroy(device);
Expand All @@ -162,6 +164,7 @@ class ShaderTemplates {
this.Sky.destroy(device);
this.SkyHDRCompressed.destroy(device);
this.SpriteCard.destroy(device);
this.Eyes.destroy(device);
}
}

Expand Down Expand Up @@ -257,6 +260,8 @@ export class MaterialCache {
return new Material_Sky(vmt);
else if (shaderType === 'spritecard')
return new Material_SpriteCard(vmt);
else if (shaderType === 'eyes')
return new Material_Eyes(vmt);
else
return new Material_Generic(vmt);
}
Expand Down
125 changes: 125 additions & 0 deletions src/SourceEngine/Materials/Material_Eyes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@

import { TextureMapping } from "../../TextureHolder.js";
import { GfxMegaStateDescriptor } from "../../gfx/platform/GfxPlatform.js";
import { GfxProgram } from "../../gfx/platform/GfxPlatformImpl.js";
import { GfxRendererLayer, makeSortKey, setSortKeyProgramKey, GfxRenderInst } from "../../gfx/render/GfxRenderInstManager.js";
import { assert } from "../../util.js";
import { SourceRenderContext } from "../Main.js";
import { MaterialCache } from "./MaterialCache.js";
import { UberShaderInstanceBasic } from "../UberShader.js";
import { MaterialShaderTemplateBase, BaseMaterial, MaterialUtil, AlphaBlendMode } from "./MaterialBase.js";
import * as P from "./MaterialParameters.js";

// UnlitTwoTexture
export class ShaderTemplate_Eyes extends MaterialShaderTemplateBase {
public static ub_ObjectParams = 2;

public override program = `
precision mediump float;
${MaterialShaderTemplateBase.Common}
layout(std140) uniform ub_ObjectParams {
Mat4x2 u_BaseTransform;
Mat4x2 u_IrisTransform;
};
varying vec3 v_PositionWorld;
// TextureBase, TextureIris
varying vec4 v_TexCoord0;
varying vec3 v_Lighting;
uniform sampler2D u_TextureBase;
uniform sampler2D u_TextureIris;
#if defined VERT
void mainVS() {
Mat4x3 t_WorldFromLocalMatrix = CalcWorldFromLocalMatrix();
vec3 t_PositionWorld = Mul(t_WorldFromLocalMatrix, vec4(a_Position, 1.0));
v_PositionWorld.xyz = t_PositionWorld;
gl_Position = Mul(u_ProjectionView, vec4(t_PositionWorld, 1.0));
v_TexCoord0.xy = Mul(u_BaseTransform, vec4(a_TexCoord01.xy, 1.0, 1.0));
v_TexCoord0.zw = Mul(u_IrisTransform, vec4(t_PositionWorld, 1.0));
// XXX(jstpierre): Move lighting into common helpers
v_Lighting.rgb = vec3(1.0);
}
#endif
#if defined FRAG
void mainPS() {
vec4 t_TextureBase = texture(SAMPLER_2D(u_TextureBase), v_TexCoord0.xy);
vec4 t_TextureIris = texture(SAMPLER_2D(u_TextureIris), v_TexCoord0.zw);
vec3 t_Glint = vec3(0.0);
// Composite iris onto base
vec4 t_FinalColor = vec4(0.0);
t_FinalColor.rgb = mix(t_TextureBase.rgb, t_TextureIris.rgb, t_TextureIris.a) * v_Lighting.rgb + t_Glint;
CalcFog(t_FinalColor, v_PositionWorld.xyz);
OutputLinearColor(t_FinalColor);
// o_Color0.rgb = vec3(v_TexCoord0.zw, 1.0);
}
#endif
`;
}

export class Material_Eyes extends BaseMaterial {
private shaderInstance: UberShaderInstanceBasic;
private gfxProgram: GfxProgram;
private megaStateFlags: Partial<GfxMegaStateDescriptor> = {};
private sortKeyBase: number = 0;

protected override initParameters(): void {
super.initParameters();

const p = this.param;

p['$iris'] = new P.ParameterTexture(true);
p['$irisframe'] = new P.ParameterNumber(0.0);
p['$iristransform'] = new P.ParameterMatrix();
}

protected override initStatic(materialCache: MaterialCache) {
super.initStatic(materialCache);

this.shaderInstance = new UberShaderInstanceBasic(materialCache.shaderTemplates.Eyes);

this.setAlphaBlendMode(this.megaStateFlags, AlphaBlendMode.None);
this.sortKeyBase = makeSortKey(GfxRendererLayer.OPAQUE);

this.setSkinningMode(this.shaderInstance);
this.setFogMode(this.shaderInstance);
this.setCullMode(this.megaStateFlags);

this.gfxProgram = this.shaderInstance.getGfxProgram(materialCache.cache);
this.sortKeyBase = setSortKeyProgramKey(this.sortKeyBase, this.gfxProgram.ResourceUniqueId);
}

private updateTextureMappings(dst: TextureMapping[]): void {
MaterialUtil.resetTextureMappings(dst);
this.paramGetTexture('$basetexture').fillTextureMapping(dst[0], this.paramGetInt('$frame'));
this.paramGetTexture('$iris').fillTextureMapping(dst[1], this.paramGetInt('$irisframe'));
}

public setOnRenderInst(renderContext: SourceRenderContext, renderInst: GfxRenderInst): void {
assert(this.isMaterialLoaded());
this.updateTextureMappings(MaterialUtil.textureMappings);

this.setupOverrideSceneParams(renderContext, renderInst);

let offs = renderInst.allocateUniformBuffer(ShaderTemplate_Eyes.ub_ObjectParams, 20);
const d = renderInst.mapUniformBufferF32(ShaderTemplate_Eyes.ub_ObjectParams);
offs += this.paramFillTextureMatrix(d, offs, '$basetexturetransform', this.paramGetFlipY(renderContext, '$basetexture'));
offs += this.paramFillTextureMatrix(d, offs, '$iristransform');

renderInst.setSamplerBindingsFromTextureMappings(MaterialUtil.textureMappings);
renderInst.setGfxProgram(this.gfxProgram);
renderInst.setMegaStateFlags(this.megaStateFlags);
renderInst.sortKey = this.sortKeyBase;
}
}
//#endregion
Loading

0 comments on commit da2d1ff

Please sign in to comment.