snake demo
This commit is contained in:
parent
38deeabf83
commit
6abcee60fb
@ -129,10 +129,12 @@
|
||||
</select>
|
||||
</div>
|
||||
-->
|
||||
<!--
|
||||
<div class="row">
|
||||
<span class="label">eye</span>
|
||||
<input type="color" class="value">
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
80
index.js
80
index.js
@ -2,6 +2,8 @@ import { getPath } from "./common.js";
|
||||
import { loadGltf } from "./index2.js";
|
||||
import { loadLight } from "./light.js";
|
||||
import { loadFlat } from "./flat.js";
|
||||
import { loadSnake } from "./snake.js";
|
||||
import { loadFont } from "./font.js";
|
||||
|
||||
if (!navigator.gpu) {
|
||||
throw new Error("WebGPU not supported on this browser.");
|
||||
@ -45,6 +47,7 @@ const module = await WebAssembly.instantiateStreaming(fetch("src/module.wasm"),
|
||||
env: {
|
||||
memory: memory,
|
||||
log: console.log,
|
||||
logStrInt: console.log,
|
||||
}
|
||||
});
|
||||
module.memory = memory;
|
||||
@ -82,7 +85,7 @@ function recreateDepth(force)
|
||||
const matrixSize = 4 * 4 * 4;
|
||||
const float4Size = 4 * 4;
|
||||
const float3Size = 4 * 3;
|
||||
const viewUniformBufferSize = (matrixSize * 2) + (float4Size * 2);
|
||||
const viewUniformBufferSize = (matrixSize * 2) + (float4Size * 2) + (4 * 4);
|
||||
|
||||
const viewUniformBuffer = device.createBuffer({
|
||||
label: "view uniform buffer",
|
||||
@ -99,8 +102,9 @@ module.instance.exports.camera_init(cameraStateAddress);
|
||||
|
||||
//const gltfRenderer = await loadGltf(device, canvasFormat, viewUniformBuffer, memory, module);
|
||||
//const lightRenderer = await loadLight(device, canvasFormat, viewUniformBuffer);
|
||||
const flatRenderer = await loadFlat(device, canvasFormat, viewUniformBuffer, module);
|
||||
|
||||
//const flatRenderer = await loadFlat(device, canvasFormat, viewUniformBuffer, module);
|
||||
//const snakeRenderer = await loadSnake(device, canvasFormat, viewUniformBuffer, module);
|
||||
const fontRenderer = await loadFont(device, canvasFormat, viewUniformBuffer, module);
|
||||
|
||||
const KEY = {
|
||||
A: 65,
|
||||
@ -189,15 +193,6 @@ function updateView()
|
||||
device.queue.writeBuffer(viewUniformBuffer, 0,
|
||||
memory.buffer, viewStateAddress,
|
||||
viewUniformBufferSize);
|
||||
|
||||
const cameraStateF32 = new Float32Array(memory.buffer, cameraStateAddress, cameraStateSize);
|
||||
/*
|
||||
eyeValueX.innerHTML = cameraStateF32[0].toFixed(1);
|
||||
eyeValueY.innerHTML = cameraStateF32[1].toFixed(1);
|
||||
eyeValueZ.innerHTML = cameraStateF32[2].toFixed(1);
|
||||
yawValue.innerHTML = cameraStateF32[9].toFixed(2);
|
||||
pitchValue.innerHTML = cameraStateF32[10].toFixed(2);
|
||||
*/
|
||||
}
|
||||
|
||||
const controlMain = document.getElementById("control-main");
|
||||
@ -207,7 +202,7 @@ function remap(low1, high1, low2, high2, value)
|
||||
return low2 + (value - low1) * (high2 - low2) / (high1 - low1);
|
||||
}
|
||||
|
||||
const sliderDefaults = {"test intensity":"0","mass12 mix":"0","circle thickness":"171","line thickness":"107","particle mass2":"13","particle count":"19","target density":"954","particle size":"70","pressure":"19","line length":"6","particle mass1":"1024","circle radius":"379"};
|
||||
const sliderDefaults = {"bone length":"32","velocity acc.":"385","velocity damp.":"796","bone count":"40"};
|
||||
|
||||
class Slider {
|
||||
constructor(label, low, high, max = 1024)
|
||||
@ -246,6 +241,7 @@ class Slider {
|
||||
} else if (this.label in sliderDefaults) {
|
||||
this.input.value = sliderDefaults[this.label];
|
||||
}
|
||||
this.input.value = sliderDefaults[this.label];
|
||||
|
||||
this.update();
|
||||
}
|
||||
@ -267,7 +263,8 @@ class Slider {
|
||||
}
|
||||
}
|
||||
|
||||
const sliders = {
|
||||
/*
|
||||
const flatSliders = {
|
||||
particleSize: new Slider("particle size", 0.0, 0.05),
|
||||
particleMass1: new Slider("particle mass1", 0.0, 0.05),
|
||||
particleMass2: new Slider("particle mass2", 0.0, 1.0),
|
||||
@ -280,27 +277,25 @@ const sliders = {
|
||||
lineLength: new Slider("line length", 0.0, 9.0),
|
||||
targetDensity: new Slider("target density", -10.0, 10.0),
|
||||
pressure: new Slider("pressure", 0.0, 1.0),
|
||||
};
|
||||
};
|
||||
*/
|
||||
|
||||
const mousePosition = new Float32Array([0, 0, 0, 0]);
|
||||
|
||||
function updateSliders()
|
||||
const snakeSliders = {
|
||||
boneCount: new Slider("bone count", 0.0, 100.0, 100),
|
||||
boneLength: new Slider("bone length", 0.0, 0.5),
|
||||
velocityDamping: new Slider("velocity damp.", 0.0, 1.0),
|
||||
velocityAcceleration: new Slider("velocity acc.", 0.0, 1.0),
|
||||
};
|
||||
|
||||
function updateSliders(sliders)
|
||||
{
|
||||
return {
|
||||
mousePosition: mousePosition,
|
||||
particleSize: sliders.particleSize.update(),
|
||||
particleMass1: sliders.particleMass1.update(),
|
||||
particleMass2: sliders.particleMass2.update(),
|
||||
particleCount: sliders.particleCount.update(),
|
||||
circleRadius: sliders.circleRadius.update(),
|
||||
circleThickness: sliders.circleThickness.update(),
|
||||
testIntensity: sliders.testIntensity.update(),
|
||||
mass12Mix: sliders.mass12Mix.update(),
|
||||
lineThickness: sliders.lineThickness.update(),
|
||||
lineLength: sliders.lineLength.update(),
|
||||
targetDensity: sliders.targetDensity.update(),
|
||||
pressure: sliders.pressure.update(),
|
||||
};
|
||||
const values = {};
|
||||
for (let [key, value] of Object.entries(sliders)) {
|
||||
values[key] = value.update();
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
function onClick(e)
|
||||
@ -308,14 +303,24 @@ function onClick(e)
|
||||
mousePosition[0] = e.clientX / canvas.width;
|
||||
mousePosition[1] = 1.0 - (e.clientY / canvas.height);
|
||||
}
|
||||
canvas.addEventListener("click", onClick);
|
||||
//canvas.addEventListener("click", onClick);
|
||||
|
||||
function onMouseMove(e)
|
||||
{
|
||||
const aspect = canvas.width / canvas.height;
|
||||
|
||||
mousePosition[0] = ((e.clientX / canvas.width) * 2 - 1) * aspect;
|
||||
mousePosition[1] = (1.0 - (e.clientY / canvas.height)) * 2 - 1;
|
||||
}
|
||||
canvas.addEventListener("mousemove", onMouseMove);
|
||||
|
||||
var canRender = false;
|
||||
var frameNumber = 0;
|
||||
function render2()
|
||||
{
|
||||
if (canRender === true) {
|
||||
const configuration = updateSliders();
|
||||
//const configuration = updateSliders(flatSliders);
|
||||
const configuration = updateSliders(snakeSliders);
|
||||
|
||||
canRender = false;
|
||||
recreateDepth(false);
|
||||
@ -341,7 +346,12 @@ function render2()
|
||||
|
||||
//gltfRenderer.render(renderPass);
|
||||
//lightRenderer.render(renderPass);
|
||||
flatRenderer.render(device, renderPass, frameNumber, configuration);
|
||||
//flatRenderer.render(device, renderPass, frameNumber, configuration);
|
||||
|
||||
//snakeRenderer.update(device, frameNumber, mousePosition, configuration);
|
||||
//snakeRenderer.render(renderPass, frameNumber);
|
||||
|
||||
fontRenderer.render(renderPass, frameNumber);
|
||||
|
||||
renderPass.end();
|
||||
|
||||
@ -357,7 +367,7 @@ function setCanRender()
|
||||
{
|
||||
canRender = true;
|
||||
}
|
||||
setInterval(setCanRender, 66.67); // 15 fps
|
||||
setInterval(setCanRender, 33.33); // 15 fps
|
||||
|
||||
recreateDepth(true);
|
||||
requestAnimationFrame(render2);
|
||||
|
||||
201
snake.js
Normal file
201
snake.js
Normal file
@ -0,0 +1,201 @@
|
||||
import { getPath } from "./common.js";
|
||||
|
||||
class SnakeRenderer {
|
||||
createBuffers(device)
|
||||
{
|
||||
const boneCount = 100;
|
||||
const boneLength = 0.1;
|
||||
this.boneSystemAddress = this.module.instance.exports.bone_system__create(boneCount, boneLength);
|
||||
const mem = new DataView(this.module.memory.buffer);
|
||||
this.bonesAddress = mem.getUint32(this.boneSystemAddress, true);
|
||||
const configurationOffset = this.module.instance.exports.bone_system__configuration_offset();
|
||||
this.configurationAddress = this.boneSystemAddress + configurationOffset;
|
||||
this.bonesBufferSize = this.module.instance.exports.bone_system__bones_size(boneCount);
|
||||
this.configurationBufferSize = this.module.instance.exports.bone_system__configuration_size();
|
||||
|
||||
this.frames = [];
|
||||
|
||||
for (let i = 0; i < 2; i++) {
|
||||
const bonesBuffer = device.createBuffer({
|
||||
label: `bone buffer ${i}`,
|
||||
size: this.bonesBufferSize,
|
||||
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
|
||||
});
|
||||
|
||||
const configurationBuffer = device.createBuffer({
|
||||
label: `bone configuration buffer ${i}`,
|
||||
size: this.configurationBufferSize,
|
||||
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
||||
});
|
||||
|
||||
const bindGroup = device.createBindGroup({
|
||||
label: `bone buffer bind group ${i}`,
|
||||
layout: this.bindGroupLayout.bone,
|
||||
entries: [{
|
||||
binding: 0,
|
||||
resource: { buffer: bonesBuffer },
|
||||
}, {
|
||||
binding: 1,
|
||||
resource: { buffer: configurationBuffer },
|
||||
}]
|
||||
});
|
||||
|
||||
this.frames.push({
|
||||
bonesBuffer: bonesBuffer,
|
||||
configurationBuffer: configurationBuffer,
|
||||
bindGroup: bindGroup,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
constructor(device, canvasFormat, viewUniformBuffer, wgsl, module)
|
||||
{
|
||||
const label = "bone";
|
||||
|
||||
this.module = module;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// shader module
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
const shaderModule = device.createShaderModule({
|
||||
label: `${label} shader`,
|
||||
code: wgsl,
|
||||
});
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// index buffer
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
const array = new Uint16Array(6);
|
||||
array[0] = 0;
|
||||
array[1] = 1;
|
||||
array[2] = 2;
|
||||
array[3] = 0;
|
||||
array[4] = 3;
|
||||
array[5] = 1;
|
||||
|
||||
this.buffer = device.createBuffer({
|
||||
label: `${label} renderer buffer`,
|
||||
size: array.byteLength,
|
||||
usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,
|
||||
});
|
||||
|
||||
device.queue.writeBuffer(this.buffer, 0, array, 0, array.length);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// pipeline
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
this.bindGroupLayout = {
|
||||
view: device.createBindGroupLayout({
|
||||
label: `${label} bind group layout view`,
|
||||
entries: [{
|
||||
binding: 0,
|
||||
visibility: GPUShaderStage.VERTEX,
|
||||
buffer: { type: "uniform" }
|
||||
}]
|
||||
}),
|
||||
bone: device.createBindGroupLayout({
|
||||
label: `${label} bind group layout particle`,
|
||||
entries: [{ // bones
|
||||
binding: 0,
|
||||
visibility: GPUShaderStage.FRAGMENT,
|
||||
buffer: { type: "read-only-storage" }
|
||||
}, { // configuration
|
||||
binding: 1,
|
||||
visibility: GPUShaderStage.FRAGMENT,
|
||||
buffer: { type: "uniform" }
|
||||
}]
|
||||
}),
|
||||
};
|
||||
|
||||
const pipelineLayout = device.createPipelineLayout({
|
||||
label: `${label} pipeline layout`,
|
||||
bindGroupLayouts: [
|
||||
this.bindGroupLayout.view,
|
||||
this.bindGroupLayout.bone
|
||||
],
|
||||
});
|
||||
|
||||
this.renderPipeline = device.createRenderPipeline({
|
||||
label: `${label} pipeline`,
|
||||
layout: pipelineLayout,
|
||||
vertex: {
|
||||
module: shaderModule,
|
||||
entryPoint: "vertexMain",
|
||||
},
|
||||
fragment: {
|
||||
module: shaderModule,
|
||||
entryPoint: "fragmentMain",
|
||||
targets: [{
|
||||
format: canvasFormat,
|
||||
}]
|
||||
},
|
||||
primitive: {
|
||||
topology: "triangle-list",
|
||||
},
|
||||
depthStencil: {
|
||||
depthWriteEnabled: true,
|
||||
depthCompare: "less",
|
||||
format: "depth24plus",
|
||||
},
|
||||
});
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// bones
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
this.createBuffers(device);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// bind group
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
this.viewBindGroup = device.createBindGroup({
|
||||
label: `${label} bind group`,
|
||||
layout: this.bindGroupLayout.view,
|
||||
entries: [{
|
||||
binding: 0,
|
||||
resource: { buffer: viewUniformBuffer },
|
||||
}],
|
||||
});
|
||||
}
|
||||
|
||||
update(device, frameNumber, mousePosition, configuration)
|
||||
{
|
||||
this.module.instance.exports.bone_system__update_configuration(this.boneSystemAddress,
|
||||
configuration.boneCount,
|
||||
configuration.boneLength,
|
||||
configuration.velocityDamping,
|
||||
configuration.velocityAcceleration);
|
||||
|
||||
this.module.instance.exports.bone_system__update(this.boneSystemAddress,
|
||||
mousePosition[0], mousePosition[1], mousePosition[2]);
|
||||
|
||||
device.queue.writeBuffer(this.frames[frameNumber].bonesBuffer, 0,
|
||||
this.module.memory.buffer, this.bonesAddress, this.bonesBufferSize);
|
||||
|
||||
device.queue.writeBuffer(this.frames[frameNumber].configurationBuffer, 0,
|
||||
this.module.memory.buffer, this.configurationAddress, this.configurationBufferSize);
|
||||
}
|
||||
|
||||
render(renderPass, frameNumber)
|
||||
{
|
||||
renderPass.setPipeline(this.renderPipeline);
|
||||
renderPass.setIndexBuffer(this.buffer, "uint16");
|
||||
renderPass.setBindGroup(0, this.viewBindGroup);
|
||||
renderPass.setBindGroup(1, this.frames[frameNumber].bindGroup);
|
||||
renderPass.drawIndexed(6);
|
||||
}
|
||||
}
|
||||
|
||||
async function loadSnake(device, canvasFormat, viewUniformBuffer, module)
|
||||
{
|
||||
const snakeWgsl = await getPath("snake.wgsl");
|
||||
|
||||
const renderer = new SnakeRenderer(device, canvasFormat, viewUniformBuffer, snakeWgsl, module);
|
||||
return renderer;
|
||||
}
|
||||
|
||||
export { loadSnake };
|
||||
90
snake.wgsl
Normal file
90
snake.wgsl
Normal file
@ -0,0 +1,90 @@
|
||||
struct Configuration {
|
||||
viewProj: mat4x4f,
|
||||
lightViewProj: mat4x4f,
|
||||
lightPosition: vec4f,
|
||||
eyePosition: vec4f,
|
||||
aspect: f32,
|
||||
};
|
||||
|
||||
struct Bone {
|
||||
position: vec4f,
|
||||
velocity: vec4f,
|
||||
};
|
||||
|
||||
struct BoneConfiguration {
|
||||
a: vec4f,
|
||||
};
|
||||
|
||||
@group(0) @binding(0) var<uniform> config: Configuration;
|
||||
@group(1) @binding(0) var<storage> bones: array<Bone>;
|
||||
@group(1) @binding(1) var<uniform> boneConfig: BoneConfiguration;
|
||||
|
||||
struct VertexInput {
|
||||
@builtin(vertex_index) vertex_index: u32,
|
||||
};
|
||||
|
||||
struct VertexOutput {
|
||||
@builtin(position) position: vec4f,
|
||||
@location(0) texture: vec2f,
|
||||
};
|
||||
|
||||
const vertices = array(
|
||||
vec2f(1.0, 0.0),
|
||||
vec2f(0.0, 1.0),
|
||||
vec2f(0.0, 0.0),
|
||||
vec2f(1.0, 1.0),
|
||||
);
|
||||
|
||||
@vertex
|
||||
fn vertexMain(input: VertexInput) -> VertexOutput
|
||||
{
|
||||
let texture = vertices[input.vertex_index];
|
||||
|
||||
let position = texture * 2.0 - 1.0;
|
||||
|
||||
var output: VertexOutput;
|
||||
output.position = vec4f(position, 0.0, 1.0);
|
||||
output.texture = position * vec2f(config.aspect, 1);
|
||||
return output;
|
||||
}
|
||||
|
||||
fn sdCircle(center: vec2f, sample: vec2f) -> f32
|
||||
{
|
||||
let distance = length(center - sample);
|
||||
return distance;
|
||||
}
|
||||
|
||||
fn sdSegment(p: vec2f, a: vec2f, b: vec2f) -> f32
|
||||
{
|
||||
let ba = b - a;
|
||||
let pa = p - a;
|
||||
let h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);
|
||||
return length(pa - h * ba);
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fragmentMain(input: VertexOutput) -> @location(0) vec4f
|
||||
{
|
||||
var color = vec3f(input.texture.xy, 0);
|
||||
|
||||
for (var i: u32 = 0; i < u32(boneConfig.a.x); i++) {
|
||||
if (sdCircle(input.texture.xy, bones[i].position.xy) < 0.01) {
|
||||
color = vec3f(1, 1, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
if (sdSegment(input.texture.xy,
|
||||
bones[i].position.xy,
|
||||
bones[i].position.xy + bones[i].velocity.xy * 0.05) < 0.002) {
|
||||
color = vec3(0, 0, 1);
|
||||
}
|
||||
*/
|
||||
/*
|
||||
if (i == 1 && sdCircle(input.texture.xy, bones[i].velocity.xy) < 0.05) {
|
||||
color = vec3(0, 0, 1);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
return vec4f(color, 1);
|
||||
}
|
||||
23
src/Makefile
23
src/Makefile
@ -9,6 +9,7 @@ CFLAGS = \
|
||||
-nostdlib \
|
||||
-I$(MINIZ) \
|
||||
-I. \
|
||||
-I../include \
|
||||
-Werror \
|
||||
-Wfatal-errors \
|
||||
-D_XM_NO_INTRINSICS_
|
||||
@ -36,6 +37,21 @@ LDFLAGS = \
|
||||
-Wl,--export=particle_system__update \
|
||||
-Wl,--export=particle__stride \
|
||||
-Wl,--export=particle_configuration__stride \
|
||||
-Wl,--export=bone_system__create \
|
||||
-Wl,--export=bone_system__bones_size \
|
||||
-Wl,--export=bone_system__configuration_size \
|
||||
-Wl,--export=bone_system__configuration_offset \
|
||||
-Wl,--export=bone_system__update \
|
||||
-Wl,--export=bone_system__update_configuration \
|
||||
-Wl,--export=font_layout__create \
|
||||
-Wl,--export=font_layout__texture_address \
|
||||
-Wl,--export=font_layout__glyph_buffer_size \
|
||||
-Wl,--export=font_layout__glyph_buffer_address \
|
||||
-Wl,--export=font_layout__texture_size \
|
||||
-Wl,--export=font_layout__texture_address \
|
||||
-Wl,--export=font_layout__layout_buffer_size \
|
||||
-Wl,--export=font_layout__layout_buffer_address \
|
||||
-Wl,--export=font_layout__layout_buffer_index \
|
||||
-Wl,--import-undefined \
|
||||
-Wl,--print-map \
|
||||
-Wl,--import-memory \
|
||||
@ -56,7 +72,12 @@ PNG_OBJ = \
|
||||
camera.o \
|
||||
fluid/particle.o \
|
||||
fluid/particle_system.o \
|
||||
fluid/api.o
|
||||
fluid/api.o \
|
||||
snake/bone.o \
|
||||
snake/bone_system.o \
|
||||
snake/api.o \
|
||||
font_layout/font_layout.o \
|
||||
font_layout/api.o
|
||||
|
||||
module.wasm: $(PNG_OBJ)
|
||||
clang++ $(CFLAGS) $(LDFLAGS) -o $@ $^
|
||||
|
||||
@ -18,6 +18,7 @@ struct ViewState {
|
||||
XMFLOAT4X4 lightViewProj;
|
||||
XMFLOAT4 lightPosition;
|
||||
XMFLOAT4 eyePosition;
|
||||
float aspect;
|
||||
};
|
||||
|
||||
static inline XMMATRIX camera_view(CameraState const * state)
|
||||
@ -150,4 +151,5 @@ void camera_view_projection(CameraState * camera_state,
|
||||
XMStoreFloat4(&view_state->lightPosition, light_position);
|
||||
XMVECTOR eye = XMLoadFloat3(&camera_state->eye);
|
||||
XMStoreFloat4(&view_state->eyePosition, eye);
|
||||
view_state->aspect = aspect;
|
||||
}
|
||||
|
||||
@ -28,5 +28,4 @@ namespace fluid
|
||||
velocity.y *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
extern "C" {
|
||||
size_t mem_size();
|
||||
size_t mem_alloc(size_t length);
|
||||
|
||||
48
src/snake/api.cpp
Normal file
48
src/snake/api.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
#include "new.h"
|
||||
#include "bone_system.h"
|
||||
|
||||
using namespace snake;
|
||||
|
||||
extern "C" {
|
||||
void logStrInt(char const * s, int a);
|
||||
|
||||
BoneSystem * bone_system__create(int boneCount, float boneLength)
|
||||
{
|
||||
BoneSystem * system = New<BoneSystem>();
|
||||
system->init(boneCount, boneLength);
|
||||
|
||||
return system;
|
||||
}
|
||||
|
||||
int bone_system__bones_size(int boneCount)
|
||||
{
|
||||
return boneCount * (sizeof (Bone));
|
||||
}
|
||||
|
||||
int bone_system__configuration_size()
|
||||
{
|
||||
return (sizeof (BoneConfiguration));
|
||||
}
|
||||
|
||||
int bone_system__configuration_offset()
|
||||
{
|
||||
return (offsetof (BoneSystem, configuration));
|
||||
}
|
||||
|
||||
void bone_system__update(BoneSystem * bone_system, float x, float y, float z)
|
||||
{
|
||||
bone_system->update(x, y, z);
|
||||
}
|
||||
|
||||
void bone_system__update_configuration(BoneSystem * bone_system,
|
||||
int boneCount,
|
||||
float boneLength,
|
||||
float velocityDamping,
|
||||
float velocityAcceleration)
|
||||
{
|
||||
bone_system->configuration.boneCount = boneCount;
|
||||
bone_system->configuration.boneLength = boneLength;
|
||||
bone_system->configuration.velocityDamping = velocityDamping;
|
||||
bone_system->configuration.velocityAcceleration = velocityAcceleration;
|
||||
}
|
||||
};
|
||||
41
src/snake/bone.cpp
Normal file
41
src/snake/bone.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
#include "bone.h"
|
||||
|
||||
namespace snake {
|
||||
extern "C" void logStrInt(char const * s, float a);
|
||||
|
||||
// assumes ray does intersect with sphere
|
||||
static inline XMVECTOR intersectRaySphere(XMVECTOR rayPosition, XMVECTOR rayDirection,
|
||||
XMVECTOR sphereCenter, float sphereRadius)
|
||||
{
|
||||
XMVECTOR m = rayPosition - sphereCenter;
|
||||
float b = XMVectorGetX(XMVector3Dot(m, rayDirection));
|
||||
float c = XMVectorGetX(XMVector3Dot(m, m)) - sphereRadius * sphereRadius;
|
||||
float discriminant = b * b - c;
|
||||
float t = -b - sqrtf(discriminant);
|
||||
return rayPosition + t * rayDirection;
|
||||
}
|
||||
|
||||
void Bone::update(Bone const * parent, BoneConfiguration const * configuration)
|
||||
{
|
||||
XMVECTOR parentPosition = XMLoadFloat4(&parent->position);
|
||||
XMVECTOR position = XMLoadFloat4(&this->position);
|
||||
XMVECTOR velocity = XMLoadFloat4(&this->velocity);
|
||||
|
||||
|
||||
position += velocity;
|
||||
velocity *= configuration->velocityDamping;
|
||||
|
||||
|
||||
XMVECTOR direction = parentPosition - position;
|
||||
XMVECTOR normal = XMVector3Normalize(direction);
|
||||
|
||||
XMVECTOR newPosition = intersectRaySphere(position, normal,
|
||||
parentPosition, configuration->boneLength);
|
||||
|
||||
XMVECTOR force = newPosition - position;
|
||||
velocity += force * configuration->velocityAcceleration;
|
||||
|
||||
XMStoreFloat4(&this->position, newPosition);
|
||||
XMStoreFloat4(&this->velocity, velocity);
|
||||
}
|
||||
}
|
||||
13
src/snake/bone.h
Normal file
13
src/snake/bone.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "directxmath/DirectXMath.h"
|
||||
#include "bone_configuration.h"
|
||||
|
||||
namespace snake {
|
||||
struct Bone {
|
||||
XMFLOAT4 position;
|
||||
XMFLOAT4 velocity;
|
||||
|
||||
void update(Bone const * parent, BoneConfiguration const * configuration);
|
||||
};
|
||||
}
|
||||
10
src/snake/bone_configuration.h
Normal file
10
src/snake/bone_configuration.h
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
namespace snake {
|
||||
struct BoneConfiguration {
|
||||
float boneCount;
|
||||
float boneLength;
|
||||
float velocityDamping;
|
||||
float velocityAcceleration;
|
||||
};
|
||||
}
|
||||
35
src/snake/bone_system.cpp
Normal file
35
src/snake/bone_system.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
#include "new.h"
|
||||
#include "bone_system.h"
|
||||
|
||||
namespace snake {
|
||||
void BoneSystem::init(int maxBones, float boneLength)
|
||||
{
|
||||
this->maxBones = maxBones;
|
||||
|
||||
configuration.boneCount = maxBones;
|
||||
configuration.boneLength = boneLength;
|
||||
configuration.velocityDamping = 0.0;
|
||||
configuration.velocityAcceleration = 0.0;
|
||||
|
||||
bones = New<Bone>(maxBones);
|
||||
|
||||
XMVECTOR direction = XMVectorSet(0, 1, 0, 0);
|
||||
for (int i = 0; i < maxBones; i++) {
|
||||
XMStoreFloat4(&bones[i].position, direction * boneLength * i);
|
||||
XMStoreFloat4(&bones[i].velocity, XMVectorZero());
|
||||
}
|
||||
}
|
||||
|
||||
void BoneSystem::update(float x, float y, float z)
|
||||
{
|
||||
bones[0].position.x = x;
|
||||
bones[0].position.y = y;
|
||||
bones[0].position.z = z;
|
||||
|
||||
for (int i = 1; i < configuration.boneCount; i++) {
|
||||
Bone const * parent = &bones[i - 1];
|
||||
Bone * bone = &bones[i];
|
||||
bone->update(parent, &configuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
15
src/snake/bone_system.h
Normal file
15
src/snake/bone_system.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "bone.h"
|
||||
#include "bone_configuration.h"
|
||||
|
||||
namespace snake {
|
||||
struct BoneSystem {
|
||||
Bone * bones;
|
||||
int maxBones;
|
||||
BoneConfiguration configuration;
|
||||
|
||||
void init(int maxBones, float boneLength);
|
||||
void update(float x, float y, float z);
|
||||
};
|
||||
}
|
||||
5
src/snake/configuration.cpp
Normal file
5
src/snake/configuration.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
namespace snake {
|
||||
struct BoneConfiguration {
|
||||
float boneLength;
|
||||
};
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user