Skip to content

Commit

Permalink
WIP Deform
Browse files Browse the repository at this point in the history
  • Loading branch information
ousttrue committed Oct 6, 2024
1 parent 686208e commit 82e454d
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 106 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ wasm build.
- [x] [glb](https://github.com/KhronosGroup/glTF-Sample-Assets/tree/main/Models/CesiumMilkTruck/glTF-Binary)
- [x] node
- [x] texture
- [ ] animation
- [ ] glTF
- [x] animation
- [x] glTF
- [ ] draco
- [ ] basisu
- [ ] vrm-0.x
- [WIP] vrm-0.x
- [ ] vrm-1.0
11 changes: 11 additions & 0 deletions deps/sokol_samples/sample_framework/Deform.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const sokol = @import("sokol");
const sg = sokol.gfx;

pub const Morph = struct {};
pub const Skin = struct {};

pub const Deform = @This();

bind: sg.Bindings = sg.Bindings{},
morph: ?Morph = null,
skin: ?Skin = null,
50 changes: 50 additions & 0 deletions deps/sokol_samples/sample_framework/Image.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
const stb = @import("stb/stb.zig");

pub const Image = @This();
width: u32,
height: u32,
channels: u32,
pixels: []const u8,

pub const white = Image{
.width = 2,
.height = 2,
.channels = 4,
.pixels = &.{
255, 255, 255, 255,
255, 255, 255, 255,
255, 255, 255, 255,
255, 255, 255, 255,
},
};

pub fn init(data: []const u8) ?@This() {
var img_width: c_int = undefined;
var img_height: c_int = undefined;
var num_channels: c_int = undefined;
const desired_channels = 4;
const pixels = stb.image.stbi_load_from_memory(
@ptrCast(&data[0]),
@intCast(data.len),
&img_width,
&img_height,
&num_channels,
desired_channels,
) orelse {
return null;
};
return .{
.width = @intCast(img_width),
.height = @intCast(img_height),
.channels = @intCast(num_channels),
.pixels = pixels[0..@intCast(img_width * img_height * num_channels)],
};
}

pub fn deinit(self: @This()) void {
stb.image.stbi_image_free(&self.pixels[0]);
}

pub fn byteLength(self: @This()) u32 {
return self.width * self.height * 4;
}
90 changes: 1 addition & 89 deletions deps/sokol_samples/sample_framework/Mesh.zig
Original file line number Diff line number Diff line change
@@ -1,102 +1,14 @@
const sokol = @import("sokol");
const sg = sokol.gfx;
const shader = @import("gltf.glsl.zig");
const stb = @import("stb/stb.zig");
const Texture = @import("Texture.zig");

pub const Vertex = struct {
position: [3]f32,
normal: [3]f32,
uv: [2]f32,
};

pub const Image = struct {
width: u32,
height: u32,
channels: u32,
pixels: []const u8,

pub const white = Image{
.width = 2,
.height = 2,
.channels = 4,
.pixels = &.{
255, 255, 255, 255,
255, 255, 255, 255,
255, 255, 255, 255,
255, 255, 255, 255,
},
};

pub fn init(data: []const u8) ?@This() {
var img_width: c_int = undefined;
var img_height: c_int = undefined;
var num_channels: c_int = undefined;
const desired_channels = 4;
const pixels = stb.image.stbi_load_from_memory(
@ptrCast(&data[0]),
@intCast(data.len),
&img_width,
&img_height,
&num_channels,
desired_channels,
) orelse {
return null;
};
return .{
.width = @intCast(img_width),
.height = @intCast(img_height),
.channels = @intCast(num_channels),
.pixels = pixels[0..@intCast(img_width * img_height * num_channels)],
};
}

pub fn deinit(self: @This()) void {
stb.image.stbi_image_free(&self.pixels[0]);
}

pub fn byteLength(self: @This()) u32 {
return self.width * self.height * 4;
}
};

pub const Texture = struct {
fs: sg.StageBindings = sg.StageBindings{},

pub fn init(image: Image, _sampler: ?sg.SamplerDesc) @This() {
// init sokol
var texture = Texture{};
texture.fs.images[shader.SLOT_colorTexture2D] = sg.allocImage();
texture.fs.samplers[shader.SLOT_colorTextureSmp] = sg.allocSampler();
sg.initSampler(
texture.fs.samplers[shader.SLOT_colorTextureSmp],
if (_sampler) |sampler|
sampler
else
sg.SamplerDesc{
.wrap_u = .REPEAT,
.wrap_v = .REPEAT,
.min_filter = .LINEAR,
.mag_filter = .LINEAR,
.compare = .NEVER,
},
);

// initialize the sokol-gfx texture
var img_desc = sg.ImageDesc{
.width = @intCast(image.width),
.height = @intCast(image.height),
// set pixel_format to RGBA8 for WebGL
.pixel_format = .RGBA8,
};
img_desc.data.subimage[0][0] = .{
.ptr = &image.pixels[0],
.size = image.byteLength(),
};
sg.initImage(texture.fs.images[shader.SLOT_colorTexture2D], img_desc);

return texture;
}
};
pub const Submesh = struct {
submesh_params: shader.SubmeshParams,
draw_count: u32,
Expand Down
51 changes: 37 additions & 14 deletions deps/sokol_samples/sample_framework/Scene.zig
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ const Vec3 = rowmath.Vec3;
const Quat = rowmath.Quat;

const Mesh = @import("Mesh.zig");
const Texture = @import("Texture.zig");
const Image = @import("Image.zig");
const Deform = @import("Deform.zig");
const Animation = @import("Animation.zig");
pub const Scene = @This();

Expand All @@ -22,10 +25,11 @@ allocator: std.mem.Allocator = undefined,
meshes: []Mesh = &.{},
pip: sg.Pipeline = undefined,
gltf: ?std.json.Parsed(zigltf.Gltf) = null,
white_texture: Mesh.Texture = undefined,
white_texture: Texture = undefined,
animations: []Animation = &.{},
current_animation: ?usize = null,
node_matrices: []Mat4 = &.{},
node_deforms: []Deform = &.{},

pub fn init(self: *@This(), allocator: std.mem.Allocator) void {
self.allocator = allocator;
Expand All @@ -49,7 +53,7 @@ pub fn init(self: *@This(), allocator: std.mem.Allocator) void {
pip_desc.layout.attrs[shader.ATTR_vs_aTexCoord].format = .FLOAT2;
self.pip = sg.makePipeline(pip_desc);

self.white_texture = Mesh.Texture.init(Mesh.Image.white, null);
self.white_texture = Texture.init(Image.white, null);
}

pub fn deinit(self: *@This()) void {
Expand Down Expand Up @@ -199,9 +203,9 @@ pub fn load(
if (texture.source) |source| {
const image_bytes = try gltf_buffer.getImageBytes(source);
const sampler = if (texture.sampler) |sampler_index| gltf.samplers[sampler_index] else null;
if (Mesh.Image.init(image_bytes)) |image| {
if (Image.init(image_bytes)) |image| {
defer image.deinit();
color_texture = Mesh.Texture.init(
color_texture = Texture.init(
image,
to_sokol_sampler(sampler),
);
Expand Down Expand Up @@ -305,9 +309,17 @@ pub fn load(
self.current_animation = 0;
}

var deforms = std.ArrayList(Deform).init(self.allocator);
defer deforms.deinit();
var node_matrices = std.ArrayList(Mat4).init(self.allocator);
defer node_matrices.deinit();
try node_matrices.resize(gltf.nodes.len);
for (gltf.nodes, 0..) |node, i| {
_ = node;
_ = i;
try deforms.append(.{});
try node_matrices.append(Mat4.identity);
}
self.node_deforms = try deforms.toOwnedSlice();
self.node_matrices = try node_matrices.toOwnedSlice();
_ = self.update(0);
}
Expand Down Expand Up @@ -462,7 +474,7 @@ pub fn draw(self: *@This(), camera: Camera) void {
sg.applyPipeline(self.pip);
const vp = camera.viewProjectionMatrix();
for (0..json.value.nodes.len) |i| {
self.draw_node(json.value, vp, i);
self.draw_node(json.value, vp, @intCast(i));
}
}
}
Expand All @@ -471,17 +483,23 @@ fn draw_node(
self: *@This(),
gltf: zigltf.Gltf,
vp: Mat4,
node_index: usize,
node_index: u32,
) void {
const node = gltf.nodes[node_index];

const model_matrix = self.node_matrices[node_index];
if (node.mesh) |mesh_index| {
self.draw_mesh(mesh_index, vp, model_matrix);
self.draw_mesh(node_index, mesh_index, vp, model_matrix);
}
}

fn draw_mesh(self: *@This(), mesh_index: u32, vp: Mat4, model: Mat4) void {
fn draw_mesh(
self: *@This(),
node_index: u32,
mesh_index: u32,
vp: Mat4,
model: Mat4,
) void {
const vs_params = shader.VsParams{
// rowmath では vec * mat の乗算順なので view_projection
// glsl では mat * vec の乗算順なので projection_view
Expand All @@ -500,18 +518,23 @@ fn draw_mesh(self: *@This(), mesh_index: u32, vp: Mat4, model: Mat4) void {
};
sg.applyUniforms(.FS, shader.SLOT_fs_params, sg.asRange(&fs_params));

var mesh = &self.meshes[mesh_index];

var base_mesh = &self.meshes[mesh_index];
var deform = &self.node_deforms[node_index];
var offset: u32 = 0;
for (mesh.submeshes) |*submesh| {
for (base_mesh.submeshes) |*submesh| {
sg.applyUniforms(
.FS,
shader.SLOT_submesh_params,
sg.asRange(&submesh.submesh_params),
);

mesh.bind.fs = submesh.color_texture.fs;
sg.applyBindings(mesh.bind);
var bind = if (deform.morph == null and deform.skin == null)
&base_mesh.bind
else
&deform.bind;

bind.fs = submesh.color_texture.fs;
sg.applyBindings(bind.*);

sg.draw(offset, submesh.draw_count, 1);

Expand Down
42 changes: 42 additions & 0 deletions deps/sokol_samples/sample_framework/Texture.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const sokol = @import("sokol");
const sg = sokol.gfx;
const shader = @import("gltf.glsl.zig");
const Image = @import("Image.zig");

pub const Texture = @This();
fs: sg.StageBindings = sg.StageBindings{},

pub fn init(image: Image, _sampler: ?sg.SamplerDesc) @This() {
// init sokol
var texture = Texture{};
texture.fs.images[shader.SLOT_colorTexture2D] = sg.allocImage();
texture.fs.samplers[shader.SLOT_colorTextureSmp] = sg.allocSampler();
sg.initSampler(
texture.fs.samplers[shader.SLOT_colorTextureSmp],
if (_sampler) |sampler|
sampler
else
sg.SamplerDesc{
.wrap_u = .REPEAT,
.wrap_v = .REPEAT,
.min_filter = .LINEAR,
.mag_filter = .LINEAR,
.compare = .NEVER,
},
);

// initialize the sokol-gfx texture
var img_desc = sg.ImageDesc{
.width = @intCast(image.width),
.height = @intCast(image.height),
// set pixel_format to RGBA8 for WebGL
.pixel_format = .RGBA8,
};
img_desc.data.subimage[0][0] = .{
.ptr = &image.pixels[0],
.size = image.byteLength(),
};
sg.initImage(texture.fs.images[shader.SLOT_colorTexture2D], img_desc);

return texture;
}

0 comments on commit 82e454d

Please sign in to comment.