Hi,
I feel that tentacles thingy appealing and gived a try to an approach with animated polylines and quadratic bezier curves. Probably worse than bones but it has been fun laugh



I use the tentacles skills to store an array of vectors that serve as polyline.

Code:
void tentacleInit(ENTITY *entTentacle) {
	c_setminmax(entTentacle);
	entTentacle->skill99 = floatv(entTentacle->max_x / 8.5); // section length
	int _i = 0;
	for (; _i<9; _i+=1) {
		entTentacle->skill[_i*3] = 50 - _i * 4;
		entTentacle->skill[1+_i*3] = 0;
		entTentacle->skill[2+_i*3] = 0;
		vec_set(&entTentacle->skill[30 + _i * 3], &entTentacle->skill[_i * 3]);
	}
	entTentacle->material = mtl_create();
	effect_load(entTentacle->material, "tentacle.fx");
	entTentacle->material->flags |= ENABLE_TREE;
	entTentacle->material->event = evnTentacle;
}



Those vectors are processed and passes to the material each frame.

Code:
void evnTentacle () {
	float fSpline[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
	fSpline[0] = -0.5 * my->skill[0];
	fSpline[1] = -0.5 * my->skill[2]; // swapped X & Z axes
	fSpline[2] = -0.5 * my->skill[1];
	int _i = 1;
	for(; _i<10; _i+=1) {
		fSpline[_i*3] = fSpline[-3+_i*3];
		fSpline[1+_i*3] = fSpline[-2+_i*3];
		fSpline[2+_i*3] = fSpline[-1+_i*3];
		fSpline[_i*3] += (float)my->skill[-3+_i*3];
		fSpline[1+_i*3] += (float)my->skill[-1+_i*3]; // swapped X & Z axes
		fSpline[2+_i*3] += (float)my->skill[-2+_i*3];
	}
	LPD3DXEFFECT fx1 = my->material->d3deffect;
	if (fx1) {
		fx1->SetValue("fSpline", fSpline, 30 * sizeof(float));
		fx1->SetValue("fStep", &my->skill99, sizeof(var));
	}
}



I presented a tentacle along the X axe so I assign the mesh into the polyline according to its position in length.

Code:
float3 fSpline[10];
float fStep;

float3 doSpline(in float depth, out float3 vTangent) {
	depth = max(depth - fStep * 0.5f, 0);
	float index = floor(depth / fStep);
	float factor = fmod(depth, fStep) / fStep;
	float3 v1 = lerp(fSpline[index], fSpline[index+1], 0.5);
	float3 v1b = lerp(v1, fSpline[index+1], factor);
	float3 v2 = lerp(fSpline[index+1], fSpline[index+2], 0.5);
	float3 v2b = lerp(fSpline[index+1], v2, factor);
	vTangent = normalize(v2b - v1b);
	return lerp(v1b, v2b, factor);
}



I use the returned tangent in order to rotate (not really) transverse sections.

Code:
void VS (
	in float4 inPos: POSITION,
	out float4 outPos: POSITION,
	out float3 outNormal: TEXCOORD0) {
		float3 vTangent = 0;
		float3 vPos = doSpline(inPos.x, vTangent);
		outPos.x = vPos.x - vTangent.y * inPos.y - vTangent.z * inPos.z;
		outPos.y = vPos.y + inPos.y;
		outPos.z = vPos.z + inPos.z;
		outPos.w = 1.0f;
		outNormal = normalize(mul(outPos.xyz - vPos, (float3x3)matWorld));
		outPos = mul(outPos, matWorldViewProj);
	}



This simplification needs the tangent to be smaller than 45 degrees from the X axe, so the tentacles has to point, more or less, to the front. Otherway it looks wrong.

Logaritmic distribution of angular speeds and segment lengths beside a single step of forward inverse kinematic make the random animation look pretty soft and natural.

Code:
void tentacleAnimate (ENTITY *entTentacle) {
	int _i = 0;
	for(; _i<9; _i+=1) {
		VECTOR vOff;
		vec_diff(&vOff, &entTentacle->skill[30+_i*3], &entTentacle->skill[_i*3]);
		var _length = 2 * time_step / (9 - _i);
		if (vec_length(&vOff) < _length) {
			entTentacle->skill[30+_i*3] = 10;
			entTentacle->skill[31+_i*3] = random(10+_i*10) - (_i+1)*5;
			entTentacle->skill[32+_i*3] = random(10+_i*10) - (_i+1)*5;
			vec_normalize(&entTentacle->skill[30+_i*3], 50 - _i * 4);
		} else {
			vec_normalize(&vOff, _length);
		}
		vec_add(&entTentacle->skill[_i*3], &vOff);
		vec_sub(&entTentacle->skill[(_i+1)*3], &vOff); // forward inverse kinematic
	}
}



Salud!