{"id":17266,"date":"2026-09-17T12:27:31","date_gmt":"2026-09-17T03:27:31","guid":{"rendered":"http:\/\/www.gisdeveloper.co.kr\/?p=17266"},"modified":"2026-09-17T13:34:05","modified_gmt":"2026-09-17T04:34:05","slug":"three-js-webgpu%ec%97%90%ec%84%9c-%ec%a7%80%ec%98%a4%eb%a9%94%ed%8a%b8%eb%a6%ac%eb%a5%bc-%ea%b5%ac%ec%84%b1%ed%95%98%eb%8a%94-%ec%a2%8c%ed%91%9c%ec%97%90-%ed%8c%8c%ed%8b%b0%ed%81%b4-%eb%b0%b0","status":"publish","type":"post","link":"http:\/\/www.gisdeveloper.co.kr\/?p=17266","title":{"rendered":"three.js, WebGPU\uc5d0\uc11c \uc9c0\uc624\uba54\ud2b8\ub9ac\ub97c \uad6c\uc131\ud558\ub294 \uc88c\ud45c\uc5d0 \ud30c\ud2f0\ud074 \ubc30\uce58\ud558\uae30"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.gisdeveloper.co.kr\/wp-content\/uploads\/2026\/09\/webgpu_particles.png\" alt=\"\" width=\"1748\" height=\"938\" class=\"aligncenter size-full wp-image-17267\" \/><\/p>\n<p>\uc704\uc758 \uacb0\uacfc\ub97c \uc704\ud574\uc11c 3\uac00\uc9c0 \ubc29\uc2dd\uc774 \uc788\uc2b5\ub2c8\ub2e4. \uccab\ubc88\uc9f8\ub294 &#8230;<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"javascript\">\r\nprivate setupModel() {\r\n  const knotGeometry = new THREE.TorusKnotGeometry(1, 0.3, 256, 64);\r\n  const positionAttribute = knotGeometry.attributes.position;\r\n  const count = positionAttribute.count;\r\n\r\n  const instancePositions = new Float32Array(count * 3);\r\n  for (let i = 0; i < count; i++) {\r\n    instancePositions[i * 3] = positionAttribute.getX(i);\r\n    instancePositions[i * 3 + 1] = positionAttribute.getY(i);\r\n    instancePositions[i * 3 + 2] = positionAttribute.getZ(i);\r\n  }\r\n\r\n  const spriteMaterial = new THREE.SpriteNodeMaterial({\r\n    transparent: true,\r\n    depthWrite: false,\r\n    blending: THREE.AdditiveBlending\r\n  });\r\n\r\n  const dist = uv().distance(vec2(0.5, 0.5));\r\n  const alphaNode = dist.smoothstep(0.5, 0.0);\r\n\r\n  spriteMaterial.colorNode = color(0xff0000);\r\n  spriteMaterial.opacityNode = alphaNode;\r\n\r\n  const instancePositionNode = instancedBufferAttribute(\r\n    new THREE.InstancedBufferAttribute(instancePositions, 3)\r\n  );\r\n\r\n  spriteMaterial.positionNode = instancePositionNode;\r\n  spriteMaterial.scaleNode = vec2(.05);\r\n\r\n  \/\/ const spriteGeometry = new THREE.PlaneGeometry(0.08, 0.08);\r\n  \/\/ const instancedSprites = new THREE.Mesh(spriteGeometry, spriteMaterial);\r\n  const instancedSprites = new THREE.Sprite(spriteMaterial); \/\/ \uc0c1\uae30 \ucf54\ub4dc\uc640 \ub3d9\uc77c\r\n  instancedSprites.count = count;\r\n\r\n  this.scene.add(instancedSprites);\r\n}\r\n<\/pre>\n<p>\ub450\ubc88\uc9f8 \ubc29\uc2dd\uc740 ...<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"javascript\">\r\nprivate setupModel() {\r\n  const knotGeometry = new THREE.TorusKnotGeometry(1, 0.3, 256, 64);\r\n  const positionAttribute = knotGeometry.attributes.position;\r\n  const count = positionAttribute.count; \/\/ \uc815\uc810 \uac1c\uc218\r\n\r\n  const spriteMaterial = new THREE.SpriteNodeMaterial({\r\n    transparent: true,\r\n    depthWrite: false,\r\n    blending: THREE.AdditiveBlending\r\n  });\r\n\r\n  const dist = uv().distance(vec2(0.5, 0.5));\r\n  const alphaNode = dist.smoothstep(0.5, 0.0);\r\n\r\n  spriteMaterial.colorNode = color(0xff0000);\r\n  spriteMaterial.opacityNode = alphaNode;\r\n  spriteMaterial.vertexNode = billboarding({\r\n    horizontal: true,\r\n    vertical: true,\r\n    horizontalRotation: false\r\n  });\r\n\r\n  const spriteGeometry = new THREE.PlaneGeometry(0.05, 0.05);\r\n  const instancedSprites = new THREE.InstancedMesh(spriteGeometry, spriteMaterial, count);\r\n\r\n  const dummy = new THREE.Object3D();\r\n  const vertex = new THREE.Vector3();\r\n\r\n  for (let i = 0; i < count; i++) {\r\n    vertex.fromBufferAttribute(positionAttribute, i);\r\n\r\n    dummy.position.copy(vertex);\r\n    dummy.updateMatrix();\r\n\r\n    instancedSprites.setMatrixAt(i, dummy.matrix);\r\n  }\r\n  instancedSprites.instanceMatrix.needsUpdate = true;\r\n\r\n  this.scene.add(instancedSprites);\r\n}\r\n<\/pre>\n<p>\uc138\ubc88\uc9f8 \ubc29\uc2dd\uc740 \ub2e4\uc74c\uacfc \uac19\uc2b5\ub2c8\ub2e4.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"javascript\">\r\nprivate setupModel() {\r\n  const knotGeometry = new THREE.TorusKnotGeometry(1, 0.3, 256, 64);\r\n  const positionAttr = knotGeometry.attributes.position;\r\n  const count = positionAttr.count;\r\n\r\n  const positionArray = new Float32Array(count * 3);\r\n  for (let i = 0; i < count; i++) {\r\n    positionArray[i * 3] = positionAttr.getX(i);\r\n    positionArray[i * 3 + 1] = positionAttr.getY(i);\r\n    positionArray[i * 3 + 2] = positionAttr.getZ(i);\r\n  }\r\n\r\n  const positionStorageBuffer = new THREE.StorageBufferAttribute(positionArray, 3);\r\n  const positionStorageNode = storage(positionStorageBuffer, 'vec3', count);\r\n\r\n  const spriteMaterial = new THREE.SpriteNodeMaterial({\r\n    transparent: true,\r\n    depthWrite: false,\r\n    blending: THREE.AdditiveBlending\r\n  });\r\n\r\n  const dist = uv().distance(vec2(0.5, 0.5));\r\n  const alphaNode = dist.smoothstep(0.5, 0.0);\r\n\r\n  spriteMaterial.colorNode = color(0xff0000);\r\n  spriteMaterial.opacityNode = alphaNode;\r\n\r\n  spriteMaterial.positionNode = positionStorageNode.element(THREE.TSL.instanceIndex);\r\n\r\n  const spriteGeometry = new THREE.PlaneGeometry(0.08, 0.08);\r\n  const instancedSprites = new THREE.Mesh(spriteGeometry, spriteMaterial);\r\n\r\n  instancedSprites.count = count;\r\n\r\n  this.scene.add(instancedSprites);\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>\uc704\uc758 \uacb0\uacfc\ub97c \uc704\ud574\uc11c 3\uac00\uc9c0 \ubc29\uc2dd\uc774 \uc788\uc2b5\ub2c8\ub2e4. \uccab\ubc88\uc9f8\ub294 &#8230; private setupModel() { const knotGeometry = new THREE.TorusKnotGeometry(1, 0.3, 256, 64); const positionAttribute = knotGeometry.attributes.position; const count = positionAttribute.count; const instancePositions = new Float32Array(count * 3); for (let i = 0; i < count; i++) { instancePositions[i * 3] = positionAttribute.getX(i); instancePositions[i * 3 + 1] = &hellip; \n\n<p class=\"link-more\"><a href=\"http:\/\/www.gisdeveloper.co.kr\/?p=17266\" class=\"more-link\">\ub354 \ubcf4\uae30<span class=\"screen-reader-text\"> &#8220;three.js, WebGPU\uc5d0\uc11c \uc9c0\uc624\uba54\ud2b8\ub9ac\ub97c \uad6c\uc131\ud558\ub294 \uc88c\ud45c\uc5d0 \ud30c\ud2f0\ud074 \ubc30\uce58\ud558\uae30&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[153,145,1],"tags":[],"class_list":["post-17266","post","type-post","status-publish","format-standard","hentry","category-shader","category-three-js","category-uncategorized"],"_links":{"self":[{"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=\/wp\/v2\/posts\/17266","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=17266"}],"version-history":[{"count":5,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=\/wp\/v2\/posts\/17266\/revisions"}],"predecessor-version":[{"id":17271,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=\/wp\/v2\/posts\/17266\/revisions\/17271"}],"wp:attachment":[{"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=17266"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=17266"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.gisdeveloper.co.kr\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=17266"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}