Skip to content

Commit

Permalink
do sprite rotation in vertex shader
Browse files Browse the repository at this point in the history
  • Loading branch information
meetric1 committed Jul 30, 2024
1 parent 5751e7d commit 109dc28
Show file tree
Hide file tree
Showing 12 changed files with 129 additions and 150 deletions.
126 changes: 25 additions & 101 deletions binary/src/flex_renderer.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "flex_renderer.h"
#include "cdll_client_int.h"
#include "cdll_client_int.h" //IVEngineClient

extern IVEngineClient* engine = NULL;

Expand All @@ -23,7 +23,7 @@ IMesh* _build_water_anisotropy(int id, FlexRendererThreadData data) {
// Frustrum culling
Vector4D dst;
Vector4DMultiply(data.view_projection_matrix, Vector4D(particle_pos.x, particle_pos.y, particle_pos.z, 1), dst);
if (dst.z < data.radius || -dst.x - dst.w > data.radius || dst.x - dst.w > data.radius || -dst.y - dst.w > data.radius || dst.y - dst.w > data.radius) continue;
if (dst.z < 0 || -dst.x - dst.w > data.radius || dst.x - dst.w > data.radius || -dst.y - dst.w > data.radius || dst.y - dst.w > data.radius) continue;

// PVS Culling
if (!engine->IsBoxVisible(particle_pos, particle_pos)) continue;
Expand All @@ -33,100 +33,27 @@ IMesh* _build_water_anisotropy(int id, FlexRendererThreadData data) {
particles_to_render++;
}


// TODO: Try probe a bunch of points in a grid for lighting and blend smoothly between them
// Vector colour = engine->GetLightForPoint(particle_pos, false);

// Don't even bother
if (particles_to_render == 0) return nullptr;

float scale_mult = 10.f / data.radius; // no fucking clue why this works
float inv_scale_mult = data.radius / 10.f; // microoptimization

IMesh* mesh = materials->GetRenderContext()->CreateStaticMesh(VERTEX_POSITION | VERTEX_NORMAL | VERTEX_TEXCOORD0_2D, "");
IMesh* mesh = materials->GetRenderContext()->CreateStaticMesh(VERTEX_GWATER2, "");
CMeshBuilder mesh_builder;
mesh_builder.Begin(mesh, MATERIAL_TRIANGLES, particles_to_render);
for (int i = start; i < start + particles_to_render; ++i) {
int particle_index = data.render_buffer[i];
Vector particle_pos = data.particle_positions[particle_index].AsVector3D();

// calculate triangle rotation
//Vector forward = (eye_pos - particle_pos).Normalized();
Vector forward = (particle_pos - data.eye_pos).Normalized();
Vector right = forward.Cross(Vector(0, 0, 1)).Normalized();
Vector up = right.Cross(forward);
Vector local_pos[3] = { (-up - right * SQRT3), up * 2.0, (-up + right * SQRT3) }; // equalateral triangle

Vector4D ani0 = data.particle_ani0[particle_index]; ani0.w *= scale_mult;
Vector4D ani1 = data.particle_ani1[particle_index]; ani1.w *= scale_mult;
Vector4D ani2 = data.particle_ani2[particle_index]; ani2.w *= scale_mult;
Vector4D particle_pos = data.particle_positions[particle_index];
Vector4D ani0 = data.particle_ani0 ? data.particle_ani0[particle_index] : Vector4D(0, 0, 0, 0);
Vector4D ani1 = data.particle_ani1 ? data.particle_ani1[particle_index] : Vector4D(0, 0, 0, 0);
Vector4D ani2 = data.particle_ani2 ? data.particle_ani2[particle_index] : Vector4D(0, 0, 0, 0);

for (int i = 0; i < 3; i++) {
// Anisotropy warping (code provided by Spanky)
Vector pos_ani = local_pos[i] * inv_scale_mult;
float dot0 = pos_ani.Dot(ani0.AsVector3D()) * ani0.w;
float dot1 = pos_ani.Dot(ani1.AsVector3D()) * ani1.w;
float dot2 = pos_ani.Dot(ani2.AsVector3D()) * ani2.w;

pos_ani += ani0.AsVector3D() * dot0 + ani1.AsVector3D() * dot1 + ani2.AsVector3D() * dot2;

Vector world_pos = particle_pos + pos_ani;
mesh_builder.TexCoord2f(0, u[i], v[i]);
mesh_builder.Position3f(world_pos.x, world_pos.y, world_pos.z);
mesh_builder.Normal3f(-forward.x, -forward.y, -forward.z);
mesh_builder.AdvanceVertex();
}
}
mesh_builder.End();

return mesh;
}

// Builds meshes of water particles without anisotropy
IMesh* _build_water(int id, FlexRendererThreadData data) {
int start = id * MAX_PRIMATIVES;
int end = min((id + 1) * MAX_PRIMATIVES, data.max_particles);

// We need to figure out how many and which particles are going to be rendered
int particles_to_render = 0;
for (int particle_index = start; particle_index < end; ++particle_index) {
Vector particle_pos = data.particle_positions[particle_index].AsVector3D();

// Frustrum culling
Vector4D dst;
Vector4DMultiply(data.view_projection_matrix, Vector4D(particle_pos.x, particle_pos.y, particle_pos.z, 1), dst);
if (dst.z < data.radius || -dst.x - dst.w > data.radius || dst.x - dst.w > data.radius || -dst.y - dst.w > data.radius || dst.y - dst.w > data.radius) continue;

// PVS Culling
if (!engine->IsBoxVisible(particle_pos, particle_pos)) continue;

// Add to our buffer
data.render_buffer[start + particles_to_render] = particle_index;
particles_to_render++;
}

// Don't even bother
if (particles_to_render == 0) return nullptr;

IMesh* mesh = materials->GetRenderContext()->CreateStaticMesh(VERTEX_POSITION | VERTEX_NORMAL | VERTEX_TEXCOORD0_2D, "");
CMeshBuilder mesh_builder;
mesh_builder.Begin(mesh, MATERIAL_TRIANGLES, particles_to_render);
for (int i = start; i < start + particles_to_render; ++i) {
int particle_index = data.render_buffer[i];
Vector particle_pos = data.particle_positions[particle_index].AsVector3D();

// calculate triangle rotation
//Vector forward = (eye_pos - particle_pos).Normalized();
Vector forward = (particle_pos - data.eye_pos).Normalized();
Vector right = forward.Cross(Vector(0, 0, 1)).Normalized();
Vector up = right.Cross(forward);
Vector local_pos[3] = { (-up - right * SQRT3) * 0.5, up, (-up + right * SQRT3) * 0.5 };

for (int i = 0; i < 3; i++) { // Same as above w/o anisotropy warping
Vector world_pos = particle_pos + local_pos[i] * data.radius;
mesh_builder.TexCoord2f(0, u[i], v[i]);
mesh_builder.Position3f(world_pos.x, world_pos.y, world_pos.z);
mesh_builder.Normal3f(-forward.x, -forward.y, -forward.z);
mesh_builder.TexCoord4f(1, ani0.x, ani0.y, ani0.z, ani0.w); // shove anisotropy in
mesh_builder.TexCoord4f(2, ani1.x, ani1.y, ani1.z, ani1.w);
mesh_builder.TexCoord4f(3, ani2.x, ani2.y, ani2.z, ani2.w);
mesh_builder.Position3f(particle_pos.x, particle_pos.y, particle_pos.z);
//mesh_builder.Normal3f(-forward.x, -forward.y, -forward.z);
mesh_builder.AdvanceVertex();
}
}
Expand Down Expand Up @@ -222,27 +149,24 @@ void FlexRenderer::build_meshes(FlexSolver* flex, float diffuse_radius) {
bool particle_ani = flex->get_parameter("anisotropy_scale") != 0; // Should we do anisotropy calculations?
float radius = flex->get_parameter("radius");

// Water particles
int max_meshes = min(ceil(max_particles / (float)MAX_PRIMATIVES), allocated);
for (int mesh_index = 0; mesh_index < max_meshes; mesh_index++) {
// update thread data
FlexRendererThreadData data;
data.eye_pos = eye_pos;
data.view_projection_matrix = view_projection_matrix;
data.particle_positions = particle_positions;
data.max_particles = max_particles;
data.radius = radius;
// thread data
FlexRendererThreadData data;
data.eye_pos = eye_pos;
data.view_projection_matrix = view_projection_matrix;
data.particle_positions = particle_positions;
data.max_particles = max_particles;
data.radius = radius;
data.render_buffer = water_buffer;
if (flex->get_parameter("anisotropy_scale") != 0) { // Should we do anisotropy calculations?
data.particle_ani0 = particle_ani0;
data.particle_ani1 = particle_ani1;
data.particle_ani2 = particle_ani2;
data.render_buffer = water_buffer;
}

int max_meshes = min(ceil(max_particles / (float)MAX_PRIMATIVES), allocated);
for (int mesh_index = 0; mesh_index < max_meshes; mesh_index++) {
// Launch thread
if (particle_ani) {
queue[mesh_index] = threads->enqueue(_build_water_anisotropy, mesh_index, data);
} else {
queue[mesh_index] = threads->enqueue(_build_water, mesh_index, data);
}
queue[mesh_index] = threads->enqueue(_build_water_anisotropy, mesh_index, data);
}

// Diffuse particles
Expand Down
2 changes: 2 additions & 0 deletions binary/src/flex_renderer.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once

#include <materialsystem/imesh.h>
#include <istudiorender.h>
#include "meshutils.h" // Fixes linker errors
Expand All @@ -11,6 +12,7 @@
#define MAX_PRIMATIVES 21845
#define MAX_THREADS 16
#define SQRT3 1.73205081
#define VERTEX_GWATER2 VERTEX_POSITION | VERTEX_TEXCOORD0_2D | VERTEX_NORMAL | VERTEX_TEXCOORD_SIZE(1, 4) | VERTEX_TEXCOORD_SIZE(2, 4) | VERTEX_TEXCOORD_SIZE(3, 4)

struct FlexRendererThreadData {
//IMesh*& water;
Expand Down
32 changes: 12 additions & 20 deletions binary/src/flex_solver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ int FlexSolver::get_max_contacts() {
return solver_description.maxContactsPerParticle;
}

void* FlexSolver::get_host(std::string name) {
inline void* FlexSolver::get_host(std::string name) {
return hosts[name];
}

Expand All @@ -62,14 +62,14 @@ std::vector<FlexMesh>* FlexSolver::get_meshes() {

// Resets particle to base parameters
void FlexSolver::set_particle(int index, Particle particle) {
((Vector4D*)hosts["particle_pos"])[index] = particle.pos;
((Vector*)hosts["particle_vel"])[index] = particle.vel;
((int*)hosts["particle_phase"])[index] = NvFlexMakePhase(0, eNvFlexPhaseSelfCollide | eNvFlexPhaseFluid);
((int*)hosts["particle_active"])[index] = index;
((Vector4D*)hosts["particle_smooth"])[index] = particle.pos;
((Vector4D*)hosts["particle_ani0"])[index] = Vector4D(0, 0, 0, 0);
((Vector4D*)hosts["particle_ani1"])[index] = Vector4D(0, 0, 0, 0);
((Vector4D*)hosts["particle_ani2"])[index] = Vector4D(0, 0, 0, 0);
((Vector4D*)get_host("particle_pos"))[index] = particle.pos;
((Vector*)get_host("particle_vel"))[index] = particle.vel;
((int*)get_host("particle_phase"))[index] = NvFlexMakePhase(0, eNvFlexPhaseSelfCollide | eNvFlexPhaseFluid);
((int*)get_host("particle_active"))[index] = index;
((Vector4D*)get_host("particle_smooth"))[index] = particle.pos;
((Vector4D*)get_host("particle_ani0"))[index] = Vector4D(0, 0, 0, 0);
((Vector4D*)get_host("particle_ani1"))[index] = Vector4D(0, 0, 0, 0);
((Vector4D*)get_host("particle_ani2"))[index] = Vector4D(0, 0, 0, 0);
}

void FlexSolver::add_particle(Particle particle) {
Expand Down Expand Up @@ -127,19 +127,13 @@ bool FlexSolver::tick(float dt, NvFlexMapFlags wait) {
Vector4D* particle_pos = (Vector4D*)NvFlexMap(get_buffer("particle_pos"), wait);
if (particle_pos) {
// Add queued particles
Vector* particle_vel = (Vector*)hosts["particle_vel"];
int* particle_phase = (int*)hosts["particle_phase"];
int* particle_active = (int*)hosts["particle_active"];
Vector4D* particle_smooth = (Vector4D*)hosts["particle_smooth"];
Vector4D* particle_ani0 = (Vector4D*)hosts["particle_ani0"];
Vector4D* particle_ani1 = (Vector4D*)hosts["particle_ani1"];
Vector4D* particle_ani2 = (Vector4D*)hosts["particle_ani2"];

for (int i = 0; i < particle_queue.size(); i++) {
int particle_index = copy_description->elementCount + i;
set_particle(particle_index, particle_queue[i]);
}

NvFlexUnmap(get_buffer("particle_pos"));

// Only copy what we just added
NvFlexCopyDesc desc;
desc.dstOffset = copy_description->elementCount;
Expand All @@ -152,11 +146,9 @@ bool FlexSolver::tick(float dt, NvFlexMapFlags wait) {
NvFlexSetPhases(solver, get_buffer("particle_phase"), &desc);
NvFlexSetActive(solver, get_buffer("particle_active"), &desc);
NvFlexSetActiveCount(solver, get_active_particles());

copy_description->elementCount += particle_queue.size();
particle_queue.clear();

NvFlexUnmap(get_buffer("particle_pos"));
} else {
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion binary/src/flex_solver.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class FlexSolver {
std::vector<FlexMesh>* get_meshes();

inline NvFlexBuffer* get_buffer(std::string name);
void* get_host(std::string name); // Returns a host (pointer of float4s) where FleX buffer data is transferred to.
inline void* get_host(std::string name); // Returns a host (pointer of float4s) where FleX buffer data is transferred to.

void add_particle(Particle particle);
void set_particle(int index, Particle particle);
Expand Down
6 changes: 5 additions & 1 deletion binary/src/shaders/GWaterNormals.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ SHADER_DRAW {
SHADOW_STATE {

// Note: Removing VERTEX_COLOR makes the shader work on all objects (Like props)
unsigned int flags = VERTEX_POSITION | VERTEX_NORMAL | VERTEX_TEXCOORD0_2D;
unsigned int flags = VERTEX_GWATER2;

pShaderShadow->VertexShaderVertexFormat(flags, 1, 0, 0);

DECLARE_STATIC_VERTEX_SHADER(GWaterNormals_vs30);
Expand All @@ -44,13 +45,16 @@ SHADER_DRAW {
const bool depthfix = params[DEPTHFIX]->GetIntValue();

pShaderAPI->SetPixelShaderConstant(0, &radius);
pShaderAPI->SetVertexShaderConstant(5, &radius); // first 4 constants are in use

DECLARE_DYNAMIC_VERTEX_SHADER(GWaterNormals_vs30);
SET_DYNAMIC_VERTEX_SHADER(GWaterNormals_vs30);

DECLARE_DYNAMIC_PIXEL_SHADER(GWaterNormals_ps30);
SET_DYNAMIC_PIXEL_SHADER_COMBO(DEPTH, depthfix);
SET_DYNAMIC_PIXEL_SHADER(GWaterNormals_ps30);


}

Draw();
Expand Down
4 changes: 2 additions & 2 deletions binary/src/shaders/fxc/GWaterFinalpass_ps30.fxc
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ float4 main(const PS_INPUT i) : COLOR {
DoSpecularFlashlight(g_FlashlightPos, i.pos, flashlightSpacePosition, smoothed_normal,
g_FlashlightAttenuationFactors.xyz, g_FlashlightAttenuationFactors.w,
FlashlightSampler, ShadowDepthSampler, NormalizeRandRotSampler, FLASHLIGHTDEPTHFILTERMODE, FLASHLIGHTSHADOWS, true, projPos,
SpecularExponent, i.view_dir * -1, false, FRAMEBUFFER, 0, g_ShadowTweaks,
SpecularExponent, -i.view_dir, false, FRAMEBUFFER, 0, g_ShadowTweaks,

// These two values are output
diffuseLightingFL, specularLightingFL);
Expand All @@ -125,7 +125,7 @@ float4 main(const PS_INPUT i) : COLOR {
float3 rimLightingLL;
float3 specularLightingLL;
PixelShaderDoSpecularLighting(i.pos, smoothed_normal,
SpecularExponent, i.view_dir * -1, i.lightAtten,
SpecularExponent, -i.view_dir, i.lightAtten,
NUM_LIGHTS, cLightInfo, false, 0, false, FRAMEBUFFER, 0, false, 1,

// Outputs
Expand Down
3 changes: 2 additions & 1 deletion binary/src/shaders/fxc/GWaterNormals_ps30.fxc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ struct PS_INPUT {
float2 P : VPOS;
float2 coord : TEXCOORD0;
float3 pos : TEXCOORD1;
float4x4 proj : TEXCOORD3;
float4x4 proj : TEXCOORD2;
float3x3 normal : NORMAL0;
};

Expand Down Expand Up @@ -40,6 +40,7 @@ PS_OUTPUT main(const PS_INPUT i) {
// Output colors to rendertargets
PS_OUTPUT o = (PS_OUTPUT)0;
o.rt0 = float4(world_normal, bulge_pos.z);
//o.rt0 = float4(i.coord.x, i.coord.y, 0, bulge_pos.z);
o.rt1 = float4(uvdmax, 0, 0, 1);
#if DEPTH
o.depth = bulge_pos.z / bulge_pos.w;
Expand Down
53 changes: 38 additions & 15 deletions binary/src/shaders/fxc/GWaterNormals_vs30.fxc
Original file line number Diff line number Diff line change
@@ -1,36 +1,59 @@
#include "common_vs_fxc.h"

float RADIUS : register(c5);

struct VS_INPUT {
float4 vPos : POSITION; // Position
float4 vNormal : NORMAL0; // Normal
float4 vTexCoord : TEXCOORD0; // Texture coordinates
float4 ani0 : TEXCOORD1; // cursed anisotropy (we have to shove it in the vertex shader)
float4 ani1 : TEXCOORD2; // its joever
float4 ani2 : TEXCOORD3;
};

struct VS_OUTPUT {
float4 projPosSetup : POSITION; // Register 1
float4 coord : TEXCOORD0; // Register 2
float3 pos : TEXCOORD1; // Register 3
float3x3 normal : NORMAL0; // Registers 8 9 10
float4x4 proj : TEXCOORD3; // Registers 4 5 6 7
float4 projPosSetup : POSITION; // Register 0
float4 coord : TEXCOORD0; // Register 1
float3 pos : TEXCOORD1; // Register 2
float4x4 proj : TEXCOORD2; // Registers 3 4 5 6
float3x3 normal : NORMAL0; // Registers 7 8 9
};

VS_OUTPUT main(const VS_INPUT v) {
VS_OUTPUT o = (VS_OUTPUT)0;

// Extract real position
float3 world_pos;
SkinPosition(0, v.vPos, 0, 0, world_pos);

// extract normal / right and up
float3 world_normal = normalize(cEyePos - world_pos);
float3 right = normalize(cross(world_normal, float3(0, 0, 1)));
float3 up = cross(world_normal, right);

// to avoid extrusion calculations (above) being called on CPU, we do them here
float3 world_pos_offset = -right * (v.vTexCoord.x - 0.5) + up * (v.vTexCoord.y - 0.5);
world_pos_offset *= (RADIUS * 0.1);

// Extract real position & normal
float3 world_normal, world_pos;
SkinPositionAndNormal(0, v.vPos, v.vNormal, 0, 0, world_pos, world_normal);
//float scale_mult = 10.f / data.radius; // no fucking clue why this works
//float inv_scale_mult = data.radius / 10.f; // microoptimization

float4 vProjPos = mul(float4(world_pos, 1), cViewProj);
vProjPos.z = dot(float4(world_pos, 1), cViewProjZ); // wtf does this even do?
// Anisotropy warping
float dot0 = dot(world_pos_offset, v.ani0.xyz) * v.ani0.w;
float dot1 = dot(world_pos_offset, v.ani1.xyz) * v.ani1.w;
float dot2 = dot(world_pos_offset, v.ani2.xyz) * v.ani2.w;
world_pos_offset += (v.ani0.xyz * dot0 + v.ani1.xyz * dot1 + v.ani2.xyz * dot2);
world_pos_offset *= RADIUS;
//world_pos_offset += (v.ani1 * dot1);

float3 extruded_world_pos = world_pos + world_pos_offset;

float4 vProjPos = mul(float4(extruded_world_pos, 1), cViewProj);
//vProjPos.z = dot(float4(extruded_world_pos, 1), cViewProjZ); // wtf does this even do?

o.projPosSetup = vProjPos;
o.coord = v.vTexCoord;
o.pos = world_pos;
o.pos = extruded_world_pos;
o.proj = cViewProj; // Used in spherical depth

float3 right = normalize(cross(world_normal, float3(0, 0, 1)));
float3 up = cross(world_normal, right);
o.normal = float3x3(
-right.x, -right.y, -right.z,
world_normal.x, world_normal.y, world_normal.z,
Expand Down
Loading

0 comments on commit 109dc28

Please sign in to comment.