自重による一軸伸長(ヤング率・ポアソン比依存性)
前回は弾性体全体に同じ応力が発生する一軸伸長を考えたね。単一の応力で表現することができるってことは、「微小体積=弾性体全体」と考えることができるので、単一の歪テンソルと応力テンソルで変形と応力を計算することができたね。今回は、位置によって応力が変化する例として、弾性体の自重による変形を考えるよ。この変形に対する歪テンソルと応力テンソルは次のとおりだね(ヤング率:$${Y}$$、ポアソン比$${\sigma}$$)。
$$
E=\left(\begin{matrix} - \frac {\sigma \rho g (L+z)}{Y} & 0 & 0\cr 0 & - \frac {\sigma \rho g (L+z)}{Y} & 0\cr 0 & 0 & \frac {\rho g(L+z) }{Y} \end{matrix} \right) \ \leftrightarrow \ P=\left(\begin{matrix} 0 & 0 & 0\cr 0 & 0 & 0\cr 0 & 0 & \rho g (L+z) \end{matrix} \right)
$$
$${\rho}$$は体積密度、$${L}$$は弾性体の長さ、$${g}$$は重力加速度で、$${z}$$は$$ 0 \sim -L$$の負の値を取ることを想定しているよ。今回のように弾性体のz座標値によって伸びが異なる場合、微小変形
$$
\boldsymbol{r}^{\prime} =\boldsymbol{r} + \delta \boldsymbol{r} = \boldsymbol{r} +D \delta \boldsymbol{x}
$$
で変形後の座標を計算することができないね。なので改めて座標変換行列$$R(z)$$を用意して、
$$
\boldsymbol{r}^{\prime} =\boldsymbol{r} + R(z)\, \delta \boldsymbol{x}
$$
で変形後の座標を計算するよ。今回z軸方向の一軸伸長を考えるので、$$Dzz$$成分のみ$${z}$$で積分して変換後の$${z}$$座標値を$${z’}$$とすると
$$
z'(z) = z+\int_0^{z} \left( \frac {\rho g(L+z) }{Y} \right)dz = z+\frac {\rho g }{Y}\, (Lz+\frac{1}{2}\,z^2)
$$
となるね。これを用いて変換行列$${ R(z)}$$の成分$$R_{zz}$$は、$${z’}$$から$${z}$$を引き算したあとに$${z}$$で割ればよいので、最終体には
$$
R=\left(\begin{matrix}- \frac {\sigma \rho g (L+z)}{Y} & 0 & 0\cr 0 & - \frac {\sigma \rho g (L+z)}{Y} & 0\cr 0 & 0 & \frac {\rho g(L+\frac{1}{2}\,z) }{Y} \end{matrix} \right)
$$
となるね。これを用いて3次元グラフィクスを作ってみたよ。下図はヤング率$${Y}$$とポアソン比$${\sigma}$$による弾性体の変形を計算した結果だよ。ヤング率が小さいほど自重で伸び、ポアソン比が大きいほどz軸方向の伸びに対するその他の方向の縮み幅が大きくなるね。
今回の計算は上面を固定する効果は加えていないのでちょっと不自然だね。今後の課題とするね。
Javascriptプログラムソース
Javascriptプログラムソースを用意したよ。もし良かったら試してみてください。これからも応援よろしくお願いしまーす!
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>一軸伸長(自重あり)</title>
<script src="https://natural-science.or.jp/files/physics/UV_Grid_Sm.js"></script>
<script id="MathJax-script" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
<style>
*{padding:0px; margin:0px}
div#canvas-frame{
width: 900px; /* 横幅 */
height: 900px; /* 縦幅 */
overflow:hidden;
}
table.matrix input{
width: 30px;
}
section#field{
padding: 10px 20px;
border: 1px solid gray;
border-radius: 10px;
margin: 10px 10px;
width: 850px;
}
</style>
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three@0.168.0/build/three.module.js",
"three/addons/": "https://unpkg.com/three@0.168.0/examples/jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { TrackballControls } from 'three/addons/controls/TrackballControls.js';
//変位テンソルの初期化
let R = [
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]
]
//ヤング率
let Y;
//ポアソン比
let sigma;
//
let Lz = 1.0;
let g = 10;
let rho = 1.0;
//変位テンソルの設定
function setR( r, R ){
let x = r[0], y = r[1], z = r[2];
R[0][0] = -sigma * rho * g / Y * ( z + Lz );
R[0][1] = 0;
R[0][2] = 0;
R[1][0] = 0;
R[1][1] = -sigma * rho * g / Y * ( z + Lz );
R[1][2] = 0;
R[2][0] = 0.0;
R[2][1] = 0.0;
R[2][2] = rho * g / Y * ( 1.0 / 2.0 * z + Lz) ;
}
//変位テンソルによる変位計算
function Deformation( D, r ){
let x = D[ 0 ][ 0 ] * r[ 0 ] + D[ 0 ][ 1 ] * r[ 1 ] + D[ 0 ][ 2 ] * r[ 2 ];
let y = D[ 1 ][ 0 ] * r[ 0 ] + D[ 1 ][ 1 ] * r[ 1 ] + D[ 1 ][ 2 ] * r[ 2 ];
let z = D[ 2 ][ 0 ] * r[ 0 ] + D[ 2 ][ 1 ] * r[ 1 ] + D[ 2 ][ 2 ] * r[ 2 ];
return [ x, y, z ];
}
//格子点座標の初期値
let initialPositionArray = [ ]
////////////////////////////////////////////////////////////////////
// windowイベントの定義
////////////////////////////////////////////////////////////////////
window.addEventListener("load", function () {
threeStart(); //Three.jsのスタート関数の実行
});
////////////////////////////////////////////////////////////////////
// Three.jsスタート関数の定義
////////////////////////////////////////////////////////////////////
function threeStart() {
initThree(); //Three.js初期化関数の実行
initLight(); //光源初期化関数の実行
initObject(); //オブジェクト初期化関数の実行
initCamera(); //カメラ初期化関数の実行
loop(); //無限ループ関数の実行
}
////////////////////////////////////////////////////////////////////
// Three.js初期化関数の定義
////////////////////////////////////////////////////////////////////
//グローバル変数の宣言
let renderer, //レンダラーオブジェクト
scene, //シーンオブジェクト
canvasFrame; //キャンバスフレームのDOM要素
function initThree() {
//キャンバスフレームDOM要素の取得
canvasFrame = document.getElementById('canvas-frame');
//レンダラーオブジェクトの生成
renderer = new THREE.WebGLRenderer({ antialias: true });
if (!renderer) alert('Three.js の初期化に失敗しました');
//レンダラーのサイズの設定
renderer.setSize(canvasFrame.clientWidth, canvasFrame.clientHeight);
//キャンバスフレームDOM要素にcanvas要素を追加
canvasFrame.appendChild(renderer.domElement);
//レンダラークリアーカラーの設定
renderer.setClearColor(0xEEEEEE, 1.0);
//シーンオブジェクトの生成
scene = new THREE.Scene();
}
////////////////////////////////////////////////////////////////////
// カメラ初期化関数の定義
////////////////////////////////////////////////////////////////////
//グローバル変数の宣言
let camera; //カメラオブジェクト
let trackball;
function initCamera() {
//カメラオブジェクトの生成
camera = new THREE.PerspectiveCamera(35, canvasFrame.clientWidth / canvasFrame.clientHeight, 1, 10000);
//カメラの位置の設定
camera.position.set(4, 4, 0.8);
//カメラの上ベクトルの設定
camera.up.set(0, 0, 1);
//カメラの中心位置ベクトルの設定
camera.lookAt(new THREE.Vector3(0,0,0)); //トラックボール利用時は自動的に無効
//トラックボールオブジェクトの宣言
trackball = new TrackballControls(camera, canvasFrame);
//トラックボール動作範囲のサイズとオフセットの設定
trackball.screen.width = canvasFrame.clientWidth; //横幅
trackball.screen.height = canvasFrame.clientHeight; //縦幅
trackball.screen.offsetLeft = canvasFrame.getBoundingClientRect().left; //左オフセット
trackball.screen.offsetTop = canvasFrame.getBoundingClientRect().top; //右オフセット
//トラックボールの回転無効化と回転速度の設定
trackball.noRotate = false;
trackball.rotateSpeed = 2.0;
//トラックボールの拡大無効化と拡大速度の設定
trackball.noZoom = false;
trackball.zoomSpeed = 4.0;
//トラックボールのカメラ中心移動の無効化と中心速度の設定
trackball.noPan = false;
trackball.panSpeed = 1.0;
trackball.target = new THREE.Vector3(0, 0, 0);
//トラックボールのスタティックムーブの有効化
trackball.staticMoving = true;
//トラックボールのダイナミックムーブ時の減衰定数
trackball.dynamicDampingFactor = 0.3;
}
////////////////////////////////////////////////////////////////////
// 光源初期化関数の定義
////////////////////////////////////////////////////////////////////
//グローバル変数の宣言
let directionalLight, //平行光源オブジェクト
ambientLight; //環境光オブジェクト
function initLight() {
//平行光源オブジェクトの生成
directionalLight = new THREE.DirectionalLight(0xffffff, 2.0, 0);
//平行光源オブジェクトの位置の設定
directionalLight.position.set(50, 50, 10);
//平行光源オブジェクトの影の生成元
directionalLight.castShadow = false;
//平行光源オブジェクトのシーンへの追加
scene.add(directionalLight);
//環境光オブジェクトの生成
ambientLight = new THREE.AmbientLight(0x666666);
//環境光オブジェクトのシーンへの追加
scene.add(ambientLight);
}
////////////////////////////////////////////////////////////////////
// オブジェクト初期化関数の定義
////////////////////////////////////////////////////////////////////
let box, sphere;
function initObject() {
//スカイドームの生成
let skydome = createSkydome();
//床オブジェクトをシーンへ追加
scene.add( skydome );
//img要素の生成
let img = new Image();
img.src = UV_Grid_Sm; //DataURL
let texture = new THREE.Texture( img );
texture.needsUpdate = true;
//カラースペースの指定
texture.colorSpace = THREE.SRGBColorSpace;
let L = 1.0;
//形状オブジェクトの宣言と生成
let geometry = new THREE.BoxGeometry(
L, //width:x軸方向の幅(デフォルト:1.0)
L, //height:y軸方向の幅(デフォルト:1.0)
Lz, //depth:z軸方向の幅(デフォルト:1.0)
1, //widthSegments:x軸方向の分割数(デフォルト:1)
1, //heightSegments:y軸方向の分割数(デフォルト:1)
100 //depthSegments:z軸方向の分割数(デフォルト:1)
);
//材質オブジェクトの宣言と生成
let material = new THREE.MeshPhongMaterial({ map: texture, color: 0xffffff, specular: 0xffffff, shininess: 200 });
//直方体オブジェクトの生成
box = new THREE.Mesh(geometry, material);
//直方体オブジェクトのシーンへの追加
scene.add(box);
//直方体オブジェクトの位置座標を設定
box.position.set(0, 0, Lz*1.2);
for(let i = 0; i < box.geometry.attributes.position.array.length/3; i++){
box.geometry.attributes.position.array[ 3 * i + 0 ] += 0;
box.geometry.attributes.position.array[ 3 * i + 1 ] += 0;
box.geometry.attributes.position.array[ 3 * i + 2 ] -= Lz/2;
}
for(let i = 0; i < box.geometry.attributes.position.array.length; i++){
initialPositionArray.push( box.geometry.attributes.position.array[i] );
}
let roof = new THREE.Mesh(
new THREE.BoxGeometry(3,3,0.02),
new THREE.MeshPhongMaterial({ color: 0x00ffff, specular: 0xffffff, shininess: 200 })
)
roof.position.set(0, 0, Lz*1.2);
scene.add( roof );
}
////////////////////////////////////////////////////////////////////
// 無限ループ関数の定義
////////////////////////////////////////////////////////////////////
//グローバル変数の宣言
let step = 0; //ステップ数
function loop() {
//トラックボールによるカメラオブジェクトのプロパティの更新
trackball.update();
Y = 13 + 10 * Math.cos( 2 * Math.PI * (step%300) / 300 );
sigma = ( step % 1500 ) / 1500 * 0.22;
for(let i = 0; i < box.geometry.attributes.position.array.length/3; i++){
let x = initialPositionArray[ 3 * i + 0 ];
let y = initialPositionArray[ 3 * i + 1 ];
let z = initialPositionArray[ 3 * i + 2 ];
let dx = [x, y, z];
setR( dx, R );
let dr = Deformation( R, dx );
box.geometry.attributes.position.array[ 3 * i + 0 ] = dx[ 0 ] + dr[ 0 ];
box.geometry.attributes.position.array[ 3 * i + 1 ] = dx[ 1 ] + dr[ 1 ];
box.geometry.attributes.position.array[ 3 * i + 2 ] = dx[ 2 ] + dr[ 2 ];
}
box.geometry.attributes.position.needsUpdate = true;
box.geometry.computeVertexNormals();
step ++;
//レンダリング
renderer.render(scene, camera);
//「loop()」関数の呼び出し
requestAnimationFrame(loop);
}
//スカイドーム生成関数
function createSkydome(){
let vertexShader = "//バーテックスシェーダー\n" +
"//頂点シェーダーからフラグメントシェーダーへの転送する変数\n" +
"varying vec3 vWorldPosition;\n" +
"void main( ) {\n" +
" //ワールド座標系における頂点座標\n" +
" vec4 worldPosition = modelMatrix * vec4( position, 1.0 );\n" +
" vWorldPosition = worldPosition.xyz;\n" +
" gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n" +
"}\n";
let fragmentShader = "//フラグメントシェーダ―\n" +
"//カスタムuniform変数の取得\n" +
"uniform vec3 topColor; //ドーム頂点色\n" +
"uniform vec3 bottomColor; //ドーム底辺色\n" +
"uniform float exp; //減衰指数\n" +
"uniform float offset; //高さ基準点\n" +
"//バーテックスシェーダーから転送された変数\n" +
"varying vec3 vWorldPosition;\n" +
"void main( ) {\n" +
" //高さの取得\n" +
" float h = normalize( vWorldPosition + vec3(0, 0, offset) ).z;\n" +
" if( h < 0.0) h = 0.0;\n" +
" gl_FragColor = vec4( mix( bottomColor, topColor, pow(h, exp) ), 1.0 );\n" +
"}\n";
//形状オブジェクトの宣言と生成
let geometry = new THREE.SphereGeometry( 500, 100, 100);
let uniforms = {
topColor: { type: "c", value: new THREE.Color(0.0, 0.3, 1.0) },
bottomColor: { type: "c", value: new THREE.Color(1.0, 1.0, 1.0)},
exp:{ type: "f", value : 0.8},
offset:{ type: "f", value : 300}
};
//材質オブジェクトの宣言と生成
let material = new THREE.ShaderMaterial( {
vertexShader: vertexShader,
fragmentShader: fragmentShader,
uniforms : uniforms,
side: THREE.BackSide,
} );
return new THREE.Mesh( geometry, material);
}
</script>
</head>
<body>
<section id="field">
<div style="font-size: 16pt; padding: 10px 5px 0px 5px; float: left;">
\( E=\left(\matrix{ - \frac {\sigma \rho g (L+z)}{Y} & 0 & 0\cr 0 & - \frac {\sigma \rho g (L+z)}{Y} & 0\cr 0 & 0 & \frac {\rho g(L+z) }{Y} } \right) \ \leftrightarrow \ P=\left(\matrix{ 0 & 0 & 0\cr 0 & 0 & 0\cr 0 & 0 & \rho g (L+z) } \right) \)
</div>
<br style="clear:both;">
</section>
<div id="canvas-frame"></div><!-- canvas要素を配置するdiv要素 -->
</body>
</html>